diff --git a/configure.py b/configure.py index 8d54384d..469d9363 100644 --- a/configure.py +++ b/configure.py @@ -1099,7 +1099,7 @@ config.libs = [ Object(Matching, "actor/npc/ac_hatumode_npc0.c"), Object(NonMatching, "actor/npc/ac_kamakura_npc0.c"), Object(NonMatching, "actor/npc/ac_normal_npc.c"), - Object(NonMatching, "actor/npc/ac_npc.c"), + Object(Matching, "actor/npc/ac_npc.c"), Object(NonMatching, "actor/npc/ac_npc2.c"), Object(Matching, "actor/npc/ac_npc_conv_master.c"), Object(Matching, "actor/npc/ac_npc_curator.c"), diff --git a/include/ac_ball.h b/include/ac_ball.h index 75bcdd4d..91fd1b0d 100644 --- a/include/ac_ball.h +++ b/include/ac_ball.h @@ -8,6 +8,12 @@ extern "C" { #endif +#define aBALL_STATE_DEAD (1 << 0) +#define aBALL_STATE_IN_HOLE (1 << 1) +#define aBALL_STATE_PLAYER_HIT_SCOOP (1 << 2) +#define aBALL_STATE_PLAYER_HIT_AXE (1 << 3) + + typedef void (*BALL_PROCESS_PROC)(ACTOR*, GAME*); typedef struct actor_ball_s { @@ -27,7 +33,7 @@ typedef struct actor_ball_s { s16 unk1FE; s_xyz angle; s16 unk206; - s16 unk208; + s16 state_flags; s16 unk20A; s16 unk20C; } BALL_ACTOR; @@ -39,4 +45,3 @@ extern ACTOR_PROFILE Ball_Profile; #endif #endif - diff --git a/include/ac_gyoei_h.h b/include/ac_gyoei_h.h index 9ac84f3d..6c49ce7b 100644 --- a/include/ac_gyoei_h.h +++ b/include/ac_gyoei_h.h @@ -22,7 +22,7 @@ typedef void (*aGYO_dt_proc)(ACTOR*, GAME*); typedef void (*aGYO_ballcheck_proc)(xyz_t*, f32, s16); typedef void (*aGYO_hitcheck_proc)(xyz_t*, s16); typedef int (*aGYO_chk_live_proc)(int, int, GAME*); -typedef int (*aGYO_search_near_proc)(f32, f32); +typedef ACTOR* (*aGYO_search_near_proc)(f32, f32); /* sizeof(aGYO_Clip_c) == 0x1C */ typedef struct ac_gyoei_clip_s { diff --git a/include/ac_npc.h b/include/ac_npc.h index 27138397..922ba313 100644 --- a/include/ac_npc.h +++ b/include/ac_npc.h @@ -57,6 +57,60 @@ enum { aNPC_JOINT_NUM }; +enum { + aNPC_ANIM_SPEED_TYPE_LOCKED, + aNPC_ANIM_SPEED_TYPE_FREE, + + aNPC_ANIM_SPEED_TYPE_NUM +}; + +enum { + aNPC_SUB_ANIM_NONE, + aNPC_SUB_ANIM_UMBRELLA, + aNPC_SUB_ANIM_UTIWA, // paper fan + aNPC_SUB_ANIM_TUE, // Tortimer's cane + + aNPC_SUB_ANIM_NUM +}; + +enum { + aNPC_TEX_ANIM_EYE, + aNPC_TEX_ANIM_MOUTH, + + aNPC_TEX_ANIM_NUM +}; + +enum { + aNPC_CHN_BASE_TYPE_RELATIVE, + aNPC_CHN_BASE_TYPE_WORLD, + + aNPC_CHN_BASE_TYPE_NUM +}; + +enum { + aNPC_CLOTH_IDX_NONE, + aNPC_CLOTH_IDX0, + aNPC_CLOTH_IDX1, + aNPC_CLOTH_IDX2, + aNPC_CLOTH_IDX3, + aNPC_CLOTH_IDX4, + aNPC_CLOTH_IDX5, + aNPC_CLOTH_IDX6, + aNPC_CLOTH_IDX7, + aNPC_CLOTH_IDX8, + aNPC_CLOTH_IDX9, + aNPC_CLOTH_IDX_ORG, + + aNPC_CLOTH_IDX_NUM +}; + +enum { + aNPC_MASK_CAT_TYPE_NONE, + aNPC_MASK_CAT_TYPE_MASKCAT, + + aNPC_MASK_CAT_TYPE_NUM +}; + typedef struct ac_npc_clip_s aNPC_Clip_c; #define aNPC_EYE_TEX_NUM 8 @@ -104,7 +158,7 @@ enum { enum { aNPC_THINK_WAIT, aNPC_THINK_WANDER, - aNPC_THINK_WANDER2, + aNPC_THINK_WALK_WANDER, aNPC_THINK_GO_HOME, aNPC_THINK_INTO_HOUSE, aNPC_THINK_LEAVE_HOUSE, @@ -131,6 +185,17 @@ enum { aNPC_THINK_PROC_NUM }; +enum { + aNPC_CT_SCHED_TYPE_NONE, + aNPC_CT_SCHED_TYPE_NORMAL, + aNPC_CT_SCHED_TYPE_STAND, + aNPC_CT_SCHED_TYPE_WANDER, + aNPC_CT_SCHED_TYPE_WALK_WANDER, + aNPC_CT_SCHED_TYPE_SPECIAL, + + aNPC_CT_SCHED_TYPE_NUM +}; + typedef void (*aNPC_TALK_REQUEST_PROC)(ACTOR*, GAME*); typedef int (*aNPC_TALK_INIT_PROC)(ACTOR*, GAME*); typedef int (*aNPC_TALK_END_CHECK_PROC)(ACTOR*, GAME*); @@ -138,14 +203,34 @@ typedef int (*aNPC_TALK_END_CHECK_PROC)(ACTOR*, GAME*); typedef struct npc_ct_data_s { mActor_proc move_proc; mActor_proc draw_proc; - int _08; + int sched_type; aNPC_TALK_REQUEST_PROC talk_request_proc; aNPC_TALK_INIT_PROC talk_init_proc; aNPC_TALK_END_CHECK_PROC talk_end_check_proc; int _18; } aNPC_ct_data_c; +enum { + aNPC_ATT_TYPE_NONE, + aNPC_ATT_TYPE_ACTOR, + aNPC_ATT_TYPE_POS, + + aNPC_ATT_TYPE_NUM +}; + +typedef struct npc_attention_s { + u8 type; + ACTOR* actor; + xyz_t pos; +} aNPC_attention_c; + +typedef struct npc_overlay_s { + u8* buf; + int used; +} aNPC_overlay_c; + typedef int (*aNPC_SETUP_ACTOR_PROC)(GAME_PLAY*, mActor_name_t, s8, int, s16, int, int, int, int); +typedef void (*aNPC_GET_OVERLAY_AREA_PROC)(ACTOR_DLFTBL*, u8*, size_t, mActor_name_t); typedef void (*aNPC_DMA_DRAW_DATA_PROC)(aNPC_draw_data_c*, mActor_name_t); typedef void (*aNPC_FREE_OVERLAY_AREA_PROC)(ACTOR_DLFTBL*); typedef ACTOR* (*aNPC_GET_ACTOR_AREA_PROC)(size_t, const char*, int); @@ -163,22 +248,31 @@ typedef void (*aNPC_DRAW_PROC)(ACTOR*, GAME*); typedef void (*aNPC_SET_DST_POS_PROC)(NPC_ACTOR*, f32, f32); typedef void (*aNPC_REBUILD_DMA_PROC)(); +typedef int (*aNPC_SET_REQUEST_ACT_PROC)(NPC_ACTOR* nactorx, u8 priority, u8 act_idx, u8 act_type, u16* arg_data); +typedef int (*aNPC_SET_HEAD_REQUEST_PROC)(NPC_ACTOR* nactorx, u8 priority, u8 type, ACTOR* target_actor, xyz_t* target_pos); typedef void (*aNPC_TALK_DEMO_PROC)(ACTOR*); typedef void (*aNPC_ANIMATION_INIT_PROC)(ACTOR*, int, int); typedef void (*aNPC_CHG_SCHEDULE_PROC)(NPC_ACTOR*, GAME_PLAY*, u8); typedef int (*aNPC_CLIP_THINK_PROC)(NPC_ACTOR*, GAME_PLAY*, int, int); - typedef int (*aNPC_FORCE_CALL_REQ_PROC)(NPC_ACTOR*, int); +typedef void (*aNPC_SET_START_POS_PROC)(ACTOR* actorx); struct ac_npc_clip_s { /* 0x000 */ aNPC_SETUP_ACTOR_PROC setupActor_proc; - /* 0x004 */ void* _004; + /* 0x004 */ aNPC_GET_OVERLAY_AREA_PROC get_overlay_area_proc; /* 0x008 */ aNPC_FREE_OVERLAY_AREA_PROC free_overlay_area_proc; /* 0x00C */ aNPC_GET_ACTOR_AREA_PROC get_actor_area_proc; /* 0x010 */ aNPC_FREE_ACTOR_AREA_PROC free_actor_area_proc; /* 0x014 */ aNPC_DMA_DRAW_DATA_PROC dma_draw_data_proc; /* 0x018 */ aNPC_SET_ATTENTION_REQUEST_PROC set_attention_request_proc; - /* 0x01C */ void* _01C[(0x0CC - 0x01C) / sizeof(void*)]; + /* 0x01C */ NPC_ACTOR* keep_actors[9]; + /* 0x040 */ int keep_actor_used[9]; + /* 0x064 */ aNPC_overlay_c keep_n_overlay[1]; + /* 0x06C */ aNPC_overlay_c keep_s_overlay[2]; + /* 0x07C */ aNPC_overlay_c keep_k_overlay[3]; + /* 0x094 */ aNPC_overlay_c keep_e_overlay[2]; + /* 0x0A4 */ aNPC_attention_c attention_request; + /* 0x0B8 */ aNPC_attention_c attention; /* 0x0CC */ aNPC_BIRTH_CHECK_PROC birth_check_proc; /* 0x0D0 */ aNPC_CT_PROC ct_proc; /* 0x0D4 */ aNPC_DT_PROC dt_proc; @@ -191,14 +285,16 @@ struct ac_npc_clip_s { /* 0x0F0 */ void* _0F0; /* 0x0F4 */ aNPC_DRAW_PROC draw_proc; /* 0x0F8 */ aNPC_REBUILD_DMA_PROC rebuild_dma_proc; - /* 0x0FC */ void* _0FC[(0x110 - 0x0FC) / sizeof(void*)]; + /* 0x0FC */ void* _0FC[(0x108 - 0x0FC) / sizeof(void*)]; + /* 0x108 */ aNPC_SET_REQUEST_ACT_PROC set_request_act_proc; + /* 0x10C */ aNPC_SET_HEAD_REQUEST_PROC set_head_request_act_proc; /* 0x110 */ aNPC_TALK_DEMO_PROC talk_demo_proc; /* 0x114 */ aNPC_ANIMATION_INIT_PROC animation_init_proc; /* 0x118 */ aNPC_CHG_SCHEDULE_PROC chg_schedule_proc; /* 0x11C */ aNPC_SET_DST_POS_PROC set_dst_pos_proc; /* 0x120 */ aNPC_CLIP_THINK_PROC think_proc; /* 0x124 */ aNPC_FORCE_CALL_REQ_PROC force_call_req_proc; - /* 0x128 */ void* _128; + /* 0x128 */ aNPC_SET_START_POS_PROC set_start_pos_proc; }; typedef struct npc_info_s { @@ -218,7 +314,51 @@ typedef struct npc_animation_s { s8 animation_id; } aNPC_ANIMATION_c; -/* TODO: draw data */ +typedef struct { + int num_check_frames; + int* check_frame_tbl; +} aNPC_se_data_c; + +enum { + aNPC_OTHER_SE_TYPE_NONE, + aNPC_OTHER_SE_TYPE1, + + aNPC_OTHER_SE_TYPE_NUM +}; + +typedef struct { + aNPC_se_data_c se_data; + u16 se_no; +} aNPC_other_se_data_c; + +#define aNPC_OTHER_SE_NUM 3 + +typedef struct { + aNPC_se_data_c lfoot; + aNPC_se_data_c rfoot; + int other_se_type; + aNPC_other_se_data_c other_se[aNPC_OTHER_SE_NUM]; +} aNPC_se_c; + +typedef struct { + u8 seq_type; + u8 last_seq_type; + u8 seq_pattern; + u8 seq_counter; + u8 pattern; + f32 pattern_counter; + s8 pattern_stop_idx; + u8 loop_counter; + u8* fixed_pattern_seq; +} aNPC_tex_anim_c; + +typedef struct { + s16 feel_type; + u8 max; + u8 set_num; + u8* set_p; +} aNPC_feel_effect_c; + typedef struct npc_draw_info_s { /* 0x000 */ int main_animation_frame; /* 0x004 */ int main_animation_state; @@ -228,39 +368,51 @@ typedef struct npc_draw_info_s { /* 0x014 */ aNPC_ANIMATION_c main_animation; /* 0x1D0 */ aNPC_ANIMATION_c sub_animation0; /* 0x38C */ aNPC_ANIMATION_c sub_animation1; - /* 0x548 */ u8 _548[0x580 - 0x548]; + /* 0x548 */ aNPC_se_c se; /* 0x580 */ int animation_id; /* 0x584 */ int texture_bank_idx; - /* 0x588 */ u8 _588[0x5B0 - 0x588]; + /* 0x588 */ aNPC_tex_anim_c tex_anim[aNPC_TEX_ANIM_NUM]; // eye -> mouth /* 0x5B0 */ u8 draw_type; - /* 0x5B1 */ u8 _5B1; - /* 0x5B2 */ u8 _5B2; - /* 0x5B3 */ u8 _5B3; - /* 0x5B4 */ u8 _5B4; - /* 0x5B5 */ u8 _5B5; - /* 0x5B6 */ u8 _5B6; - /* 0x5B7 */ u8 _5B7; - /* 0x5B8 */ u8 _5B8; - /* 0x5B9 */ u8 _5B9; - /* 0x5BA */ u8 _5BA; - /* 0x5BB */ u8 _5BB; - /* 0x5BC */ u8 _5BC; - /* 0x5BD */ u8 _5BD; - /* 0x5BE */ u8 _5BE; - /* 0x5BE */ u8 _5BF[0x5D0 - 0x5BF]; - /* 0x5D0 */ f32 animation_speed; - /* 0x5D4 */ u8 _5D4[0x5D8 - 0x5D4]; + /* 0x5B1 */ u8 cloth_change_step; + /* 0x5B2 */ mActor_name_t next_cloth_no; + /* 0x5B4 */ mActor_name_t cloth_no; + /* 0x5B6 */ u8 next_org_idx; + /* 0x5B7 */ u8 org_idx; + /* 0x5B8 */ s8 cloth_idx; + /* 0x5B9 */ u8 chn_base_type; + /* 0x5BA */ u16 _5BA; + /* 0x5BC */ u8 umb_state; + /* 0x5BD */ u8 sub_anim_type; + /* 0x5BE */ u8 anim_speed_type; + /* 0x5BF */ u8 loop_flag; + /* 0x5C0 */ s16 effect_pattern; + /* 0x5C2 */ s16 effect_type; + /* 0x5C4 */ aNPC_feel_effect_c* feel_effect; + /* 0x5C8 */ f32 feel_effect_counter; + /* 0x5CC */ s16 shape_bank; + /* 0x5CE */ s16 tex_bank; + /* 0x5D0 */ f32 frame_speed; + /* 0x5D4 */ f32 frame_sub_speed; /* 0x5D8 */ xyz_t shadow_pos; - /* 0x5E4 */ u8 _5E4[0x630 - 0x5E4]; + /* 0x5E4 */ aNPC_draw_tex_data_c draw_tex_data; } aNPC_draw_info_c; typedef void (*aNPC_THINK_PROC)(NPC_ACTOR*, GAME_PLAY*, int); #define aNPC_THINK_INTERRUPT_FRIENDSHIP (1 << 0) #define aNPC_THINK_INTERRUPT_FATIGUE (1 << 1) -#define aNPC_THINK_INTERRUPT_OBSTANCE (1 << 2) +#define aNPC_THINK_INTERRUPT_OBSTACLE (1 << 2) #define aNPC_THINK_INTERRUPT_ENTRANCE (1 << 3) +enum { + aNPC_FORCE_CALL_NONE, + aNPC_FORCE_CALL_REQUEST, + aNPC_FORCE_CALL_SET, + aNPC_FORCE_CALL_START, + + aNPC_FORCE_CALL_NUM +}; + /* sizeof(aNPC_think_info_c) == 0x18 */ typedef struct npc_think_info_s { /* 0x00 */ int idx; @@ -277,7 +429,7 @@ typedef void (*aNPC_SCHEDULE_PROC)(NPC_ACTOR*, GAME_PLAY*, int); typedef struct npc_schedule_info_s { u8 type; - u8 state; + u8 step; mNPS_schedule_c schedule; aNPC_SCHEDULE_PROC schedule_proc; } aNPC_schedule_info_c; @@ -289,6 +441,7 @@ enum { aNPC_ACT_OBJ_TARGET_NPC, aNPC_ACT_OBJ_4, aNPC_ACT_OBJ_5, + aNPC_ACT_OBJ_BALL, aNPC_ACT_OBJ_INSECT, aNPC_ACT_OBJ_FISH, @@ -304,14 +457,16 @@ enum { aNPC_ACT_TYPE_NUM }; +#define aNPC_ACT_NONE 0xFF + enum { aNPC_ACT_WAIT, aNPC_ACT_WALK, - aNPC_ACT_WALK2, + aNPC_ACT_RUN, aNPC_ACT_TURN, aNPC_ACT_TURN2, aNPC_ACT_CHASE_INSECT, - aNPC_ACT_CHASE_INSECT2, + aNPC_ACT_CHASE_GYOEI, aNPC_ACT_GREETING, aNPC_ACT_TALK, aNPC_ACT_INTO_HOUSE, @@ -324,7 +479,7 @@ enum { aNPC_ACT_CLAP, aNPC_ACT_TRANS, aNPC_ACT_GET, - aNPC_ACT_GET2, + aNPC_ACT_CHANGE_CLOTH, aNPC_ACT_PITFALL, aNPC_ACT_REVIVE, aNPC_ACT_SPECIAL, @@ -332,6 +487,76 @@ enum { aNPC_ACT_NUM }; +enum { + aNPC_ACTION_PROC_TYPE_INIT, + aNPC_ACTION_PROC_TYPE_CHG_DATA, + aNPC_ACTION_PROC_TYPE_MAIN, + + aNPC_ACTION_PROC_TYPE_NUM +}; + +enum { + aNPC_ACTION_TYPE_WAIT, + aNPC_ACTION_TYPE_WAIT_KI, + aNPC_ACTION_TYPE_WAIT_DO, + aNPC_ACTION_TYPE_WAIT_AI, + aNPC_ACTION_TYPE_WAIT_NEMU, + aNPC_ACTION_TYPE_WALK, + aNPC_ACTION_TYPE_WALK_KI, + aNPC_ACTION_TYPE_WALK_DO, + aNPC_ACTION_TYPE_WALK_AI, + aNPC_ACTION_TYPE_RUN, + aNPC_ACTION_TYPE_RUN_KI, + aNPC_ACTION_TYPE_RUN_DO, + aNPC_ACTION_TYPE_RUN_AI, + aNPC_ACTION_TYPE_TURN, + aNPC_ACTION_TYPE_TURN2, + aNPC_ACTION_TYPE_PAL_WAIT, + aNPC_ACTION_TYPE_GREETING0, + aNPC_ACTION_TYPE_GREETING1, + aNPC_ACTION_TYPE_GREETING2, + aNPC_ACTION_TYPE_GREETING3, + aNPC_ACTION_TYPE_GURATUKU, + aNPC_ACTION_TYPE_OTIRU1, + aNPC_ACTION_TYPE_OTIRU2, + aNPC_ACTION_TYPE_MOGAKU, + aNPC_ACTION_TYPE_DERU1, + aNPC_ACTION_TYPE_DERU2, + aNPC_ACTION_TYPE_TALK_TURN, + aNPC_ACTION_TYPE_TALK, + aNPC_ACTION_TYPE_OPEN_DOOR, + aNPC_ACTION_TYPE_GO_OUT, + aNPC_ACTION_TYPE_UMB_OPEN, + aNPC_ACTION_TYPE_UMB_CLOSE, + aNPC_ACTION_TYPE_TRANSFER_MOVE, + aNPC_ACTION_TYPE_TRANSFER, + aNPC_ACTION_TYPE_TRANSFER_WAIT, + aNPC_ACTION_TYPE_TRANSFER_F, + aNPC_ACTION_TYPE_TRANSFER_F_WAIT, + aNPC_ACTION_TYPE_SEND_MAIL, + aNPC_ACTION_TYPE_GET_MOVE, + aNPC_ACTION_TYPE_GET, + aNPC_ACTION_TYPE_GET_PULL, + aNPC_ACTION_TYPE_GET_PULL_WAIT, + aNPC_ACTION_TYPE_GET_PUTAWAY, + aNPC_ACTION_TYPE_GET_EAT, + aNPC_ACTION_TYPE_GET_CHANGE, + aNPC_ACTION_TYPE_GET_RETURN, + aNPC_ACTION_TYPE_GET_F, + aNPC_ACTION_TYPE_GET_PULL_F, + aNPC_ACTION_TYPE_GET_PULL_WAIT_F, + aNPC_ACTION_TYPE_GET_PUTAWAY_F, + aNPC_ACTION_TYPE_GET_RETURN_F, + aNPC_ACTION_TYPE_ESTIMATE_F, + aNPC_ACTION_TYPE_ENSOU_E, + aNPC_ACTION_TYPE_WAIT_E, + aNPC_ACTION_TYPE_GYAFUN1, + aNPC_ACTION_TYPE_GYAFUN2, + aNPC_ACTION_TYPE_CLAP, + + aNPC_ACTION_TYPE_NUM +}; + typedef void (*aNPC_ACTION_PROC)(NPC_ACTOR*, GAME_PLAY*, int); #define aNPC_ACTION_END_STEP 0xFF @@ -341,9 +566,9 @@ typedef struct npc_action_s { u8 idx; u8 step; u8 type; - u8 prev_priority; + u8 prev_idx; u8 prev_step; - s16 act_timer; + u16 act_timer; u8 feel; u8 act_obj; u16 act_obj_id; @@ -384,6 +609,14 @@ typedef struct npc_request_s { #define aNPC_COND_DEMO_SKIP_FOOTSTEPS_VFX (1 << 14) /* 0x4000 */ #define aNPC_COND_DEMO_SKIP_UZAI_CHECK (1 << 15) /* 0x8000 */ +enum { + aNPC_ENTRANCE_TYPE_NONE, // not near any entrance + aNPC_ENTRANCE_TYPE_NEARBY, // near a house entrance + aNPC_ENTRANCE_TYPE_AT, // at a house entrance + + aNPC_ENTRANCE_TYPE_NUM +}; + typedef struct npc_condition_s { u8 hide_flg; u8 hide_request; @@ -413,11 +646,21 @@ typedef struct npc_condition_s { typedef struct npc_uzai_s { int step; - u8 counter; + u8 tool; u8 flag; u8 cross; } aNPC_uzai_c; +enum { + aNPC_ITEM_TYPE_NONE, + aNPC_ITEM_TYPE_UMBRELLA, + aNPC_ITEM_TYPE_KEITAI, + aNPC_ITEM_TYPE_PUTAWAY, + aNPC_ITEM_TYPE_LEFT_HAND, + + aNPC_ITEM_TYPE_NUM +}; + typedef struct npc_hand_s { u8 item_type; u8 requested_item_type; @@ -431,6 +674,14 @@ typedef struct npc_hand_s { xyz_t pos; } aNPC_hand_c; +enum { + aNPC_HEAD_TARGET_NONE, + aNPC_HEAD_TARGET_ACTOR, + aNPC_HEAD_TARGET_POS, + + aNPC_HEAD_TARGET_NUM +}; + typedef struct npc_head_s { s16 angle_x; s16 angle_y; @@ -450,12 +701,31 @@ enum { aNPC_FOOT_NUM }; -typedef struct npc_movement_s { +typedef struct npc_speed_s { f32 max_speed; f32 acceleration; f32 deceleration; - f32 target_pos_x; - f32 target_pos_z; +} aNPC_spd_c; + +enum { + aNPC_MOVE_RANGE_TYPE_BLOCK, + aNPC_MOVE_RANGE_TYPE_CIRCLE, + + aNPC_MOVE_RANGE_TYPE_NUM +}; + +enum { + aNPC_FRIENDSHIP_NORMAL, // default + aNPC_FRIENDSHIP_AVOID, // avoid player (hate player) + aNPC_FRIENDSHIP_SEARCH, // search for player (love player) + + aNPC_FRIENDSHIP_NUM +}; + +typedef struct npc_movement_s { + aNPC_spd_c speed; + f32 dst_pos_x; + f32 dst_pos_z; f32 avoid_pos_x; f32 avoid_pos_z; s16 move_timer; @@ -475,17 +745,49 @@ typedef struct npc_movement_s { u8 demo_move_timer; } aNPC_movement_c; +enum { + aNPC_BG_CHECK_TYPE_NONE, // no collision + aNPC_BG_CHECK_TYPE_ONLY_GROUND, // only ground collision + aNPC_BG_CHECK_TYPE_NORMAL, // standard + aNPC_BG_CHECK_TYPE_RANGE, // standard plus range + + aNPC_BG_CHECK_TYPE_NUM +}; + typedef struct npc_collision_s { ClObjPipe_c pipe; f32 BGcheck_radius; u8 collision_flag; - u8 priority; + u8 check_kind; u8 turn_flag; u16 _24; s16 turn_angle; f32 bg_rev_add; } aNPC_collision_c; +enum { + aNPC_TALK_TYPE_NONE, + aNPC_TALK_TYPE_START, + aNPC_TALK_TYPE_CONTINUE, + + aNPC_TALK_TYPE_NUM +}; + +enum { + aNPC_TALK_TURN_NORMAL, + aNPC_TALK_TURN_HEAD, + aNPC_TALK_TURN_NONE, + + aNPC_TALK_TURN_NUM +}; + +enum { + aNPC_MANPU_CODE_RESET_KEKE = 0xFD, + aNPC_MANPU_CODE_RESET_SIT = 0xFE, + aNPC_MANPU_CODE_RESET = 0xFF, + aNPC_MANPU_CODE_NONE = 0, +}; + typedef struct npc_actor_talk_info_s { aNPC_TALK_REQUEST_PROC talk_request_proc; aNPC_TALK_INIT_PROC talk_init_proc; @@ -525,6 +827,8 @@ enum { aNPC_SCHEDULE_TYPE_NUM }; +#define aNPC_SCHEDULE_NONE 0xFF + enum { aNPC_SCHEDULE_PROC_INIT, aNPC_SCHEDULE_PROC_MAIN, @@ -561,27 +865,41 @@ struct npc_actor_s { int _990; }; -typedef struct npc_control_cloth_s { - u8 dma_flag; - u8 init_flag; - s16 _02; - mActor_name_t cloth_item; - u8 in_use_count; - Object_Bank_c texture_bank; - Object_Bank_c palette_bank; -} aNPC_cloth_c; - -typedef struct npc_control_actor_s { - ACTOR* actor_class; - aNPC_cloth_c cloth[10]; - u8 _8F4[0x9D8 - 0x8F4]; // TODO -} NPC_CONTROL_ACTOR; - typedef struct npc_destruct_table_proc { aNPC_SUB_PROC unk0; aNPC_SUB_PROC unk4; } NPC_DT_PROCS; +typedef struct { + aNPC_se_data_c* lfoot_data; + aNPC_se_data_c* rfoot_data; + int other_se_type; + aNPC_other_se_data_c* other_se_data; +} aNPC_se_data_table_c; + +typedef struct { + cKF_Animation_R_c anim; + f32 start_frame; + f32 end_frame; + int mode; + f32 morph_counter; + u8* eye_seq_p; + s16 eye_seq_type; + s16 eye_seq_stop_frame; + u8* mouth_seq_p; + s16 mouth_seq_type; + s16 mouth_seq_stop_frame; + s16 feel_effect_set_frame; + s16 feel_effect_type; + aNPC_feel_effect_c* feel_effect; + aNPC_se_data_table_c* se_data_table; +} aNPC_Animation_c; + +typedef struct { + aNPC_Animation_c* anim_p; + int anim_idx; +} aNPC_anim_info_c; + extern ACTOR_PROFILE Npc_Profile; #ifdef __cplusplus diff --git a/include/ac_tools.h b/include/ac_tools.h index 7aca802a..61c031d7 100644 --- a/include/ac_tools.h +++ b/include/ac_tools.h @@ -90,8 +90,8 @@ typedef struct tools_s { /* 0x1C8 */ int work2; } TOOLS_ACTOR; -typedef ACTOR* (*ToolBirthProc)(int, int, ACTOR*, GAME*, s16, int*); -typedef int (*ToolChgRequestModeProc)(ACTOR*, ACTOR*, int); +typedef ACTOR* (*ToolBirthProc)(int kind, int mode, ACTOR* parent_actor, GAME* game, s16 arg, int* bank_id); +typedef int (*ToolChgRequestModeProc)(ACTOR* parent_actor, ACTOR* tool, int mode); typedef struct ToolClip { ToolBirthProc aTOL_birth_proc; diff --git a/include/audio.h b/include/audio.h index 34c4afba..d0cce542 100644 --- a/include/audio.h +++ b/include/audio.h @@ -62,8 +62,8 @@ extern void sAdo_SysTrgStart(u16 id); extern void sAdo_PlyWalkSe(u16 walk, const xyz_t* pos); extern void sAdo_PlyWalkSeRoom(u8 walk, const xyz_t* pos); -extern void sAdo_NpcWalkSe(int walk, const xyz_t* pos); -extern void sAdo_NpcWalkSeRoom(int walk, const xyz_t* pos); +extern void sAdo_NpcWalkSe(u16 se_no, const xyz_t* pos); +extern void sAdo_NpcWalkSeRoom(u16 se_no, const xyz_t* pos); extern void sAdo_PlayerStatusLevel(f32 speed, int p); diff --git a/include/audio_defs.h b/include/audio_defs.h index f0ac21bc..c7fd5dcb 100644 --- a/include/audio_defs.h +++ b/include/audio_defs.h @@ -40,12 +40,20 @@ typedef enum audio_sound_effects { NA_SE_SENTAKU_OPEN, NA_SE_SENTAKU_KETTEI, + NA_SE_TUMBLE_GRASS, + NA_SE_TUMBLE_SOIL, + NA_SE_TUMBLE_STONE, + NA_SE_TUMBLE_WOOD, + NA_SE_TUMBLE_BUSH, + NA_SE_TUMBLE_SNOW, + NA_SE_ZOOMDOWN_LONG = 0x15, NA_SE_LIGHT_ON, NA_SE_LIGHT_OFF, NA_SE_25 = 0x25, NA_SE_26 = 0x26, + NA_SE_27 = 0x27, NA_SE_2A = 0x2A, @@ -156,6 +164,9 @@ typedef enum audio_sound_effects { NA_SE_SOUND_KNOCK, + NA_SE_TUMBLE_SAND = 0x156, + NA_SE_TUMBLE_WAVE, + NA_SE_ARAIIKI_BOY = 0x158, NA_SE_ARAIIKI_GIRL = 0x15A, @@ -210,6 +221,8 @@ typedef enum audio_sound_effects { NA_SE_KARABURI = 0x43A, + NA_SE_43D = 0x43D, + NA_SE_ROD_STROKE_SMALL = 0x445, NA_SE_446 = 0x446, @@ -227,6 +240,19 @@ typedef enum audio_sound_effects { NA_SE_COIN_GASAGOSO = 0x465, + // Footsteps + NA_SE_FOOTSTEP_BEGIN = 0x4200, + NA_SE_FOOTSTEP_GRASS, + NA_SE_FOOTSTEP_SOIL, + NA_SE_FOOTSTEP_STONE, + NA_SE_FOOTSTEP_WOOD, + NA_SE_FOOTSTEP_BUSH, + NA_SE_FOOTSTEP_SNOW, + NA_SE_FOOTSTEP_7, + NA_SE_FOOTSTEP_SAND, + NA_SE_FOOTSTEP_WAVE, + NA_SE_FOOTSTEP_PLUSSBRIDGE, + } AudioSE; typedef enum bgm_e { diff --git a/include/jaudio_NES/game64.h b/include/jaudio_NES/game64.h index e92de74a..b94f8b29 100644 --- a/include/jaudio_NES/game64.h +++ b/include/jaudio_NES/game64.h @@ -16,8 +16,8 @@ extern void Na_BgmStop(u16); extern void Na_SysTrgStart(u16); extern void Na_PlyWalkSe(u16, u16, f32); extern void Na_PlyWalkSeRoom(u8, u16, f32); -extern void Na_NpcWalkSe(int, u16, f32); -extern void Na_NpcWalkSeRoom(int, u16, f32); +extern void Na_NpcWalkSe(u16, u16, f32); +extern void Na_NpcWalkSeRoom(u16, u16, f32); extern void Na_PlayerStatusLevel(f32, int); extern void Na_VoiceSe(u8, u8, u8, s16, u8, u8); extern void Na_MessageStatus(u8); diff --git a/include/m_collision_bg.h b/include/m_collision_bg.h index 4fd3647b..07766ae0 100644 --- a/include/m_collision_bg.h +++ b/include/m_collision_bg.h @@ -174,6 +174,7 @@ typedef struct collision_unit_info_s { mActor_name_t item; } mCoBG_UnitInfo_c; +#define mCoBG_DIDNT_HIT_WALL 0 #define mCoBG_HIT_WALL (1 << 0) /* in contact with *any* wall */ #define mCoBG_HIT_WALL_FRONT (1 << 1) /* in contact with wall to the front */ #define mCoBG_HIT_WALL_RIGHT (1 << 2) /* in contact with wall to the right */ @@ -183,13 +184,16 @@ typedef struct collision_unit_info_s { typedef struct collision_bg_check_result_s { u32 on_ground : 1; u32 hit_attribute_wall : 5; - u32 hit_wall : 5; + // + u32 hit_wall : 5; // 2 bits in prev byte u32 hit_wall_count : 3; u32 unk_flag0 : 1; - u32 unit_attribute : 6; + // + u32 unit_attribute : 6; // 1 bit in prev byte u32 is_on_move_bg_obj : 1; u32 is_in_water : 1; u32 unk_flag1 : 1; + // u32 unk_flag2 : 1; u32 unk_flag3 : 1; u32 unk_flag4 : 1; @@ -356,6 +360,8 @@ extern int mCoBG_CheckAcceptDesignSign(const xyz_t* pos_p); extern void mCoBG_VirtualBGCheck(xyz_t* rev_pos_p, mCoBG_Check_c* bg_check, const xyz_t* start_pos_p, const xyz_t* end_pos_p, s16 angle_y, s16 water_flag, s16 ground_flag, f32 range, f32 ground_dist, s16 attr_wall, s16 rev_type, s16 check_type); +extern f32 mCoBG_Wpos2GroundCheckOnly(const xyz_t* pos_p, f32 ground_dist); +extern int mCoBG_Wpos2CheckNpc(xyz_t wpos); typedef int (*mCoBG_LINECHECK_PROC)(mActor_name_t); @@ -370,6 +376,7 @@ extern int mCoBG_WoodSoundEffect(const xyz_t* pos_p); extern void mCoBG_InitMoveBgData(); extern void mCoBG_InitBlockBgCheckMode(); +extern void mCoBG_InitBgCheckResult(mCoBG_CheckResult_c* check_result); extern void mCoBG_InitDecalCircle(); extern void mCoBG_CalcTimerDecalCircle(); diff --git a/include/m_collision_obj.h b/include/m_collision_obj.h index 66255085..d3c463e8 100644 --- a/include/m_collision_obj.h +++ b/include/m_collision_obj.h @@ -18,6 +18,10 @@ enum collision_type { ClObj_TYPE_NUM }; +#define ClObj_FLAG_COLLIDED (1 << 1) + +#define ClObj_DID_COLLIDE(obj) ((obj).collision_flags0 & ClObj_FLAG_COLLIDED) + enum weight { MASS_IMMOVABLE, MASS_HEAVY, MASS_NORMAL }; #define MASSTYPE_IMMOVABLE 0xFF diff --git a/include/m_demo.h b/include/m_demo.h index 357bbd8d..60e671ab 100644 --- a/include/m_demo.h +++ b/include/m_demo.h @@ -207,6 +207,7 @@ extern int mDemo_Check_DiffAngle_forTalk(s16 diff_angle); extern void mDemo_KeepCamera(int camera_type); #define mDemo_CAN_ACTOR_TALK(actor) (!mDemo_Check(mDemo_TYPE_SPEAK, (actor)) && !mDemo_Check(mDemo_TYPE_TALK, (actor))) +#define mDemo_IS_ACTOR_TALKING(actor) (mDemo_Check(mDemo_TYPE_SPEAK, (actor)) == TRUE || mDemo_Check(mDemo_TYPE_TALK, (actor)) == TRUE) #ifdef __cplusplus } diff --git a/include/m_name_table.h b/include/m_name_table.h index ccb86e89..c9ad70c4 100644 --- a/include/m_name_table.h +++ b/include/m_name_table.h @@ -219,6 +219,7 @@ extern int mNT_check_unknown(mActor_name_t item_no); #define ITEM_IS_WISP(n) ((n) >= ITM_SPIRIT0 && (n) <= ITM_SPIRIT4) #define ITEM_IS_PAPER(n) ((n) >= ITM_PAPER_START && (n) <= (ITM_PAPER_END - 1)) #define ITEM_IS_CLOTH(n) ((n) >= ITM_CLOTH_START && (n) < ITM_CLOTH_END) +#define ITEM_IS_NPC_CLOTH(n) ((n) == RSV_CLOTH || ITEM_IS_CLOTH(n)) #define ITEM_IS_RSVCLOTH(n) ((n) >= RSV_CLOTH && (n) <= RSV_CLOTH7) #define ITEM_IS_RSVNWORG(n) ((n) >= RSV_NW_ORIGINAL0 && (n) <= RSV_NW_ORIGINAL7) @@ -532,6 +533,7 @@ extern int mNT_check_unknown(mActor_name_t item_no); #define ITEM_IS_PLAYER_HOUSE(item) ((item) >= HOUSE0 && (item) < (HOUSE3 + 1)) #define ITEM_IS_NPC_HOUSE(item) ((item) >= NPC_HOUSE_START && (item) < NPC_HOUSE_END) +#define ITEM_IS_DUMMY_NPC_HOUSE(item) ((item) >= DUMMY_NPC_HOUSE_START && (item) < (DUMMY_NPC_HOUSE_END + 1)) #define ITEM_IS_ISLAND_NPC_HOUSE(item) ((item) >= COTTAGE_NPC && (item) < COTTAGE_NPC_END) #define ITEM_IS_SIGNBOARD(item) ((item) >= SIGNBOARD_START && (item) <= SIGNBOARD_END) @@ -545,6 +547,7 @@ extern int mNT_check_unknown(mActor_name_t item_no); #define ITEM_IS_SCOOP(item) ((item) >= ITM_SHOVEL && (item) <= ITM_SHOVEL) #define ITEM_IS_GOLD_SCOOP(item) ((item) >= ITM_GOLDEN_SHOVEL && (item) <= ITM_GOLDEN_SHOVEL) #define ITEM_IS_PAINT(item) ((item) >= ITM_RED_PAINT && (item) <= ITM_BROWN_PAINT) +#define ITEM_IS_TOOL(item) ((item) >= ITM_TOOL_START && (item) < ITM_TOOL_END) #define BG_CATEGORY 0 #define ENV_CATEGORY 8 @@ -2715,11 +2718,11 @@ extern int mNT_check_unknown(mActor_name_t item_no); #define SP_NPC_NEEDLEWORK0 (SP_NPC_START + 112) // D070 #define SP_NPC_NEEDLEWORK1 (SP_NPC_START + 113) // D071 #define SP_NPC_SENDO (SP_NPC_START + 114) // D072 -// +#define SP_NPC_PRESENT_NPC (SP_NPC_START + 115) // D073 #define SP_NPC_EV_SONCHO2 (SP_NPC_START + 116) // D074 #define SP_NPC_MASK_CAT (SP_NPC_START + 117) // D075 #define SP_NPC_MASK_CAT2 (SP_NPC_START + 118) // D076 -// +#define SP_NPC_GO_HONE_NPC (SP_NPC_START + 119) // D077 #define SP_NPC_SONCHO_D078 (SP_NPC_START + 120) // D078 #define SP_NPC_SONCHO_D079 (SP_NPC_START + 121) // D079 #define SP_NPC_SASHO (SP_NPC_START + 122) // D07A @@ -3019,6 +3022,7 @@ extern int mNT_check_unknown(mActor_name_t item_no); #define NPC_END (NPC_START + 236) #define DUMMY_START 0xF000 +#define DUMMY_NPC_HOUSE_START (DUMMY_START + 5) // 0xF005 #define DUMMY_NPC_HOUSE_000 (DUMMY_START + 5) // F005 #define DUMMY_NPC_HOUSE_001 (DUMMY_START + 6) // F006 #define DUMMY_NPC_HOUSE_002 (DUMMY_START + 7) // F007 @@ -3257,6 +3261,7 @@ extern int mNT_check_unknown(mActor_name_t item_no); #define DUMMY_NPC_HOUSE_235 (DUMMY_START + 240) // F0F0 #define DUMMY_NPC_HOUSE_236 (DUMMY_START + 241) // F0F1 #define DUMMY_NPC_HOUSE_237 (DUMMY_START + 242) // F0F2 +#define DUMMY_NPC_HOUSE_END (DUMMY_START + 242) // F0F2 #define DUMMY_HOUSE0 0xF0F3 #define DUMMY_HOUSE1 0xF0F4 #define DUMMY_HOUSE2 0xF0F5 diff --git a/include/m_npc.h b/include/m_npc.h index 18b0b854..05710e88 100644 --- a/include/m_npc.h +++ b/include/m_npc.h @@ -14,6 +14,7 @@ #include "m_private_h.h" #include "m_field_make.h" #include "m_name_table.h" +#include "ac_npc_h.h" #ifdef __cplusplus extern "C" { @@ -217,7 +218,7 @@ typedef struct animal_s { /* 0x8EA */ u8 removing; /* TRUE when the villager is leaving town, FALSE otherwise */ /* 0x8EB */ u8 cloth_original_id; /* 0xFF when not wearing an Able Sister's pattern, otherwise 0-3 indicating which pattern */ - /* 0x8EC */ s8 umbrella_id; /* 0xFF when no umbrella, 0-31 when a standard umbrella, 32-35 when using an Able + /* 0x8EC */ u8 umbrella_id; /* 0xFF when no umbrella, 0-31 when a standard umbrella, 32-35 when using an Able Sister's pattern */ /* 0x8ED */ u8 unk_8ED; /* Exists according to mISL_gc_to_agb_animal, but seems unused in practice */ /* 0x8EE */ mActor_name_t @@ -371,7 +372,7 @@ extern int mNpc_GetPresentClothMemoryIdx_rnd(Anmmem_c* memory); extern int mNpc_CheckTalkPresentCloth(Animal_c* animal); extern void mNpc_ChangePresentCloth(); extern u8* mNpc_GetWordEnding(ACTOR* actor); -extern void mNpc_ResetWordEnding(ACTOR* actor); +extern void mNpc_ResetWordEnding(NPC_ACTOR* nactorx); extern int mNpc_GetFreeEventNpcIdx(); extern int mNpc_RegistEventNpc(mActor_name_t event_id, mActor_name_t texture_id, mActor_name_t npc_id, mActor_name_t cloth_id); diff --git a/include/m_npc_personal_id.h b/include/m_npc_personal_id.h index df7cd1dc..e756a386 100644 --- a/include/m_npc_personal_id.h +++ b/include/m_npc_personal_id.h @@ -10,12 +10,12 @@ extern "C" { #endif enum { - mNpc_LOOKS_GIRL, - mNpc_LOOKS_KO_GIRL, - mNpc_LOOKS_BOY, - mNpc_LOOKS_SPORT_MAN, - mNpc_LOOKS_GRIM_MAN, - mNpc_LOOKS_NANIWA_LADY, + mNpc_LOOKS_GIRL, // 'normal' + mNpc_LOOKS_KO_GIRL, // 'peppy' + mNpc_LOOKS_BOY, // 'lazy' + mNpc_LOOKS_SPORT_MAN, // 'jock' + mNpc_LOOKS_GRIM_MAN, // 'cranky' + mNpc_LOOKS_NANIWA_LADY, // 'snooty' mNpc_LOOKS_UNSET, mNpc_LOOKS_NUM = mNpc_LOOKS_UNSET diff --git a/include/m_npc_schedule_h.h b/include/m_npc_schedule_h.h index 5b23b728..46c39023 100644 --- a/include/m_npc_schedule_h.h +++ b/include/m_npc_schedule_h.h @@ -14,6 +14,7 @@ enum { mNPS_SCHED_SLEEP, /* asleep in their house */ mNPS_SCHED_STAND, /* standing around town?? */ mNPS_SCHED_WANDER, /* wander around town */ + mNPS_SCHED_WALK_WANDER, /* walk wander */ mNPS_SCHED_SPECIAL, /* unique schedule method for each NPC actor type */ mNPS_SCHED_TYPE_NUM diff --git a/include/m_scene.h b/include/m_scene.h index 2fe17195..04b9accf 100644 --- a/include/m_scene.h +++ b/include/m_scene.h @@ -56,6 +56,7 @@ typedef struct door_data_s { } Door_data_c; #define mSc_OBJECT_BANK_NUM 70 +#define mSC_BANK_NONE 0xFF typedef struct object_bank_s { s16 bank_id; diff --git a/include/types.h b/include/types.h index da3702ad..1731c885 100644 --- a/include/types.h +++ b/include/types.h @@ -89,6 +89,7 @@ typedef u32 unknown; #define BUTTON_A 0x8000 #define FRAMES_PER_SECOND 60 +#define FRAMES_PER_MINUTE (FRAMES_PER_SECOND * 60) #define ARRAY_SIZE(arr, type) (sizeof(arr) / sizeof(type)) #define ARRAY_COUNT(arr) (int)(sizeof(arr) / sizeof(arr[0])) diff --git a/src/actor/ac_ball.c b/src/actor/ac_ball.c index e4bfb823..65456eb3 100644 --- a/src/actor/ac_ball.c +++ b/src/actor/ac_ball.c @@ -161,7 +161,8 @@ static void aBALL_actor_ct(ACTOR* actor, GAME* game) { static void aBALL_actor_dt(ACTOR* actor, GAME* game) { BALL_ACTOR* ball = (BALL_ACTOR*)actor; - if ((ball->unk208 & 1) || (ball->unk208 & 2) || (mRlib_Set_Position_Check(actor) == 0)) { + if ((ball->state_flags & aBALL_STATE_DEAD) || (ball->state_flags & aBALL_STATE_IN_HOLE) || + (mRlib_Set_Position_Check(actor) == 0)) { Common_Set(ball_pos, ZeroVec); } else { Common_Set(ball_pos, actor->world.position); @@ -183,7 +184,7 @@ static void aBALL_position_move(BALL_ACTOR* actor) { chase_f(&actor->actor_class.speed, actor->ball_max_speed, actor->ball_acceleration); } - if (!(actor->unk208 & 2)) { + if (!(actor->state_flags & aBALL_STATE_IN_HOLE)) { mRlib_spdF_Angle_to_spdXZ(&actor->actor_class.position_speed, &actor->actor_class.speed, &actor->actor_class.world.angle.y); chase_f(&actor->actor_class.position_speed.y, actor->actor_class.max_velocity_y, actor->actor_class.gravity); @@ -243,7 +244,7 @@ static void aBALL_BGcheck(BALL_ACTOR* actor) { } } - if (actor->actor_class.bg_collision_check.result.hit_wall & 1) { + if (actor->actor_class.bg_collision_check.result.hit_wall & mCoBG_HIT_WALL) { hit_angle = mRlib_Get_HitWallAngleY(&actor->actor_class); rot = actor->actor_class.world.angle.y - (hit_angle + 0x8000); if (ABS(rot) < 0x4000) { @@ -290,15 +291,16 @@ static void aBALL_OBJcheck(BALL_ACTOR* actor, GAME*) { wade = mFI_GetPlayerWade(); - if (actor->ball_pipe.collision_obj.collision_flags0 & 2) { + if (ClObj_DID_COLLIDE(actor->ball_pipe.collision_obj)) { collided = actor->ball_pipe.collision_obj.collided_actor; - actor->ball_pipe.collision_obj.collision_flags0 &= ~2; + actor->ball_pipe.collision_obj.collision_flags0 &= ~ClObj_FLAG_COLLIDED; if (mQst_CheckSoccerTarget(collided) != 0) { mQst_NextSoccer(collided); actor->actor_class.speed = 0.0f; actor->actor_class.position_speed = ZeroVec; - } else if ((collided != NULL) && (!(actor->unk208 & 2)) && (wade != 1) && (wade != 2)) { + } else if ((collided != NULL) && (!(actor->state_flags & aBALL_STATE_IN_HOLE)) && (wade != mFI_WADE_START) && + (wade != mFI_WADE_INPROGRESS)) { if (actor->collider != collided) { pos_speed = collided->position_speed; actor->collider = collided; @@ -343,14 +345,14 @@ static void aBALL_OBJcheck(BALL_ACTOR* actor, GAME*) { actor->actor_class.world.angle.y = atans_table(newSpeedZ, newSpeedX); actor->actor_class.speed *= 0.9f; - sAdo_OngenTrgStartSpeed(actor->actor_class.speed, 0x25, &actor->actor_class.world.position); + sAdo_OngenTrgStartSpeed(actor->actor_class.speed, NA_SE_25, &actor->actor_class.world.position); actor->unk20C = GETREG(TAKREG, 15) + 30; } else { collision = actor->actor_class.status_data.collision_vec; xyz_t_add(&actor->actor_class.position_speed, &collision, &collisionSpeed); - if ((wade != 1) && (wade != 2)) { + if ((wade != mFI_WADE_START) && (wade != mFI_WADE_INPROGRESS)) { actor->actor_class.speed = sqrtf((collisionSpeed.x * collisionSpeed.x) + (collisionSpeed.z * collisionSpeed.z)); actor->actor_class.speed = CLAMP_MAX(actor->actor_class.speed, 11.0f); @@ -376,21 +378,20 @@ static void aBALL_OBJcheck(BALL_ACTOR* actor, GAME*) { static void aBALL_House_Tree_Rev_Check(BALL_ACTOR* actor) { if (mRlib_HeightGapCheck_And_ReversePos(&actor->actor_class) != 1) { - actor->unk208 |= 1; + actor->state_flags |= aBALL_STATE_DEAD; Actor_delete(&actor->actor_class); } } static void aBALL_process_air_init(ACTOR* actor, GAME* game) { BALL_ACTOR* ball = (BALL_ACTOR*)actor; + f32 bg_y; - f32 angle; + bg_y = mCoBG_GetBgY_AngleS_FromWpos(NULL, actor->world.position, 0.0f); + actor->shape_info.draw_shadow = TRUE; - angle = mCoBG_GetBgY_AngleS_FromWpos(NULL, actor->world.position, 0.0f); - actor->shape_info.draw_shadow = 1; - - if ((ball->process_proc == aBALL_process_ground) && ((actor->world.position.y - angle) > 20.0f)) { - sAdo_OngenTrgStart(0x43D, &actor->world.position); + if ((ball->process_proc == aBALL_process_ground) && ((actor->world.position.y - bg_y) > 20.0f)) { + sAdo_OngenTrgStart(NA_SE_43D, &actor->world.position); } ball->process_proc = aBALL_process_air; @@ -418,8 +419,7 @@ static void aBALL_process_air(ACTOR* actor, GAME* game) { static void aBALL_process_ground_init(ACTOR* actor, GAME* game) { BALL_ACTOR* ball = (BALL_ACTOR*)actor; - actor->shape_info.draw_shadow = 1; - + actor->shape_info.draw_shadow = TRUE; if (actor->position_speed.y > 0.0f) { ball->process_proc = aBALL_process_air; } else { @@ -461,7 +461,7 @@ static void aBALL_process_ground(ACTOR* actor, GAME* game) { if (speed_x < 1.0f) { speed_z = ABS(actor->position_speed.z); if (speed_z < 1.0f) { - ball->unk208 |= 2; + ball->state_flags |= aBALL_STATE_IN_HOLE; ball->ball_pipe.attribute.pipe.height = 20; ball->ball_pipe.attribute.pipe.radius = 18; actor->status_data.weight = MASSTYPE_HEAVY; @@ -513,8 +513,8 @@ static void aBALL_process_ground(ACTOR* actor, GAME* game) { effect_type = 0; } - Common_Get(clip).effect_clip->effect_make_proc(0x33, actor->world.position, 1, actor->world.angle.y, game, - actor->npc_id, 0, effect_type); + Common_Get(clip).effect_clip->effect_make_proc(eEC_EFFECT_BUSH_HAPPA, actor->world.position, 1, + actor->world.angle.y, game, actor->npc_id, 0, effect_type); } } } @@ -532,7 +532,7 @@ static void aBALL_set_spd_relations_in_water(ACTOR* actor, GAME* game) { int apply_angle; - height = mCoBG_GetWaterHeight_File(actor->world.position, "ac_ball.c", 0x361); + height = mCoBG_GetWaterHeight_File(actor->world.position, __FILE__, 0x361); add_calc0(&ball->ball_y, 0.5f, 100.0f); mCoBG_GetWaterFlow(&pos_flow, actor->bg_collision_check.result.unit_attribute); @@ -549,8 +549,8 @@ static void aBALL_set_spd_relations_in_water(ACTOR* actor, GAME* game) { if (ball->timer < 0x20) { if (!(game->frame_counter & 3) && (ball->timer < 0x10) || !(game->frame_counter & 7)) { - Common_Get(clip).effect_clip->effect_make_proc(0x45, actor->world.position, 1, actor->world.angle.y, game, - actor->npc_id, 1, 0); + Common_Get(clip).effect_clip->effect_make_proc(eEC_EFFECT_TURI_HAMON, actor->world.position, 1, + actor->world.angle.y, game, actor->npc_id, 1, 0); } ball->timer++; } @@ -686,24 +686,24 @@ static void aBALL_status_check(ACTOR* actor, GAME* game) { PLAYER_ACTOR* player2; int i; - if (ball->unk208 & 4) { + if (ball->state_flags & aBALL_STATE_PLAYER_HIT_SCOOP) { player = GET_PLAYER_ACTOR(play); - ball->unk208 &= ~4; + ball->state_flags &= ~aBALL_STATE_PLAYER_HIT_SCOOP; if (aBALL_player_angle_distance_check(actor, player) || F32_IS_ZERO(actor->speed)) { actor->world.angle.y = player->actor_class.shape_info.rotation.y; actor->speed = 2.0f; actor->position_speed.y = 4.5f; - if (ball->unk208 & 2) { + if (ball->state_flags & aBALL_STATE_IN_HOLE) { ball->ball_pipe.attribute.pipe.height = 30; ball->ball_pipe.attribute.pipe.radius = 13; - ball->unk208 &= ~2; + ball->state_flags &= ~aBALL_STATE_IN_HOLE; actor->status_data.weight = 0x64; } } } - if (ball->unk208 & 8) { - ball->unk208 &= ~8; - if (!(ball->unk208 & 2)) { + if (ball->state_flags & aBALL_STATE_PLAYER_HIT_AXE) { + ball->state_flags &= ~aBALL_STATE_PLAYER_HIT_AXE; + if (!(ball->state_flags & aBALL_STATE_IN_HOLE)) { player2 = GET_PLAYER_ACTOR(play); if (aBALL_player_angle_distance_check(actor, player2) || F32_IS_ZERO(actor->speed)) { actor->world.angle.y = player2->actor_class.shape_info.rotation.y + 0x2000; @@ -713,20 +713,21 @@ static void aBALL_status_check(ACTOR* actor, GAME* game) { } } - if (!(ball->unk208 & 1)) { + if (!(ball->state_flags & aBALL_STATE_DEAD)) { if (actor->bg_collision_check.result.is_in_water) { - sAdo_OngenTrgStart(0x27, &actor->world.position); - ball->unk208 |= 1; + sAdo_OngenTrgStart(NA_SE_27, &actor->world.position); + ball->state_flags |= aBALL_STATE_DEAD; if (Common_Get(clip).gyo_clip != NULL) { Common_Get(clip).gyo_clip->ballcheck_gyoei_proc(&actor->world.position, 20.0f, 0); } ball->ball_pipe.attribute.pipe.height = 10; - Common_Get(clip).effect_clip->effect_make_proc(0x3A, actor->world.position, 1, 0, game, actor->npc_id, 1, - 0); + Common_Get(clip).effect_clip->effect_make_proc(eEC_EFFECT_AMI_MIZU, actor->world.position, 1, 0, game, + actor->npc_id, 1, 0); for (i = 2; i < 6; i++) { - Common_Get(clip).effect_clip->effect_make_proc(0x3B, actor->world.position, 1, actor->world.angle.y, - game, actor->npc_id, 0, i | FTR1_START); + Common_Get(clip).effect_clip->effect_make_proc(eEC_EFFECT_MIZUTAMA, actor->world.position, 1, + actor->world.angle.y, game, actor->npc_id, 0, + i | 0x3000); } } } @@ -738,8 +739,8 @@ static void aBALL_actor_move(ACTOR* actor, GAME* game) { aBALL_House_Tree_Rev_Check(ball); - if (!(actor->state_bitfield & 0x40)) { - if (actor->bg_collision_check.result.is_in_water || (ball->unk208 & 2)) { + if (!(actor->state_bitfield & ACTOR_STATE_NO_CULL)) { + if (actor->bg_collision_check.result.is_in_water || (ball->state_flags & aBALL_STATE_IN_HOLE)) { Actor_delete(actor); } if (actor->speed == 0.0f) { diff --git a/src/actor/ac_hatumode_clip_think.c_inc b/src/actor/ac_hatumode_clip_think.c_inc index 878c7088..1fe980bd 100644 --- a/src/actor/ac_hatumode_clip_think.c_inc +++ b/src/actor/ac_hatumode_clip_think.c_inc @@ -22,7 +22,7 @@ static void aHN0_normal_wait_init(HATUMODE_NPC0_ACTOR* hatumode_npc, GAME_PLAY* } static void aHN0_move_init(HATUMODE_NPC0_ACTOR* hatumode_npc, GAME_PLAY* play) { - aHN0_set_request_act(hatumode_npc, 4, aNPC_ACT_WALK2, aNPC_ACT_TYPE_TO_POINT, aNPC_ACT_OBJ_DEFAULT, hatumode_npc->pos[0], hatumode_npc->pos[1]); + aHN0_set_request_act(hatumode_npc, 4, aNPC_ACT_RUN, aNPC_ACT_TYPE_TO_POINT, aNPC_ACT_OBJ_DEFAULT, hatumode_npc->pos[0], hatumode_npc->pos[1]); hatumode_npc->timer = 20; hatumode_npc->npc_class.actor_class.status_data.weight = MASSTYPE_HEAVY; } diff --git a/src/actor/ac_tools.c b/src/actor/ac_tools.c index 19660eb4..d624329d 100644 --- a/src/actor/ac_tools.c +++ b/src/actor/ac_tools.c @@ -53,7 +53,7 @@ static void aTOL_check_data_bank(int id, ACTOR* actor) { } } -static ACTOR* aTOL_birth_proc(int name, int id, ACTOR* tool, GAME* game, s16 arg, int* arg5) { +static ACTOR* aTOL_birth_proc(int kind, int mode, ACTOR* parent_actor, GAME* game, s16 arg, int* bank_id) { static s16 profile_table[] = { mAc_PROFILE_T_UMBRELLA, mAc_PROFILE_T_UMBRELLA, mAc_PROFILE_T_UMBRELLA, mAc_PROFILE_T_UMBRELLA, mAc_PROFILE_T_UMBRELLA, mAc_PROFILE_T_UMBRELLA, mAc_PROFILE_T_UMBRELLA, mAc_PROFILE_T_UMBRELLA, @@ -74,34 +74,35 @@ static ACTOR* aTOL_birth_proc(int name, int id, ACTOR* tool, GAME* game, s16 arg mAc_PROFILE_T_REI2, mAc_PROFILE_T_ZINNIA1, mAc_PROFILE_T_ZINNIA2, mAc_PROFILE_T_COBRA1, }; - TOOLS_ACTOR* child; + ACTOR* child; GAME_PLAY* play = (GAME_PLAY*)game; - aTOL_check_data_bank(name, tool); - - child = (TOOLS_ACTOR*)Actor_info_make_child_actor(&play->actor_info, tool, game, profile_table[name], 0.0f, 0.0f, + aTOL_check_data_bank(kind, parent_actor); + child = Actor_info_make_child_actor(&play->actor_info, parent_actor, game, profile_table[kind], 0.0f, 0.0f, 0.0f, 0, 0, 0, -1, 0, arg, -1); if (child != NULL) { - child->work0 = id; - child->tool_name = name; + TOOLS_ACTOR* tool = (TOOLS_ACTOR*)child; + + tool->work0 = mode; + tool->tool_name = kind; } - if (arg5 != NULL) { - *arg5 = -1; + if (bank_id != NULL) { + *bank_id = -1; } - return &child->actor_class; + return child; } -static int aTOL_chg_request_mode_proc(ACTOR* actor, ACTOR* tool, int id) { +static int aTOL_chg_request_mode_proc(ACTOR* actor, ACTOR* tool, int mode) { TOOLS_ACTOR* t_actor = (TOOLS_ACTOR*)tool; if (actor != tool->parent_actor) { return FALSE; } - t_actor->work0 = id; + t_actor->work0 = mode; return TRUE; } diff --git a/src/actor/npc/ac_hatumode_npc0.c b/src/actor/npc/ac_hatumode_npc0.c index 06bf0f4c..43c6dde5 100644 --- a/src/actor/npc/ac_hatumode_npc0.c +++ b/src/actor/npc/ac_hatumode_npc0.c @@ -72,7 +72,7 @@ static void aHN0_actor_ct(ACTOR* actorx, GAME* game) { actorx->cull_radius = 800.0f; } - h_npc->npc_class.collision.priority = 0; + h_npc->npc_class.collision.check_kind = aNPC_BG_CHECK_TYPE_NONE; actorx->world.position.y = mCoBG_GetBgY_OnlyCenter_FromWpos2(actorx->world.position, 0.0f); actorx->position_speed.y = 0.0f; actorx->gravity = 0.0f; diff --git a/src/actor/npc/ac_hatumode_npc0_schedule.c_inc b/src/actor/npc/ac_hatumode_npc0_schedule.c_inc index 205fdd76..5ee338ec 100644 --- a/src/actor/npc/ac_hatumode_npc0_schedule.c_inc +++ b/src/actor/npc/ac_hatumode_npc0_schedule.c_inc @@ -112,10 +112,10 @@ static void aHN0_move_bf(HATUMODE_NPC0_ACTOR* h_npc, GAME_PLAY* play) { } static void aHN0_move_wait(HATUMODE_NPC0_ACTOR* h_npc, GAME_PLAY* play) { - if (h_npc->npc_class.action.idx == aNPC_ACT_WALK2) { + if (h_npc->npc_class.action.idx == aNPC_ACT_RUN) { aHN0_setup_think_proc(h_npc, play, ++h_npc->think_idx); h_npc->npc_class.actor_class.status_data.weight = MASSTYPE_IMMOVABLE; - } else if ((s16)h_npc->npc_class.movement.target_pos_x != h_npc->pos[0] || (s16)h_npc->npc_class.movement.target_pos_z != h_npc->pos[1]) { + } else if ((s16)h_npc->npc_class.movement.dst_pos_x != h_npc->pos[0] || (s16)h_npc->npc_class.movement.dst_pos_z != h_npc->pos[1]) { h_npc->move_think_idx = h_npc->think_idx - 1; aHN0_setup_think_proc(h_npc, play, 33); } diff --git a/src/actor/npc/ac_npc.c b/src/actor/npc/ac_npc.c new file mode 100644 index 00000000..e7070939 --- /dev/null +++ b/src/actor/npc/ac_npc.c @@ -0,0 +1,127 @@ +#include "ac_npc.h" + +#include "libultra/libultra.h" +#include "m_common_data.h" +#include "m_player_lib.h" +#include "m_msg.h" +#include "ac_handOverItem.h" +#include "sys_matrix.h" +#include "m_rcp.h" +#include "jsyswrap.h" +#include "dolphin/os.h" +#include "ac_ev_ghost.h" +#include "ac_gyoei.h" +#include "m_melody.h" +#include "ac_ball.h" +#include "m_actor_shadow.h" + +extern aNPC_draw_data_c npc_draw_data_tbl[]; + +#define aNPC_CLOTH_TEX_SIZE ((32*32)/2) +#define aNPC_CLOTH_PAL_SIZE (16*sizeof(u16)) + +#define aNPC_GET_TYPE(npc) (ITEM_NAME_GET_TYPE((npc)->actor_class.npc_id)) +#define aNPC_IS_NRM_NPC(npc) (aNPC_GET_TYPE(npc) == NAME_TYPE_NPC) +#define aNPC_IS_SP_NPC(npc) (aNPC_GET_TYPE(npc) == NAME_TYPE_SPNPC) +#define aNPC_GET_ANM(npc) ((npc)->npc_info.animal) +#define aNPC_GET_LOOKS(npc) (aNPC_GET_ANM(npc)->id.looks) + +typedef struct npc_control_cloth_s { + /* 0x00 */ u8 dma_flag; + /* 0x01 */ u8 init_flag; + /* 0x02 */ s16 _02; + /* 0x04 */ mActor_name_t cloth_item; + /* 0x06 */ s8 in_use_count; + /* 0x07 */ u8 id; + /* 0x08 */ Object_Bank_c texture_bank; + /* 0x0A */ Object_Bank_c palette_bank; +} aNPC_cloth_c; + +typedef struct npc_control_talk_area_s { + u32 frame_counter; + ACTOR* talk_actor; + f32 radius; + xyz_t center_pos; +} aNPC_talk_area_c; + +#define aNPC_CTRL_CLOTH_NUM 10 + +typedef struct npc_control_actor_s { + /* 0x000 */ ACTOR actor_class; + /* 0x174 */ aNPC_cloth_c cloth[aNPC_CTRL_CLOTH_NUM]; + /* 0x8F4 */ u8 _8F4[0x9B0 - 0x8F4]; // TODO + /* 0x9B0 */ aNPC_talk_area_c talk_area; + /* 0x9C8 */ ACTOR* door_exit_actor; + /* 0x9CC */ int door_exit_timer; + /* 0x9D0 */ ACTOR* umbrella_open_actor; + /* 0x9D4 */ int umbrella_open_timer; +} NPC_CONTROL_ACTOR; + +static aNPC_Clip_c aNPC_clip; +static u16 aNPC_req_default_data[aNPC_REQUEST_ARG_NUM] = { 0, 0, 0, 0, 0, 0 }; +static ACTOR* aNPC_ctrlActor = NULL; + +static void aNPC_actor_ct_c(ACTOR* actorx, GAME* game); +static void aNPC_actor_dt_c(ACTOR* actorx, GAME* game); +static void aNPC_actor_move_c(ACTOR* actorx, GAME* game); + +// clang-format off +ACTOR_PROFILE Npc_Profile = { + mAc_PROFILE_NPC, + ACTOR_PART_CONTROL, + ACTOR_STATE_NO_DRAW_WHILE_CULLED | ACTOR_STATE_NO_MOVE_WHILE_CULLED, + EMPTY_NO, + ACTOR_OBJ_BANK_KEEP, + sizeof(NPC_CONTROL_ACTOR), + &aNPC_actor_ct_c, + &aNPC_actor_dt_c, + &aNPC_actor_move_c, + mActor_NONE_PROC1, + NULL, +}; +// clang-format on + +static void aNPC_set_frame_sub_speed(NPC_ACTOR* nactorx, int seqNo); +static void aNPC_TumbleSe(xyz_t* pos_p); +static void aNPC_WalkSe(xyz_t* pos_p); +static void aNPC_OngenTrgStart(NPC_ACTOR* nactorx, u16 se_no); +static int aNPC_set_request_act(NPC_ACTOR* nactorx, u8 prio, u8 act_idx, u8 act_type, u16* args); +static int aNPC_set_head_request(NPC_ACTOR* nactorx, u8 prio, u8 type, ACTOR* target_actor, xyz_t* target_pos); +static void aNPC_set_feel_info(NPC_ACTOR* nactorx, int feel, int timer); +static void aNPC_set_dst_pos(NPC_ACTOR* nactorx, f32 pos_x, f32 pos_z); +static void aNPC_schedule_proc(NPC_ACTOR* nactorx, GAME_PLAY* play); +static void aNPC_action_proc(NPC_ACTOR* nactorx, GAME_PLAY* play); +static void aNPC_talk_area_check(NPC_ACTOR* nactorx, GAME_PLAY* play); +static void aNPC_set_feel_effect(GAME* game, NPC_ACTOR* nactorx); +static void aNPC_set_other_effect(GAME* game, NPC_ACTOR* nactorx); +static void aNPC_act_get_chg_cloth(NPC_ACTOR* nactorx, GAME_PLAY* play); +static void aNPC_act_get_chg_umb(NPC_ACTOR* nactorx, GAME_PLAY* play); +static void aNPC_act_get_chg_cloth_and_umb(NPC_ACTOR* nactorx, GAME_PLAY* play); +static void aNPC_act_umb_close_main_proc(NPC_ACTOR* nactorx, GAME_PLAY* play); +static void aNPC_set_hide_request(NPC_ACTOR* nactorx, u8 req); +static void aNPC_reset_out_of_door_flg(NPC_CONTROL_ACTOR* ctrl, ACTOR* actorx); +static void aNPC_reset_umb_open_flg(NPC_CONTROL_ACTOR* ctrl, ACTOR* actorx); +static int aNPC_setP_friendship(NPC_ACTOR* nactorx); +static void aNPC_think_in_block_chg_native_info(ACTOR* actorx, f32 home_x, f32 home_z); +static int aNPC_check_home_block(NPC_ACTOR* nactorx); +static void aNPC_set_schedule(NPC_ACTOR* nactorx, GAME_PLAY* play); +static void aNPC_dma_draw_data_proc(aNPC_draw_data_c* draw_data_p, mActor_name_t npc_name); + +#include "../src/actor/npc/ac_npc_data.c_inc" +#include "../src/actor/npc/ac_npc_cloth.c_inc" +#include "../src/actor/npc/ac_npc_anime.c_inc" +#include "../src/actor/npc/ac_npc_sound.c_inc" +#include "../src/actor/npc/ac_npc_hand.c_inc" +#include "../src/actor/npc/ac_npc_head.c_inc" +#include "../src/actor/npc/ac_npc_talk.c_inc" +#include "../src/actor/npc/ac_npc_move.c_inc" +#include "../src/actor/npc/ac_npc_draw.c_inc" +#include "../src/actor/npc/ac_npc_effect.c_inc" +#include "../src/actor/npc/ac_npc_action.c_inc" +#include "../src/actor/npc/ac_npc_think.c_inc" +#include "../src/actor/npc/ac_npc_schedule.c_inc" +#include "../src/actor/npc/ac_npc_init.c_inc" +#include "../src/actor/npc/ac_npc_ct.c_inc" +#include "../src/actor/npc/ac_npc_dt.c_inc" +#include "../src/actor/npc/ac_npc_save.c_inc" +#include "../src/actor/npc/ac_npc_ctrl.c_inc" diff --git a/src/actor/npc/ac_npc_act_chase_insect.c_inc b/src/actor/npc/ac_npc_act_chase_insect.c_inc new file mode 100644 index 00000000..d0dc18a7 --- /dev/null +++ b/src/actor/npc/ac_npc_act_chase_insect.c_inc @@ -0,0 +1,153 @@ +enum { + aNPC_ACT_CHASE_INSECT_STEP_WAIT, + aNPC_ACT_CHASE_INSECT_STEP_WALK, + aNPC_ACT_CHASE_INSECT_STEP_RUN, + aNPC_ACT_CHASE_INSECT_STEP_TURN, + aNPC_ACT_CHASE_INSECT_STEP_SEARCH, + + aNPC_ACT_CHASE_INSECT_STEP_NUM +}; + +static int aNPC_act_chase_insect_check_end(NPC_ACTOR* nactorx) { + ACTOR* target = nactorx->movement.target; + int ret = FALSE; + + if (nactorx->action.act_timer == 0) { + ret = TRUE; + } else if (nactorx->action.act_obj == aNPC_ACT_OBJ_INSECT) { + switch (target->id) { + case mAc_PROFILE_ANT: + if (target->mv_proc == NULL && target->dw_proc == NULL) { + ret = TRUE; + } + break; + case mAc_PROFILE_INSECT: { + aINS_INSECT_ACTOR* insect = (aINS_INSECT_ACTOR*)target; + + if (!insect->exist_flag) { + ret = TRUE; + } + break; + } + default: + ret = TRUE; + break; + } + } else { + aGYO_CTRL_ACTOR* gyo = (aGYO_CTRL_ACTOR*)target; + + if (!gyo->exist) { + ret = TRUE; + } + } + + return ret; +} + +static void aNPC_act_chase_insect_chg_step(NPC_ACTOR* nactorx) { + // clang-format off + static u8 act_idx[] = { + aNPC_ACTION_TYPE_WAIT, + aNPC_ACTION_TYPE_WALK, + aNPC_ACTION_TYPE_RUN, + aNPC_ACTION_TYPE_TURN, + }; + // clang-format on + + u8 feel = aNPC_get_feel_info(nactorx); + ACTOR* target = nactorx->movement.target; + f32 dx = target->world.position.x - nactorx->actor_class.world.position.x; + f32 dz = target->world.position.z - nactorx->actor_class.world.position.z; + f32 dist = SQ(dx) + SQ(dz); + s16 angle = atans_table(dz, dx) - nactorx->actor_class.shape_info.rotation.y; + u8 step; + + switch (nactorx->action.act_obj) { + case aNPC_ACT_OBJ_INSECT: + if (dist < SQ(80.0f)) { + if (ABS(angle) > DEG2SHORT_ANGLE2(22.5f)) { + step = aNPC_ACT_CHASE_INSECT_STEP_TURN; + } else { + step = aNPC_ACT_CHASE_INSECT_STEP_WAIT; + } + } else if (dist < SQ(120.0f)) { + step = aNPC_ACT_CHASE_INSECT_STEP_WALK; + } else { + step = aNPC_ACT_CHASE_INSECT_STEP_RUN; + } + break; + case aNPC_ACT_OBJ_FISH: + if (dist < SQ(100.0f)) { + if (ABS(angle) > DEG2SHORT_ANGLE2(22.5f)) { + step = aNPC_ACT_CHASE_INSECT_STEP_TURN; + } else { + step = aNPC_ACT_CHASE_INSECT_STEP_WAIT; + } + } else { + step = aNPC_ACT_CHASE_INSECT_STEP_WALK; + } + break; + default: + nactorx->action.step = aNPC_ACTION_END_STEP; + step = aNPC_ACTION_END_STEP; + break; + } + + if (step != nactorx->action.step || feel != nactorx->action.feel) { + nactorx->action.step = step; + nactorx->action.feel = feel; + aNPC_setupAction(nactorx, act_idx[step]); + } +} + +typedef int (*aNPC_ACT_CHASE_INSECT_PROC)(NPC_ACTOR* nactorx); + +static void aNPC_act_chase_insect_main_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + static aNPC_ACT_CHASE_INSECT_PROC act_proc[] = { + &aNPC_act_wait, + &aNPC_act_search_move, + &aNPC_act_search_move, + &aNPC_act_search_turn, + }; + + if (aNPC_act_chase_insect_check_end(nactorx) == TRUE) { + nactorx->action.step = aNPC_ACTION_END_STEP; + } else { + u8 step; + + switch (nactorx->draw.main_animation_state) { + case cKF_STATE_CONTINUE: + if (nactorx->movement.dst_pos_x == nactorx->movement.avoid_pos_x && nactorx->movement.dst_pos_z == nactorx->movement.avoid_pos_z) { + aNPC_act_chase_insect_chg_step(nactorx); + } + break; + } + + step = nactorx->action.step; + (*act_proc[step])(nactorx); + nactorx->action.step = step; + } +} + +static void aNPC_act_chase_insect_chg_data_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + u16* arg_p = nactorx->request.act_args; + + nactorx->action.act_obj = arg_p[0]; + nactorx->action.act_obj_id = EMPTY_NO; +} + +static void aNPC_act_chase_insect_init_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + nactorx->action.step = aNPC_ACT_CHASE_INSECT_STEP_SEARCH; + nactorx->action.act_timer = 1 * FRAMES_PER_MINUTE; + aNPC_act_chase_insect_chg_step(nactorx); +} + +static void aNPC_act_chase_insect_proc(NPC_ACTOR* nactorx, GAME_PLAY* play, int type) { + static aNPC_SUB_PROC act_proc[] = { + &aNPC_act_chase_insect_init_proc, + &aNPC_act_chase_insect_chg_data_proc, + &aNPC_act_chase_insect_main_proc, + }; + + (*act_proc[type])(nactorx, play); +} diff --git a/src/actor/npc/ac_npc_act_clap.c_inc b/src/actor/npc/ac_npc_act_clap.c_inc new file mode 100644 index 00000000..a70eadaa --- /dev/null +++ b/src/actor/npc/ac_npc_act_clap.c_inc @@ -0,0 +1,22 @@ +static void aNPC_act_clap_main_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + if (!mPlib_check_player_actor_main_index_catch_insect((GAME*)play) && + !mPlib_check_player_actor_main_index_catch_fish((GAME*)play)) { + nactorx->action.step = aNPC_ACTION_END_STEP; + } +} + +static void aNPC_act_clap_init_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + nactorx->action.step = 0; + nactorx->movement.mv_angl = nactorx->actor_class.player_angle_y; + aNPC_setupAction(nactorx, aNPC_ACTION_TYPE_CLAP); +} + +static void aNPC_act_clap_proc(NPC_ACTOR* nactorx, GAME_PLAY* play, int type) { + static aNPC_SUB_PROC act_proc[] = { + &aNPC_act_clap_init_proc, + (aNPC_SUB_PROC)&none_proc1, + &aNPC_act_clap_main_proc, + }; + + (*act_proc[type])(nactorx, play); +} diff --git a/src/actor/npc/ac_npc_act_ensou.c_inc b/src/actor/npc/ac_npc_act_ensou.c_inc new file mode 100644 index 00000000..7755d694 --- /dev/null +++ b/src/actor/npc/ac_npc_act_ensou.c_inc @@ -0,0 +1,32 @@ +enum { + aNPC_ACT_ENSOU_STEP_ENSOU, + + aNPC_ACT_ENSOU_STEP_NUM +}; + +static void aNPC_act_ensou_main_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + u8 step = aNPC_ACT_ENSOU_STEP_ENSOU; + + if (nactorx->draw.main_animation_state == cKF_STATE_CONTINUE) { + nactorx->condition_info.demo_flg = aNPC_COND_DEMO_SKIP_HEAD_LOOKAT; + step = aNPC_ACTION_END_STEP; + } + + nactorx->action.step = step; +} + +static void aNPC_act_ensou_init_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + nactorx->condition_info.demo_flg = aNPC_COND_DEMO_SKIP_ENTRANCE_CHECK | aNPC_COND_DEMO_SKIP_HEAD_LOOKAT | aNPC_COND_DEMO_SKIP_FORWARD_CHECK | aNPC_COND_DEMO_SKIP_BGCHECK | aNPC_COND_DEMO_SKIP_MOVE_CIRCLE_REV | aNPC_COND_DEMO_SKIP_MOVE_RANGE_CHECK; + nactorx->action.step = aNPC_ACT_ENSOU_STEP_ENSOU; + aNPC_setupAction(nactorx, aNPC_ACTION_TYPE_ENSOU_E); +} + +static void aNPC_act_ensou_proc(NPC_ACTOR* nactorx, GAME_PLAY* play, int type) { + static aNPC_SUB_PROC act_proc[] = { + &aNPC_act_ensou_init_proc, + (aNPC_SUB_PROC)&none_proc1, + &aNPC_act_ensou_main_proc, + }; + + (*act_proc[type])(nactorx, play); +} diff --git a/src/actor/npc/ac_npc_act_get.c_inc b/src/actor/npc/ac_npc_act_get.c_inc new file mode 100644 index 00000000..3d2c13fe --- /dev/null +++ b/src/actor/npc/ac_npc_act_get.c_inc @@ -0,0 +1,364 @@ +enum { + aNPC_ACT_GET_STEP_MOVE, + aNPC_ACT_GET_STEP_GET, + aNPC_ACT_GET_STEP_PULL, + aNPC_ACT_GET_STEP_PULL_WAIT, + aNPC_ACT_GET_STEP_PUTAWAY, + aNPC_ACT_GET_STEP_EAT, + aNPC_ACT_GET_STEP_CHG_CLOTH, + aNPC_ACT_GET_STEP_CHG_UMB, + aNPC_ACT_GET_STEP_CHG_CLOTH_AND_UMB, + aNPC_ACT_GET_STEP_RETURN, + aNPC_ACT_GET_STEP_RETURN_WAIT, + aNPC_ACT_GET_STEP_ESTIMATE, + + aNPC_ACT_GET_STEP_NUM +}; + +enum { + aNPC_CLOTH_CHG_STEP_START, + aNPC_CLOTH_CHG_STEP_1, + aNPC_CLOTH_CHG_STEP_2, + aNPC_CLOTH_CHG_STEP_END, + + aNPC_CLOTH_CHG_STEP_NUM +}; + +static void aNPC_act_get_chg_step(NPC_ACTOR* nactorx, u8 step) { + // clang-format off + static u8 act_idx[] = { + aNPC_ACTION_TYPE_WALK, + aNPC_ACTION_TYPE_GET, + aNPC_ACTION_TYPE_GET_PULL, + aNPC_ACTION_TYPE_GET_PULL_WAIT, + aNPC_ACTION_TYPE_GET_PUTAWAY, + aNPC_ACTION_TYPE_GET_EAT, + aNPC_ACTION_TYPE_GET_CHANGE, + aNPC_ACTION_TYPE_GET_CHANGE, + aNPC_ACTION_TYPE_GET_CHANGE, + aNPC_ACTION_TYPE_GET_RETURN, + aNPC_ACTION_TYPE_GET_RETURN, + aNPC_ACTION_TYPE_ESTIMATE_F, + }; + // clang-format on + + // clang-format off + static u8 act_idx_f[] = { + aNPC_ACTION_TYPE_WALK, + aNPC_ACTION_TYPE_GET_F, + aNPC_ACTION_TYPE_GET_PULL_F, + aNPC_ACTION_TYPE_GET_PULL_WAIT_F, + aNPC_ACTION_TYPE_GET_PUTAWAY_F, + aNPC_ACTION_TYPE_GET_EAT, + aNPC_ACTION_TYPE_GET_CHANGE, + aNPC_ACTION_TYPE_GET_CHANGE, + aNPC_ACTION_TYPE_GET_CHANGE, + aNPC_ACTION_TYPE_GET_RETURN_F, + aNPC_ACTION_TYPE_GET_RETURN_F, + aNPC_ACTION_TYPE_ESTIMATE_F, + }; + // clang-format on + + int check_for_fish = CLIP(handOverItem_clip)->master_actor == (ACTOR*)nactorx; + u8 next_act_idx; + + switch (step) { + case aNPC_ACT_GET_STEP_MOVE: + nactorx->movement.demo_move_timer = 80; + break; + case aNPC_ACT_GET_STEP_GET: + check_for_fish = TRUE; + break; + case aNPC_ACT_GET_STEP_PUTAWAY: + aNPC_OngenTrgStart(nactorx, NA_SE_GASAGOSO); + break; + case aNPC_ACT_GET_STEP_CHG_CLOTH: + aNPC_OngenTrgStart(nactorx, NA_SE_WEAR); + nactorx->draw.cloth_change_step = aNPC_CLOTH_CHG_STEP_START; + if (ITEM_IS_CLOTH(Common_Get(npc_chg_cloth)) == FALSE) { + aNPC_setup_chg_cloth(nactorx, ITM_CLOTH_START, 0xFF); + } else { + aNPC_setup_chg_cloth(nactorx, Common_Get(npc_chg_cloth), 0xFF); + } + break; + case aNPC_ACT_GET_STEP_CHG_UMB: + aNPC_OngenTrgStart(nactorx, NA_SE_WEAR); + nactorx->draw.umb_state = 0; + break; + case aNPC_ACT_GET_STEP_CHG_CLOTH_AND_UMB: + aNPC_OngenTrgStart(nactorx, NA_SE_WEAR); + nactorx->draw.cloth_change_step = aNPC_CLOTH_CHG_STEP_START; + nactorx->draw.umb_state = 0; + break; + } + + nactorx->action.step = step; + if (check_for_fish == TRUE && ITEM_IS_FISH(CLIP(handOverItem_clip)->item) == TRUE) { + next_act_idx = act_idx_f[step]; + } else { + next_act_idx = act_idx[step]; + } + + aNPC_setupAction(nactorx, next_act_idx); +} + +static void aNPC_act_get_move(NPC_ACTOR* nactorx, GAME_PLAY* play) { + if (nactorx->movement.demo_move_timer != 0) { + nactorx->movement.demo_move_timer--; + } + + if (!aNPC_act_search_move(nactorx) || + (nactorx->collision.collision_flag & (mCoBG_HIT_WALL | mCoBG_HIT_WALL_FRONT)) != 0 || + nactorx->movement.demo_move_timer == 0) { + aNPC_act_get_chg_step(nactorx, aNPC_ACT_GET_STEP_GET); + } +} + +static void aNPC_act_get(NPC_ACTOR* nactorx, GAME_PLAY* play) { + if (nactorx->draw.main_animation_state == cKF_STATE_STOPPED) { + ACTOR* item_actor = CLIP(handOverItem_clip)->chg_master_proc((ACTOR*)nactorx); + + if (item_actor != NULL) { + CLIP(handOverItem_clip)->chg_request_mode_proc((ACTOR*)nactorx, aHOI_REQUEST_GET_PULL); + nactorx->left_hand.item_actor_p = item_actor; + nactorx->left_hand.item = CLIP(handOverItem_clip)->item; + aNPC_act_get_chg_step(nactorx, aNPC_ACT_GET_STEP_PULL); + } + } +} + +static void aNPC_act_get_pull(NPC_ACTOR* nactorx, GAME_PLAY* play) { + static u8 next_step[] = { + aNPC_ACT_GET_STEP_EAT, // aHOI_REQUEST_EAT + aNPC_ACT_GET_STEP_CHG_CLOTH, // aHOI_REQUEST_CHANGE + aNPC_ACT_GET_STEP_PUTAWAY, // aHOI_REQUEST_PUTAWAY + aNPC_ACT_GET_STEP_PULL_WAIT, // aHOI_REQUEST_GET_PULL_WAIT + }; + + if (nactorx->draw.main_animation_state == cKF_STATE_STOPPED) { + CLIP(handOverItem_clip)->chg_request_mode_proc((ACTOR*)nactorx, CLIP(handOverItem_clip)->player_after_mode); + aNPC_act_get_chg_step(nactorx, next_step[CLIP(handOverItem_clip)->player_after_mode - aHOI_REQUEST_EAT]); + } +} + +static void aNPC_act_get_pull_wait(NPC_ACTOR* nactorx, GAME_PLAY* play) { + aNPC_check_manpu_demoCode((ACTOR*)nactorx); + + if (nactorx->draw.main_animation_state == cKF_STATE_STOPPED || nactorx->draw.main_animation_state == cKF_STATE_CONTINUE) { + int order = mDemo_Get_OrderValue(mDemo_ORDER_NPC0, 1); + + if (order != 0) { + u8 step = nactorx->action.step; + int mode; + + switch (order) { + case 10: + mode = aHOI_REQUEST_RETURN; + step = aNPC_ACT_GET_STEP_RETURN; + break; + case 11: + mode = aHOI_REQUEST_ESTIMATE; + step = aNPC_ACT_GET_STEP_ESTIMATE; + break; + case 12: + mode = aHOI_REQUEST_EAT; + step = aNPC_ACT_GET_STEP_EAT; + break; + case 14: + mode = aHOI_REQUEST_PUTAWAY; + step = aNPC_ACT_GET_STEP_PUTAWAY; + break; + case 1: + mode = aHOI_REQUEST_CHANGE; + step = aNPC_ACT_GET_STEP_CHG_CLOTH; + break; + default: + mode = aHOI_REQUEST_RETURN; + break; + } + + if (step != nactorx->action.step) { + CLIP(handOverItem_clip)->chg_request_mode_proc((ACTOR*)nactorx, mode); + mDemo_Set_OrderValue(mDemo_ORDER_NPC0, 1, 0); + aNPC_act_get_chg_step(nactorx, step); + } + } + } +} + +static void aNPC_act_get_putaway(NPC_ACTOR* nactorx, GAME_PLAY* play) { + if (nactorx->draw.main_animation_state == cKF_STATE_STOPPED) { + aNPC_clear_left_hand_info(nactorx); + aNPC_act_return_trans_item(nactorx); + } +} + +static void aNPC_act_get_chg_cloth(NPC_ACTOR* nactorx, GAME_PLAY* play) { + if (nactorx->draw.cloth_change_step == aNPC_CLOTH_CHG_STEP_END) { + aNPC_act_get_putaway(nactorx, play); + } + + if (cKF_FrameControl_passCheck_now(&nactorx->draw.main_animation.keyframe.frame_control, 26.0f) == TRUE) { + nactorx->draw.cloth_change_step = aNPC_CLOTH_CHG_STEP_1; + } + + switch (nactorx->draw.cloth_change_step) { + case aNPC_CLOTH_CHG_STEP_1: + aNPC_cancel_cloth_data(nactorx); + nactorx->draw.cloth_change_step = aNPC_CLOTH_CHG_STEP_2; + // fallthrough 1 -> 2 + case aNPC_CLOTH_CHG_STEP_2: + if (aNPC_change_cloth_data(nactorx) == TRUE) { + mActor_name_t cloth = nactorx->draw.cloth_no; + u8 org_idx = nactorx->draw.org_idx; + + aNPC_setup_next_cloth(nactorx, cloth, org_idx); + aNPC_setup_cloth(nactorx, cloth, org_idx); + nactorx->draw.cloth_change_step = aNPC_CLOTH_CHG_STEP_END; + } + break; + } +} + +static void aNPC_act_get_chg_umb(NPC_ACTOR* nactorx, GAME_PLAY* play) { + if (nactorx->draw.umb_state == aNPC_CLOTH_CHG_STEP_END) { + aNPC_act_get_putaway(nactorx, play); + } + + if (cKF_FrameControl_passCheck_now(&nactorx->draw.main_animation.keyframe.frame_control, 26.0f) == TRUE) { + nactorx->draw.umb_state = aNPC_CLOTH_CHG_STEP_1; + } + + switch (nactorx->draw.umb_state) { + case aNPC_CLOTH_CHG_STEP_1: + aNPC_change_umbrella(nactorx); + nactorx->draw.umb_state = aNPC_CLOTH_CHG_STEP_2; + // fallthrough 1 -> 2 + case aNPC_CLOTH_CHG_STEP_2: + if (CLIP(tools_clip)->aTOL_chg_request_mode_proc((ACTOR*)nactorx, nactorx->right_hand.prev_item_actor_p, aTOL_ACTION_DESTRUCT) == TRUE) { + nactorx->npc_info.animal->umbrella_id = nactorx->right_hand.umbrella_type; + nactorx->draw.umb_state = aNPC_CLOTH_CHG_STEP_END; + } + break; + } +} + +static void aNPC_act_get_chg_cloth_and_umb(NPC_ACTOR* nactorx, GAME_PLAY* play) { + if (nactorx->draw.cloth_change_step == aNPC_CLOTH_CHG_STEP_END && nactorx->draw.umb_state == aNPC_CLOTH_CHG_STEP_END) { + aNPC_act_get_putaway(nactorx, play); + } + + if (cKF_FrameControl_passCheck_now(&nactorx->draw.main_animation.keyframe.frame_control, 26.0f) == TRUE) { + nactorx->draw.cloth_change_step = aNPC_CLOTH_CHG_STEP_1; + nactorx->draw.umb_state = aNPC_CLOTH_CHG_STEP_1; + } + + switch (nactorx->draw.cloth_change_step) { + case aNPC_CLOTH_CHG_STEP_1: + aNPC_cancel_cloth_data(nactorx); + nactorx->draw.cloth_change_step = aNPC_CLOTH_CHG_STEP_2; + // fallthrough 1 -> 2 + case aNPC_CLOTH_CHG_STEP_2: + if (aNPC_change_cloth_data(nactorx) == TRUE) { + mActor_name_t cloth = nactorx->draw.cloth_no; + u8 org_idx = nactorx->draw.org_idx; + + aNPC_setup_next_cloth(nactorx, cloth, org_idx); + aNPC_setup_cloth(nactorx, cloth, org_idx); + nactorx->draw.cloth_change_step = aNPC_CLOTH_CHG_STEP_END; + } + break; + } + + switch (nactorx->draw.umb_state) { + case aNPC_CLOTH_CHG_STEP_1: + aNPC_change_umbrella(nactorx); + nactorx->draw.umb_state = aNPC_CLOTH_CHG_STEP_2; + // fallthrough 1 -> 2 + case aNPC_CLOTH_CHG_STEP_2: + if (CLIP(tools_clip)->aTOL_chg_request_mode_proc((ACTOR*)nactorx, nactorx->right_hand.prev_item_actor_p, aTOL_ACTION_DESTRUCT) == TRUE) { + nactorx->npc_info.animal->umbrella_id = nactorx->right_hand.umbrella_type; + nactorx->draw.umb_state = aNPC_CLOTH_CHG_STEP_END; + } + break; + } +} + +static void aNPC_act_get_return(NPC_ACTOR* nactorx, GAME_PLAY* play) { + if (nactorx->draw.main_animation_state == cKF_STATE_STOPPED) { + CLIP(handOverItem_clip)->chg_request_mode_proc((ACTOR*)nactorx, aHOI_REQUEST_TRANS_WAIT); + CLIP(handOverItem_clip)->player_after_mode = aHOI_REQUEST_PUTAWAY; + aNPC_act_get_chg_step(nactorx, aNPC_ACT_GET_STEP_RETURN_WAIT); + } +} + +static void aNPC_act_estimate(NPC_ACTOR* nactorx, GAME_PLAY* play) { + if (nactorx->draw.main_animation_state == cKF_STATE_STOPPED) { + CLIP(handOverItem_clip)->chg_request_mode_proc((ACTOR*)nactorx, aHOI_REQUEST_GET_PULL_WAIT); + aNPC_act_get_chg_step(nactorx, aNPC_ACT_GET_STEP_PULL_WAIT); + } +} + +static void aNPC_act_get_main_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + // clang-format off + static aNPC_SUB_PROC act_proc[] = { + &aNPC_act_get_move, + &aNPC_act_get, + &aNPC_act_get_pull, + &aNPC_act_get_pull_wait, + &aNPC_act_get_putaway, + &aNPC_act_get_putaway, + &aNPC_act_get_chg_cloth, + &aNPC_act_get_chg_umb, + &aNPC_act_get_chg_cloth_and_umb, + &aNPC_act_get_return, + &aNPC_act_trans_wait, + &aNPC_act_estimate + }; + // clang-format on + + if ((*nactorx->talk_info.talk_end_check_proc)((ACTOR*)nactorx, (GAME*)play) == TRUE) { + aNPC_setup_talk_end(nactorx); + nactorx->action.step = aNPC_ACTION_END_STEP; + } else { + aNPC_check_feel_demoCode((ACTOR*)nactorx); + (*act_proc[nactorx->action.step])(nactorx, play); + } +} + +static void aNPC_act_get_chg_data_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + nactorx->action.act_obj = aNPC_ACT_OBJ_PLAYER; +} + +static void aNPC_act_get_init_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + u16* arg_data = nactorx->request.act_args; + u8 step = aNPC_ACT_GET_STEP_MOVE; + + nactorx->condition_info.trans_demo_flg_save = nactorx->condition_info.demo_flg; + nactorx->condition_info.demo_flg = + aNPC_COND_DEMO_SKIP_UZAI_CHECK | aNPC_COND_DEMO_SKIP_ENTRANCE_CHECK | aNPC_COND_DEMO_SKIP_HEAD_LOOKAT | + aNPC_COND_DEMO_SKIP_TALK_CHECK | aNPC_COND_DEMO_SKIP_ITEM | aNPC_COND_DEMO_SKIP_FORWARD_CHECK | + aNPC_COND_DEMO_SKIP_OBJ_COL_CHECK | aNPC_COND_DEMO_SKIP_MOVE_CIRCLE_REV | aNPC_COND_DEMO_SKIP_MOVE_RANGE_CHECK; + + if (nactorx->action.idx == aNPC_ACT_GET) { + if (nactorx->actor_class.player_distance_xz < 50.0f || arg_data[0] != 0) { + step = aNPC_ACT_GET_STEP_GET; + } else { + nactorx->movement.arrival_area_radius = SQ(50.0f); + } + } else { + step = aNPC_ACT_GET_STEP_CHG_CLOTH; + } + + aNPC_act_get_chg_step(nactorx, step); +} + +static void aNPC_act_get_proc(NPC_ACTOR* nactorx, GAME_PLAY* play, int type) { + static aNPC_SUB_PROC act_proc[] = { + &aNPC_act_get_init_proc, + &aNPC_act_get_chg_data_proc, + &aNPC_act_get_main_proc, + }; + + (*act_proc[type])(nactorx, play); +} diff --git a/src/actor/npc/ac_npc_act_greeting.c_inc b/src/actor/npc/ac_npc_act_greeting.c_inc new file mode 100644 index 00000000..e7562ddd --- /dev/null +++ b/src/actor/npc/ac_npc_act_greeting.c_inc @@ -0,0 +1,661 @@ +typedef struct { + mActor_name_t npc_name; + int bx; + int bz; + s8 friendship; + mActor_name_t* cloth_p; + u8* org_idx_p; + u8* ending_p; +} aNPC_around_npc_c; + +typedef struct { + int count; + aNPC_around_npc_c around_npc[ANIMAL_NUM_MAX]; +} aNPC_around_npc_list_c; + +enum { + aNPC_ACT_GREETING_STEP_TURN, + aNPC_ACT_GREETING_STEP_APPROACH, + aNPC_ACT_GREETING_STEP_WAIT, + aNPC_ACT_GREETING_STEP_GREETING0, + aNPC_ACT_GREETING_STEP_GREETING1, + aNPC_ACT_GREETING_STEP_GREETING2, + aNPC_ACT_GREETING_STEP_GREETING3, + aNPC_ACT_GREETING_STEP_CHG_CLOTH, + aNPC_ACT_GREETING_STEP_CHG_UMB, + aNPC_ACT_GREETING_STEP_CHG_CLOTH_AND_UMB, + aNPC_ACT_GREETING_STEP_CHG_WAIT, + + aNPC_ACT_GREETING_STEP_NUM +}; + +static aNPC_around_npc_list_c aNPC_aroundNpcInfoList; + +static void aNPC_act_greeting_chg_step(NPC_ACTOR* nactorx, u8 step); + +static void aNPC_setup_turn_round_palActor(NPC_ACTOR* nactorx, NPC_ACTOR* pal_nactorx) { + nactorx->movement.target = (ACTOR*)pal_nactorx; + aNPC_set_dst_pos(nactorx, pal_nactorx->actor_class.world.position.x, pal_nactorx->actor_class.world.position.z); + nactorx->movement.arrival_area_radius = SQ(50.0f); +} + +static s8 aNPC_get_animal_friendship(NPC_ACTOR* nactorx) { + int mem_idx; + s8 friendship; + + friendship = 0; + mem_idx = mNpc_GetAnimalMemoryIdx(&Now_Private->player_ID, nactorx->npc_info.animal->memories, ANIMAL_MEMORY_NUM); + if (mem_idx != -1) { + friendship = nactorx->npc_info.animal->memories[mem_idx].friendship; + } + + return friendship; +} + +static void aNPC_setup_greeting_end_sub(NPC_ACTOR* nactorx) { + nactorx->palActor = NULL; + nactorx->palActorIgnoreTimer = 10 * FRAMES_PER_SECOND; + nactorx->condition_info.greeting_flag = FALSE; + + if (ITEM_NAME_GET_TYPE(nactorx->actor_class.npc_id) == NAME_TYPE_NPC) { + nactorx->right_hand.umbrella_disabled_flag = FALSE; + } + + nactorx->condition_info.demo_flg = nactorx->condition_info.trans_demo_flg_save; + nactorx->actor_class.state_bitfield = nactorx->condition_info.actor_state_save; + + if (nactorx->actor_class.status_data.weight < MASSTYPE_HEAVY) { + nactorx->actor_class.status_data.weight = 50; + } +} + +static void aNPC_setup_greeting_end(NPC_ACTOR* nactorx) { + ACTOR* palActor = nactorx->palActor; + + if (palActor != NULL) { + NPC_ACTOR* pal_nactorx = (NPC_ACTOR*)palActor; + + switch (pal_nactorx->condition_info.greeting_flag) { + case 3: + case 4: + case 5: + aNPC_act_greeting_chg_step(nactorx, 10); + break; + default: + aNPC_setup_greeting_end_sub(pal_nactorx); + pal_nactorx->action.step = aNPC_ACTION_END_STEP; + aNPC_setup_greeting_end_sub(nactorx); + nactorx->action.step = aNPC_ACTION_END_STEP; + break; + } + } else { + aNPC_setup_greeting_end_sub(nactorx); + nactorx->action.step = aNPC_ACTION_END_STEP; + } +} + +static void aNPC_sort_aroundNpcInfoList(aNPC_around_npc_list_c* list_p) { + aNPC_around_npc_c tmp; + s8 max; + int max_idx; + int count; + int i; + int j; + + count = list_p->count; + for (i = 0; i < count; i += 2) { + max = list_p->around_npc[i].friendship; + max_idx = i; + + for (j = i; j < count; j++) { + if (list_p->around_npc[j].friendship > max) { + max = list_p->around_npc[j].friendship; + max_idx = j; + } + } + + mem_copy((u8*)&tmp, (u8*)&list_p->around_npc[i], sizeof(tmp)); + mem_copy((u8*)&list_p->around_npc[i], (u8*)&list_p->around_npc[max_idx], sizeof(tmp)); + mem_copy((u8*)&list_p->around_npc[max_idx], (u8*)&tmp, sizeof(tmp)); + } +} + +static void aNPC_make_aroundNpcInfoList(NPC_ACTOR* nactorx0, NPC_ACTOR* nactorx1) { + aNPC_around_npc_list_c* list_p = &aNPC_aroundNpcInfoList; + mActor_name_t name0 = nactorx0->actor_class.npc_id; + mActor_name_t name1 = nactorx1->actor_class.npc_id; + mNpc_NpcList_c* npclist_p = Common_Get(npclist); + Animal_c* animal_p = Save_Get(animals); + aNPC_around_npc_c* aroundNpc_p; + int mem_idx; + int bx; + int bz; + int npc_bx; + int npc_bz; + int d_bx; + int d_bz; + int i; + + bzero(list_p, sizeof(aNPC_aroundNpcInfoList)); + mFI_Wpos2BlockNum(&bx, &bz, nactorx0->actor_class.world.position); + + for (i = 0; i < ANIMAL_NUM_MAX; i++) { + if (npclist_p->name != EMPTY_NO && npclist_p->name != name0 && npclist_p->name != name1) { + mFI_Wpos2BlockNum(&npc_bx, &npc_bz, npclist_p->position); + d_bx = ABS(npc_bx - bx); + d_bz = ABS(npc_bz - bz); + + if (d_bx + d_bz == 1) { + mem_idx = mNpc_GetAnimalMemoryIdx(&Now_Private->player_ID, animal_p->memories, ANIMAL_MEMORY_NUM); + + if (mem_idx != -1) { + aroundNpc_p = &list_p->around_npc[list_p->count]; + list_p->count++; + aroundNpc_p->npc_name = npclist_p->name; + aroundNpc_p->bx = npc_bx; + aroundNpc_p->bz = npc_bz; + aroundNpc_p->friendship = animal_p->memories[mem_idx].friendship; + aroundNpc_p->cloth_p = &animal_p->cloth; + aroundNpc_p->org_idx_p = &animal_p->cloth_original_id; + aroundNpc_p->ending_p = animal_p->catchphrase; + } + } + } + + npclist_p++; + animal_p++; + } + + aNPC_sort_aroundNpcInfoList(list_p); +} + +static void aNPC_decide_AB_Actor(NPC_ACTOR** nactorx_A, NPC_ACTOR** nactorx_B, NPC_ACTOR* nactorx, + NPC_ACTOR* pal_nactorx) { + s8 friendship0 = aNPC_get_animal_friendship(nactorx); + s8 friendship1 = aNPC_get_animal_friendship(pal_nactorx); + + if (friendship0 == friendship1) { + if (RANDOM_F(1.0f) < 0.5f) { + *nactorx_A = nactorx; + *nactorx_B = pal_nactorx; + } else { + *nactorx_A = pal_nactorx; + *nactorx_B = nactorx; + } + } else if (friendship0 < friendship1) { + *nactorx_A = pal_nactorx; + *nactorx_B = nactorx; + } else { + *nactorx_A = nactorx; + *nactorx_B = pal_nactorx; + } +} + +static int aNPC_chk_same_cloth(mActor_name_t cloth0, u8 org_idx0, mActor_name_t cloth1, u8 org_idx1) { + int ret = FALSE; + if (cloth0 == cloth1) { +// @BUG - this doesn't return FALSE when the original designs are different +#ifndef BUGFIXES + if (cloth0 == RSV_CLOTH && org_idx0 == org_idx1) { + ret = TRUE; + } else { + ret = TRUE; + } +#else + if (cloth0 == RSV_CLOTH) { + if (org_idx0 == org_idx1) { + ret = TRUE; + } + } else { + ret = TRUE; + } +#endif + } + + return ret; +} + +static void aNPC_set_feel_sub(NPC_ACTOR* nactorx_A, NPC_ACTOR* nactorx_B) { + static int feel_table[] = { mNpc_FEEL_ANGRY, mNpc_FEEL_SAD, mNpc_FEEL_NORMAL }; + static int addTim_table[] = { 1, 1, 0 }; + static int relation_table[] = { -8, -4, 0 }; + int idx = RANDOM(ARRAY_COUNT(feel_table)); + + aNPC_set_relation(nactorx_A, nactorx_B, relation_table[idx]); + aNPC_set_feel_info(nactorx_A, feel_table[idx], addTim_table[idx]); +} + +static void aNPC_set_feel(NPC_ACTOR* nactorx_A, NPC_ACTOR* nactorx_B, GAME_PLAY* play) { + aNPC_set_feel_sub(nactorx_A, nactorx_B); + aNPC_set_feel_sub(nactorx_B, nactorx_A); +} + +static void aNPC_copy_cloth(NPC_ACTOR* nactorx_A, NPC_ACTOR* nactorx_B, GAME_PLAY* play) { + mActor_name_t cloth = nactorx_A->npc_info.animal->cloth; + u8 org_idx = nactorx_A->npc_info.animal->cloth_original_id; + + if (aNPC_chk_same_cloth(nactorx_B->npc_info.animal->cloth, nactorx_B->npc_info.animal->cloth_original_id, cloth, + org_idx) == FALSE) { + aNPC_setup_chg_cloth(nactorx_B, cloth, org_idx); + } else { + Actor_info* info_p; + aNPC_around_npc_c* aroundNpc_p; + int i; + + aNPC_make_aroundNpcInfoList(nactorx_A, nactorx_B); + + info_p = &play->actor_info; + aroundNpc_p = aNPC_aroundNpcInfoList.around_npc; + for (i = 0; i < aNPC_aroundNpcInfoList.count; i++) { + if (aNPC_chk_same_cloth(*aroundNpc_p->cloth_p, *aroundNpc_p->org_idx_p, cloth, org_idx) == FALSE) { + ACTOR* aroundNpc_actor = Actor_info_fgName_search(info_p, aroundNpc_p->npc_name, ACTOR_PART_NPC); + + if (aroundNpc_actor == NULL) { + *aroundNpc_p->cloth_p = cloth; + *aroundNpc_p->org_idx_p = org_idx; + break; + } + } + + aroundNpc_p++; + } + } + + aNPC_set_relation(nactorx_A, nactorx_B, 8); + aNPC_set_feel_info(nactorx_A, mNpc_FEEL_HAPPY, 1); + aNPC_set_relation(nactorx_B, nactorx_A, 8); + aNPC_set_feel_info(nactorx_B, mNpc_FEEL_HAPPY, 1); +} + +static void aNPC_copy_end_words(NPC_ACTOR* nactorx_A, NPC_ACTOR* nactorx_B, GAME_PLAY* play) { + Animal_c* animal_A = nactorx_A->npc_info.animal; + Animal_c* animal_B = nactorx_B->npc_info.animal; + + if (mNpc_GetLooks2Sex(animal_A->id.looks) == mNpc_GetLooks2Sex(animal_B->id.looks)) { + if (mem_cmp(animal_A->catchphrase, animal_B->catchphrase, ANIMAL_CATCHPHRASE_LEN) == FALSE) { + mem_copy(animal_B->catchphrase, animal_A->catchphrase, ANIMAL_CATCHPHRASE_LEN); + } else { + aNPC_around_npc_c* aroundNpc_p; + int i; + u8 ending[ANIMAL_CATCHPHRASE_LEN]; + + aNPC_make_aroundNpcInfoList(nactorx_A, nactorx_B); + mem_copy(ending, animal_A->catchphrase, ANIMAL_CATCHPHRASE_LEN); + aroundNpc_p = aNPC_aroundNpcInfoList.around_npc; + for (i = 0; i < aNPC_aroundNpcInfoList.count; i++) { + if (mem_cmp(aroundNpc_p->ending_p, ending, ANIMAL_CATCHPHRASE_LEN) == FALSE) { + mem_copy(aroundNpc_p->ending_p, ending, ANIMAL_CATCHPHRASE_LEN); + break; + } + + aroundNpc_p++; + } + } + } + + aNPC_set_relation(nactorx_A, nactorx_B, 8); + aNPC_set_feel_info(nactorx_A, mNpc_FEEL_HAPPY, 1); + aNPC_set_relation(nactorx_B, nactorx_A, 8); + aNPC_set_feel_info(nactorx_B, mNpc_FEEL_HAPPY, 1); +} + +static void aNPC_set_cloth(NPC_ACTOR* nactorx_A, NPC_ACTOR* nactorx_B, GAME_PLAY* play) { + Animal_c* animal_p = nactorx_A->npc_info.animal; + mActor_name_t cur_cloth = animal_p->cloth; + u8 cur_org_idx = animal_p->cloth_original_id; + + mSP_SelectRandomItem_New(NULL, &animal_p->cloth, 1, &cur_cloth, 1, mSP_KIND_CLOTH, mSP_LISTTYPE_ABC, FALSE); + aNPC_setup_chg_cloth(nactorx_A, animal_p->cloth, 0xFF); + aNPC_setup_cloth(nactorx_A, cur_cloth, cur_org_idx); + aNPC_set_relation(nactorx_A, nactorx_B, -4); + aNPC_set_feel_info(nactorx_A, mNpc_FEEL_SAD, 1); +} + +static void aNPC_reset_end_words(NPC_ACTOR* nactorx_A, NPC_ACTOR* nactorx_B, GAME_PLAY* play) { + mNpc_ResetWordEnding(nactorx_B); + aNPC_set_relation(nactorx_A, nactorx_B, -8); + aNPC_set_feel_info(nactorx_A, mNpc_FEEL_ANGRY, 1); +} + +static void aNPC_chg_sp_cloth(NPC_ACTOR* nactorx_A, NPC_ACTOR* nactorx_B, GAME_PLAY* play) { + Animal_c* animal_p = nactorx_A->npc_info.animal; + u8 org_idx; + + if (animal_p->cloth == RSV_CLOTH) { + do { + org_idx = RANDOM_F(4); + } while (org_idx == animal_p->cloth_original_id); + } else { + org_idx = RANDOM_F(4); + } + + aNPC_setup_chg_cloth(nactorx_A, RSV_CLOTH, org_idx); + aNPC_set_relation(nactorx_A, nactorx_B, 8); + aNPC_set_feel_info(nactorx_A, mNpc_FEEL_HAPPY, 1); +} + +static void aNPC_chg_sp_umb(NPC_ACTOR* nactorx_A, NPC_ACTOR* nactorx_B, GAME_PLAY* play) { + Animal_c* animal_p = nactorx_A->npc_info.animal; + u8 org_idx; + + if (animal_p->umbrella_id >= (ITM_MY_ORG_UMBRELLA0 - ITM_UMBRELLA_START) && + animal_p->umbrella_id <= (ITM_MY_ORG_UMBRELLA7 - ITM_UMBRELLA_START)) { + do { + org_idx = (ITM_MY_ORG_UMBRELLA0 - ITM_UMBRELLA_START) + RANDOM(4); + } while (org_idx == animal_p->umbrella_id); + } else { + org_idx = (ITM_MY_ORG_UMBRELLA0 - ITM_UMBRELLA_START) + RANDOM(4); + } + + nactorx_A->right_hand.umbrella_type = org_idx; + if (nactorx_A->right_hand.item_type != aNPC_ITEM_TYPE_UMBRELLA) { + animal_p->umbrella_id = org_idx; + } +} + +static void aNPC_reset_cloth_and_umb(NPC_ACTOR* nactorx_A, NPC_ACTOR* nactorx_B, GAME_PLAY* play) { + Animal_c* animal_p = nactorx_A->npc_info.animal; + mActor_name_t cloth = animal_p->cloth; + u8 org_id = animal_p->cloth_original_id; + u8 umb = animal_p->umbrella_id; + + mNpc_SetDefAnimalCloth(animal_p); + aNPC_setup_chg_cloth(nactorx_A, animal_p->cloth, 0xFF); + aNPC_setup_cloth(nactorx_A, cloth, org_id); + mNpc_SetDefAnimalUmbrella(animal_p); + nactorx_A->right_hand.umbrella_type = animal_p->umbrella_id; + if (nactorx_A->right_hand.item_type == aNPC_ITEM_TYPE_UMBRELLA) { + animal_p->umbrella_id = umb; + } + + aNPC_set_relation(nactorx_A, nactorx_B, -4); + aNPC_set_feel_info(nactorx_A, mNpc_FEEL_SAD, 1); +} + +enum { + aNPC_GREETING_REACTION_SET_FEEL, + aNPC_GREETING_REACTION_COPY_END_WORDS, + aNPC_GREETING_REACTION_RESET_END_WORDS, + aNPC_GREETING_REACTION_CHG_SP_UMB, + aNPC_GREETING_REACTION_COPY_CLOTH, + aNPC_GREETING_REACTION_SET_CLOTH, + aNPC_GREETING_REACTION_CHG_SP_CLOTH, + aNPC_GREETING_REACTION_RESET_CLOTH_AND_UMB, + + aNPC_GREETING_REACTION_NUM +}; + +typedef void (*aNPC_GREETING_REACTION_PROC)(NPC_ACTOR*, NPC_ACTOR*, GAME_PLAY*); + +static void aNPC_act_greeting_reaction(NPC_ACTOR* nactorx, GAME_PLAY* play) { + // clang-format off + static f32 react_rate_table[] = { + 0.2f, + 0.1f, + 0.1f, + 0.1f, + 0.1f, + 0.05f, + 0.1f, + 0.05f, + }; + // clang-format on + + // clang-format off + static aNPC_GREETING_REACTION_PROC react_proc_table[] = { + &aNPC_set_feel, + &aNPC_copy_end_words, + &aNPC_reset_end_words, + &aNPC_chg_sp_umb, + &aNPC_copy_cloth, + &aNPC_set_cloth, + &aNPC_chg_sp_cloth, + &aNPC_reset_cloth_and_umb, + }; + // clang-format on + + int sp_npc_flag; + u8 greeting_flag; + ACTOR* palActor = nactorx->palActor; + NPC_ACTOR* pal_nactorx = (NPC_ACTOR*)palActor; + Animal_c* animal_p = nactorx->npc_info.animal; + Animal_c* animal_pal = pal_nactorx->npc_info.animal; + aNPC_GREETING_REACTION_PROC* reaction_proc; + f32* rate_p; + + sp_npc_flag = TRUE; + greeting_flag = 2; + if (ITEM_NAME_GET_TYPE(nactorx->actor_class.npc_id) == NAME_TYPE_NPC && + ITEM_NAME_GET_TYPE(pal_nactorx->actor_class.npc_id) == NAME_TYPE_NPC) { + sp_npc_flag = FALSE; + } + + if (pal_nactorx->condition_info.greeting_flag != 1 && pal_nactorx->condition_info.greeting_flag != 3 && + pal_nactorx->condition_info.greeting_flag != 4 && pal_nactorx->condition_info.greeting_flag != 5) { + aNPC_setup_turn_round_palActor(nactorx, pal_nactorx); + aNPC_setup_turn_round_palActor(pal_nactorx, nactorx); + + if (sp_npc_flag == FALSE) { + NPC_ACTOR* nactorx_A; + NPC_ACTOR* nactorx_B; + f32 rnd = fqrand(); + int react = aNPC_GREETING_REACTION_NUM; + + reaction_proc = react_proc_table; + rate_p = react_rate_table; + + if (mNpc_CheckTalkPresentCloth(animal_p) == TRUE || mNpc_CheckTalkPresentCloth(animal_pal) == TRUE) { + react = aNPC_GREETING_REACTION_COPY_CLOTH; + } + + for (react; react != 0; react--) { + rnd -= *rate_p; + if (rnd < 0.0f) { + aNPC_decide_AB_Actor(&nactorx_A, &nactorx_B, nactorx, pal_nactorx); + (*reaction_proc)(nactorx_A, nactorx_B, play); + break; + } + + rate_p++; + reaction_proc++; + } + + greeting_flag = 1; + } + } + + nactorx->condition_info.trans_demo_flg_save = nactorx->condition_info.demo_flg; + nactorx->condition_info.demo_flg = aNPC_COND_DEMO_SKIP_UZAI_CHECK | aNPC_COND_DEMO_SKIP_ENTRANCE_CHECK | + aNPC_COND_DEMO_SKIP_HEAD_LOOKAT | aNPC_COND_DEMO_SKIP_TALK_CHECK | + aNPC_COND_DEMO_SKIP_ITEM | aNPC_COND_DEMO_SKIP_FORWARD_CHECK | + aNPC_COND_DEMO_SKIP_MOVE_CIRCLE_REV | aNPC_COND_DEMO_SKIP_MOVE_RANGE_CHECK; + if (nactorx->actor_class.status_data.weight < MASSTYPE_HEAVY) { + nactorx->actor_class.status_data.weight = MASSTYPE_HEAVY - 1; + } + + nactorx->condition_info.actor_state_save = nactorx->actor_class.state_bitfield; + nactorx->actor_class.state_bitfield |= ACTOR_STATE_NO_MOVE_WHILE_CULLED; + + if (sp_npc_flag == FALSE) { + if (!aNPC_chk_same_cloth(animal_p->cloth, animal_p->cloth_original_id, nactorx->draw.cloth_no, + nactorx->draw.org_idx)) { + greeting_flag = 3; + } + + if (animal_p->umbrella_id != nactorx->right_hand.umbrella_type) { + if (greeting_flag == 3) { + greeting_flag = 5; + } else { + greeting_flag = 4; + } + } + } + + nactorx->condition_info.greeting_flag = greeting_flag; +} + +static u8 aNPC_get_greeting_step(ACTOR* actorx) { + // clang-format off + static u8 step_table[] = { + aNPC_ACT_GREETING_STEP_GREETING1, // normal + aNPC_ACT_GREETING_STEP_GREETING0, // peppy + aNPC_ACT_GREETING_STEP_GREETING1, // lazy + aNPC_ACT_GREETING_STEP_GREETING0, // jock + aNPC_ACT_GREETING_STEP_GREETING2, // cranky + aNPC_ACT_GREETING_STEP_GREETING3, // snooty + }; + // clang-format on + + return step_table[mNpc_GetNpcLooks(actorx)]; +} + +static void aNPC_act_greeting_chg_step(NPC_ACTOR* nactorx, u8 step) { + // clang-format off + static u8 act_idx[] = { + aNPC_ACTION_TYPE_TURN, + aNPC_ACTION_TYPE_WALK, + aNPC_ACTION_TYPE_PAL_WAIT, + aNPC_ACTION_TYPE_GREETING0, + aNPC_ACTION_TYPE_GREETING1, + aNPC_ACTION_TYPE_GREETING2, + aNPC_ACTION_TYPE_GREETING3, + aNPC_ACTION_TYPE_GET_CHANGE, + aNPC_ACTION_TYPE_GET_CHANGE, + aNPC_ACTION_TYPE_GET_CHANGE, + }; + // clang-format on + + if (step == aNPC_ACT_GREETING_STEP_APPROACH) { + nactorx->movement.demo_move_timer = 80; + } + + nactorx->action.step = step; + aNPC_setupAction(nactorx, act_idx[step]); +} + +static void aNPC_act_greeting_turn(NPC_ACTOR* nactorx, GAME_PLAY* play) { + if (!aNPC_act_turn(nactorx)) { + ACTOR* palActor = nactorx->palActor; + u8 step = aNPC_ACT_GREETING_STEP_APPROACH; + + if (search_position_distance(&palActor->world.position, &nactorx->actor_class.world.position) < 50.0f || + nactorx->actor_class.status_data.weight >= MASSTYPE_HEAVY) { + step = aNPC_ACT_GREETING_STEP_WAIT; + } + + aNPC_act_greeting_chg_step(nactorx, step); + } +} + +static void aNPC_act_greeting_approach(NPC_ACTOR* nactorx, GAME_PLAY* play) { + if (nactorx->movement.demo_move_timer != 0) { + nactorx->movement.demo_move_timer--; + } + + if (!aNPC_act_search_move(nactorx) || + (nactorx->collision.collision_flag & (mCoBG_HIT_WALL | mCoBG_HIT_WALL_FRONT)) != 0 || + nactorx->movement.demo_move_timer == 0) { + aNPC_act_greeting_chg_step(nactorx, aNPC_ACT_GREETING_STEP_WAIT); + } +} + +static void aNPC_act_greeting_wait(NPC_ACTOR* nactorx, GAME_PLAY* play) { + ACTOR* palActor = nactorx->palActor; + NPC_ACTOR* pal_nactorx = (NPC_ACTOR*)palActor; + + if (pal_nactorx->action.step == aNPC_ACT_GREETING_STEP_WAIT) { + aNPC_act_greeting_chg_step(pal_nactorx, aNPC_get_greeting_step(palActor)); + aNPC_act_greeting_chg_step(nactorx, aNPC_get_greeting_step((ACTOR*)nactorx)); + } +} + +static void aNPC_act_greeting(NPC_ACTOR* nactorx, GAME_PLAY* play) { + if (nactorx->draw.main_animation_state == cKF_STATE_STOPPED) { + switch (nactorx->condition_info.greeting_flag) { + case 3: + aNPC_OngenTrgStart(nactorx, NA_SE_WEAR); + nactorx->draw.cloth_change_step = 0; + aNPC_act_greeting_chg_step(nactorx, aNPC_ACT_GREETING_STEP_CHG_CLOTH); + break; + case 4: + aNPC_OngenTrgStart(nactorx, NA_SE_WEAR); + nactorx->draw.umb_state = 0; + aNPC_act_greeting_chg_step(nactorx, aNPC_ACT_GREETING_STEP_CHG_UMB); + break; + case 5: + aNPC_OngenTrgStart(nactorx, NA_SE_WEAR); + nactorx->draw.cloth_change_step = 0; + nactorx->draw.umb_state = 0; + aNPC_act_greeting_chg_step(nactorx, aNPC_ACT_GREETING_STEP_CHG_CLOTH_AND_UMB); + break; + default: + aNPC_setup_greeting_end(nactorx); + break; + } + } +} + +static void aNPC_act_greeting_chg_cloth(NPC_ACTOR* nactorx, GAME_PLAY* play) { + aNPC_act_get_chg_cloth(nactorx, play); + + if (nactorx->action.step == aNPC_ACTION_END_STEP) { + aNPC_setup_greeting_end(nactorx); + } +} + +static void aNPC_act_greeting_chg_umb(NPC_ACTOR* nactorx, GAME_PLAY* play) { + aNPC_act_get_chg_umb(nactorx, play); + + if (nactorx->action.step == aNPC_ACTION_END_STEP) { + aNPC_setup_greeting_end(nactorx); + } +} + +static void aNPC_act_greeting_chg_cloth_and_umb(NPC_ACTOR* nactorx, GAME_PLAY* play) { + aNPC_act_get_chg_cloth_and_umb(nactorx, play); + + if (nactorx->action.step == aNPC_ACTION_END_STEP) { + aNPC_setup_greeting_end(nactorx); + } +} + +static void aNPC_act_greeting_main_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + // clang-format off + static aNPC_SUB_PROC act_proc[] = { + &aNPC_act_greeting_turn, + &aNPC_act_greeting_approach, + &aNPC_act_greeting_wait, + &aNPC_act_greeting, + &aNPC_act_greeting, + &aNPC_act_greeting, + &aNPC_act_greeting, + &aNPC_act_greeting_chg_cloth, + &aNPC_act_greeting_chg_umb, + &aNPC_act_greeting_chg_cloth_and_umb, + (aNPC_SUB_PROC)&none_proc1, + }; + // clang-format on + + if (nactorx->palActor == NULL) { + aNPC_setup_greeting_end(nactorx); + } else if (((NPC_ACTOR*)nactorx->palActor)->palActor != (ACTOR*)nactorx) { + nactorx->palActor = NULL; + aNPC_setup_greeting_end(nactorx); + } else { + (*act_proc[nactorx->action.step])(nactorx, play); + } +} + +static void aNPC_act_greeting_init_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + nactorx->right_hand.umbrella_disabled_flag = TRUE; + nactorx->request.umb_flag = 0; + aNPC_act_greeting_reaction(nactorx, play); + aNPC_act_greeting_chg_step(nactorx, aNPC_ACT_GREETING_STEP_TURN); +} + +static void aNPC_act_greeting_proc(NPC_ACTOR* nactorx, GAME_PLAY* play, int type) { + static aNPC_SUB_PROC act_proc[] = { &aNPC_act_greeting_init_proc, (aNPC_SUB_PROC)&none_proc1, + &aNPC_act_greeting_main_proc }; + + (*act_proc[type])(nactorx, play); +} diff --git a/src/actor/npc/ac_npc_act_into_house.c_inc b/src/actor/npc/ac_npc_act_into_house.c_inc new file mode 100644 index 00000000..52d64e44 --- /dev/null +++ b/src/actor/npc/ac_npc_act_into_house.c_inc @@ -0,0 +1,135 @@ +enum { + aNPC_ACT_INTO_HOUSE_STEP_TURN, + aNPC_ACT_INTO_HOUSE_STEP_APPROACH, + aNPC_ACT_INTO_HOUSE_STEP_UMB_CLOSE, + aNPC_ACT_INTO_HOUSE_STEP_REQUEST_PERMIT_WAIT, + aNPC_ACT_INTO_HOUSE_STEP_INTO, + + aNPC_ACT_INTO_HOUSE_STEP_NUM +}; + +static void aNPC_act_into_house_chg_step(NPC_ACTOR* nactorx, u8 step) { + // clang-format off + static u8 act_idx[] = { + aNPC_ACTION_TYPE_TURN, + aNPC_ACTION_TYPE_WALK, + aNPC_ACTION_TYPE_UMB_CLOSE, + aNPC_ACTION_TYPE_WAIT, + aNPC_ACTION_TYPE_OPEN_DOOR + }; + // clang-format on + + nactorx->action.step = step; + aNPC_setupAction(nactorx, act_idx[step]); +} + +static int aNPC_act_into_house_chg_into_step(NPC_ACTOR* nactorx, GAME_PLAY* play) { + int ret = FALSE; + + if (aNPC_request_house(nactorx, play, 1) == TRUE) { + aNPC_act_into_house_chg_step(nactorx, aNPC_ACT_INTO_HOUSE_STEP_INTO); + ret = TRUE; + } + + return ret; +} + +static void aNPC_act_into_house_turn(NPC_ACTOR* nactorx, GAME_PLAY* play) { + if (!aNPC_act_turn(nactorx)) { + aNPC_act_into_house_chg_step(nactorx, aNPC_ACT_INTO_HOUSE_STEP_APPROACH); + } +} + +static void aNPC_act_into_house_approach(NPC_ACTOR* nactorx, GAME_PLAY* play) { + chase_f(&nactorx->actor_class.world.position.x, nactorx->movement.dst_pos_x, 0.25f); + + if (!aNPC_act_move(nactorx) && + chase_angle(&nactorx->actor_class.shape_info.rotation.y, DEG2SHORT_ANGLE2(180.0f), 0x600)) { + if (nactorx->right_hand.item_type == aNPC_ITEM_TYPE_UMBRELLA) { + if (CLIP(tools_clip) + ->aTOL_chg_request_mode_proc((ACTOR*)nactorx, nactorx->right_hand.item_actor_p, + aTOL_ACTION_PUTAWAY) == TRUE) { + aNPC_act_into_house_chg_step(nactorx, aNPC_ACT_INTO_HOUSE_STEP_UMB_CLOSE); + } + } else { + aNPC_act_into_house_chg_into_step(nactorx, play); + } + } +} + +static void aNPC_act_into_house_umb_close(NPC_ACTOR* nactorx, GAME_PLAY* play) { + if (nactorx->right_hand.item_type == aNPC_ITEM_TYPE_UMBRELLA) { + aNPC_act_umb_close_main_proc(nactorx, play); + } + + if (nactorx->action.step == aNPC_ACTION_END_STEP) { + if (!aNPC_act_into_house_chg_into_step(nactorx, play)) { + aNPC_act_into_house_chg_step(nactorx, aNPC_ACT_INTO_HOUSE_STEP_REQUEST_PERMIT_WAIT); + } + } +} + +static void aNPC_act_into_house_request_permit_wait(NPC_ACTOR* nactorx, GAME_PLAY* play) { + aNPC_act_into_house_chg_into_step(nactorx, play); +} + +static void aNPC_act_into_house_into(NPC_ACTOR* nactorx, GAME_PLAY* play) { + if (!aNPC_act_anm_seq(nactorx)) { + nactorx->actor_class.world.position.x = nactorx->npc_info.list->house_position.x + mFI_UT_WORLDSIZE_HALF_X_F; + nactorx->actor_class.world.position.z = nactorx->npc_info.list->house_position.z + mFI_UT_WORLDSIZE_HALF_Z_F; + + if (nactorx->right_hand.item_actor_p != NULL) { + Actor_delete(nactorx->right_hand.item_actor_p); + nactorx->right_hand.item_actor_p = NULL; + } + + nactorx->actor_class.status_data.weight = 50; + aNPC_set_hide_request(nactorx, TRUE); + aNPC_setup_stay_my_house(nactorx); + nactorx->action.step = aNPC_ACTION_END_STEP; + } + + chase_f(&nactorx->actor_class.world.position.x, nactorx->movement.dst_pos_x, 0.5f); + chase_f(&nactorx->actor_class.world.position.z, nactorx->movement.dst_pos_z - 4.0f, 0.5f); + chase_angle(&nactorx->actor_class.shape_info.rotation.y, DEG2SHORT_ANGLE2(180.0f), 0x600); +} + +static void aNPC_act_into_house_main_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + static aNPC_SUB_PROC act_proc[] = { + &aNPC_act_into_house_turn, &aNPC_act_into_house_approach, + &aNPC_act_into_house_umb_close, &aNPC_act_into_house_request_permit_wait, + &aNPC_act_into_house_into, + }; + + if (nactorx->action.step < aNPC_ACT_INTO_HOUSE_STEP_NUM) { + (*act_proc[nactorx->action.step])(nactorx, play); + } +} + +static void aNPC_act_into_house_init_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + u8 step = aNPC_ACT_INTO_HOUSE_STEP_TURN; + + nactorx->actor_class.status_data.weight = MASSTYPE_HEAVY; + nactorx->condition_info.demo_flg = + aNPC_COND_DEMO_SKIP_UZAI_CHECK | aNPC_COND_DEMO_SKIP_ENTRANCE_CHECK | aNPC_COND_DEMO_SKIP_HEAD_LOOKAT | + aNPC_COND_DEMO_SKIP_TALK_CHECK | aNPC_COND_DEMO_SKIP_ITEM | aNPC_COND_DEMO_SKIP_FORWARD_CHECK | + aNPC_COND_DEMO_SKIP_MOVE_Y | aNPC_COND_DEMO_SKIP_MOVE_CIRCLE_REV | aNPC_COND_DEMO_SKIP_MOVE_RANGE_CHECK; + nactorx->movement.arrival_area_radius = 72.0f; + nactorx->palActorIgnoreTimer = -1; + + if (ABS(nactorx->actor_class.world.angle.y) > DEG2SHORT_ANGLE2(157.5f)) { + step = aNPC_ACT_INTO_HOUSE_STEP_APPROACH; + } + + aNPC_act_into_house_chg_step(nactorx, step); +} + +static void aNPC_act_into_house_proc(NPC_ACTOR* nactorx, GAME_PLAY* play, int type) { + static aNPC_SUB_PROC act_proc[] = { + &aNPC_act_into_house_init_proc, + (aNPC_SUB_PROC)&none_proc1, + &aNPC_act_into_house_main_proc, + }; + + (*act_proc[type])(nactorx, play); +} diff --git a/src/actor/npc/ac_npc_act_leave_house.c_inc b/src/actor/npc/ac_npc_act_leave_house.c_inc new file mode 100644 index 00000000..7d9dbd48 --- /dev/null +++ b/src/actor/npc/ac_npc_act_leave_house.c_inc @@ -0,0 +1,84 @@ +enum { + aNPC_ACT_LEAVE_HOUSE_STEP_WAIT, + aNPC_ACT_LEAVE_HOUSE_STEP_OUT_OF_DOOR, + aNPC_ACT_LEAVE_HOUSE_STEP_TURN, + + aNPC_ACT_LEAVE_HOUSE_STEP_NUM +}; + +static void aNPC_act_leave_house_chg_step(NPC_ACTOR* nactorx, u8 step) { + // clang-format off + static u8 act_idx[] = { + aNPC_ACTION_TYPE_WAIT, + aNPC_ACTION_TYPE_GO_OUT, + aNPC_ACTION_TYPE_TURN, + }; + // clang-format on + + nactorx->action.step = step; + aNPC_setupAction(nactorx, act_idx[step]); +} + +static void aNPC_act_leave_house_wait(NPC_ACTOR* nactorx, GAME_PLAY* play) { + NPC_CONTROL_ACTOR* ctrl = (NPC_CONTROL_ACTOR*)aNPC_ctrlActor; + + if (ctrl->door_exit_actor == NULL && ctrl->door_exit_timer == 0) { + if (!aNPC_check_entrance_humanoid(nactorx, play)) { + if (play->fb_wipe_mode == 0 && play->fb_fade_type == 0) { + if (aNPC_request_house(nactorx, play, 2) == TRUE) { + aNPC_act_leave_house_chg_step(nactorx, aNPC_ACT_LEAVE_HOUSE_STEP_OUT_OF_DOOR); + nactorx->npc_info.animal->is_home = FALSE; + aNPC_set_hide_request(nactorx, FALSE); + ctrl->door_exit_actor = (ACTOR*)nactorx; + } + } + } + } +} + +static void aNPC_act_leave_house_out_of_door(NPC_ACTOR* nactorx, GAME_PLAY* play) { + if (!aNPC_act_anm_seq(nactorx)) { + aNPC_act_leave_house_chg_step(nactorx, aNPC_ACT_LEAVE_HOUSE_STEP_TURN); + } +} + +static void aNPC_act_leave_house_turn(NPC_ACTOR* nactorx, GAME_PLAY* play) { + if (!aNPC_act_turn(nactorx)) { + aNPC_reset_out_of_door_flg((NPC_CONTROL_ACTOR*)aNPC_ctrlActor, (ACTOR*)nactorx); + if (ITEM_NAME_GET_TYPE(nactorx->actor_class.npc_id) == NAME_TYPE_NPC) { + nactorx->palActorIgnoreTimer = 0; + } + + nactorx->action.step = aNPC_ACTION_END_STEP; + } +} + +static void aNPC_act_leave_house_main_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + static aNPC_SUB_PROC act_proc[] = { + &aNPC_act_leave_house_wait, &aNPC_act_leave_house_out_of_door, + &aNPC_act_leave_house_turn, + }; + + (*act_proc[nactorx->action.step])(nactorx, play); +} + +static void aNPC_act_leave_house_init_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + nactorx->palActorIgnoreTimer = -1; + nactorx->movement.arrival_area_radius = 72.0f; + nactorx->condition_info.demo_flg = + aNPC_COND_DEMO_SKIP_UZAI_CHECK | aNPC_COND_DEMO_SKIP_ENTRANCE_CHECK | aNPC_COND_DEMO_SKIP_HEAD_LOOKAT | + aNPC_COND_DEMO_SKIP_TALK_CHECK | aNPC_COND_DEMO_SKIP_ITEM | aNPC_COND_DEMO_SKIP_FORWARD_CHECK | + aNPC_COND_DEMO_SKIP_MOVE_Y | aNPC_COND_DEMO_SKIP_MOVE_CIRCLE_REV | aNPC_COND_DEMO_SKIP_MOVE_RANGE_CHECK; + + aNPC_act_leave_house_chg_step(nactorx, aNPC_ACT_LEAVE_HOUSE_STEP_WAIT); +} + +static void aNPC_act_leave_house_proc(NPC_ACTOR* nactorx, GAME_PLAY* play, int type) { + static aNPC_SUB_PROC act_proc[] = { + &aNPC_act_leave_house_init_proc, + (aNPC_SUB_PROC)&none_proc1, + &aNPC_act_leave_house_main_proc, + }; + + (*act_proc[type])(nactorx, play); +} diff --git a/src/actor/npc/ac_npc_act_pitfall.c_inc b/src/actor/npc/ac_npc_act_pitfall.c_inc new file mode 100644 index 00000000..cb3312ca --- /dev/null +++ b/src/actor/npc/ac_npc_act_pitfall.c_inc @@ -0,0 +1,105 @@ +enum { + aNPC_ACT_PITFALL_STEP_TOTTER, + aNPC_ACT_PITFALL_STEP_FALL, + aNPC_ACT_PITFALL_STEP_FALL2, + aNPC_ACT_PITFALL_STEP_STRUGGLE, + + aNPC_ACT_PITFALL_STEP_NUM +}; + +static void aNPC_act_pitfall_chg_step(NPC_ACTOR* nactorx, u8 step) { + // clang-format off + static u8 act_idx[] = { + aNPC_ACTION_TYPE_GURATUKU, + aNPC_ACTION_TYPE_OTIRU1, + aNPC_ACTION_TYPE_OTIRU2, + aNPC_ACTION_TYPE_MOGAKU, + }; + // clang-format on + + nactorx->action.step = step; + aNPC_setupAction(nactorx, act_idx[step]); +} + +static void aNPC_act_pitfall_totter(NPC_ACTOR* nactorx, GAME_PLAY* play) { + int move_flag = FALSE; + + if (nactorx->actor_class.shape_info.rotation.y == nactorx->movement.mv_angl) { + move_flag = TRUE; + } + + move_flag &= chase_f(&nactorx->actor_class.world.position.x, nactorx->movement.dst_pos_x, 1.5f); + move_flag &= chase_f(&nactorx->actor_class.world.position.z, nactorx->movement.dst_pos_z, 1.5f); + + if (!aNPC_act_anm_seq(nactorx) && move_flag == TRUE) { + u8 step; + + if (nactorx->draw.sub_anim_type == aNPC_SUB_ANIM_NONE) { + step = aNPC_ACT_PITFALL_STEP_FALL; + } else { + nactorx->draw.sub_anim_type = aNPC_SUB_ANIM_NONE; + step = aNPC_ACT_PITFALL_STEP_FALL2; + } + + aNPC_act_pitfall_chg_step(nactorx, step); + } +} + +static void aNPC_act_pitfall_fall(NPC_ACTOR* nactorx, GAME_PLAY* play) { + if (!aNPC_act_anm_seq(nactorx)) { + nactorx->talk_info.turn = aNPC_TALK_TURN_NONE; + nactorx->talk_info.default_animation = aNPC_ANIM_MOGAKU1; + nactorx->condition_info.demo_flg = + aNPC_COND_DEMO_SKIP_UZAI_CHECK | aNPC_COND_DEMO_SKIP_ENTRANCE_CHECK | aNPC_COND_DEMO_SKIP_HEAD_LOOKAT | + aNPC_COND_DEMO_SKIP_ITEM | aNPC_COND_DEMO_SKIP_FORWARD_CHECK | aNPC_COND_DEMO_SKIP_BGCHECK | + aNPC_COND_DEMO_SKIP_MOVE_Y | aNPC_COND_DEMO_SKIP_MOVE_CIRCLE_REV | aNPC_COND_DEMO_SKIP_MOVE_RANGE_CHECK; + aNPC_act_pitfall_chg_step(nactorx, aNPC_ACT_PITFALL_STEP_STRUGGLE); + } +} + +static void aNPC_act_pitfall_main_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + // clang-format off + static aNPC_SUB_PROC act_proc[] = { + &aNPC_act_pitfall_totter, + &aNPC_act_pitfall_fall, + &aNPC_act_pitfall_fall, + (aNPC_SUB_PROC)&none_proc1, + }; + // clang-format on + + (*act_proc[nactorx->action.step])(nactorx, play); +} + +static void aNPC_act_pitfall_init_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + u8 step; + u32 demo_flg; + + if (nactorx->talk_info.default_animation == aNPC_ANIM_MOGAKU1) { + step = aNPC_ACT_PITFALL_STEP_STRUGGLE; + demo_flg = aNPC_COND_DEMO_SKIP_UZAI_CHECK | aNPC_COND_DEMO_SKIP_ENTRANCE_CHECK | + aNPC_COND_DEMO_SKIP_HEAD_LOOKAT | aNPC_COND_DEMO_SKIP_ITEM | aNPC_COND_DEMO_SKIP_FORWARD_CHECK | + aNPC_COND_DEMO_SKIP_BGCHECK | aNPC_COND_DEMO_SKIP_MOVE_Y | aNPC_COND_DEMO_SKIP_MOVE_CIRCLE_REV | + aNPC_COND_DEMO_SKIP_MOVE_RANGE_CHECK; + } else { + step = aNPC_ACT_PITFALL_STEP_TOTTER; + demo_flg = aNPC_COND_DEMO_SKIP_UZAI_CHECK | aNPC_COND_DEMO_SKIP_ENTRANCE_CHECK | + aNPC_COND_DEMO_SKIP_HEAD_LOOKAT | aNPC_COND_DEMO_SKIP_TALK_CHECK | aNPC_COND_DEMO_SKIP_ITEM | + aNPC_COND_DEMO_SKIP_FORWARD_CHECK | aNPC_COND_DEMO_SKIP_BGCHECK | aNPC_COND_DEMO_SKIP_MOVE_Y | + aNPC_COND_DEMO_SKIP_MOVE_CIRCLE_REV | aNPC_COND_DEMO_SKIP_MOVE_RANGE_CHECK; + } + + nactorx->movement.mv_angl = 0; + nactorx->movement.mv_add_angl = DEG2SHORT_ANGLE2(22.5f); + aNPC_act_pitfall_chg_step(nactorx, step); + nactorx->condition_info.demo_flg = demo_flg; +} + +static void aNPC_act_pitfall_proc(NPC_ACTOR* nactorx, GAME_PLAY* play, int type) { + static aNPC_SUB_PROC act_proc[] = { + &aNPC_act_pitfall_init_proc, + (aNPC_SUB_PROC)&none_proc1, + &aNPC_act_pitfall_main_proc, + }; + + (*act_proc[type])(nactorx, play); +} diff --git a/src/actor/npc/ac_npc_act_react_tool.c_inc b/src/actor/npc/ac_npc_act_react_tool.c_inc new file mode 100644 index 00000000..eefecc3e --- /dev/null +++ b/src/actor/npc/ac_npc_act_react_tool.c_inc @@ -0,0 +1,121 @@ +enum { + aNPC_ACT_REACT_TOOL_STEP_SURPRISE, + aNPC_ACT_REACT_TOOL_STEP_SURPRISE2, + aNPC_ACT_REACT_TOOL_STEP_SURPRISE_UZAI, + aNPC_ACT_REACT_TOOL_STEP_LOOK_PLAYER, + + aNPC_ACT_REACT_TOOL_STEP_NUM +}; + +static void aNPC_act_react_tool_chg_step(NPC_ACTOR* nactorx, u8 step); + +static void aNPC_setup_react_tool_end(NPC_ACTOR* nactorx) { + nactorx->head.angle_add_x = 0x200; + nactorx->head.angle_add_y = 0x400; + nactorx->palActorIgnoreTimer = 0; + nactorx->condition_info.demo_flg = 0; + nactorx->action.step = aNPC_ACTION_END_STEP; +} + +static void aNPC_act_react_tool_surprise(NPC_ACTOR* nactorx, GAME_PLAY* play) { + if (!aNPC_act_anm_seq(nactorx)) { + aNPC_setup_react_tool_end(nactorx); + } +} + +static void aNPC_act_react_tool_surprise2(NPC_ACTOR* nactorx, GAME_PLAY* play) { + if (!aNPC_act_anm_seq(nactorx)) { + nactorx->act_react_tool_timer = 5 * FRAMES_PER_SECOND; + aNPC_act_react_tool_chg_step(nactorx, aNPC_ACT_REACT_TOOL_STEP_LOOK_PLAYER); + } +} + +static void aNPC_act_react_tool_look_player(NPC_ACTOR* nactorx, GAME_PLAY* play) { + ACTOR* playerx = GET_PLAYER_ACTOR_ACTOR(play); + + if (playerx != NULL) { + aNPC_set_head_request(nactorx, 4, aNPC_HEAD_TARGET_ACTOR, playerx, NULL); + } + + nactorx->act_react_tool_timer--; + if (nactorx->act_react_tool_timer < 0) { + aNPC_setup_react_tool_end(nactorx); + } +} + +static void aNPC_act_react_tool_chg_step(NPC_ACTOR* nactorx, u8 step) { + // clang-format off + static u8 act_idx[] = { + aNPC_ACTION_TYPE_GYAFUN1, + aNPC_ACTION_TYPE_GYAFUN2, + aNPC_ACTION_TYPE_GYAFUN2, + aNPC_ACTION_TYPE_WAIT, + }; + // clang-format on + + nactorx->action.step = step; + aNPC_setupAction(nactorx, act_idx[step]); +} + +static void aNPC_act_react_tool_main_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + // clang-format off + static aNPC_SUB_PROC act_proc[] = { + &aNPC_act_react_tool_surprise, + &aNPC_act_react_tool_surprise2, + &aNPC_act_react_tool_surprise, + &aNPC_act_react_tool_look_player, + }; + // clang-format on + + (*act_proc[nactorx->action.step])(nactorx, play); +} + +static void aNPC_act_react_tool_init_proc(NPC_ACTOR* nactorx, GAME_PLAY* play); + +static void aNPC_act_react_tool_chg_data_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + if (nactorx->action.idx == nactorx->action.prev_idx) { + aNPC_act_react_tool_init_proc(nactorx, play); + } +} + +static void aNPC_act_react_tool_init_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + u8 step = aNPC_ACT_REACT_TOOL_STEP_SURPRISE; + int feel = aNPC_get_feel_info(nactorx); + + nactorx->movement.mv_angl = nactorx->actor_class.shape_info.rotation.y; + nactorx->head.angle_add_x = 0x600; + nactorx->head.angle_add_y = 0xC00; + nactorx->palActorIgnoreTimer = -1; + + if (nactorx->think.force_call_flag == aNPC_FORCE_CALL_REQUEST) { + nactorx->condition_info.demo_flg = 0; + } else { + nactorx->condition_info.demo_flg = aNPC_COND_DEMO_SKIP_ENTRANCE_CHECK | aNPC_COND_DEMO_SKIP_HEAD_LOOKAT | + aNPC_COND_DEMO_SKIP_TALK_CHECK | aNPC_COND_DEMO_SKIP_ITEM | aNPC_COND_DEMO_SKIP_FORWARD_CHECK | + aNPC_COND_DEMO_SKIP_MOVE_Y | aNPC_COND_DEMO_SKIP_MOVE_CIRCLE_REV | aNPC_COND_DEMO_SKIP_MOVE_RANGE_CHECK; + } + + switch (feel) { + case mNpc_FEEL_UZAI_0: + case mNpc_FEEL_UZAI_1: + step = aNPC_ACT_REACT_TOOL_STEP_SURPRISE_UZAI; + break; + default: + if (aNPC_check_look_player(nactorx, play)) { + step = aNPC_ACT_REACT_TOOL_STEP_SURPRISE2; + } + break; + } + + aNPC_act_react_tool_chg_step(nactorx, step); +} + +static void aNPC_act_react_tool_proc(NPC_ACTOR* nactorx, GAME_PLAY* play, int type) { + static aNPC_SUB_PROC act_proc[] = { + &aNPC_act_react_tool_init_proc, + &aNPC_act_react_tool_chg_data_proc, + &aNPC_act_react_tool_main_proc, + }; + + (*act_proc[type])(nactorx, play); +} diff --git a/src/actor/npc/ac_npc_act_revive.c_inc b/src/actor/npc/ac_npc_act_revive.c_inc new file mode 100644 index 00000000..070e3644 --- /dev/null +++ b/src/actor/npc/ac_npc_act_revive.c_inc @@ -0,0 +1,34 @@ +static void aNPC_act_revive_main_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + if (!aNPC_act_anm_seq(nactorx)) { + nactorx->action.step = aNPC_ACTION_END_STEP; + } +} + +static void aNPC_act_revive_init_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + u8 act = aNPC_ACTION_TYPE_DERU1; + + if (nactorx->right_hand.item_type == aNPC_ITEM_TYPE_UMBRELLA) { + act = aNPC_ACTION_TYPE_DERU2; + } + + CLIP(bg_item_clip) + ->pit_exit_proc(*nactorx->condition_info.under_fg_p, nactorx->condition_info.ut_x, nactorx->condition_info.ut_z, + nactorx->actor_class.npc_id); + nactorx->action.step = 0; + nactorx->condition_info.demo_flg = aNPC_COND_DEMO_SKIP_UZAI_CHECK | aNPC_COND_DEMO_SKIP_ENTRANCE_CHECK | + aNPC_COND_DEMO_SKIP_HEAD_LOOKAT | aNPC_COND_DEMO_SKIP_TALK_CHECK | + aNPC_COND_DEMO_SKIP_ITEM | aNPC_COND_DEMO_SKIP_FORWARD_CHECK | + aNPC_COND_DEMO_SKIP_BGCHECK | aNPC_COND_DEMO_SKIP_MOVE_Y | + aNPC_COND_DEMO_SKIP_MOVE_CIRCLE_REV | aNPC_COND_DEMO_SKIP_MOVE_RANGE_CHECK; + aNPC_setupAction(nactorx, act); +} + +static void aNPC_act_revive_proc(NPC_ACTOR* nactorx, GAME_PLAY* play, int type) { + static aNPC_SUB_PROC act_proc[] = { + &aNPC_act_revive_init_proc, + (aNPC_SUB_PROC)&none_proc1, + &aNPC_act_revive_main_proc, + }; + + (*act_proc[type])(nactorx, play); +} diff --git a/src/actor/npc/ac_npc_act_talk.c_inc b/src/actor/npc/ac_npc_act_talk.c_inc new file mode 100644 index 00000000..340710e4 --- /dev/null +++ b/src/actor/npc/ac_npc_act_talk.c_inc @@ -0,0 +1,127 @@ +enum { + aNPC_ACT_TALK_STEP_TALK_TURN, + aNPC_ACT_TALK_STEP_TALK_WAIT, + aNPC_ACT_TALK_STEP_TALK, + + aNPC_ACT_TALK_STEP_NUM +}; + +static void aNPC_Init_OrderValue(void) { + int i; + int j; + + for (i = mDemo_ORDER_NPC0; i < mDemo_ORDER_NPC2; i++) { + for (j = 0; j < mDemo_ORDER_VALUE_MAX; j++) { + mDemo_Set_OrderValue(i, j, 0); + } + } +} + +static void aNPC_talk_demo_proc(ACTOR* actorx) { + aNPC_check_feel_demoCode(actorx); + aNPC_check_manpu_demoCode(actorx); + aNPC_check_timing_demoCode(actorx); +} + +static int aNPC_talk_end_check(ACTOR* actorx, GAME* game) { + int ret = FALSE; + + if (((NPC_ACTOR*)actorx)->think.force_call_flag != aNPC_FORCE_CALL_NONE) { + if (!mDemo_Check(mDemo_TYPE_SPEAK, actorx)) { + ret = TRUE; + } + } else { + if (CLIP(quest_manager_clip)->talk_check_proc != NULL && CLIP(quest_manager_clip)->talk_check_proc(actorx) == TRUE) { + ret = TRUE; + } + } + + return ret; +} + +static void aNPC_act_talk_chg_step(NPC_ACTOR* nactorx, u8 step) { + // clang-format off + static u8 act_idx[] = { + aNPC_ACTION_TYPE_TALK_TURN, + aNPC_ACTION_TYPE_TALK, + aNPC_ACTION_TYPE_TALK, + }; + // clang-format on + + nactorx->action.step = step; + aNPC_setupAction(nactorx, act_idx[step]); +} + +static void aNPC_act_talk_turn(NPC_ACTOR* nactorx, GAME_PLAY* play) { + if (!aNPC_act_turn(nactorx)) { + aNPC_act_talk_chg_step(nactorx, aNPC_ACT_TALK_STEP_TALK_WAIT); + } +} + +static void aNPC_act_talk_wait(NPC_ACTOR* nactorx, GAME_PLAY* play) { + if (ITEM_NAME_GET_TYPE(nactorx->actor_class.npc_id) == NAME_TYPE_SPNPC) { + if ((*nactorx->talk_info.talk_init_proc)((ACTOR*)nactorx, (GAME*)play) == TRUE && mDemo_Check_SpeakerAble() == TRUE) { + mMld_ActorMakeMelody((ACTOR*)nactorx); + aNPC_act_talk_chg_step(nactorx, aNPC_ACT_TALK_STEP_TALK); + + if (nactorx->npc_info.animal != NULL && nactorx->talk_info.memory == TRUE) { + mNpc_SetAnimalLastTalk(nactorx->npc_info.animal); + } + } + } else if (nactorx->think.force_call_flag != aNPC_FORCE_CALL_NONE) { + mMld_ActorMakeMelody((ACTOR*)nactorx); + mDemo_Set_ListenAble(); + aNPC_act_talk_chg_step(nactorx, aNPC_ACT_TALK_STEP_TALK); + } else if (CLIP(quest_manager_clip)->talk_start_proc((ACTOR*)nactorx) == TRUE) { + aNPC_act_talk_chg_step(nactorx, aNPC_ACT_TALK_STEP_TALK); + } +} + +static void aNPC_act_talk(NPC_ACTOR* nactorx, GAME_PLAY* play) { + if ((*nactorx->talk_info.talk_end_check_proc)((ACTOR*)nactorx, (GAME*)play) == TRUE) { + aNPC_setup_talk_end(nactorx); + nactorx->action.step = aNPC_ACTION_END_STEP; + } else { + aNPC_talk_demo_proc((ACTOR*)nactorx); + } +} + +static void aNPC_act_talk_main_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + static aNPC_SUB_PROC act_proc[] = { + &aNPC_act_talk_turn, + &aNPC_act_talk_wait, + &aNPC_act_talk, + }; + + (*act_proc[nactorx->action.step])(nactorx, play); +} + +static void aNPC_act_talk_init_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + u8 step = aNPC_ACT_TALK_STEP_TALK_TURN; + + if (nactorx->condition_info.talk_condition == aNPC_TALK_TYPE_CONTINUE) { + step = aNPC_ACT_TALK_STEP_TALK; + } else { + aNPC_Init_OrderValue(); + if (nactorx->talk_info.turn != aNPC_TALK_TURN_NORMAL) { + step = aNPC_ACT_TALK_STEP_TALK_WAIT; + } + nactorx->condition_info.talk_condition = aNPC_TALK_TYPE_CONTINUE; + } + + if (ITEM_NAME_GET_TYPE(nactorx->actor_class.npc_id) == NAME_TYPE_NPC) { + if (nactorx->npc_info.animal->mood != mNpc_FEEL_PITFALL) { + nactorx->condition_info.demo_flg &= aNPC_COND_DEMO_SKIP_LOVE_CHECK | aNPC_COND_DEMO_SKIP_MOVE_CIRCLE_REV | aNPC_COND_DEMO_SKIP_MOVE_RANGE_CHECK; + } + } else { + nactorx->condition_info.demo_flg &= aNPC_COND_DEMO_SKIP_LOVE_CHECK | aNPC_COND_DEMO_SKIP_BGCHECK | aNPC_COND_DEMO_SKIP_OBJ_COL_CHECK | aNPC_COND_DEMO_SKIP_MOVE_Y | aNPC_COND_DEMO_SKIP_MOVE_CIRCLE_REV | aNPC_COND_DEMO_SKIP_MOVE_RANGE_CHECK; + } + + aNPC_act_talk_chg_step(nactorx, step); +} + +static void aNPC_act_talk_proc(NPC_ACTOR* nactorx, GAME_PLAY* play, int type) { + static aNPC_SUB_PROC act_proc[] = { &aNPC_act_talk_init_proc, (aNPC_SUB_PROC)&none_proc1, &aNPC_act_talk_main_proc }; + + (*act_proc[type])(nactorx, play); +} diff --git a/src/actor/npc/ac_npc_act_trans.c_inc b/src/actor/npc/ac_npc_act_trans.c_inc new file mode 100644 index 00000000..1aa935ad --- /dev/null +++ b/src/actor/npc/ac_npc_act_trans.c_inc @@ -0,0 +1,160 @@ +enum { + aNPC_ACT_TRANS_STEP_MOVE, + aNPC_ACT_TRANS_STEP_TRANS, + aNPC_ACT_TRANS_STEP_TRANS_F, + aNPC_ACT_TRANS_STEP_WAIT, + aNPC_ACT_TRANS_STEP_WAIT_F, + aNPC_ACT_TRANS_STEP_SEND_MAIL, + aNPC_ACT_TRANS_STEP_SEND_MAIL_WAIT, + + aNPC_ACT_TRANS_STEP_NUM +}; + +static void aNPC_act_trans_chg_step(NPC_ACTOR* nactorx, u8 step) { + // clang-format off + static u8 act_idx[] = { + aNPC_ACTION_TYPE_WALK, + aNPC_ACTION_TYPE_TRANSFER, + aNPC_ACTION_TYPE_TRANSFER_F, + aNPC_ACTION_TYPE_TRANSFER_WAIT, + aNPC_ACTION_TYPE_TRANSFER_F_WAIT, + aNPC_ACTION_TYPE_SEND_MAIL, + aNPC_ACTION_TYPE_TALK, + }; + // clang-format on + + u8 timer = 0; + + switch (step) { + case aNPC_ACT_TRANS_STEP_MOVE: + timer = 80; + break; + case aNPC_ACT_TRANS_STEP_TRANS: + case aNPC_ACT_TRANS_STEP_SEND_MAIL: + aNPC_OngenTrgStart(nactorx, NA_SE_GASAGOSO); + break; + } + + switch (step) { + case aNPC_ACT_TRANS_STEP_TRANS: + case aNPC_ACT_TRANS_STEP_WAIT: { + mActor_name_t item = nactorx->left_hand.item; + + if (ITEM_IS_FISH(item) == TRUE) { + step++; + } + + break; + } + } + + nactorx->movement.demo_move_timer = timer; + nactorx->action.step = step; + aNPC_setupAction(nactorx, act_idx[step]); +} + +static void aNPC_act_trans_set_arg_data(NPC_ACTOR* nactorx) { + u16* arg_data = nactorx->request.act_args; + + nactorx->left_hand.item = arg_data[0]; + nactorx->left_hand.after_mode = arg_data[1]; + nactorx->left_hand.present_flag = arg_data[2]; + nactorx->left_hand.requested_item_type = aNPC_ITEM_TYPE_LEFT_HAND; +} + +static void aNPC_act_trans_move(NPC_ACTOR* nactorx, GAME_PLAY* play) { + if (nactorx->movement.demo_move_timer != 0) { + nactorx->movement.demo_move_timer--; + } + + if (!aNPC_act_search_move(nactorx) || + (nactorx->collision.collision_flag & (mCoBG_HIT_WALL | mCoBG_HIT_WALL_FRONT)) != 0 || + nactorx->movement.demo_move_timer == 0) { + aNPC_act_trans_set_arg_data(nactorx); + aNPC_act_trans_chg_step(nactorx, aNPC_ACT_TRANS_STEP_TRANS); + } +} + +static void aNPC_act_trans(NPC_ACTOR* nactorx, GAME_PLAY* play) { + if (nactorx->draw.main_animation_state == cKF_STATE_STOPPED && + CLIP(handOverItem_clip)->master_actor == (ACTOR*)nactorx) { + CLIP(handOverItem_clip)->chg_request_mode_proc((ACTOR*)nactorx, aHOI_REQUEST_TRANS_WAIT); + aNPC_act_trans_chg_step(nactorx, aNPC_ACT_TRANS_STEP_WAIT); + } +} + +static void aNPC_act_trans_wait(NPC_ACTOR* nactorx, GAME_PLAY* play) { + aNPC_check_manpu_demoCode((ACTOR*)nactorx); + + if (CLIP(handOverItem_clip)->master_actor != (ACTOR*)nactorx) { + aNPC_clear_left_hand_info(nactorx); + aNPC_act_return_trans_item(nactorx); + } +} + +static void aNPC_act_trans_send_mail(NPC_ACTOR* nactorx, GAME_PLAY* play) { + if (nactorx->draw.main_animation_state == cKF_STATE_STOPPED && + CLIP(handOverItem_clip)->master_actor == (ACTOR*)nactorx) { + CLIP(handOverItem_clip)->chg_request_mode_proc((ACTOR*)nactorx, aHOI_REQUEST_TRANS_WAIT); + aNPC_clear_left_hand_info(nactorx); + aNPC_act_trans_chg_step(nactorx, aNPC_ACT_TRANS_STEP_SEND_MAIL_WAIT); + } +} + +static void aNPC_act_trans_main_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + // clang-format off + static aNPC_SUB_PROC act_proc[] = { + &aNPC_act_trans_move, + &aNPC_act_trans, + &aNPC_act_trans, + &aNPC_act_trans_wait, + &aNPC_act_trans_wait, + &aNPC_act_trans_send_mail, + &aNPC_act_trans_wait, + }; + // clang-format on + + if ((*nactorx->talk_info.talk_end_check_proc)((ACTOR*)nactorx, (GAME*)play) == TRUE) { + aNPC_setup_talk_end(nactorx); + nactorx->action.step = aNPC_ACTION_END_STEP; + } else { + aNPC_check_feel_demoCode((ACTOR*)nactorx); + (*act_proc[nactorx->action.step])(nactorx, play); + } +} + +static void aNPC_act_trans_chg_data_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + nactorx->action.act_obj = aNPC_ACT_OBJ_PLAYER; +} + +static void aNPC_act_trans_init_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + u8 step; + + nactorx->condition_info.trans_demo_flg_save = nactorx->condition_info.demo_flg; + nactorx->condition_info.demo_flg = + aNPC_COND_DEMO_SKIP_UZAI_CHECK | aNPC_COND_DEMO_SKIP_ENTRANCE_CHECK | aNPC_COND_DEMO_SKIP_HEAD_LOOKAT | + aNPC_COND_DEMO_SKIP_TALK_CHECK | aNPC_COND_DEMO_SKIP_ITEM | aNPC_COND_DEMO_SKIP_FORWARD_CHECK | + aNPC_COND_DEMO_SKIP_OBJ_COL_CHECK | aNPC_COND_DEMO_SKIP_MOVE_CIRCLE_REV | aNPC_COND_DEMO_SKIP_MOVE_RANGE_CHECK; + nactorx->movement.arrival_area_radius = SQ(50.0f); + if (nactorx->request.act_args[0] == ITM_FORTUNE_SLIP) { + aNPC_act_trans_set_arg_data(nactorx); + step = aNPC_ACT_TRANS_STEP_SEND_MAIL; + } else if (nactorx->request.act_args[2] == 2) { + aNPC_act_trans_set_arg_data(nactorx); + step = aNPC_ACT_TRANS_STEP_TRANS; + } else { + step = aNPC_ACT_TRANS_STEP_MOVE; + } + + aNPC_act_trans_chg_step(nactorx, step); +} + +static void aNPC_act_trans_proc(NPC_ACTOR* nactorx, GAME_PLAY* play, int type) { + static aNPC_SUB_PROC act_proc[] = { + &aNPC_act_trans_init_proc, + &aNPC_act_trans_chg_data_proc, + &aNPC_act_trans_main_proc, + }; + + (*act_proc[type])(nactorx, play); +} diff --git a/src/actor/npc/ac_npc_act_turn.c_inc b/src/actor/npc/ac_npc_act_turn.c_inc new file mode 100644 index 00000000..7a98c7e9 --- /dev/null +++ b/src/actor/npc/ac_npc_act_turn.c_inc @@ -0,0 +1,66 @@ +enum { + aNPC_ACT_TURN_STEP_MAIN, + + aNPC_ACT_TURN_STEP_NUM +}; + +typedef int (*aNPC_ACT_TURN_PROC)(NPC_ACTOR* nactorx); + +static void aNPC_act_turn_main_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + static aNPC_ACT_TURN_PROC act_proc[] = { + &aNPC_act_turn, + &aNPC_act_turn, + &aNPC_act_search_turn, + &aNPC_act_to_point_turn, + }; + + if (!(*act_proc[nactorx->action.type])(nactorx)) { + nactorx->action.step = aNPC_ACTION_END_STEP; + } +} + +static void aNPC_act_turn_chg_data_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + u16* arg_p = nactorx->request.act_args; + s16 prev_move_x = nactorx->action.move_x; + s16 prev_move_z = nactorx->action.move_z; + + nactorx->action.act_obj = arg_p[0]; + nactorx->action.act_obj_id = arg_p[1]; + nactorx->action.move_x = arg_p[2]; + nactorx->action.move_z = arg_p[3]; + + if (nactorx->action.step == aNPC_ACTION_END_STEP && + (nactorx->action.move_x != prev_move_x || nactorx->action.move_z != prev_move_z || + nactorx->action.type == aNPC_ACT_TYPE_SEARCH)) { + nactorx->action.step = aNPC_ACT_TURN_STEP_MAIN; + } +} + +static void aNPC_act_turn_init_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + u8 action; + + nactorx->action.step = aNPC_ACT_TURN_STEP_MAIN; + if (nactorx->action.type == aNPC_ACT_TYPE_AVOID) { + aNPC_set_avoid_pos(nactorx, nactorx->action.move_x, nactorx->action.move_z, nactorx->request.act_args[4]); + } else { + aNPC_set_dst_pos(nactorx, nactorx->action.move_x, nactorx->action.move_z); + } + + if (nactorx->action.idx == aNPC_ACT_TURN) { + action = 13; + } else { + action = 14; + } + + aNPC_setupAction(nactorx, action); +} + +static void aNPC_act_turn_proc(NPC_ACTOR* nactorx, GAME_PLAY* play, int type) { + static aNPC_SUB_PROC act_proc[] = { + &aNPC_act_turn_init_proc, + &aNPC_act_turn_chg_data_proc, + &aNPC_act_turn_main_proc, + }; + + (*act_proc[type])(nactorx, play); +} diff --git a/src/actor/npc/ac_npc_act_umb_close.c_inc b/src/actor/npc/ac_npc_act_umb_close.c_inc new file mode 100644 index 00000000..4bb1a5fd --- /dev/null +++ b/src/actor/npc/ac_npc_act_umb_close.c_inc @@ -0,0 +1,33 @@ +enum { + aNPC_ACT_UMB_CLOSE_STEP_CLOSE, + + aNPC_ACT_UMB_CLOSE_STEP_NUM +}; + +static void aNPC_act_umb_close_main_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + if (!aNPC_act_anm_seq(nactorx) && CLIP(tools_clip) != NULL) { + if (CLIP(tools_clip) + ->aTOL_chg_request_mode_proc((ACTOR*)nactorx, nactorx->right_hand.item_actor_p, aTOL_ACTION_DESTRUCT) == + TRUE) { + nactorx->right_hand.item_type = aNPC_ITEM_TYPE_NONE; + nactorx->right_hand.item_actor_p = NULL; + nactorx->action.step = aNPC_ACTION_END_STEP; + } + } +} + +static void aNPC_act_umb_close_init_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + nactorx->action.step = aNPC_ACT_UMB_CLOSE_STEP_CLOSE; + nactorx->draw.sub_anim_type = aNPC_SUB_ANIM_NONE; + aNPC_setupAction(nactorx, aNPC_ACTION_TYPE_UMB_CLOSE); +} + +static void aNPC_act_umb_close_proc(NPC_ACTOR* nactorx, GAME_PLAY* play, int type) { + static aNPC_SUB_PROC act_proc[] = { + &aNPC_act_umb_close_init_proc, + (aNPC_SUB_PROC)&none_proc1, + &aNPC_act_umb_close_main_proc, + }; + + (*act_proc[type])(nactorx, play); +} diff --git a/src/actor/npc/ac_npc_act_umb_open.c_inc b/src/actor/npc/ac_npc_act_umb_open.c_inc new file mode 100644 index 00000000..fd12e6ea --- /dev/null +++ b/src/actor/npc/ac_npc_act_umb_open.c_inc @@ -0,0 +1,47 @@ +enum { + aNPC_ACT_UMB_OPEN_STEP_OPEN, + + aNPC_ACT_UMB_OPEN_STEP_NUM +}; + +static void aNPC_act_umb_open_main_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + if (!aNPC_act_anm_seq(nactorx)) { + if (nactorx->request.umb_flag == TRUE) { + nactorx->request.umb_flag = FALSE; + } else { + aNPC_reset_umb_open_flg((NPC_CONTROL_ACTOR*)aNPC_ctrlActor, (ACTOR*)nactorx); + } + + nactorx->palActorIgnoreTimer = 0; + nactorx->draw.sub_anim_type = aNPC_SUB_ANIM_UMBRELLA; + nactorx->condition_info.demo_flg = 0; + nactorx->action.step = aNPC_ACTION_END_STEP; + } +} + +static void aNPC_act_umb_open_init_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + nactorx->action.step = aNPC_ACT_UMB_OPEN_STEP_OPEN; + nactorx->palActorIgnoreTimer = -1; + nactorx->condition_info.demo_flg = + aNPC_COND_DEMO_SKIP_UZAI_CHECK | aNPC_COND_DEMO_SKIP_ENTRANCE_CHECK | aNPC_COND_DEMO_SKIP_HEAD_LOOKAT | + aNPC_COND_DEMO_SKIP_TALK_CHECK | aNPC_COND_DEMO_SKIP_ITEM | aNPC_COND_DEMO_SKIP_FORWARD_CHECK | + aNPC_COND_DEMO_SKIP_MOVE_Y | aNPC_COND_DEMO_SKIP_MOVE_CIRCLE_REV | aNPC_COND_DEMO_SKIP_MOVE_RANGE_CHECK; + + if (nactorx->request.umb_flag == TRUE) { + aNPC_setupAction(nactorx, aNPC_wait_action[aNPC_get_feel_info(nactorx)]); + nactorx->draw.main_animation.keyframe.frame_control.mode = cKF_FRAMECONTROL_STOP; + nactorx->draw.main_animation.keyframe.morph_counter = 0.0f; + } else { + aNPC_setupAction(nactorx, aNPC_ACTION_TYPE_UMB_OPEN); + } +} + +static void aNPC_act_umb_open_proc(NPC_ACTOR* nactorx, GAME_PLAY* play, int type) { + static aNPC_SUB_PROC act_proc[] = { + &aNPC_act_umb_open_init_proc, + (aNPC_SUB_PROC)&none_proc1, + &aNPC_act_umb_open_main_proc, + }; + + (*act_proc[type])(nactorx, play); +} diff --git a/src/actor/npc/ac_npc_act_wait.c_inc b/src/actor/npc/ac_npc_act_wait.c_inc new file mode 100644 index 00000000..66249674 --- /dev/null +++ b/src/actor/npc/ac_npc_act_wait.c_inc @@ -0,0 +1,43 @@ +enum { + aNPC_ACT_WAIT_STEP_MAIN, + + aNPC_ACT_WAIT_STEP_NUM +}; + +static void aNPC_act_wait_main_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + if (nactorx->draw.main_animation_state == cKF_STATE_CONTINUE) { + u8 feel = aNPC_get_feel_info(nactorx); + + if (nactorx->action.feel != feel) { + nactorx->action.feel = feel; + aNPC_setupAction(nactorx, aNPC_wait_action[feel]); + } + } + + if (!aNPC_act_wait(nactorx)) { + nactorx->action.step = aNPC_ACTION_END_STEP; + } +} + +static void aNPC_act_wait_chg_data_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + u16* arg_p = nactorx->request.act_args; + + nactorx->action.act_obj = arg_p[0]; + nactorx->action.act_obj_id = arg_p[1]; + + if (nactorx->action.feel != (u8)aNPC_get_feel_info(nactorx)) { + nactorx->action.step = aNPC_ACT_WAIT_STEP_MAIN; + } +} + +static void aNPC_act_wait_init_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + nactorx->action.step = aNPC_ACT_WAIT_STEP_MAIN; + nactorx->action.feel = aNPC_get_feel_info(nactorx); + aNPC_setupAction(nactorx, aNPC_wait_action[aNPC_get_feel_info(nactorx)]); +} + +static void aNPC_act_wait_proc(NPC_ACTOR* nactorx, GAME_PLAY* play, int type) { + static aNPC_SUB_PROC act_proc[] = { &aNPC_act_wait_init_proc, &aNPC_act_wait_chg_data_proc, &aNPC_act_wait_main_proc }; + + (*act_proc[type])(nactorx, play); +} diff --git a/src/actor/npc/ac_npc_act_walk.c_inc b/src/actor/npc/ac_npc_act_walk.c_inc new file mode 100644 index 00000000..15c92b6b --- /dev/null +++ b/src/actor/npc/ac_npc_act_walk.c_inc @@ -0,0 +1,79 @@ +enum { + aNPC_ACT_WALK_STEP_MAIN, + + aNPC_ACT_WALK_STEP_NUM +}; + +static void aNPC_act_walk_setupAction(NPC_ACTOR* nactorx, u8 feel) { + u8 act; + + nactorx->action.feel = feel; + if (nactorx->action.idx == aNPC_ACT_WALK) { + act = aNPC_walk_action[feel]; + } else { + act = aNPC_run_action[feel]; + } + + aNPC_setupAction(nactorx, act); +} + +typedef int (*aNPC_ACT_WALK_PROC)(NPC_ACTOR* nactorx); + +static void aNPC_act_walk_main_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + static aNPC_ACT_WALK_PROC act_proc[] = { + &aNPC_act_move, + &aNPC_act_avoid_move, + &aNPC_act_search_move, + &aNPC_act_to_point_move, + }; + + if (nactorx->draw.main_animation_state == cKF_STATE_CONTINUE) { + u8 feel = aNPC_get_feel_info(nactorx); + + if (nactorx->action.feel != feel) { + aNPC_act_walk_setupAction(nactorx, feel); + } + } + + if (!(*act_proc[nactorx->action.type])(nactorx)) { + nactorx->action.step = aNPC_ACTION_END_STEP; + } +} + +static void aNPC_act_walk_chg_data_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + u16* arg_p = nactorx->request.act_args; + s16 prev_move_x = nactorx->action.move_x; + s16 prev_move_z = nactorx->action.move_z; + + nactorx->action.act_obj = arg_p[0]; + nactorx->action.act_obj_id = arg_p[1]; + nactorx->action.move_x = arg_p[2]; + nactorx->action.move_z = arg_p[3]; + + if (nactorx->action.step == aNPC_ACTION_END_STEP && (nactorx->action.move_x != prev_move_x || nactorx->action.move_z != prev_move_z || nactorx->action.type == aNPC_ACT_TYPE_SEARCH)) { + nactorx->action.step = aNPC_ACT_WALK_STEP_MAIN; + } +} + +static void aNPC_act_walk_init_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + u16* arg_p = nactorx->request.act_args; + f32 range; + u8 feel; + + nactorx->action.step = aNPC_ACT_WALK_STEP_MAIN; + if (arg_p[5] == 0) { + range = 72.0f; + } else { + range = (f32)arg_p[5]; + } + + nactorx->movement.arrival_area_radius = range; + feel = aNPC_get_feel_info(nactorx); + aNPC_act_walk_setupAction(nactorx, feel); +} + +static void aNPC_act_walk_proc(NPC_ACTOR* nactorx, GAME_PLAY* play, int type) { + static aNPC_SUB_PROC act_proc[] = { &aNPC_act_walk_init_proc, &aNPC_act_walk_chg_data_proc, &aNPC_act_walk_main_proc }; + + (*act_proc[type])(nactorx, play); +} diff --git a/src/actor/npc/ac_npc_action.c_inc b/src/actor/npc/ac_npc_action.c_inc new file mode 100644 index 00000000..625399f3 --- /dev/null +++ b/src/actor/npc/ac_npc_action.c_inc @@ -0,0 +1,498 @@ +// clang-format off +static u8 aNPC_wait_action[] = { + aNPC_ACTION_TYPE_WAIT, + aNPC_ACTION_TYPE_WAIT_KI, + aNPC_ACTION_TYPE_WAIT_DO, + aNPC_ACTION_TYPE_WAIT_AI, + aNPC_ACTION_TYPE_WAIT_NEMU, + aNPC_ACTION_TYPE_WAIT, + aNPC_ACTION_TYPE_WAIT_DO, + aNPC_ACTION_TYPE_WAIT_AI, + aNPC_ACTION_TYPE_WAIT_DO, +}; +// clang-format on + +// clang-format off +static u8 aNPC_walk_action[] = { + aNPC_ACTION_TYPE_WALK, + aNPC_ACTION_TYPE_WALK_KI, + aNPC_ACTION_TYPE_WALK_DO, + aNPC_ACTION_TYPE_WALK_AI, + aNPC_ACTION_TYPE_WALK, + aNPC_ACTION_TYPE_WALK, + aNPC_ACTION_TYPE_WALK_DO, + aNPC_ACTION_TYPE_WALK_AI, + aNPC_ACTION_TYPE_WALK_DO, +}; +// clang-format on + +// clang-format off +static u8 aNPC_run_action[] = { + aNPC_ACTION_TYPE_RUN, + aNPC_ACTION_TYPE_RUN_KI, + aNPC_ACTION_TYPE_RUN_DO, + aNPC_ACTION_TYPE_RUN_AI, + aNPC_ACTION_TYPE_RUN, + aNPC_ACTION_TYPE_RUN, + aNPC_ACTION_TYPE_RUN_DO, + aNPC_ACTION_TYPE_RUN_AI, + aNPC_ACTION_TYPE_RUN_DO, +}; +// clang-format on + +static void aNPC_setup_stay_my_house(NPC_ACTOR* nactorx) { + mNPS_schedule_c* sched_p = nactorx->npc_info.schedule; + + nactorx->npc_info.animal->is_home = TRUE; + if (sched_p->saved_type == mNPS_SCHED_SLEEP && sched_p->current_type != mNPS_SCHED_SLEEP) { + sched_p->forced_timer = 0; + sched_p->current_type = sched_p->saved_type; + } +} + +static int aNPC_request_house(NPC_ACTOR* nactorx, GAME_PLAY* play, int request) { + ACTOR* house_actor; + mActor_name_t house_item; + int ret = FALSE; + + if (nactorx->actor_class.block_z == mISL_BLOCK_Z) { + house_item = COTTAGE_NPC; + } else { + house_item = NPC_HOUSE_START + (nactorx->npc_info.animal->id.npc_id - NPC_START); + } + + house_actor = Actor_info_fgName_search(&play->actor_info, house_item, ACTOR_PART_ITEM); + if (house_actor != NULL && ((STRUCTURE_ACTOR*)house_actor)->request_type == 0) { + ((STRUCTURE_ACTOR*)house_actor)->request_type = request; + house_actor->state_bitfield |= ACTOR_STATE_NO_MOVE_WHILE_CULLED; + ret = TRUE; + } + + return ret; +} + +static int aNPC_check_arrive_destination(NPC_ACTOR* nactorx) { + f32 range = nactorx->movement.arrival_area_radius; + f32 dist; + f32 distX = nactorx->movement.avoid_pos_x - nactorx->actor_class.world.position.x; + f32 distZ = nactorx->movement.avoid_pos_z - nactorx->actor_class.world.position.z; + int ret = FALSE; + + dist = SQ(distX) + SQ(distZ); + if (dist < range) { + if (nactorx->movement.dst_pos_x == nactorx->movement.avoid_pos_x && + nactorx->movement.dst_pos_z == nactorx->movement.avoid_pos_z) { + ret = TRUE; + } else { + aNPC_set_avoid_pos(nactorx, nactorx->movement.dst_pos_x, nactorx->movement.dst_pos_z, 0); + } + } + + return ret; +} + +static int aNPC_get_animal_idx(NPC_ACTOR* nactorx) { + Animal_c* target_animal = nactorx->npc_info.animal; + Animal_c* animal = Save_Get(animals); + int i; + int ret = -1; + + for (i = 0; i < ANIMAL_NUM_MAX; i++) { + if (animal == target_animal) { + ret = i; + break; + } + + animal++; + } + + return ret; +} + +static void aNPC_set_relation(NPC_ACTOR* nactorx0, NPC_ACTOR* nactorx1, int add) { + Animal_c* animal = nactorx0->npc_info.animal; + + if (animal != NULL) { + int other_idx = aNPC_get_animal_idx(nactorx1); + + if (other_idx != -1) { + u8* relation_p = animal->animal_relations + other_idx; + int relation = *relation_p + add; + + if (relation < 0) { + relation = 0; + } else if (relation > 255) { + relation = 255; + } + + *relation_p = relation; + } + } +} + +static void aNPC_set_feel_info(NPC_ACTOR* nactorx, int feel, int timer) { + Animal_c* animal = nactorx->npc_info.animal; + + if (animal != NULL) { + int feel_timer = nactorx->condition_info.feel_tim; + + if (feel != animal->mood) { + animal->mood = feel; + if (feel == mNpc_FEEL_NORMAL) { + feel_timer = 0; + } else { + feel_timer = timer * FRAMES_PER_MINUTE; + } + } else { + feel_timer += timer * FRAMES_PER_MINUTE; + if (feel_timer > (10 * FRAMES_PER_MINUTE)) { + feel_timer = 10 * FRAMES_PER_MINUTE; + } + } + + nactorx->condition_info.feel_tim = feel_timer; + } +} + +static void aNPC_set_act_obj(NPC_ACTOR* nactorx, GAME_PLAY* play) { + switch (nactorx->action.act_obj) { + case aNPC_ACT_OBJ_PLAYER: + nactorx->movement.target = GET_PLAYER_ACTOR_ACTOR(play); + break; + case aNPC_ACT_OBJ_TARGET_NPC: + nactorx->movement.target = + Actor_info_fgName_search(&play->actor_info, nactorx->action.act_obj_id, ACTOR_PART_NPC); + break; + case aNPC_ACT_OBJ_BALL: + nactorx->movement.target = Actor_info_name_search(&play->actor_info, mAc_PROFILE_BALL, ACTOR_PART_BG); + break; + case aNPC_ACT_OBJ_INSECT: + if (CLIP(insect_clip) != NULL) { + nactorx->movement.target = + CLIP(insect_clip) + ->search_near_insect_proc(nactorx->actor_class.world.position.x, + nactorx->actor_class.world.position.z, (GAME*)play); + } else { + nactorx->movement.target = NULL; + } + break; + case aNPC_ACT_OBJ_FISH: + /* @BUG - shouldn't this just check for gyo_clip? */ + if (CLIP(gyo_clip)->make_gyoei_proc != NULL) { + nactorx->movement.target = CLIP(gyo_clip)->search_near_gyoei_proc( + nactorx->actor_class.world.position.x, nactorx->actor_class.world.position.z); + } else { + nactorx->movement.target = NULL; + } + break; + default: + nactorx->movement.target = NULL; + break; + } +} + +static int aNPC_check_live_target(ACTOR* actorx) { + int ret = TRUE; + + if (actorx == NULL || (actorx->mv_proc == NULL && actorx->dw_proc == NULL)) { + ret = FALSE; + } + + return ret; +} + +static int aNPC_act_wait(NPC_ACTOR* nactorx) { + int ret = TRUE; + + if (nactorx->draw.main_animation_state == cKF_STATE_CONTINUE) { + if (nactorx->draw.loop_flag == FALSE) { + if (nactorx->condition_info.fatigue < 200) { + ret = FALSE; + } + } else { + nactorx->draw.loop_flag--; + } + } + + return ret; +} + +static int aNPC_act_move(NPC_ACTOR* nactorx) { + int ret = TRUE; + + aNPC_set_mv_angl(nactorx); + if (aNPC_check_arrive_destination(nactorx) == TRUE) { + ret = FALSE; + } + + return ret; +} + +static int aNPC_act_search_move(NPC_ACTOR* nactorx) { + ACTOR* target = nactorx->movement.target; + int ret = TRUE; + + if (!aNPC_check_live_target(target)) { + ret = FALSE; + } else { + xyz_t dst_pos; + int bx; + int bz; + + xyz_t_move(&dst_pos, &target->world.position); + if (!mFI_Wpos2BlockNum(&bx, &bz, target->world.position) || bx != nactorx->actor_class.block_x || bz != nactorx->actor_class.block_z) { + ret = FALSE; + } else { + ACTOR* actorx = (ACTOR*)nactorx; + ACTOR* speaker; + ACTOR* listener; + + if (nactorx->movement.dst_pos_x == nactorx->movement.avoid_pos_x && nactorx->movement.dst_pos_z == nactorx->movement.avoid_pos_z) { + aNPC_set_dst_pos(nactorx, dst_pos.x, dst_pos.z); + } else { + nactorx->movement.dst_pos_x = dst_pos.x; + nactorx->movement.dst_pos_z = dst_pos.z; + } + + aNPC_set_mv_angl(nactorx); + mDemo_Get_Talk_Actors(&speaker, &listener); + + if ((target == speaker || target == listener) && actorx != speaker && actorx != listener) { + ret = FALSE; + } else if (aNPC_check_arrive_destination(nactorx) == TRUE) { + ret = FALSE; + } + } + } + + return ret; +} + +static int aNPC_act_avoid_move(NPC_ACTOR* nactorx) { + ACTOR* target = nactorx->movement.target; + int ret = TRUE; + + if (!aNPC_check_live_target(target)) { + ret = FALSE; + } else { + xyz_t dst_pos; + s16 angle = atans_table(target->world.position.z - nactorx->actor_class.world.position.z, target->world.position.x - nactorx->actor_class.world.position.x); + static s16 offset_angl[] = { DEG2SHORT_ANGLE2(0.0f), DEG2SHORT_ANGLE2(45.0f), DEG2SHORT_ANGLE2(-45.0f) }; + s16 check_angle; + mActor_name_t* fg_p; + xyz_t rev; + int i; + + for (i = 0; i < 3; i++) { + check_angle = angle + offset_angl[i]; + dst_pos.x = nactorx->actor_class.world.position.x - sin_s(check_angle) * mFI_UT_WORLDSIZE_X_F; + dst_pos.z = nactorx->actor_class.world.position.z - cos_s(check_angle) * mFI_UT_WORLDSIZE_Z_F; + + if (aNPC_moveRangeCheck(nactorx, &rev, dst_pos, nactorx->movement.range_type) == TRUE) { + fg_p = mFI_GetUnitFG(dst_pos); + if (*fg_p == EMPTY_NO || ITEM_NAME_GET_TYPE(*fg_p) == NAME_TYPE_ITEM1 || ITEM_IS_FTR(*fg_p)) { + break; + } + } + } + + if (i >= 3) { + dst_pos.x = nactorx->movement.avoid_pos_x; + dst_pos.z = nactorx->movement.avoid_pos_z; + } + + if (nactorx->movement.dst_pos_x == nactorx->movement.avoid_pos_x && nactorx->movement.dst_pos_z == nactorx->movement.avoid_pos_z) { + aNPC_set_dst_pos(nactorx, dst_pos.x, dst_pos.z); + } else { + nactorx->movement.dst_pos_x = dst_pos.x; + nactorx->movement.dst_pos_z = dst_pos.z; + } + + aNPC_set_mv_angl(nactorx); + if (aNPC_check_arrive_destination(nactorx) == TRUE) { + ret = FALSE; + } + } + + return ret; +} + +static int aNPC_act_to_point_move(NPC_ACTOR* nactorx) { + if (nactorx->movement.dst_pos_x == nactorx->movement.avoid_pos_x && nactorx->movement.dst_pos_z == nactorx->movement.avoid_pos_z) { + aNPC_set_dst_pos(nactorx, nactorx->action.move_x, nactorx->action.move_z); + } else { + nactorx->movement.dst_pos_x = nactorx->action.move_x; + nactorx->movement.dst_pos_z = nactorx->action.move_z; + } + + return aNPC_act_move(nactorx); +} + +static int aNPC_act_turn(NPC_ACTOR* nactorx) { + int ret = TRUE; + + if (nactorx->actor_class.shape_info.rotation.y == nactorx->movement.mv_angl) { + ret = FALSE; + } + + return ret; +} + +static int aNPC_act_search_turn(NPC_ACTOR* nactorx) { + ACTOR* target = nactorx->movement.target; + int ret = TRUE; + + if (!aNPC_check_live_target(target)) { + ret = FALSE; + } else { + aNPC_set_dst_pos(nactorx, target->world.position.x, target->world.position.z); + if (nactorx->actor_class.shape_info.rotation.y == nactorx->movement.mv_angl) { + ret = FALSE; + } + } + + return ret; +} + +static int aNPC_act_to_point_turn(NPC_ACTOR* nactorx) { + int ret = TRUE; + + aNPC_set_dst_pos(nactorx, nactorx->action.move_x, nactorx->action.move_z); + if (nactorx->actor_class.shape_info.rotation.y == nactorx->movement.mv_angl) { + ret = FALSE; + } + + return ret; +} + +static int aNPC_act_anm_seq(NPC_ACTOR* nactorx) { + int ret = TRUE; + + if (nactorx->draw.main_animation_state == cKF_STATE_STOPPED) { + ret = FALSE; + } + + return ret; +} + +static void aNPC_act_return_trans_item(NPC_ACTOR* nactorx) { + if (nactorx->condition_info.talk_condition != aNPC_TALK_TYPE_NONE) { + if (aNPC_set_request_act(nactorx, 4, aNPC_ACT_TALK, aNPC_ACT_OBJ_DEFAULT, aNPC_req_default_data) == TRUE) { + nactorx->condition_info.demo_flg = nactorx->condition_info.trans_demo_flg_save; + nactorx->action.step = aNPC_ACTION_END_STEP; + } + } else { + if (nactorx->action.idx != aNPC_ACT_GREETING) { + nactorx->condition_info.demo_flg = 0; + } + + nactorx->action.step = aNPC_ACTION_END_STEP; + } +} + +static void aNPC_act_special_proc(NPC_ACTOR* nactorx, GAME_PLAY* play, int type) { + (*nactorx->action.act_proc)(nactorx, play, type); +} + +// included act files + +#include "../src/actor/npc/ac_npc_act_wait.c_inc" +#include "../src/actor/npc/ac_npc_act_walk.c_inc" +#include "../src/actor/npc/ac_npc_act_turn.c_inc" +#include "../src/actor/npc/ac_npc_act_chase_insect.c_inc" +#include "../src/actor/npc/ac_npc_act_greeting.c_inc" +#include "../src/actor/npc/ac_npc_act_talk.c_inc" +#include "../src/actor/npc/ac_npc_act_into_house.c_inc" +#include "../src/actor/npc/ac_npc_act_leave_house.c_inc" +#include "../src/actor/npc/ac_npc_act_umb_open.c_inc" +#include "../src/actor/npc/ac_npc_act_umb_close.c_inc" +#include "../src/actor/npc/ac_npc_act_trans.c_inc" +#include "../src/actor/npc/ac_npc_act_get.c_inc" +#include "../src/actor/npc/ac_npc_act_ensou.c_inc" +#include "../src/actor/npc/ac_npc_act_pitfall.c_inc" +#include "../src/actor/npc/ac_npc_act_revive.c_inc" +#include "../src/actor/npc/ac_npc_act_react_tool.c_inc" +#include "../src/actor/npc/ac_npc_act_clap.c_inc" + +typedef void (*aNPC_ACT_PROC)(NPC_ACTOR* nactorx, GAME_PLAY* play, int type); + +static aNPC_ACT_PROC aNPC_act_proc[] = { + &aNPC_act_wait_proc, + &aNPC_act_walk_proc, + &aNPC_act_walk_proc, + &aNPC_act_turn_proc, + &aNPC_act_turn_proc, + &aNPC_act_chase_insect_proc, + &aNPC_act_chase_insect_proc, + &aNPC_act_greeting_proc, + &aNPC_act_talk_proc, + &aNPC_act_into_house_proc, + &aNPC_act_leave_house_proc, + &aNPC_act_umb_open_proc, + &aNPC_act_umb_close_proc, + &aNPC_act_ensou_proc, + &aNPC_act_talk_proc, + &aNPC_act_react_tool_proc, + &aNPC_act_clap_proc, + &aNPC_act_trans_proc, + &aNPC_act_get_proc, + &aNPC_act_get_proc, + &aNPC_act_pitfall_proc, + &aNPC_act_revive_proc, + &aNPC_act_special_proc, +}; + +static void aNPC_chk_request_act(NPC_ACTOR* nactorx, GAME_PLAY* play) { + if (nactorx->request.act_priority >= nactorx->action.priority && nactorx->request.act_priority != 0) { + u8 prev_idx = nactorx->action.idx; + u8 prev_obj = nactorx->action.act_obj; + mActor_name_t prev_obj_name = nactorx->action.act_obj_id; + + nactorx->action.prev_idx = nactorx->action.idx; + nactorx->action.prev_step = nactorx->action.step; + nactorx->action.priority = nactorx->request.act_priority; + nactorx->action.idx = nactorx->request.act_idx; + nactorx->action.type = nactorx->request.act_type; + + (*aNPC_act_proc[nactorx->action.idx])(nactorx, play, aNPC_ACTION_PROC_TYPE_CHG_DATA); + if (nactorx->action.act_obj != prev_obj || nactorx->action.act_obj_id != prev_obj_name) { + aNPC_set_act_obj(nactorx, play); + } + + if (nactorx->request.act_idx != prev_idx) { + (*aNPC_act_proc[nactorx->action.idx])(nactorx, play, aNPC_ACTION_PROC_TYPE_INIT); + } + } + + nactorx->request.act_priority = 0; +} + +static int aNPC_set_request_act(NPC_ACTOR* nactorx, u8 prio, u8 act_idx, u8 act_type, u16* args) { + int ret = FALSE; + + if (prio >= nactorx->request.act_priority) { + nactorx->request.act_priority = prio; + nactorx->request.act_idx = act_idx; + nactorx->request.act_type = act_type; + + if (args != NULL) { + mem_copy((u8*)nactorx->request.act_args, (u8*)args, sizeof(nactorx->request.act_args)); + } + + ret = TRUE; + } + + return ret; +} + +static void aNPC_action_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + aNPC_chk_request_act(nactorx, play); + + if (nactorx->action.step != aNPC_ACTION_END_STEP && nactorx->action.idx != aNPC_ACT_NONE) { + (*aNPC_act_proc[nactorx->action.idx])(nactorx, play, aNPC_ACTION_PROC_TYPE_MAIN); + } + + if (nactorx->action.step == aNPC_ACTION_END_STEP) { + nactorx->action.priority = 0; + } +} diff --git a/src/actor/npc/ac_npc_anime.c_inc b/src/actor/npc/ac_npc_anime.c_inc new file mode 100644 index 00000000..2427093d --- /dev/null +++ b/src/actor/npc/ac_npc_anime.c_inc @@ -0,0 +1,680 @@ +static int aNPC_get_feel_info(NPC_ACTOR* nactorx) { + int ret = mNpc_FEEL_NORMAL; + + if ((nactorx->condition_info.demo_flg & aNPC_COND_DEMO_SKIP_FEEL_CHECK) == 0) { + Animal_c* animal = nactorx->npc_info.animal; + + if (animal != NULL) { + ret = animal->mood; + } + } + + return ret; +} + +static void aNPC_clear_all_morph_counter(NPC_ACTOR* nactorx) { + nactorx->draw.main_animation.keyframe.morph_counter = 0.0f; + nactorx->draw.sub_animation0.keyframe.morph_counter = 0.0f; + nactorx->draw.sub_animation1.keyframe.morph_counter = 0.0f; +} + +static int aNPC_check_talk_anime(NPC_ACTOR* nactorx, int seqNo) { + int feel; + + switch (seqNo) { + case aNPC_ANIM_TALK_TURN1: + + if (nactorx->talk_info.default_turn_animation != -1) { + seqNo = nactorx->talk_info.default_turn_animation; + } else { + // clang-format off + static int talk_def_anime[mNpc_FEEL_ALL_NUM] = { + aNPC_ANIM_WALK1, + aNPC_ANIM_WALK1, + aNPC_ANIM_WALK_DO1, + aNPC_ANIM_WALK_AI1, + aNPC_ANIM_WALK1, + aNPC_ANIM_WALK1, + aNPC_ANIM_WALK_DO1, + aNPC_ANIM_WALK_AI1, + aNPC_ANIM_WALK_DO1, + }; + // clang-format on + + feel = nactorx->talk_info.feel; + if (feel == 0xFF) { + feel = aNPC_get_feel_info(nactorx); + } + + seqNo = talk_def_anime[feel]; + } + break; + case aNPC_ANIM_TALK1: + if (nactorx->talk_info.default_animation != -1) { + seqNo = nactorx->talk_info.default_animation; + } else { + // clang-format off + static int talk_def_anime[mNpc_FEEL_ALL_NUM] = { + aNPC_ANIM_WAIT1, + aNPC_ANIM_WAIT1, + aNPC_ANIM_WAIT_DO1, + aNPC_ANIM_WAIT_AI1, + aNPC_ANIM_WAIT_NEMU1, + aNPC_ANIM_WAIT1, + aNPC_ANIM_WAIT_DO1, + aNPC_ANIM_WAIT_AI1, + aNPC_ANIM_WAIT_DO1, + }; + // clang-format on + + feel = nactorx->talk_info.feel; + if (feel == 0xFF) { + feel = aNPC_get_feel_info(nactorx); + } + + seqNo = talk_def_anime[feel]; + } + break; + } + + return seqNo; +} + +static void aNPC_set_anime_se_info(NPC_ACTOR* nactorx, aNPC_Animation_c* anim) { + if (anim->se_data_table != NULL) { + aNPC_se_data_table_c* data_table_p = anim->se_data_table; + aNPC_se_data_c* data_p; + aNPC_other_se_data_c* other_data_p; + aNPC_other_se_data_c* dst_data_p; + int n; + int i; + + data_p = data_table_p->lfoot_data; + if (data_p != NULL) { + nactorx->draw.se.lfoot.num_check_frames = data_p->num_check_frames; + nactorx->draw.se.lfoot.check_frame_tbl = data_p->check_frame_tbl; + } else { + nactorx->draw.se.lfoot.num_check_frames = 0; + } + + data_p = data_table_p->rfoot_data; + if (data_p != NULL) { + nactorx->draw.se.rfoot.num_check_frames = data_p->num_check_frames; + nactorx->draw.se.rfoot.check_frame_tbl = data_p->check_frame_tbl; + } else { + nactorx->draw.se.rfoot.num_check_frames = 0; + } + + n = data_table_p->other_se_type; + if (n != aNPC_OTHER_SE_TYPE_NONE) { + nactorx->draw.se.other_se_type = n; + other_data_p = data_table_p->other_se_data; + dst_data_p = nactorx->draw.se.other_se; + + while (n != 0) { + dst_data_p->se_data.num_check_frames = other_data_p->se_data.num_check_frames; + dst_data_p->se_data.check_frame_tbl = other_data_p->se_data.check_frame_tbl; + dst_data_p->se_no = other_data_p->se_no; + other_data_p++; + dst_data_p++; + n--; + } + } else { + aNPC_other_se_data_c* dst_data_p = nactorx->draw.se.other_se; + int i; + + for (i = 0; i < aNPC_OTHER_SE_NUM; i++) { + dst_data_p->se_data.num_check_frames = 0; + dst_data_p++; + } + } + } else { + bzero(&nactorx->draw.se, sizeof(nactorx->draw.se)); + } +} + +static void aNPC_Animation_init(ACTOR* actorx, int seqNo, int talk_flag) { + NPC_ACTOR* nactorx = (NPC_ACTOR*)actorx; + aNPC_anim_info_c* info_main; + aNPC_anim_info_c* info_sub0; + aNPC_anim_info_c* info_sub1; + aNPC_Animation_c* main_anim; + aNPC_Animation_c* anim_sub0; + aNPC_Animation_c* anim_sub1; + cKF_SkeletonInfo_R_c* kf_main; + cKF_SkeletonInfo_R_c* kf_sub0; + cKF_SkeletonInfo_R_c* kf_sub1; + f32 start; + f32 tmp; + + seqNo = aNPC_check_talk_anime(nactorx, seqNo); + aNPC_set_frame_sub_speed(nactorx, seqNo); + info_main = &aNPC_animeTable[seqNo]; + + if (nactorx->draw.sub_anim_type == aNPC_SUB_ANIM_NONE) { + info_sub0 = info_main; + } else { + info_sub0 = &aNPC_animeTable[aNPC_sub_animeSeqNoTable[nactorx->draw.sub_anim_type]]; + } + + if (nactorx->talk_info.type == 0) { + info_sub1 = info_main; + } else { + switch (nactorx->draw.shape_bank) { + case ACTOR_OBJ_BANK_286: + case ACTOR_OBJ_BANK_191: + case ACTOR_OBJ_BANK_148: + case ACTOR_OBJ_BANK_107: + case ACTOR_OBJ_BANK_253: + case ACTOR_OBJ_BANK_330: + case ACTOR_OBJ_BANK_291: + case ACTOR_OBJ_BANK_401: + info_sub1 = &aNPC_animeTable[aNPC_ANIM_KUTIPAKU2]; + break; + default: + info_sub1 = &aNPC_animeTable[aNPC_ANIM_KUTIPAKU1]; + break; + } + } + + main_anim = info_main->anim_p; + kf_main = &nactorx->draw.main_animation.keyframe; + + cKF_SkeletonInfo_R_init( + kf_main, kf_main->skeleton, &main_anim->anim, main_anim->start_frame, main_anim->end_frame, + (seqNo == nactorx->draw.animation_id) ? nactorx->draw.main_animation.keyframe.frame_control.current_frame + : main_anim->start_frame, + nactorx->draw.frame_speed * nactorx->draw.frame_sub_speed, main_anim->morph_counter, main_anim->mode, NULL); + + if (main_anim->eye_seq_p != NULL) { + nactorx->draw.tex_anim[aNPC_TEX_ANIM_EYE].fixed_pattern_seq = main_anim->eye_seq_p; + } else { + nactorx->draw.tex_anim[aNPC_TEX_ANIM_EYE].fixed_pattern_seq = NULL; + } + nactorx->draw.tex_anim[aNPC_TEX_ANIM_EYE].seq_type = main_anim->eye_seq_type; + nactorx->draw.tex_anim[aNPC_TEX_ANIM_EYE].pattern_stop_idx = main_anim->eye_seq_stop_frame; + + if (main_anim->mouth_seq_p != NULL) { + nactorx->draw.tex_anim[aNPC_TEX_ANIM_MOUTH].fixed_pattern_seq = main_anim->mouth_seq_p; + } else { + nactorx->draw.tex_anim[aNPC_TEX_ANIM_MOUTH].fixed_pattern_seq = NULL; + } + nactorx->draw.tex_anim[aNPC_TEX_ANIM_MOUTH].seq_type = main_anim->mouth_seq_type; + nactorx->draw.tex_anim[aNPC_TEX_ANIM_MOUTH].pattern_stop_idx = main_anim->mouth_seq_stop_frame; + + if (nactorx->draw.effect_type != -1 && nactorx->draw.effect_type != main_anim->feel_effect_type) { + eEC_CLIP->effect_kill_proc(nactorx->draw.effect_type, actorx->npc_id); + } + + nactorx->draw.effect_type = main_anim->feel_effect_type; + nactorx->draw.effect_pattern = main_anim->feel_effect_set_frame; + if (main_anim->feel_effect != NULL) { + nactorx->draw.feel_effect = main_anim->feel_effect; + } else { + nactorx->draw.feel_effect = NULL; + } + + anim_sub0 = info_sub0->anim_p; + kf_sub0 = &nactorx->draw.sub_animation0.keyframe; + cKF_SkeletonInfo_R_init(kf_sub0, kf_sub0->skeleton, &anim_sub0->anim, anim_sub0->start_frame, anim_sub0->end_frame, + anim_sub0->start_frame, nactorx->draw.frame_speed, anim_sub0->morph_counter, + anim_sub0->mode, NULL); + + anim_sub1 = info_sub1->anim_p; + kf_sub1 = &nactorx->draw.sub_animation1.keyframe; + cKF_SkeletonInfo_R_init(kf_sub1, kf_sub1->skeleton, &anim_sub1->anim, anim_sub1->start_frame, anim_sub1->end_frame, + anim_sub1->start_frame, nactorx->draw.frame_speed, anim_sub1->morph_counter, + anim_sub1->mode, NULL); + + { + f32 speed = 0.5f; + + if (main_anim->mouth_seq_type == 0 && main_anim->mouth_seq_p == NULL && talk_flag != TRUE) { + nactorx->draw.sub_animation1.keyframe.frame_control.current_frame = 1.0f; + speed = 0.0f; + } + + nactorx->draw.sub_animation1.keyframe.frame_control.speed = speed; + } + + nactorx->draw.animation_id = seqNo; + nactorx->draw.main_animation_state = cKF_STATE_NONE; + nactorx->draw.sub_animation0_state = cKF_STATE_NONE; + nactorx->draw.sub_animation1_state = cKF_STATE_NONE; + nactorx->draw.main_animation_frame = (int)nactorx->draw.main_animation.keyframe.frame_control.current_frame; + nactorx->draw.main_animation_frame_changed = TRUE; + aNPC_set_anime_se_info(nactorx, main_anim); +} + +static int aNPC_check_anime_timing(NPC_ACTOR* nactorx, aNPC_se_data_c* se) { + int ret = FALSE; + cKF_FrameControl_c* fc_p = &nactorx->draw.main_animation.keyframe.frame_control; + + if (nactorx->draw.main_animation.keyframe.frame_control.speed != 0.0f) { + int* pattern_p = se->check_frame_tbl; + int n; + + for (n = se->num_check_frames; n != 0; n--) { + if (cKF_FrameControl_passCheck_now(fc_p, (f32)*pattern_p) == TRUE) { + ret = TRUE; + break; + } + + pattern_p++; + } + } + + return ret; +} + +static void aNPC_anime_proc_foot(NPC_ACTOR* nactorx, GAME* game, xyz_t* pos_p, aNPC_se_data_c* se) { + if (aNPC_check_anime_timing(nactorx, se) == TRUE) { + ACTOR* actorx = (ACTOR*)nactorx; + + switch (Save_Get(scene_no)) { + case SCENE_START_DEMO: + case SCENE_START_DEMO2: + case SCENE_START_DEMO3: + break; + default: + if (actorx->drawn) { + if ((nactorx->condition_info.demo_flg & aNPC_COND_DEMO_SKIP_BGCHECK) == 0 && + (nactorx->condition_info.demo_flg & aNPC_COND_DEMO_SKIP_FOOTSTEPS_VFX) == 0) { + s16 angleY = actorx->shape_info.rotation.y; + mActor_name_t name_id = actorx->npc_id; + s16 bg_attr = actorx->bg_collision_check.result.unit_attribute; + + eEC_CLIP->effect_make_proc(eEC_EFFECT_WALK_ASIMOTO, *pos_p, 1, angleY, game, name_id, bg_attr, + 0); + eEC_CLIP->effect_make_proc(eEC_EFFECT_FOOTPRINT, *pos_p, 1, angleY, game, name_id, bg_attr, 0); + } + } + break; + } + + if (nactorx->draw.animation_id == aNPC_ANIM_KOKERU1) { + aNPC_TumbleSe(pos_p); + } else { + aNPC_WalkSe(pos_p); + } + } +} + +static void aNPC_anime_proc_other(NPC_ACTOR* nactorx, aNPC_other_se_data_c* other_se_p) { + if (aNPC_check_anime_timing(nactorx, &other_se_p->se_data) == TRUE) { + aNPC_OngenTrgStart(nactorx, other_se_p->se_no); + } +} + +static void aNPC_anime_se_proc(NPC_ACTOR* nactorx, GAME* game) { + if ((nactorx->condition_info.demo_flg & aNPC_COND_DEMO_SKIP_FOOTSTEPS) == 0) { + aNPC_anime_proc_foot(nactorx, game, &nactorx->feet[0], &nactorx->draw.se.lfoot); + aNPC_anime_proc_foot(nactorx, game, &nactorx->feet[1], &nactorx->draw.se.rfoot); + } + + { + aNPC_other_se_data_c* other_se_p = nactorx->draw.se.other_se; + int type = nactorx->draw.se.other_se_type; + + while (type != 0) { + aNPC_anime_proc_other(nactorx, other_se_p); + other_se_p++; + type--; + } + } +} + +static void aNPC_anime_proc(NPC_ACTOR* nactorx, GAME* game) { + cKF_FrameControl_c* fc_main = &nactorx->draw.main_animation.keyframe.frame_control; + int last_cur = (int)fc_main->current_frame; + s8* part_tbl = aNPC_part_tbl[nactorx->draw.sub_anim_type > aNPC_SUB_ANIM_NONE][nactorx->talk_info.type == 1]; + + // clang-format off + cKF_SkeletonInfo_R_T_combine_play( + &nactorx->draw.main_animation_state, &nactorx->draw.sub_animation0_state, &nactorx->draw.sub_animation1_state, + &nactorx->draw.main_animation.keyframe, &nactorx->draw.sub_animation0.keyframe, &nactorx->draw.sub_animation1.keyframe, + part_tbl + ); + // clang-format on + + nactorx->draw.main_animation_frame_changed = last_cur != (int)fc_main->current_frame; + nactorx->draw.main_animation_frame = (int)fc_main->current_frame; + aNPC_anime_se_proc(nactorx, game); +} + +static int aNPC_check_kutipaku(NPC_ACTOR* nactorx) { + ACTOR* actorx = (ACTOR*)nactorx; + int ret = FALSE; + + if (((mDemo_Check(mDemo_TYPE_SPEAK, actorx) == TRUE || mDemo_Check(mDemo_TYPE_SPEECH, actorx) == TRUE || + mDemo_Check(mDemo_TYPE_TALK, actorx) == TRUE) && + mMsg_Check_NowUtter() == TRUE) || + nactorx->condition_info.greeting_flag) { + ret = TRUE; + } + + return ret; +} + +typedef struct { + u8 pattern; + u8 pattern_counter; +} aNPC_anm_data_c; + +static aNPC_anm_data_c* aNPC_getP_anmData(int type, int pat, int counter, int part_type) { + static aNPC_anm_data_c eye_normal_blink[4] = { + { 0x00, 0x01 }, + { 0x01, 0x01 }, + { 0x02, 0x03 }, + { 0x01, 0x01 }, + }; + + static aNPC_anm_data_c eye_angry_blink[4] = { + { 0x03, 0x01 }, + { 0x01, 0x01 }, + { 0x02, 0x03 }, + { 0x01, 0x01 }, + }; + + static aNPC_anm_data_c eye_sadly_blink[4] = { + { 0x04, 0x01 }, + { 0x01, 0x01 }, + { 0x02, 0x03 }, + { 0x01, 0x01 }, + }; + + static aNPC_anm_data_c eye_laugh_blink[4] = { + { 0x05, 0x01 }, + { 0x01, 0x01 }, + { 0x02, 0x03 }, + { 0x01, 0x01 }, + }; + + static aNPC_anm_data_c eye_surprise_blink[4] = { + { 0x06, 0x01 }, + { 0x01, 0x01 }, + { 0x02, 0x03 }, + { 0x01, 0x01 }, + }; + + static aNPC_anm_data_c eye_cry_blink[4] = { + { 0x07, 0x01 }, + { 0x01, 0x01 }, + { 0x02, 0x03 }, + { 0x01, 0x01 }, + }; + + static aNPC_anm_data_c* eye_anm_table_type[7] = { + NULL, eye_normal_blink, eye_angry_blink, eye_sadly_blink, eye_laugh_blink, eye_surprise_blink, eye_cry_blink, + }; + + static aNPC_anm_data_c** eye_anm_table[2] = { + eye_anm_table_type, + eye_anm_table_type, + }; + + static aNPC_anm_data_c mouth_normal_move_typeA[6] = { + { 0x00, 0x01 }, { 0x01, 0x01 }, { 0x02, 0x01 }, { 0x01, 0x01 }, { 0x00, 0x01 }, { 0x00, 0x00 }, + }; + + static aNPC_anm_data_c mouth_normal_move_typeB[4] = { + { 0x00, 0x01 }, + { 0x01, 0x01 }, + { 0x00, 0x01 }, + { 0x00, 0x00 }, + }; + + static aNPC_anm_data_c mouth_normal_move_typeC[8] = { + { 0x00, 0x01 }, { 0x01, 0x01 }, { 0x02, 0x01 }, { 0x01, 0x01 }, + { 0x02, 0x01 }, { 0x01, 0x01 }, { 0x00, 0x01 }, { 0x00, 0x00 }, + }; + + static aNPC_anm_data_c mouth_angry_move_typeA[6] = { + { 0x03, 0x01 }, { 0x04, 0x01 }, { 0x05, 0x01 }, { 0x04, 0x01 }, { 0x03, 0x01 }, { 0x00, 0x00 }, + }; + + static aNPC_anm_data_c mouth_angry_move_typeB[4] = { + { 0x03, 0x01 }, + { 0x04, 0x01 }, + { 0x03, 0x01 }, + { 0x00, 0x00 }, + }; + + static aNPC_anm_data_c mouth_angry_move_typeC[8] = { + { 0x03, 0x01 }, { 0x04, 0x01 }, { 0x05, 0x01 }, { 0x04, 0x01 }, + { 0x05, 0x01 }, { 0x04, 0x01 }, { 0x03, 0x01 }, { 0x00, 0x00 }, + }; + + static aNPC_anm_data_c* mouth_anm_table_typeA[3] = { + NULL, + mouth_normal_move_typeA, + mouth_angry_move_typeA, + }; + + static aNPC_anm_data_c* mouth_anm_table_typeB[3] = { + NULL, + mouth_normal_move_typeB, + mouth_angry_move_typeB, + }; + + static aNPC_anm_data_c* mouth_anm_table_typeC[3] = { + NULL, + mouth_normal_move_typeC, + mouth_angry_move_typeC, + }; + + static aNPC_anm_data_c** mouth_anm_table[3] = { + mouth_anm_table_typeA, + mouth_anm_table_typeB, + mouth_anm_table_typeC, + }; + + static aNPC_anm_data_c*** anm_table[2] = { + eye_anm_table, + mouth_anm_table, + }; + + return &anm_table[part_type][pat][type][counter]; +} + +static u8 aNPC_get_seq_cnt(int type, int pat, int part_type) { + static u8 eye_seq_cnt_table_type[7] = { + 0x00, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + }; + + static u8* eye_seq_cnt_table[2] = { + eye_seq_cnt_table_type, + eye_seq_cnt_table_type, + }; + + static u8 mouth_seq_cnt_table_typeA[3] = { + 0x00, + 0x04, + 0x04, + }; + + static u8 mouth_seq_cnt_table_typeB[3] = { + 0x00, + 0x02, + 0x02, + }; + + static u8 mouth_seq_cnt_table_typeC[3] = { + 0x00, + 0x06, + 0x06, + }; + + static u8* mouth_seq_cnt_table[3] = { + mouth_seq_cnt_table_typeA, + mouth_seq_cnt_table_typeB, + mouth_seq_cnt_table_typeC, + }; + + static u8** seq_cnt_table[2] = { + eye_seq_cnt_table, + mouth_seq_cnt_table, + }; + + return seq_cnt_table[part_type][pat][type]; +} + +static void aNPC_set_tex_anime(aNPC_tex_anim_c* tex_anime, u8 type, int part_type, int wait_time, u8 loop_count) { + static f32 rnd_base[] = { 2.0f, 3.0f }; + u8 pat = RANDOM_F(rnd_base[part_type]); + aNPC_anm_data_c* data_p = aNPC_getP_anmData(type, pat, 0, part_type); + + tex_anime->seq_type = type; + tex_anime->seq_pattern = pat; + tex_anime->seq_counter = aNPC_get_seq_cnt(type, pat, part_type); + tex_anime->pattern = data_p->pattern; + if (wait_time == -1) { + tex_anime->pattern_counter = data_p->pattern_counter; + } else { + tex_anime->pattern_counter = wait_time; + } + tex_anime->loop_counter = loop_count; +} + +static void aNPC_tex_anm_ctrl_stop_seq(aNPC_tex_anim_c* tex_anim) { + tex_anim->pattern = tex_anim->pattern_stop_idx; + tex_anim->pattern_counter = 0; + tex_anim->seq_counter = 0; + tex_anim->loop_counter = 1; +} + +static void aNPC_tex_anm_ctrl_set_pat(aNPC_tex_anim_c* tex_anim, int part_type) { + aNPC_anm_data_c* data_p; + + tex_anim->seq_counter--; + data_p = aNPC_getP_anmData(tex_anim->seq_type, tex_anim->seq_pattern, tex_anim->seq_counter, part_type); + tex_anim->pattern = data_p->pattern; + tex_anim->pattern_counter = data_p->pattern_counter; +} + +static void aNPC_tex_anm_ctrl_rnd_seq(aNPC_tex_anim_c* tex_anim, int part_type) { + if (tex_anim->last_seq_type != tex_anim->seq_type) { + aNPC_set_tex_anime(tex_anim, tex_anim->seq_type, part_type, -1, 1 + RANDOM_F(3)); + } else if (tex_anim->pattern_counter <= 0) { + if (tex_anim->seq_counter == 0) { + tex_anim->loop_counter--; + if (tex_anim->loop_counter == 0) { + aNPC_set_tex_anime(tex_anim, tex_anim->seq_type, part_type, 32 + RANDOM(16), 1 + RANDOM_F(3)); + } else { + aNPC_set_tex_anime(tex_anim, tex_anim->seq_type, part_type, -1, tex_anim->loop_counter); + } + } else { + aNPC_tex_anm_ctrl_set_pat(tex_anim, part_type); + } + } else { + tex_anim->pattern_counter -= 0.5f; + } +} + +static void aNPC_tex_anm_ctrl_talk_seq(aNPC_tex_anim_c* tex_anim, int part_type) { + if (tex_anim->last_seq_type != tex_anim->seq_type) { + aNPC_set_tex_anime(tex_anim, tex_anim->seq_type, part_type, 0, 1 + RANDOM_F(3)); + } else if (tex_anim->pattern_counter <= 0) { + if (tex_anim->seq_counter == 0) { + tex_anim->loop_counter--; + if (tex_anim->loop_counter == 0) { + aNPC_set_tex_anime(tex_anim, tex_anim->seq_type, part_type, 0, 1 + RANDOM_F(3)); + } else { + aNPC_set_tex_anime(tex_anim, tex_anim->seq_type, part_type, 0, tex_anim->loop_counter); + } + } else { + aNPC_tex_anm_ctrl_set_pat(tex_anim, part_type); + } + } else { + tex_anim->pattern_counter -= 0.25f; + } +} + +static void aNPC_tex_anm_ctrl_fix_seq(NPC_ACTOR* nactorx, aNPC_tex_anim_c* tex_anim) { + tex_anim->pattern = tex_anim->fixed_pattern_seq[nactorx->draw.main_animation_frame - 1]; +} + +static void aNPC_tex_anm_ctrl(NPC_ACTOR* nactorx) { + u8 seq_type_bak; + aNPC_tex_anim_c* tex_anim = nactorx->draw.tex_anim; + int i; + + for (i = 0; i < aNPC_TEX_ANIM_NUM; i++) { + seq_type_bak = tex_anim->seq_type; + + if (tex_anim->fixed_pattern_seq == NULL) { + if (i == aNPC_TEX_ANIM_MOUTH) { + if ((nactorx->condition_info.demo_flg & aNPC_COND_DEMO_SKIP_KUTIPAKU) == 0) { + if (aNPC_check_kutipaku(nactorx) == TRUE) { + if (tex_anim->seq_type == 0) { + tex_anim->seq_type = 1; + } + + aNPC_tex_anm_ctrl_talk_seq(tex_anim, i); + } else if (tex_anim->pattern_stop_idx != -1) { + tex_anim->pattern = tex_anim->pattern_stop_idx; + } else { + tex_anim->pattern = 0; + } + } + } else { + if (seq_type_bak == 0) { + aNPC_tex_anm_ctrl_stop_seq(tex_anim); + } else { + aNPC_tex_anm_ctrl_rnd_seq(tex_anim, i); + } + } + } else { + aNPC_tex_anm_ctrl_fix_seq(nactorx, tex_anim); + } + + tex_anim->last_seq_type = tex_anim->seq_type; + tex_anim->seq_type = seq_type_bak; + tex_anim++; + } + + if (nactorx->talk_info.type == 1) { + int timer = nactorx->talk_info.kutipaku_timer; + + if (aNPC_check_kutipaku(nactorx) == TRUE && + (nactorx->condition_info.demo_flg & aNPC_COND_DEMO_SKIP_KUTIPAKU) == 0) { + nactorx->draw.sub_animation1.keyframe.frame_control.speed = 0.5f; + timer = 8; + } else if (timer > 0) { + nactorx->draw.sub_animation1.keyframe.frame_control.speed = 0.5f; + timer--; + } else { + nactorx->draw.sub_animation1.keyframe.frame_control.current_frame = 1.0f; + nactorx->draw.sub_animation1.keyframe.frame_control.speed = 0.0f; + timer = 0; + } + + nactorx->talk_info.kutipaku_timer = timer; + } +} + +static void aNPC_set_frame_sub_speed(NPC_ACTOR* nactorx, int seqNo) { + f32 speed; + + switch (seqNo) { + case aNPC_ANIM_GET_CHANGE1: + case aNPC_ANIM_DERU1: + case aNPC_ANIM_DERU2: + speed = 2.0f; + break; + default: + speed = 1.0f; + break; + } + + nactorx->draw.frame_sub_speed = speed; +} + +static void aNPC_set_anime_speed(NPC_ACTOR* nactorx) { + if (nactorx->draw.anim_speed_type == aNPC_ANIM_SPEED_TYPE_LOCKED) { + nactorx->draw.frame_speed = 0.5f; + } + + nactorx->draw.main_animation.keyframe.frame_control.speed = + nactorx->draw.frame_speed * nactorx->draw.frame_sub_speed; +} diff --git a/src/actor/npc/ac_npc_cloth.c_inc b/src/actor/npc/ac_npc_cloth.c_inc new file mode 100644 index 00000000..49da4f9f --- /dev/null +++ b/src/actor/npc/ac_npc_cloth.c_inc @@ -0,0 +1,300 @@ +static void aNPC_dma_cloth_data(ACTOR* actorx) { + NPC_CONTROL_ACTOR* ctrl = (NPC_CONTROL_ACTOR*)actorx; + aNPC_cloth_c* cloth = ctrl->cloth; + int i; + + for (i = 0; i < aNPC_CTRL_CLOTH_NUM; i++) { + if (cloth->cloth_item != EMPTY_NO && cloth->dma_flag == TRUE) { + if (ITEM_IS_NPC_CLOTH(cloth->cloth_item) == FALSE) { + cloth->cloth_item = ITM_CLOTH000; + } + + mSc_background_dmacopy_controller(&cloth->texture_bank); + mSc_background_dmacopy_controller(&cloth->palette_bank); + if (cloth->texture_bank.state == 0 && cloth->palette_bank.state == 0) { + cloth->dma_flag = FALSE; + } + } + + cloth++; + } +} + +static u32 aNPC_getP_cloth_tex_rom(aNPC_cloth_c* cloth) { + u32 addr = JW_GetAramAddress(RESOURCE_TEX_BOY); + + return addr + (ITEM_IS_CLOTH(cloth->cloth_item) ? (cloth->cloth_item - ITM_CLOTH000) : 0) * aNPC_CLOTH_TEX_SIZE; +} + +static u32 aNPC_getP_cloth_pal_rom(aNPC_cloth_c* cloth) { + u32 addr = JW_GetAramAddress(RESOURCE_PALLET_BOY); + + return addr + (ITEM_IS_CLOTH(cloth->cloth_item) ? (cloth->cloth_item - ITM_CLOTH000) : 0) * aNPC_CLOTH_PAL_SIZE; +} + +static void aNPC_dma_cloth_tex_data_fg(aNPC_cloth_c* cloth) { + _JW_GetResourceAram(aNPC_getP_cloth_tex_rom(cloth), (u8*)cloth->texture_bank.ram_start, aNPC_CLOTH_TEX_SIZE); + DCStoreRangeNoSync(cloth->texture_bank.ram_start, aNPC_CLOTH_TEX_SIZE); +} + +static void aNPC_dma_cloth_pal_data_fg(aNPC_cloth_c* cloth) { + _JW_GetResourceAram(aNPC_getP_cloth_pal_rom(cloth), (u8*)cloth->palette_bank.ram_start, aNPC_CLOTH_PAL_SIZE); + DCStoreRangeNoSync(cloth->palette_bank.ram_start, aNPC_CLOTH_PAL_SIZE); +} + +static void aNPC_dma_cloth_data_fg(void) { + NPC_CONTROL_ACTOR* ctrl = (NPC_CONTROL_ACTOR*)aNPC_ctrlActor; + aNPC_cloth_c* cloth = ctrl->cloth; + int i; + + for (i = 0; i < aNPC_CTRL_CLOTH_NUM; i++) { + if (cloth->cloth_item != EMPTY_NO && cloth->dma_flag == TRUE) { + if (!ITEM_IS_NPC_CLOTH(cloth->cloth_item)) { + cloth->cloth_item = ITM_CLOTH000; + } + + aNPC_dma_cloth_tex_data_fg(cloth); + aNPC_dma_cloth_pal_data_fg(cloth); + cloth->dma_flag = FALSE; + cloth->texture_bank.state = 0; + cloth->palette_bank.state = 0; + } + + cloth++; + } +} + +static void aNPC_reset_trans_condition_cloth_data(void) { + NPC_CONTROL_ACTOR* ctrl = (NPC_CONTROL_ACTOR*)aNPC_ctrlActor; + aNPC_cloth_c* cloth = ctrl->cloth; + int i; + + for (i = 0; i < aNPC_CTRL_CLOTH_NUM; i++) { + if (cloth->id != mSC_BANK_NONE && cloth->cloth_item != EMPTY_NO) { + cloth->dma_flag = TRUE; + cloth->texture_bank.state = 1; + cloth->palette_bank.state = 1; + } else { + cloth->cloth_item = EMPTY_NO; + cloth->in_use_count = 0; + } + + cloth++; + } +} + +static int aNPC_get_same_cloth_data_area(aNPC_cloth_c* cloth, mActor_name_t item) { + int i; + + for (i = 0; i < aNPC_CTRL_CLOTH_NUM; i++) { + if (cloth->cloth_item == item) { + return i; + } + + cloth++; + } + + return -1; +} + +static int aNPC_dma_cloth_data_check(aNPC_cloth_c* cloth, mActor_name_t item, NPC_ACTOR* nactorx) { + int idx; + + if (item == RSV_CLOTH) { + idx = 1 + aNPC_CTRL_CLOTH_NUM; + } else { + idx = aNPC_get_same_cloth_data_area(cloth, item); + if (idx != -1) { + cloth[idx].init_flag = FALSE; + cloth[idx].in_use_count++; + } + idx += 1; + } + + if (idx == (1 + aNPC_CTRL_CLOTH_NUM) && nactorx->npc_info.animal == NULL) { + idx = -1; + } + + return idx; +} + +static int aNPC_get_new_cloth_data_area(aNPC_cloth_c* cloth) { + int i; + + for (i = 0; i < aNPC_CTRL_CLOTH_NUM; i++) { + if (cloth->id != mSC_BANK_NONE && cloth->cloth_item == EMPTY_NO) { + return i; + } + + cloth++; + } + + return -1; +} + +static int aNPC_get_no_use_cloth_data_area(aNPC_cloth_c* cloth) { + int i; + + for (i = 0; i < aNPC_CTRL_CLOTH_NUM; i++) { + if (cloth->id != mSC_BANK_NONE && cloth->dma_flag == FALSE && cloth->init_flag == FALSE && cloth->in_use_count == 0) { + return i; + } + + cloth++; + } + + return -1; +} + +static void aNPC_cancel_cloth_data(NPC_ACTOR* nactorx) { + int idx = nactorx->draw.cloth_idx - 1; + + if (idx >= 0 && idx < 9) { + NPC_CONTROL_ACTOR* ctrl = (NPC_CONTROL_ACTOR*)aNPC_ctrlActor; + aNPC_cloth_c* cloth = ctrl->cloth + idx; + + cloth->in_use_count--; + } +} + +static void aNPC_dma_regist_cloth_data(mActor_name_t item) { + if (item != RSV_CLOTH) { + NPC_CONTROL_ACTOR* ctrl = (NPC_CONTROL_ACTOR*)aNPC_ctrlActor; + aNPC_cloth_c* cloth = ctrl->cloth; + int idx = aNPC_get_same_cloth_data_area(cloth, item); + + if (idx == -1) { + idx = aNPC_get_new_cloth_data_area(cloth); + + if (idx == -1) { + idx = aNPC_get_no_use_cloth_data_area(cloth); + } + + if (idx != -1) { + cloth += idx; + cloth->dma_flag = TRUE; + cloth->init_flag = TRUE; + cloth->in_use_count = 0; + cloth->cloth_item = item; + cloth->texture_bank._14 = 0; + cloth->texture_bank.rom_addr = aNPC_getP_cloth_tex_rom(cloth); + cloth->texture_bank.state = 1; + cloth->palette_bank._14 = 0; + cloth->palette_bank.rom_addr = aNPC_getP_cloth_pal_rom(cloth); + cloth->palette_bank.state = 1; + } + } + } +} + +static int aNPC_dma_regist_check_cloth_data(mActor_name_t item) { + NPC_CONTROL_ACTOR* ctrl = (NPC_CONTROL_ACTOR*)aNPC_ctrlActor; + aNPC_cloth_c* cloth = ctrl->cloth; + int i; + int ret = FALSE; + + if (item == RSV_CLOTH) { + return TRUE; + } + + for (i = 0; i < aNPC_CTRL_CLOTH_NUM; i++) { + if (cloth->cloth_item == item && cloth->dma_flag == FALSE) { + ret = TRUE; + break; + } + + cloth++; + } + + return ret; +} + +static void aNPC_keep_cloth_data_area(Object_Exchange_c* exc) { + NPC_CONTROL_ACTOR* ctrl = (NPC_CONTROL_ACTOR*)aNPC_ctrlActor; + aNPC_cloth_c* cloth = ctrl->cloth; + int bank_id = exc->bank_idx; + Object_Bank_c* bank = exc->banks + bank_id; + int i; + + for (i = 0; i < aNPC_CTRL_CLOTH_NUM; i++) { + if (mSc_secure_exchange_keep_bank(exc, 0, aNPC_CLOTH_TEX_SIZE + aNPC_CLOTH_PAL_SIZE) != NULL) { + cloth->texture_bank.size = aNPC_CLOTH_TEX_SIZE; + cloth->texture_bank.ram_start = bank->ram_start; + cloth->texture_bank.dma_start = bank->ram_start; + + cloth->palette_bank.size = aNPC_CLOTH_PAL_SIZE; + cloth->palette_bank.ram_start = bank->ram_start + aNPC_CLOTH_TEX_SIZE; + cloth->palette_bank.dma_start = cloth->palette_bank.ram_start; + + cloth->id = bank_id; + bank++; + bank_id++; + } else { + cloth->texture_bank.ram_start = NULL; + cloth->palette_bank.ram_start = NULL; + cloth->id = mSC_BANK_NONE; + } + + cloth->cloth_item = EMPTY_NO; + cloth->texture_bank.bank_id = -1; + cloth->palette_bank.bank_id = -1; + cloth->in_use_count = 0; + cloth->dma_flag = FALSE; + + cloth++; + } +} + +static void aNPC_rebuild_cloth_data(void) { + aNPC_reset_trans_condition_cloth_data(); + aNPC_dma_cloth_data_fg(); +} + +static int aNPC_change_cloth_data(NPC_ACTOR* nactorx) { + NPC_CONTROL_ACTOR* ctrl = (NPC_CONTROL_ACTOR*)aNPC_ctrlActor; + mActor_name_t cloth = nactorx->draw.cloth_no; + int ret = FALSE; + + if (ITEM_IS_NPC_CLOTH(cloth) == FALSE) { + cloth = ITM_CLOTH000; + nactorx->draw.cloth_no = ITM_CLOTH000; + } + + if (cloth == RSV_CLOTH) { + nactorx->draw.cloth_idx = aNPC_CLOTH_IDX_ORG; + ret = TRUE; + } else { + aNPC_dma_regist_cloth_data(cloth); + aNPC_dma_cloth_data_fg(); + + if (aNPC_dma_regist_check_cloth_data(cloth) == TRUE) { + nactorx->draw.cloth_idx = aNPC_dma_cloth_data_check(ctrl->cloth, cloth, nactorx); + ret = TRUE; + } + } + + if (nactorx->draw.cloth_idx == aNPC_CLOTH_IDX_ORG && nactorx->npc_info.animal == NULL) { + nactorx->draw.cloth_idx = -1; + } + + return ret; +} + +static void aNPC_setup_chg_cloth(NPC_ACTOR* nactorx, mActor_name_t cloth, u8 org_idx) { + nactorx->draw.cloth_no = cloth; + nactorx->draw.org_idx = org_idx; +} + +static void aNPC_setup_next_cloth(NPC_ACTOR* nactorx, mActor_name_t cloth, u8 org_idx) { + nactorx->draw.next_cloth_no = cloth; + nactorx->draw.next_org_idx = org_idx; +} + +static void aNPC_setup_cloth(NPC_ACTOR* nactorx, mActor_name_t cloth, u8 org_idx) { + Animal_c* animal = nactorx->npc_info.animal; + + if (animal != NULL) { + animal->cloth = cloth; + animal->cloth_original_id = org_idx; + } +} diff --git a/src/actor/npc/ac_npc_ct.c_inc b/src/actor/npc/ac_npc_ct.c_inc new file mode 100644 index 00000000..2b783b0a --- /dev/null +++ b/src/actor/npc/ac_npc_ct.c_inc @@ -0,0 +1,273 @@ +static void aNPC_make_accessory(ACTOR* actorx, GAME* game, s16 type, s16 joint) { + NPC_ACTOR* nactorx = (NPC_ACTOR*)actorx; + + if (CLIP(tools_clip) != NULL) { + ACTOR* acc_actor = CLIP(tools_clip)->aTOL_birth_proc(type, aTOL_ACTION_S_TAKEOUT, actorx, game, -1, NULL); + + if (acc_actor != NULL) { + nactorx->accessory.type = type; + nactorx->accessory.pos_joint_idx = joint; + nactorx->accessory.accessory = acc_actor; + xyz_t_move(&acc_actor->world.position, &actorx->world.position); + } + } +} + +static int aNPC_setP_friendship(NPC_ACTOR* nactorx) { + Animal_c* animal = aNPC_GET_ANM(nactorx); + int mem_idx; + s8* friendship_p = NULL; + int ret = FALSE; + + mem_idx = mNpc_GetAnimalMemoryIdx(&Now_Private->player_ID, animal->memories, ANIMAL_MEMORY_NUM); + if (mem_idx != -1) { + friendship_p = &animal->memories[mem_idx].friendship; + ret = TRUE; + } + + nactorx->condition_info.friendship = friendship_p; + return ret; +} + +static void aNPC_check_force_use_umbrella(NPC_ACTOR* nactorx) { + u8 req = FALSE; + + if (aNPC_GET_ANM(nactorx)->is_home == FALSE && Common_Get(weather) == mEnv_WEATHER_RAIN) { + req = TRUE; + } + + nactorx->request.umb_flag = req; +} + +static void aNPC_set_start_pos(ACTOR* actorx) { + NPC_ACTOR* nactorx = (NPC_ACTOR*)actorx; + Animal_c* animal = aNPC_GET_ANM(nactorx); + + mNpcW_GetAppearStatusWay(&nactorx->condition_info.appear_flag, &nactorx->condition_info.appear_rotation, animal); +} + +static void aNPC_actor_schedule(NPC_ACTOR* nactorx, int type) { + mNPS_schedule_c* sched_p = &nactorx->schedule.schedule; + + switch (type) { + case aNPC_CT_SCHED_TYPE_NORMAL: + aNPC_first_set_schedule(nactorx); + break; + case aNPC_CT_SCHED_TYPE_STAND: + sched_p->current_type = mNPS_SCHED_STAND; + nactorx->npc_info.schedule = sched_p; + nactorx->schedule.type = aNPC_SCHEDULE_TYPE_STAND; + break; + case aNPC_CT_SCHED_TYPE_WANDER: + sched_p->current_type = mNPS_SCHED_WANDER; + nactorx->npc_info.schedule = sched_p; + nactorx->schedule.type = aNPC_SCHEDULE_TYPE_WANDER; + break; + case aNPC_CT_SCHED_TYPE_WALK_WANDER: + sched_p->current_type = mNPS_SCHED_WALK_WANDER; + nactorx->npc_info.schedule = sched_p; + nactorx->schedule.type = aNPC_SCHEDULE_TYPE_WALK_WANDER; + break; + case aNPC_CT_SCHED_TYPE_SPECIAL: + sched_p->current_type = mNPS_SCHED_SPECIAL; + nactorx->npc_info.schedule = sched_p; + nactorx->schedule.type = aNPC_SCHEDULE_TYPE_SPECIAL; + break; + default: + sched_p->current_type = mNPS_SCHED_STAND; + nactorx->npc_info.schedule = sched_p; + nactorx->schedule.type = aNPC_SCHEDULE_TYPE_STAND; + break; + } +} + +static void aNPC_actor_ct(ACTOR* actorx, GAME* game, aNPC_ct_data_c* ct_data) { + int name_type; + mActor_name_t org_name = actorx->npc_id; + mActor_name_t npc_name = org_name; + aNPC_draw_data_c draw_data; + + name_type = ITEM_NAME_GET_TYPE(actorx->npc_id); + if (name_type != NAME_TYPE_NPC && name_type != NAME_TYPE_SPNPC) { + Actor_delete(actorx); + actorx->sv_proc = NULL; + actorx->dt_proc = NULL; + mNpc_RenewalSetNpc(actorx); + } else { + NPC_ACTOR* nactorx = (NPC_ACTOR*)actorx; + cKF_Skeleton_R_c* skeleton; + f32 scale; + f32 eye_y; + + aNPC_dma_draw_data_proc(&draw_data, org_name); + mem_copy((u8*)&nactorx->draw.draw_tex_data, (u8*)&draw_data.tex_data, sizeof(draw_data.tex_data)); + nactorx->draw.shape_bank = draw_data.model_bank; + nactorx->draw.tex_bank = draw_data.texture_bank; + nactorx->talk_info.type = draw_data.talk_type; + nactorx->draw.draw_type = draw_data.species_sub_idx; + + if (aNPC_GET_ANM(nactorx) != NULL) { + nactorx->right_hand.umbrella_type = aNPC_GET_ANM(nactorx)->umbrella_id; + } else { + nactorx->right_hand.umbrella_type = draw_data.umbrella_type; + } + + if (draw_data.accessory_type != -1) { + aNPC_make_accessory(actorx, game, draw_data.accessory_type, draw_data.accessory_joint); + } + + skeleton = draw_data.model_skeleton; + eye_y = (f32)draw_data.eye_height; + scale = draw_data.scale; + + cKF_SkeletonInfo_R_ct(&nactorx->draw.main_animation.keyframe, skeleton, NULL, nactorx->draw.main_animation.work, nactorx->draw.main_animation.morph); + cKF_SkeletonInfo_R_ct(&nactorx->draw.sub_animation0.keyframe, skeleton, NULL, nactorx->draw.sub_animation0.work, nactorx->draw.sub_animation0.morph); + cKF_SkeletonInfo_R_ct(&nactorx->draw.sub_animation1.keyframe, skeleton, NULL, nactorx->draw.sub_animation1.work, nactorx->draw.sub_animation1.morph); + Shape_Info_init(actorx, 0.0f, &mAc_ActorShadowEllipse, 9.0f, 17.0f); + actorx->shape_info.ofs_y = 2.0f; + + { + ClObjPipe_c* pipe_p = &nactorx->collision.pipe; + + ClObjPipe_ct(game, pipe_p); + ClObjPipe_set5(game, pipe_p, actorx, &aNPC_CoInfoData); + CollisionCheck_Status_set3(&actorx->status_data, &aNPC_StatusData); + pipe_p->attribute.pipe.radius = draw_data.col_radius; + pipe_p->attribute.pipe.height = draw_data.col_height; + } + + nactorx->move_proc = ct_data->move_proc; + nactorx->draw_proc = ct_data->draw_proc; + + nactorx->draw.animation_id = aNPC_ANIM_NUM; + nactorx->draw.effect_pattern = 0xFF; + nactorx->draw.effect_type = -1; + nactorx->draw.anim_speed_type = aNPC_ANIM_SPEED_TYPE_LOCKED; + + nactorx->collision.BGcheck_radius = 18.0f; + nactorx->collision.check_kind = aNPC_BG_CHECK_TYPE_RANGE; + + nactorx->eye_y = eye_y; + nactorx->action.idx = aNPC_ACT_NONE; + + nactorx->left_hand.after_mode = aHOI_REQUEST_PUTAWAY; + nactorx->draw.main_animation.animation_id = -1; + nactorx->draw.sub_animation0.animation_id = -1; + nactorx->draw.sub_animation1.animation_id = -1; + nactorx->draw.sub_anim_type = aNPC_SUB_ANIM_NONE; + + nactorx->talk_info.talk_request_proc = ct_data->talk_request_proc; + nactorx->talk_info.talk_init_proc = ct_data->talk_init_proc; + nactorx->talk_info.talk_end_check_proc = ct_data->talk_end_check_proc; + nactorx->talk_info.default_animation = -1; + nactorx->talk_info.default_turn_animation = -1; + nactorx->talk_info.default_act = aNPC_ACT_TALK; + nactorx->talk_info.turn = aNPC_TALK_TURN_NORMAL; + + nactorx->schedule.type = aNPC_SCHEDULE_NONE; + + nactorx->movement.range_center_x = (((int)actorx->block_x + 0.5f) * mFI_BK_WORLDSIZE_X_F); + nactorx->movement.range_center_z = (((int)actorx->block_z + 0.5f) * mFI_BK_WORLDSIZE_Z_F); + nactorx->movement.range_radius = 280.0f; + nactorx->movement.movement_ut_x = -1; + nactorx->movement.movement_ut_z = -1; + + // @duplicate, already set above + nactorx->action.idx = aNPC_ACT_NONE; + nactorx->action.act_obj = aNPC_ACT_OBJ_DEFAULT; + + nactorx->think.force_call_msg_no = -1; + nactorx->think.force_call_camera_type = CAMERA2_PROCESS_NORMAL; + + nactorx->talk_info.feel = 0xFF; + nactorx->talk_info.memory = TRUE; + + nactorx->head.angle_add_x = 0x200; + nactorx->head.angle_add_y = 0x400; + + nactorx->draw.frame_sub_speed = 1.0f; + + if (mEv_CheckTitleDemo() > 0) { + actorx->status_data.weight = 0; + } + + xyz_t_move(&nactorx->feet[aNPC_FOOT_LEFT], &actorx->world.position); + xyz_t_move(&nactorx->feet[aNPC_FOOT_RIGHT], &actorx->world.position); + aNPC_set_hide_flg(nactorx, TRUE); + + if (name_type == NAME_TYPE_NPC) { + Animal_c* animal = aNPC_GET_ANM(nactorx); + mActor_name_t cloth = animal->cloth; + u8 org_idx; + + if (animal->cloth == RSV_CLOTH) { + org_idx = animal->cloth_original_id; + } else { + org_idx = 0xFF; + } + + aNPC_setup_next_cloth(nactorx, cloth, org_idx); + aNPC_setup_chg_cloth(nactorx, cloth, org_idx); + + nactorx->condition_info.feel_tim = animal->mood_time * FRAMES_PER_MINUTE; + nactorx->talk_info.talk_end_check_proc = &aNPC_talk_end_check; + aNPC_set_start_pos(actorx); + aNPC_setP_friendship(nactorx); + aNPC_check_force_use_umbrella(nactorx); + nactorx->talk_info.melody_inst = draw_data.voice_type; + nactorx->talk_info.npc_voice_id = draw_data.voice_type; + } else { + mNpc_EventNpc_c* event_npc = mNpc_GetSameEventNpc(org_name); + + if (event_npc != NULL) { + mActor_name_t texture_name = event_npc->texture_id; + + npc_name = event_npc->npc_id; // r29 + nactorx->npc_info.event = event_npc; + event_npc->exists = TRUE; + if (ITEM_NAME_GET_TYPE(texture_name) == NAME_TYPE_NPC) { + aNPC_dma_draw_data_proc(&draw_data, texture_name); + } + } else { + mNpc_MaskNpc_c* mask_npc = mNpc_GetSameMaskNpc(org_name); + + if (mask_npc != NULL) { + mActor_name_t mask_id = mask_npc->npc_id; + + npc_name = mask_id; // r29 + nactorx->npc_info.mask = mask_npc; + mask_npc->exists = TRUE; + + if (ITEM_NAME_GET_TYPE(npc_name) == NAME_TYPE_NPC) { + aNPC_dma_draw_data_proc(&draw_data, mask_id); + } + } + } + + nactorx->talk_info.melody_inst = draw_data.voice_type; + nactorx->talk_info.npc_voice_id = draw_data.voice_type; + nactorx->right_hand.umbrella_disabled_flag = TRUE; + } + + nactorx->npc_info.npc_name = npc_name; + actorx->max_velocity_y = -20.0f; + actorx->gravity = -1.0f; + + { + mActor_name_t* fg_p = mFI_GetUnitFG(actorx->world.position); + + if (fg_p != NULL && (ITEM_IS_HOLE(*fg_p) || *fg_p == HOLE_SHINE)) { + mFI_SetFG_common(EMPTY_NO, actorx->world.position, TRUE); + } + } + + actorx->scale.x = scale; + actorx->scale.y = scale; + actorx->scale.z = scale; + actorx->unknown_b4 = TRUE; + + if (ct_data->sched_type != aNPC_CT_SCHED_TYPE_NONE) { + aNPC_actor_schedule(nactorx, ct_data->sched_type); + } + } +} diff --git a/src/actor/npc/ac_npc_ctrl.c_inc b/src/actor/npc/ac_npc_ctrl.c_inc new file mode 100644 index 00000000..62368796 --- /dev/null +++ b/src/actor/npc/ac_npc_ctrl.c_inc @@ -0,0 +1,1002 @@ +static int aNPC_actor_birth_check(ACTOR* actorx, GAME* game) { + GAME_PLAY* play = (GAME_PLAY*)game; + Actor_info* info = &play->actor_info; + Actor_list* list = &info->list[actorx->part]; + ACTOR* actor_p = list->actor; + mActor_name_t npc_name = actorx->npc_id; + int n; + int ret = TRUE; + + for (n = list->num_actors; n != 0; n--) { + if (actor_p != actorx && actor_p->npc_id == npc_name && + (actor_p->mv_proc != NULL || actor_p->dw_proc != NULL)) { + Actor_delete(actorx); + actorx->sv_proc = NULL; + actorx->dt_proc = NULL; + mNpc_RenewalSetNpc(actorx); + ret = FALSE; + break; + } + + actor_p = actor_p->next_actor; + } + + if (ret == TRUE) { + mNpc_EventNpc_c* event_npc = Common_Get(event_npc); + int i; + + for (i = 0; i < mNpc_EVENT_NPC_NUM; i++) { + if (event_npc->in_use == TRUE && event_npc->npc_id == npc_name) { + Actor_delete(actorx); + actorx->sv_proc = NULL; + actorx->dt_proc = NULL; + mNpc_RenewalSetNpc(actorx); + ret = FALSE; + break; + } + + event_npc++; + } + } + + return ret; +} + +static void aNPC_rebuild_dma(void) { + aNPC_rebuild_cloth_data(); +} + +static void aNPC_set_attention_request_proc(u8 type, ACTOR* target_p, xyz_t* pos_p) { + aNPC_attention_c* attention_request = &CLIP(npc_clip)->attention_request; + + attention_request->type = type; + attention_request->actor = target_p; + if (pos_p != NULL) { + xyz_t_move(&attention_request->pos, pos_p); + } +} + +static int aNPC_get_draw_data_idx(mActor_name_t npc_name) { + int ret = -1; + + switch (ITEM_NAME_GET_TYPE(npc_name)) { + case NAME_TYPE_SPNPC: { + mNpc_EventNpc_c* event_npc = mNpc_GetSameEventNpc(npc_name); + + if (event_npc != NULL) { + if (ITEM_NAME_GET_TYPE(event_npc->texture_id) == NAME_TYPE_NPC) { + ret = event_npc->texture_id - NPC_START; + } else { + ret = ALL_NPC_NUM + event_npc->texture_id - SP_NPC_START; + } + } else { + mNpc_MaskNpc_c* mask_npc = mNpc_GetSameMaskNpc(npc_name); + + if (mask_npc != NULL) { + if (ITEM_NAME_GET_TYPE(mask_npc->npc_id) == NAME_TYPE_NPC) { + ret = mask_npc->npc_id - NPC_START; + } else { + ret = ALL_NPC_NUM + mask_npc->npc_id - SP_NPC_START; + } + } else { + ret = ALL_NPC_NUM + npc_name - SP_NPC_START; + } + } + } break; + + case NAME_TYPE_NPC: + ret = npc_name - NPC_START; + break; + } + + return ret; +} + +static int aNPC_check_dma_cloth_data(int idx) { + int ret = FALSE; + + if (idx < ANIMAL_NUM_MAX) { + Animal_c* animal; + + if (idx == -ANIMAL_NUM_MAX) { + animal = &Save_Get(island).animal; + } else { + animal = Save_GetPointer(animals[idx]); + } + + if (!aNPC_dma_regist_check_cloth_data(animal->cloth)) { + aNPC_dma_regist_cloth_data(animal->cloth); + } else { + ret = TRUE; + } + } else { + ret = TRUE; + } + + return ret; +} + +static int aNPC_check_dma_cloth_data_sub(mActor_name_t cloth) { + int ret = TRUE; + + if (!aNPC_dma_regist_check_cloth_data(cloth)) { + aNPC_dma_regist_cloth_data(cloth); + ret = FALSE; + } + + return ret; +} + +static int aNPC_check_dma_eventNpc_cloth_data(mNpc_EventNpc_c* event_npc) { + int ret = TRUE; + + if (event_npc->cloth_id != EMPTY_NO) { + ret = aNPC_check_dma_cloth_data_sub(event_npc->cloth_id); + } else if (ITEM_NAME_GET_TYPE(event_npc->texture_id) == NAME_TYPE_NPC) { + int idx = mNpc_SearchAnimalinfo(Save_Get(animals), event_npc->texture_id, ANIMAL_NUM_MAX); + + ret = aNPC_check_dma_cloth_data(idx); + } + + return ret; +} + +static int aNPC_check_dma_maskNpc_cloth_data(mNpc_MaskNpc_c* mask_npc) { + int ret = TRUE; + + if (mask_npc->cloth_id != EMPTY_NO) { + ret = aNPC_check_dma_cloth_data_sub(mask_npc->cloth_id); + } + + return ret; +} + +static int aNPC_setupNpc_check(s8 idx, mActor_name_t name) { + int ret = FALSE; + int res; + + if (ITEM_NAME_GET_TYPE(name) == NAME_TYPE_SPNPC) { + mNpc_EventNpc_c* event_npc = mNpc_GetSameEventNpc(name); + + if (event_npc != NULL) { + res = aNPC_check_dma_eventNpc_cloth_data(event_npc); + } else { + mNpc_MaskNpc_c* mask_npc = mNpc_GetSameMaskNpc(name); + + if (mask_npc != NULL) { + res = aNPC_check_dma_maskNpc_cloth_data(mask_npc); + } else { + res = TRUE; + } + } + } else { + res = aNPC_check_dma_cloth_data(idx); + } + + if (res == TRUE) { + ret = TRUE; + } + + return ret; +} + +static int aNPC_setupActor_sub(GAME_PLAY* play, s8 idx, mActor_name_t name, s16 profile, xyz_t* pos, s16 mvlist_no, + s16 arg) { + int ret = FALSE; + + if (aNPC_setupNpc_check(idx, name) == TRUE) { + if (Actor_info_make_actor(&play->actor_info, (GAME*)play, profile, pos->x, pos->y, pos->z, 0, 0, 0, + play->block_table.block_x, play->block_table.block_z, mvlist_no, name, arg, idx, + -1) != NULL) { + ret = TRUE; + } + } + + return ret; +} + +static int aNPC_setupActor_proc(GAME_PLAY* play, mActor_name_t name, s8 idx, int mvlist_no, s16 arg, int bx, int bz, int ux, int uz) { + // clang-format off + static s16 event_npc_profile_table[] = { + mAc_PROFILE_EV_ARTIST, + mAc_PROFILE_EV_BROKER, + mAc_PROFILE_EV_DESIGNER, + mAc_PROFILE_NPC_POST_GIRL, + mAc_PROFILE_NPC_GUIDE, + mAc_PROFILE_NPC_GUIDE2, + mAc_PROFILE_EV_CARPETPEDDLER, + mAc_PROFILE_EV_KABUPEDDLER, + mAc_PROFILE_NPC_SHOP_MASTER, + mAc_PROFILE_NPC_CONV_MASTER, + mAc_PROFILE_NPC_SUPER_MASTER, + mAc_PROFILE_NPC_DEPART_MASTER, + mAc_PROFILE_EV_GYPSY, + mAc_PROFILE_NPC_POLICE, + mAc_PROFILE_NPC_STATION_MASTER, + mAc_PROFILE_EV_SANTA, + mAc_PROFILE_NPC_POLICE2, + mAc_PROFILE_NPC_POST_MAN, + mAc_PROFILE_NPC_POST_GIRL, + mAc_PROFILE_EV_BROKER2, + mAc_PROFILE_NPC_RCN_GUIDE, + mAc_PROFILE_NPC_RCN_GUIDE, + mAc_PROFILE_NPC_RCN_GUIDE, + mAc_PROFILE_NPC_RCN_GUIDE, + mAc_PROFILE_NPC_P_SEL, + mAc_PROFILE_NPC_RCN_GUIDE2, + mAc_PROFILE_NPC_RCN_GUIDE2, + mAc_PROFILE_NPC_RCN_GUIDE2, + mAc_PROFILE_NPC_RCN_GUIDE2, + mAc_PROFILE_EV_ANGLER, + mAc_PROFILE_NPC_SHOP_MASTERSP, + mAc_PROFILE_NPC_P_SEL2, + mAc_PROFILE_HALLOWEEN_NPC, + mAc_PROFILE_HALLOWEEN_NPC, + mAc_PROFILE_HALLOWEEN_NPC, + mAc_PROFILE_HALLOWEEN_NPC, + mAc_PROFILE_HALLOWEEN_NPC, + mAc_PROFILE_EV_PUMPKIN, + mAc_PROFILE_NPC_MAMEDANUKI, + mAc_PROFILE_HANABI_NPC0, + mAc_PROFILE_HANABI_NPC1, + mAc_PROFILE_HANABI_NPC1, + mAc_PROFILE_HANABI_NPC1, + mAc_PROFILE_HANABI_NPC1, + mAc_PROFILE_EV_YOMISE, + mAc_PROFILE_TOKYOSO_NPC0, + mAc_PROFILE_TOKYOSO_NPC1, + mAc_PROFILE_TOKYOSO_NPC1, + mAc_PROFILE_TOKYOSO_NPC1, + mAc_PROFILE_TOKYOSO_NPC1, + mAc_PROFILE_HANAMI_NPC0, + mAc_PROFILE_HANAMI_NPC0, + mAc_PROFILE_HANAMI_NPC0, + mAc_PROFILE_HANAMI_NPC0, + mAc_PROFILE_HANAMI_NPC1, + mAc_PROFILE_NPC_MAMEDANUKI, + mAc_PROFILE_NPC_SLEEP_OBABA, + mAc_PROFILE_EV_YOMISE, + mAc_PROFILE_NPC_SHOP_MASTERSP, + mAc_PROFILE_NPC_SHOP_MASTERSP, + mAc_PROFILE_NPC_SHOP_MASTERSP, + mAc_PROFILE_EV_MIKO, + mAc_PROFILE_NPC_MAJIN, + mAc_PROFILE_TUKIMI_NPC1, + mAc_PROFILE_TUKIMI_NPC1, + mAc_PROFILE_TUKIMI_NPC1, + mAc_PROFILE_TUKIMI_NPC1, + mAc_PROFILE_TUKIMI_NPC1, + mAc_PROFILE_COUNTDOWN_NPC0, + mAc_PROFILE_COUNTDOWN_NPC1, + mAc_PROFILE_COUNTDOWN_NPC1, + mAc_PROFILE_COUNTDOWN_NPC1, + mAc_PROFILE_COUNTDOWN_NPC1, + mAc_PROFILE_TURI_NPC0, + mAc_PROFILE_TURI_NPC0, + mAc_PROFILE_TURI_NPC0, + mAc_PROFILE_TURI_NPC0, + mAc_PROFILE_TURI_NPC0, + mAc_PROFILE_TAISOU_NPC0, + mAc_PROFILE_TAISOU_NPC0, + mAc_PROFILE_TAISOU_NPC0, + mAc_PROFILE_TAISOU_NPC0, + mAc_PROFILE_TAISOU_NPC0, + mAc_PROFILE_TAMAIRE_NPC0, + mAc_PROFILE_TAMAIRE_NPC1, + mAc_PROFILE_TAMAIRE_NPC1, + mAc_PROFILE_TAMAIRE_NPC1, + mAc_PROFILE_TAMAIRE_NPC1, + mAc_PROFILE_HATUMODE_NPC0, + mAc_PROFILE_HATUMODE_NPC0, + mAc_PROFILE_HATUMODE_NPC0, + mAc_PROFILE_HATUMODE_NPC0, + mAc_PROFILE_HATUMODE_NPC0, + mAc_PROFILE_NPC_TOTAKEKE, + mAc_PROFILE_KAMAKURA_NPC0, + mAc_PROFILE_TUNAHIKI_NPC0, + mAc_PROFILE_TUNAHIKI_NPC1, + mAc_PROFILE_TUNAHIKI_NPC1, + mAc_PROFILE_TUNAHIKI_NPC1, + mAc_PROFILE_TUNAHIKI_NPC1, + mAc_PROFILE_EV_DOZAEMON, + mAc_PROFILE_NPC_MAJIN2, + mAc_PROFILE_NPC_RTC, + mAc_PROFILE_NPC_ENGINEER, + mAc_PROFILE_NPC_MAJIN3, + mAc_PROFILE_NPC_MAJIN4, + mAc_PROFILE_NPC_RESTART, + mAc_PROFILE_NPC_MAJIN5, + mAc_PROFILE_EV_DOKUTU, + mAc_PROFILE_NPC_CURATOR, + mAc_PROFILE_EV_SONCHO, + mAc_PROFILE_EV_GHOST, + mAc_PROFILE_NPC_NEEDLEWORK, + mAc_PROFILE_NPC_NEEDLEWORK, + mAc_PROFILE_NPC_SENDO, + mAc_PROFILE_PRESENT_NPC, + mAc_PROFILE_EV_SONCHO2, + mAc_PROFILE_NPC_MASK_CAT, + mAc_PROFILE_NPC_MASK_CAT2, + mAc_PROFILE_GO_HOME_NPC, + mAc_PROFILE_TAISOU_NPC0, + mAc_PROFILE_EV_SONCHO2, + mAc_PROFILE_NPC_SHASHO, + mAc_PROFILE_EV_CASTAWAY, + mAc_PROFILE_NPC_MAJIN, + mAc_PROFILE_NPC_MAJIN, + mAc_PROFILE_NPC_MAJIN, + mAc_PROFILE_NPC_SONCHO, + mAc_PROFILE_NPC_MAJIN, + mAc_PROFILE_EV_MAJIN, + mAc_PROFILE_HARVEST_NPC0, + mAc_PROFILE_HARVEST_NPC0, + mAc_PROFILE_HARVEST_NPC0, + mAc_PROFILE_HARVEST_NPC0, + mAc_PROFILE_HARVEST_NPC1, + mAc_PROFILE_EV_SPEECH_SONCHO, + mAc_PROFILE_GROUNDHOG_NPC0, + mAc_PROFILE_GROUNDHOG_NPC0, + mAc_PROFILE_GROUNDHOG_NPC0, + mAc_PROFILE_GROUNDHOG_NPC0, + mAc_PROFILE_GROUNDHOG_NPC0, + mAc_PROFILE_EV_TURKEY, + mAc_PROFILE_NPC_HEM, + mAc_PROFILE_KAMAKURA_NPC0, + }; + // clang-format on + + // clang-format off + static f32 pos_table[] = { + (mFI_UNIT_BASE_SIZE_F * 0.5f) + ( 0 * mFI_UNIT_BASE_SIZE_F), + (mFI_UNIT_BASE_SIZE_F * 0.5f) + ( 1 * mFI_UNIT_BASE_SIZE_F), + (mFI_UNIT_BASE_SIZE_F * 0.5f) + ( 2 * mFI_UNIT_BASE_SIZE_F), + (mFI_UNIT_BASE_SIZE_F * 0.5f) + ( 3 * mFI_UNIT_BASE_SIZE_F), + (mFI_UNIT_BASE_SIZE_F * 0.5f) + ( 4 * mFI_UNIT_BASE_SIZE_F), + (mFI_UNIT_BASE_SIZE_F * 0.5f) + ( 5 * mFI_UNIT_BASE_SIZE_F), + (mFI_UNIT_BASE_SIZE_F * 0.5f) + ( 6 * mFI_UNIT_BASE_SIZE_F), + (mFI_UNIT_BASE_SIZE_F * 0.5f) + ( 7 * mFI_UNIT_BASE_SIZE_F), + (mFI_UNIT_BASE_SIZE_F * 0.5f) + ( 8 * mFI_UNIT_BASE_SIZE_F), + (mFI_UNIT_BASE_SIZE_F * 0.5f) + ( 9 * mFI_UNIT_BASE_SIZE_F), + (mFI_UNIT_BASE_SIZE_F * 0.5f) + (10 * mFI_UNIT_BASE_SIZE_F), + (mFI_UNIT_BASE_SIZE_F * 0.5f) + (11 * mFI_UNIT_BASE_SIZE_F), + (mFI_UNIT_BASE_SIZE_F * 0.5f) + (12 * mFI_UNIT_BASE_SIZE_F), + (mFI_UNIT_BASE_SIZE_F * 0.5f) + (13 * mFI_UNIT_BASE_SIZE_F), + (mFI_UNIT_BASE_SIZE_F * 0.5f) + (14 * mFI_UNIT_BASE_SIZE_F), + (mFI_UNIT_BASE_SIZE_F * 0.5f) + (15 * mFI_UNIT_BASE_SIZE_F), + }; + // clang-format on + + s16 profile; + xyz_t pos; + + profile = mAc_PROFILE_NORMAL_NPC; + switch (ITEM_NAME_GET_TYPE(name)) { + case NAME_TYPE_SPNPC: + switch (name) { + case SP_NPC_POST_GIRL: + if (Common_Get(post_girl_npc_type) == 1) { + name = SP_NPC_POST_GIRL2; + } + break; + case SP_NPC_SHOP_MASTER: + case SP_NPC_CONV_MASTER: + case SP_NPC_SUPER_MASTER: + case SP_NPC_DEPART_MASTER: + if (mEv_CheckFirstJob() == TRUE) { + name = SP_NPC_RCN_GUIDE2 + (name - SP_NPC_SHOP_MASTER); + } else if (Common_Get(tanuki_shop_status) == mSP_TANUKI_SHOP_STATUS_FUKUBIKI) { + switch (name) { + case SP_NPC_CONV_MASTER: + name = SP_NPC_SHOP_MASTERSP_2; + break; + case SP_NPC_SUPER_MASTER: + name = SP_NPC_SHOP_MASTERSP_3; + break; + case SP_NPC_DEPART_MASTER: + name = SP_NPC_SHOP_MASTERSP_4; + break; + // case SP_NPC_SHOP_MASTER: + default: + name = SP_NPC_SHOP_MASTERSP; + break; + } + } + break; + } + profile = event_npc_profile_table[name - SP_NPC_START]; + break; + case NAME_TYPE_NPC: + profile = mAc_PROFILE_NORMAL_NPC; + break; + } + + { + f32 x; + f32 z; + + mFI_BkNum2WposXZ(&x, &z, bx, bz); + pos.x = x + pos_table[ux]; + pos.z = z + pos_table[uz]; + pos.y = mCoBG_GetBgY_OnlyCenter_FromWpos(pos, 0.0f); + } + + aNPC_setupActor_sub(play, idx, name, profile, &pos, mvlist_no, arg); +} + +static int aNPC_get_overlay_free_area_idx(aNPC_overlay_c* overlay, int max) { + int i; + + for (i = 0; i < max; i++) { + if (!overlay->used) { + return i; + } + + overlay++; + } + + return -1; +} + +static void aNPC_get_overlay_area_proc_sub(ACTOR_DLFTBL* dlftbl, size_t size, size_t max_size, aNPC_overlay_c* overlay, int max, mActor_name_t npc_name) { + int idx = aNPC_get_overlay_free_area_idx(overlay, max); + + if (idx != -1) { + dlftbl->alloc_buf = overlay[idx].buf; + overlay[idx].used = TRUE; + } else { + dlftbl->alloc_buf = NULL; + } +} + +// @optimization - this whole chain can be removed, it's unused in GC titles +static void aNPC_get_overlay_area_proc(ACTOR_DLFTBL* dlftbl, u8* name_p, size_t size, mActor_name_t npc_name) { + switch (ITEM_NAME_GET_TYPE(npc_name)) { + case NAME_TYPE_NPC: + aNPC_get_overlay_area_proc_sub(dlftbl, size, 0x800, CLIP(npc_clip)->keep_n_overlay, 1, npc_name); + break; + case NAME_TYPE_SPNPC: { + mNpc_EventNpc_c* event_npc = mNpc_GetSameEventNpc(npc_name); + + if (event_npc != NULL) { + aNPC_get_overlay_area_proc_sub(dlftbl, size, 0x2800, CLIP(npc_clip)->keep_e_overlay, 2, npc_name); + } else { + mNpc_MaskNpc_c* mask_npc = mNpc_GetSameMaskNpc(npc_name); + + if (mask_npc != NULL) { + aNPC_get_overlay_area_proc_sub(dlftbl, size, 0x3000, CLIP(npc_clip)->keep_k_overlay, 3, npc_name); + } else { + switch (npc_name) { + case SP_NPC_KABUPEDDLER: + case SP_NPC_POLICE: + case SP_NPC_STATION_MASTER: + case SP_NPC_POST_MAN: + case SP_NPC_EV_DOZAEMON: + case SP_NPC_ENGINEER: + case SP_NPC_MAJIN5: + case SP_NPC_EV_SONCHO: + case SP_NPC_EV_GHOST: + case SP_NPC_SENDO: + case SP_NPC_MASK_CAT: + case SP_NPC_GO_HONE_NPC: + aNPC_get_overlay_area_proc_sub(dlftbl, size, 0x3000, CLIP(npc_clip)->keep_k_overlay, 3, npc_name); + break; + default: + aNPC_get_overlay_area_proc_sub(dlftbl, size, 0x2000, CLIP(npc_clip)->keep_s_overlay, 2, npc_name); + break; + } + } + } + } + break; + } +} + +static void aNPC_free_overlay_area_proc(ACTOR_DLFTBL* dlftbl) { + aNPC_overlay_c* overlay_p; + int i; + + overlay_p = CLIP(npc_clip)->keep_n_overlay; + for (i = 0; i < 1; i++) { + if (overlay_p->buf == dlftbl->alloc_buf) { + overlay_p->used = FALSE; + dlftbl->alloc_buf = NULL; + return; + } + + overlay_p++; + } + + overlay_p = CLIP(npc_clip)->keep_s_overlay; + for (i = 0; i < 2; i++) { + if (overlay_p->buf == dlftbl->alloc_buf) { + overlay_p->used = FALSE; + dlftbl->alloc_buf = NULL; + return; + } + + overlay_p++; + } + + overlay_p = CLIP(npc_clip)->keep_k_overlay; + for (i = 0; i < 3; i++) { + if (overlay_p->buf == dlftbl->alloc_buf) { + overlay_p->used = FALSE; + dlftbl->alloc_buf = NULL; + return; + } + + overlay_p++; + } + + overlay_p = CLIP(npc_clip)->keep_e_overlay; + for (i = 0; i < 2; i++) { + if (overlay_p->buf == dlftbl->alloc_buf) { + overlay_p->used = FALSE; + dlftbl->alloc_buf = NULL; + return; + } + + overlay_p++; + } +} + +static ACTOR* aNPC_get_actor_area_proc(size_t size, const char* actor_name, int line) { + NPC_ACTOR** actor = CLIP(npc_clip)->keep_actors; + int* used = CLIP(npc_clip)->keep_actor_used; + int i; + + if (size > 0x9D0) { + return NULL; + } + + for (i = 0; i < 9; i++) { + if (*actor != NULL && *used == FALSE) { + *used = TRUE; + return (ACTOR*)*actor; + } + + actor++; + used++; + } + + return NULL; +} + +static void aNPC_free_actor_area_proc(ACTOR* actorx) { + NPC_ACTOR* nactorx = (NPC_ACTOR*)actorx; + NPC_ACTOR** actor = CLIP(npc_clip)->keep_actors; + int* used = CLIP(npc_clip)->keep_actor_used; + int i; + + for (i = 0; i < 9; i++) { + if (*actor == nactorx) { + *used = FALSE; + break; + } + + actor++; + used++; + } +} + +static void aNPC_dma_draw_data_proc(aNPC_draw_data_c* draw_data_p, mActor_name_t npc_name) { + int idx = aNPC_get_draw_data_idx(npc_name); + + mem_copy((u8*)draw_data_p, (u8*)&npc_draw_data_tbl[idx], sizeof(aNPC_draw_data_c)); +} + +typedef struct { + u64 align; + u8 buf[0x9D0]; +} aNPC_actor_class_overlay_c; + +typedef struct { + u64 align; + u8 buf[0x800]; +} aNPC_n_overlay_c; + +typedef struct { + u64 align; + u8 buf[0x2000]; +} aNPC_s_overlay_c; + +typedef struct { + u64 align; + u8 buf[0x3000]; +} aNPC_k_overlay_c; + +typedef struct { + u64 align; + u8 buf[0x2800]; +} aNPC_e_overlay_c; + +static aNPC_actor_class_overlay_c aNPC_n_actor_cl_tbl[9]; +static aNPC_n_overlay_c aNPC_n_overlay[1]; +static aNPC_s_overlay_c aNPC_s_overlay[2]; +static aNPC_k_overlay_c aNPC_k_overlay[3]; +static aNPC_e_overlay_c aNPC_e_overlay[2]; + +static void aNPC_keep_actor_class(void) { + NPC_ACTOR** actor = CLIP(npc_clip)->keep_actors; + int* used = CLIP(npc_clip)->keep_actor_used; + int i; + + for (i = 0; i < 9; i++) { + *actor = (NPC_ACTOR*)ALIGN_NEXT((u32)aNPC_n_actor_cl_tbl[i].buf, 16); + *used = FALSE; + + actor++; + used++; + } +} + +static void aNPC_free_actor_class(void) { + NPC_ACTOR** actor = CLIP(npc_clip)->keep_actors; + int i; + + for (i = 0; i < 9; i++) { + if (*actor != NULL) { + *actor = NULL; + } + actor++; + } +} + +static void aNPC_keep_n_overlay_area(aNPC_overlay_c* overlay_p) { + int i; + + for (i = 0; i < 1; i++) { + overlay_p->buf = (u8*)&aNPC_n_overlay[i].buf; + overlay_p->used = FALSE; + overlay_p++; + } +} + +static void aNPC_keep_s_overlay_area(aNPC_overlay_c* overlay_p) { + int i; + + for (i = 0; i < 2; i++) { + overlay_p->buf = (u8*)&aNPC_s_overlay[i].buf; + overlay_p->used = FALSE; + overlay_p++; + } +} + +static void aNPC_keep_k_overlay_area(aNPC_overlay_c* overlay_p) { + int i; + + for (i = 0; i < 3; i++) { + overlay_p->buf = (u8*)&aNPC_k_overlay[i].buf; + overlay_p->used = FALSE; + overlay_p++; + } +} + +static void aNPC_keep_e_overlay_area(aNPC_overlay_c* overlay_p) { + int i; + + for (i = 0; i < 2; i++) { + overlay_p->buf = (u8*)&aNPC_e_overlay[i].buf; + overlay_p->used = FALSE; + overlay_p++; + } +} + +static void aNPC_free_overlay_area(aNPC_overlay_c* overlay_p, int n) { + int i; + + for (i = 0; i != n; i++) { + if (overlay_p->buf != NULL) { + overlay_p->buf = NULL; + } + + overlay_p++; + } +} + +static void aNPC_actor_ct_c(ACTOR* actorx, GAME* game) { + GAME_PLAY* play = (GAME_PLAY*)game; + Object_Exchange_c* obj_ex = &play->object_exchange; + NPC_CONTROL_ACTOR* ctrl = (NPC_CONTROL_ACTOR*)actorx; + + aNPC_ctrlActor = actorx; + aNPC_keep_cloth_data_area(obj_ex); + + if (CLIP(npc_clip) == NULL) { + CLIP(npc_clip) = &aNPC_clip; + bzero(&aNPC_clip, sizeof(aNPC_clip)); + + CLIP(npc_clip)->setupActor_proc = &aNPC_setupActor_proc; + CLIP(npc_clip)->get_overlay_area_proc = &aNPC_get_overlay_area_proc; + CLIP(npc_clip)->free_overlay_area_proc = &aNPC_free_overlay_area_proc; + CLIP(npc_clip)->get_actor_area_proc = &aNPC_get_actor_area_proc; + CLIP(npc_clip)->free_actor_area_proc = &aNPC_free_actor_area_proc; + CLIP(npc_clip)->dma_draw_data_proc = &aNPC_dma_draw_data_proc; + CLIP(npc_clip)->set_attention_request_proc = &aNPC_set_attention_request_proc; + CLIP(npc_clip)->birth_check_proc = &aNPC_actor_birth_check; + CLIP(npc_clip)->ct_proc = &aNPC_actor_ct; + CLIP(npc_clip)->dt_proc = &aNPC_actor_dt; + CLIP(npc_clip)->save_proc = &aNPC_actor_save; + CLIP(npc_clip)->init_proc = &aNPC_actor_init; + CLIP(npc_clip)->move_proc = &aNPC_actor_move; + CLIP(npc_clip)->move_before_proc = &aNPC_actor_move_show_before; + CLIP(npc_clip)->move_after_proc = &aNPC_actor_move_show_after; + CLIP(npc_clip)->draw_proc = &aNPC_actor_draw; + CLIP(npc_clip)->rebuild_dma_proc = &aNPC_rebuild_dma; + CLIP(npc_clip)->set_request_act_proc = &aNPC_set_request_act; + CLIP(npc_clip)->set_head_request_act_proc = &aNPC_set_head_request; + CLIP(npc_clip)->talk_demo_proc = &aNPC_talk_demo_proc; + CLIP(npc_clip)->animation_init_proc = &aNPC_Animation_init; + CLIP(npc_clip)->chg_schedule_proc = &aNPC_chg_schedule; + CLIP(npc_clip)->set_dst_pos_proc = &aNPC_set_dst_pos; + CLIP(npc_clip)->think_proc = &aNPC_think_proc; + CLIP(npc_clip)->force_call_req_proc = &aNPC_force_call_req_proc; + CLIP(npc_clip)->set_start_pos_proc = &aNPC_set_start_pos; + + aNPC_keep_actor_class(); + aNPC_keep_n_overlay_area(CLIP(npc_clip)->keep_n_overlay); + aNPC_keep_s_overlay_area(CLIP(npc_clip)->keep_s_overlay); + aNPC_keep_k_overlay_area(CLIP(npc_clip)->keep_k_overlay); + aNPC_keep_e_overlay_area(CLIP(npc_clip)->keep_e_overlay); + } + + if (play->block_table.block_z == mISL_BLOCK_Z) { + int bx; + int bz; + int ux; + int uz; + Island_c* island_p; + Animal_c* islander_p; + mNpc_NpcList_c* list_p; + mNPS_schedule_c* sched_p; + + island_p = &Save_Get(island); + islander_p = &island_p->animal; + list_p = &Common_Get(island_npclist[0]); + + if (list_p->name == EMPTY_NO) { + mNpc_SetNpcList(list_p, islander_p, 1, TRUE); + bx = (int)islander_p->home_info.block_x; + bz = (int)islander_p->home_info.block_z; + ux = (int)islander_p->home_info.ut_x; + uz = (int)islander_p->home_info.ut_z; + } else { + int ret = mFI_Wpos2BkandUtNuminBlock(&bx, &bz, &ux, &uz, list_p->position); + + if (ret == FALSE) { + bx = (int)islander_p->home_info.block_x; + bz = (int)islander_p->home_info.block_z; + ux = (int)islander_p->home_info.ut_x; + uz = (int)islander_p->home_info.ut_z; + } else { + if (!mNpc_CheckNpcSet(bx, bz, ux, uz) && !mNpc_GetMakeUtNuminBlock_area(&ux, &uz, bx, bz, 0)) { + bx = (int)islander_p->home_info.block_x; + bz = (int)islander_p->home_info.block_z; + ux = (int)islander_p->home_info.ut_x; + uz = (int)islander_p->home_info.ut_z; + } + } + } + + if (mFI_RegistMoveActorList(list_p->name, bx, bz, ux, uz, -ANIMAL_NUM_MAX, 0)) { + sched_p = Common_GetPointer(npc_schedule[ANIMAL_NUM_MAX]); + + if (sched_p->id != NULL) { + mNPS_reset_schedule_area(sched_p->id); + } + + mNPS_set_island_schedule_area(&islander_p->id); + } + } +} + +static void aNPC_actor_dt_c(ACTOR* actorx, GAME* game) { + if (CLIP(npc_clip) != NULL) { + aNPC_free_actor_class(); + aNPC_free_overlay_area(CLIP(npc_clip)->keep_n_overlay, 1); + aNPC_free_overlay_area(CLIP(npc_clip)->keep_s_overlay, 2); + aNPC_free_overlay_area(CLIP(npc_clip)->keep_k_overlay, 3); + aNPC_free_overlay_area(CLIP(npc_clip)->keep_e_overlay, 2); + CLIP(npc_clip) = NULL; + } +} + +static int aNPC_check_cond_to_greeting(NPC_ACTOR* nactorx) { + int ret = TRUE; + + if (nactorx->actor_class.ct_proc != NULL || nactorx->palActor != NULL || nactorx->palActorIgnoreTimer != 0 || nactorx->condition_info.hide_flg == TRUE) { + ret = FALSE; + } else { + switch (aNPC_get_feel_info(nactorx)) { + case mNpc_FEEL_ANGRY: + case mNpc_FEEL_SAD: + case mNpc_FEEL_SLEEPY: + ret = FALSE; + break; + } + } + + return ret; +} + +static void aNPC_greeting_area_check(GAME_PLAY* play) { + Actor_list* list = &play->actor_info.list[ACTOR_PART_NPC]; + ACTOR* actor = list->actor; + int n = list->num_actors; + xyz_t pos; + NPC_ACTOR* nactor; + ACTOR* next_actor; + int i; + + n--; + for (n; n > 0; n--) { + nactor = (NPC_ACTOR*)actor; + i = n; + + xyz_t_move(&pos, &actor->world.position); + if (aNPC_check_cond_to_greeting(nactor) == TRUE) { + next_actor = actor->next_actor; + + for (i; i != 0; i--) { + NPC_ACTOR* next_nactor = next_nactor = (NPC_ACTOR*)next_actor; + + if (aNPC_check_cond_to_greeting(next_nactor) == TRUE) { + f32 dy = next_actor->world.position.y - pos.y; + + if (ABS(dy) < 40.0f) { + f32 dx = next_actor->world.position.x - pos.x; + f32 dz = next_actor->world.position.z - pos.z; + f32 dist = SQ(dx) + SQ(dz); + + if (dist < SQ(80.0f)) { + nactor->palActor = (ACTOR*)next_nactor; + next_nactor->palActor = (ACTOR*)nactor; + break; + } + } + } + + next_actor = next_actor->next_actor; + } + } + + actor = actor->next_actor; + } + + actor = list->actor; + for (n = list->num_actors; n != 0; n--) { + NPC_ACTOR* nactor = (NPC_ACTOR*)actor; + + if (nactor->palActorIgnoreTimer > 0) { + nactor->palActorIgnoreTimer--; + } + + actor = actor->next_actor; + } +} + +static void aNPC_set_attention(void) { + aNPC_attention_c* attention_p = &CLIP(npc_clip)->attention; + aNPC_attention_c* req_p = &CLIP(npc_clip)->attention_request; + + if (req_p->type != aNPC_ATTENTION_TYPE_NONE) { + mem_copy((u8*)attention_p, (u8*)req_p, sizeof(aNPC_attention_c)); + } else { + bzero(attention_p, sizeof(aNPC_attention_c)); + } + + req_p->type = aNPC_ATTENTION_TYPE_NONE; +} + +static void aNPC_force_reset_out_of_door_flg(NPC_CONTROL_ACTOR* ctrl) { + int timer; + + ctrl->door_exit_actor = NULL; + timer = 1 * FRAMES_PER_SECOND + RANDOM(3) * FRAMES_PER_SECOND; + ctrl->door_exit_timer = timer; +} + +static void aNPC_reset_out_of_door_flg(NPC_CONTROL_ACTOR* ctrl, ACTOR* actorx) { + if (ctrl->door_exit_actor == actorx) { + aNPC_force_reset_out_of_door_flg(ctrl); + } +} + +static void aNPC_force_reset_umb_open_flg(NPC_CONTROL_ACTOR* ctrl) { + int timer; + + ctrl->umbrella_open_actor = NULL; + timer = FRAMES_PER_SECOND * 0.5f + RANDOM_F(FRAMES_PER_SECOND * 0.5f); + ctrl->umbrella_open_timer = timer; +} + +static void aNPC_reset_umb_open_flg(NPC_CONTROL_ACTOR* ctrl, ACTOR* actorx) { + if (ctrl->umbrella_open_actor == actorx) { + aNPC_force_reset_umb_open_flg(ctrl); + } +} + +static void aNPC_actor_move_c(ACTOR* actorx, GAME* game) { + NPC_CONTROL_ACTOR* ctrl = (NPC_CONTROL_ACTOR*)actorx; + GAME_PLAY* play = (GAME_PLAY*)game; + + aNPC_dma_cloth_data(actorx); + if (mEv_CheckTitleDemo() <= 0) { + aNPC_greeting_area_check(play); + } + + aNPC_set_attention(); + if (mFI_ActorisBorn() == TRUE) { + aNPC_force_reset_out_of_door_flg(ctrl); + aNPC_force_reset_umb_open_flg(ctrl); + } + + if (ctrl->door_exit_timer > 0 && ctrl->door_exit_timer < (3 * FRAMES_PER_SECOND)) { + ctrl->door_exit_timer--; + } else { + aNPC_force_reset_out_of_door_flg(ctrl); + } + + if (ctrl->umbrella_open_timer > 0 && ctrl->umbrella_open_timer < (1 * FRAMES_PER_SECOND)) { + ctrl->umbrella_open_timer--; + } else { + aNPC_force_reset_umb_open_flg(ctrl); + } +} + +static void aNPC_set_talk_area_info(GAME_PLAY* play) { + NPC_CONTROL_ACTOR* ctrl = (NPC_CONTROL_ACTOR*)aNPC_ctrlActor; + ACTOR* playerx = GET_PLAYER_ACTOR_ACTOR(play); + + if (ctrl != NULL && playerx != NULL) { + aNPC_talk_area_c* talk_area = &ctrl->talk_area; + + if (talk_area->frame_counter != play->game_frame) { + ACTOR* talk_actor = mDemo_Get_talk_actor(); + + if (talk_actor != NULL && talk_actor->part == ACTOR_PART_NPC) { + f32 dx; + f32 dz; + + talk_area->frame_counter = play->game_frame; + talk_area->talk_actor = talk_actor; + + dx = talk_actor->world.position.x - playerx->world.position.x; + dz = talk_actor->world.position.z - playerx->world.position.z; + talk_area->radius = SQ(60.0f) + (SQ(dx) + SQ(dz)) * 0.25f; + talk_area->center_pos.x = (playerx->world.position.x + talk_actor->world.position.x) * 0.5f; + talk_area->center_pos.z = (playerx->world.position.z + talk_actor->world.position.z) * 0.5f; + } + } + } +} + +static void aNPC_talk_area_check(NPC_ACTOR* nactorx, GAME_PLAY* play) { + NPC_CONTROL_ACTOR* ctrl = (NPC_CONTROL_ACTOR*)aNPC_ctrlActor; + u8 turn = FALSE; + + if (ctrl != NULL) { + aNPC_talk_area_c* talk_area = &ctrl->talk_area; + + aNPC_set_talk_area_info(play); + if (talk_area->frame_counter == play->game_frame && talk_area->talk_actor != (ACTOR*)nactorx) { + f32 dx; + f32 dz; + + dx = talk_area->center_pos.x - nactorx->actor_class.world.position.x; + dz = talk_area->center_pos.z - nactorx->actor_class.world.position.z; + + if ((SQ(dx) + SQ(dz)) < talk_area->radius) { + s16 angle = atans_table(dz, dx); + s16 dangle = angle - nactorx->actor_class.shape_info.rotation.y; + + if (ABS(dangle) < DEG2SHORT_ANGLE2(90.0f)) { + nactorx->collision.turn_angle = angle + DEG2SHORT_ANGLE2(180.0f); + turn = TRUE; + } + } + } + } + + nactorx->collision.turn_flag = turn; +} diff --git a/src/actor/npc/ac_npc_data.c_inc b/src/actor/npc/ac_npc_data.c_inc new file mode 100644 index 00000000..269dd181 --- /dev/null +++ b/src/actor/npc/ac_npc_data.c_inc @@ -0,0 +1,625 @@ +extern aNPC_Animation_c cKF_ba_r_npc_1_run1; +extern aNPC_Animation_c cKF_ba_r_npc_1_walk1; +extern aNPC_Animation_c cKF_ba_r_npc_1_walk_ki1; +extern aNPC_Animation_c cKF_ba_r_npc_1_walk_do1; +extern aNPC_Animation_c cKF_ba_r_npc_1_walk_ai1; +extern aNPC_Animation_c cKF_ba_r_npc_1_wait1; +extern aNPC_Animation_c cKF_ba_r_npc_1_wait_ki1; +extern aNPC_Animation_c cKF_ba_r_npc_1_wait_do1; +extern aNPC_Animation_c cKF_ba_r_npc_1_wait_ai1; +extern aNPC_Animation_c cKF_ba_r_npc_1_wait_nemu1; +extern aNPC_Animation_c cKF_ba_r_npc_1_aisatu1; +extern aNPC_Animation_c cKF_ba_r_npc_1_aisatu2; +extern aNPC_Animation_c cKF_ba_r_npc_1_aisatu3; +extern aNPC_Animation_c cKF_ba_r_npc_1_aisatu4; +extern aNPC_Animation_c cKF_ba_r_npc_1_guratuku1; +extern aNPC_Animation_c cKF_ba_r_npc_1_otiru1; +extern aNPC_Animation_c cKF_ba_r_npc_1_otiru2; +extern aNPC_Animation_c cKF_ba_r_npc_1_mogaku1; +extern aNPC_Animation_c cKF_ba_r_npc_1_deru1; +extern aNPC_Animation_c cKF_ba_r_npc_1_deru2; +extern aNPC_Animation_c cKF_ba_r_npc_1_walk1; +extern aNPC_Animation_c cKF_ba_r_npc_1_wait1; +extern aNPC_Animation_c cKF_ba_r_npc_1_open1; +extern aNPC_Animation_c cKF_ba_r_npc_1_go_out1; +extern aNPC_Animation_c cKF_ba_r_npc_1_umb_open1; +extern aNPC_Animation_c cKF_ba_r_npc_1_umb_close1; +extern aNPC_Animation_c cKF_ba_r_npc_1_transfer1; +extern aNPC_Animation_c cKF_ba_r_npc_1_trans_wait1; +extern aNPC_Animation_c cKF_ba_r_npc_1_get1; +extern aNPC_Animation_c cKF_ba_r_npc_1_get_pull1; +extern aNPC_Animation_c cKF_ba_r_npc_1_get_pull_wait1; +extern aNPC_Animation_c cKF_ba_r_npc_1_get_putaway1; +extern aNPC_Animation_c cKF_ba_r_npc_1_get_eat1; +extern aNPC_Animation_c cKF_ba_r_npc_1_get_change1; +extern aNPC_Animation_c cKF_ba_r_npc_1_get_return1; +extern aNPC_Animation_c cKF_ba_r_npc_1_transfer_f1; +extern aNPC_Animation_c cKF_ba_r_npc_1_trans_wait_f1; +extern aNPC_Animation_c cKF_ba_r_npc_1_get_f1; +extern aNPC_Animation_c cKF_ba_r_npc_1_get_pull_f1; +extern aNPC_Animation_c cKF_ba_r_npc_1_get_pull_wait_f1; +extern aNPC_Animation_c cKF_ba_r_npc_1_get_putaway_f1; +extern aNPC_Animation_c cKF_ba_r_npc_1_get_return_f1; +extern aNPC_Animation_c cKF_ba_r_npc_1_estimate_f1; +extern aNPC_Animation_c cKF_ba_r_npc_1_contract1; +extern aNPC_Animation_c cKF_ba_r_npc_1_contract2; +extern aNPC_Animation_c cKF_ba_r_npc_1_contract3; +extern aNPC_Animation_c cKF_ba_r_npc_1_not_contract1; +extern aNPC_Animation_c cKF_ba_r_npc_1_fly1; +extern aNPC_Animation_c cKF_ba_r_npc_1_flyaway1; +extern aNPC_Animation_c cKF_ba_r_npc_1_delivery1; +extern aNPC_Animation_c cKF_ba_r_npc_1_kyoro1; +extern aNPC_Animation_c cKF_ba_r_npc_1_landing1; +extern aNPC_Animation_c cKF_ba_r_npc_1_landing2; +extern aNPC_Animation_c cKF_ba_r_npc_1_landing3; +extern aNPC_Animation_c cKF_ba_r_npc_1_open_d1; +extern aNPC_Animation_c cKF_ba_r_npc_1_sitdown_d1; +extern aNPC_Animation_c cKF_ba_r_npc_1_sitdown_wait_d1; +extern aNPC_Animation_c cKF_ba_r_npc_1_standup_d1; +extern aNPC_Animation_c cKF_ba_r_npc_1_open_d2; +extern aNPC_Animation_c cKF_ba_r_npc_1_to_deck_d1; +extern aNPC_Animation_c cKF_ba_r_npc_1_keitai_on1; +extern aNPC_Animation_c cKF_ba_r_npc_1_keitai_talk1; +extern aNPC_Animation_c cKF_ba_r_npc_1_keitai_talk2; +extern aNPC_Animation_c cKF_ba_r_npc_1_keitai_off1; +extern aNPC_Animation_c cKF_ba_r_npc_1_wait_e1; +extern aNPC_Animation_c cKF_ba_r_npc_1_ensou_e1; +extern aNPC_Animation_c cKF_ba_r_npc_1_banzai1; +extern aNPC_Animation_c cKF_ba_r_npc_1_clap1; +extern aNPC_Animation_c cKF_ba_r_npc_1_kokkuri_d1; +extern aNPC_Animation_c cKF_ba_r_npc_1_kokkuri_d2; +extern aNPC_Animation_c cKF_ba_r_npc_1_saisen1; +extern aNPC_Animation_c cKF_ba_r_npc_1_omairi1; +extern aNPC_Animation_c cKF_ba_r_npc_1_sitdown_wait1; +extern aNPC_Animation_c cKF_ba_r_npc_1_sitdown_drink1; +extern aNPC_Animation_c cKF_ba_r_npc_1_sitdown_clap1; +extern aNPC_Animation_c cKF_ba_r_npc_1_dance1; +extern aNPC_Animation_c cKF_ba_r_npc_1_kuisinbo1; +extern aNPC_Animation_c cKF_ba_r_npc_1_sanbasi1; +extern aNPC_Animation_c cKF_ba_r_npc_1_wait_r1; +extern aNPC_Animation_c cKF_ba_r_npc_1_appear1; +extern aNPC_Animation_c cKF_ba_r_npc_1_go_ug1; +extern aNPC_Animation_c cKF_ba_r_npc_1_intro1_a; +extern aNPC_Animation_c cKF_ba_r_npc_1_intro1_b; +extern aNPC_Animation_c cKF_ba_r_npc_1_taisou1; +extern aNPC_Animation_c cKF_ba_r_npc_1_taisou2; +extern aNPC_Animation_c cKF_ba_r_npc_1_taisou3_a; +extern aNPC_Animation_c cKF_ba_r_npc_1_taisou3_b; +extern aNPC_Animation_c cKF_ba_r_npc_1_taisou4_a; +extern aNPC_Animation_c cKF_ba_r_npc_1_taisou4_b; +extern aNPC_Animation_c cKF_ba_r_npc_1_taisou5_a; +extern aNPC_Animation_c cKF_ba_r_npc_1_taisou5_b; +extern aNPC_Animation_c cKF_ba_r_npc_1_taisou6_a; +extern aNPC_Animation_c cKF_ba_r_npc_1_taisou6_b; +extern aNPC_Animation_c cKF_ba_r_npc_1_taisou7; +extern aNPC_Animation_c cKF_ba_r_npc_1_kiduku1; +extern aNPC_Animation_c cKF_ba_r_npc_1_kiduku2; +extern aNPC_Animation_c cKF_ba_r_npc_1_cracker_wait1; +extern aNPC_Animation_c cKF_ba_r_npc_1_cracker_fire1; +extern aNPC_Animation_c cKF_ba_r_npc_1_cracker_run1; +extern aNPC_Animation_c cKF_ba_r_npc_1_cracker_count1; +extern aNPC_Animation_c cKF_ba_r_npc_1_warmup1; +extern aNPC_Animation_c cKF_ba_r_npc_1_ready1; +extern aNPC_Animation_c cKF_ba_r_npc_1_asihumi1; +extern aNPC_Animation_c cKF_ba_r_npc_1_kokeru1; +extern aNPC_Animation_c cKF_ba_r_npc_1_kokeru_getup1; +extern aNPC_Animation_c cKF_ba_r_npc_1_tired1; +extern aNPC_Animation_c cKF_ba_r_npc_1_tamakome1; +extern aNPC_Animation_c cKF_ba_r_npc_1_youi1; +extern aNPC_Animation_c cKF_ba_r_npc_1_don1; +extern aNPC_Animation_c cKF_ba_r_npc_1_tunahiki_aiko1; +extern aNPC_Animation_c cKF_ba_r_npc_1_tunahiki_yuri1; +extern aNPC_Animation_c cKF_ba_r_npc_1_tunahiki_furi1; +extern aNPC_Animation_c cKF_ba_r_npc_1_hatafuri1; +extern aNPC_Animation_c cKF_ba_r_npc_1_tamahiroi1; +extern aNPC_Animation_c cKF_ba_r_npc_1_tamanage1; +extern aNPC_Animation_c cKF_ba_r_npc_1_getup_seg1; +extern aNPC_Animation_c cKF_ba_r_npc_1_getup_wait_seg1; +extern aNPC_Animation_c cKF_ba_r_npc_1_piku_seg1; +extern aNPC_Animation_c cKF_ba_r_npc_1_4haku_e1; +extern aNPC_Animation_c cKF_ba_r_npc_1_3haku_e1; +extern aNPC_Animation_c cKF_ba_r_npc_1_send_mail1; +extern aNPC_Animation_c cKF_ba_r_npc_1_turi_wait1; +extern aNPC_Animation_c cKF_ba_r_npc_1_misin1; +extern aNPC_Animation_c cKF_ba_r_npc_1_wipkogu1; +extern aNPC_Animation_c cKF_ba_r_npc_1_wipwait1; +extern aNPC_Animation_c cKF_ba_r_npc_1_wipwait2; +extern aNPC_Animation_c cKF_ba_r_npc_1_gstwait1; +extern aNPC_Animation_c cKF_ba_r_npc_1_gyafun1; +extern aNPC_Animation_c cKF_ba_r_npc_1_gyafun2; +extern aNPC_Animation_c cKF_ba_r_npc_1_tkykyoro1; +extern aNPC_Animation_c cKF_ba_r_npc_1_muka1; +extern aNPC_Animation_c cKF_ba_r_npc_1_muka2; +extern aNPC_Animation_c cKF_ba_r_npc_1_gaaan1; +extern aNPC_Animation_c cKF_ba_r_npc_1_gaaan2; +extern aNPC_Animation_c cKF_ba_r_npc_1_smile1; +extern aNPC_Animation_c cKF_ba_r_npc_1_smile2; +extern aNPC_Animation_c cKF_ba_r_npc_1_ha1; +extern aNPC_Animation_c cKF_ba_r_npc_1_ha2; +extern aNPC_Animation_c cKF_ba_r_npc_1_punpun1; +extern aNPC_Animation_c cKF_ba_r_npc_1_punpun2; +extern aNPC_Animation_c cKF_ba_r_npc_1_a1; +extern aNPC_Animation_c cKF_ba_r_npc_1_a2; +extern aNPC_Animation_c cKF_ba_r_npc_1_aseru1; +extern aNPC_Animation_c cKF_ba_r_npc_1_aseru2; +extern aNPC_Animation_c cKF_ba_r_npc_1_buruburu1; +extern aNPC_Animation_c cKF_ba_r_npc_1_buruburu2; +extern aNPC_Animation_c cKF_ba_r_npc_1_goukyu1; +extern aNPC_Animation_c cKF_ba_r_npc_1_goukyu2; +extern aNPC_Animation_c cKF_ba_r_npc_1_happy1; +extern aNPC_Animation_c cKF_ba_r_npc_1_happy2; +extern aNPC_Animation_c cKF_ba_r_npc_1_hate1; +extern aNPC_Animation_c cKF_ba_r_npc_1_hate2; +extern aNPC_Animation_c cKF_ba_r_npc_1_hirameki1; +extern aNPC_Animation_c cKF_ba_r_npc_1_hirameki2; +extern aNPC_Animation_c cKF_ba_r_npc_1_hyuuu1; +extern aNPC_Animation_c cKF_ba_r_npc_1_hyuuu2; +extern aNPC_Animation_c cKF_ba_r_npc_1_lovelove1; +extern aNPC_Animation_c cKF_ba_r_npc_1_lovelove2; +extern aNPC_Animation_c cKF_ba_r_npc_1_muuuuu1; +extern aNPC_Animation_c cKF_ba_r_npc_1_muuuuu2; +extern aNPC_Animation_c cKF_ba_r_npc_1_otikomu1; +extern aNPC_Animation_c cKF_ba_r_npc_1_otikomu2; +extern aNPC_Animation_c cKF_ba_r_npc_1_shituren1; +extern aNPC_Animation_c cKF_ba_r_npc_1_shituren2; +extern aNPC_Animation_c cKF_ba_r_npc_1_warudakumi1; +extern aNPC_Animation_c cKF_ba_r_npc_1_warudakumi2; +extern aNPC_Animation_c cKF_ba_r_npc_1_neboke1; +extern aNPC_Animation_c cKF_ba_r_npc_1_neboke2; +extern aNPC_Animation_c cKF_ba_r_npc_1_love1; +extern aNPC_Animation_c cKF_ba_r_npc_1_love2; +extern aNPC_Animation_c cKF_ba_r_npc_1_niko1; +extern aNPC_Animation_c cKF_ba_r_npc_1_musu1; +extern aNPC_Animation_c cKF_ba_r_npc_1_komari1; +extern aNPC_Animation_c cKF_ba_r_npc_1_hate_f1; +extern aNPC_Animation_c cKF_ba_r_npc_1_hate_f2; +extern aNPC_Animation_c cKF_ba_r_npc_1_ha_f1; +extern aNPC_Animation_c cKF_ba_r_npc_1_ha_f2; +extern aNPC_Animation_c cKF_ba_r_npc_1_happy_f1; +extern aNPC_Animation_c cKF_ba_r_npc_1_happy_f2; +extern aNPC_Animation_c cKF_ba_r_npc_1_aseru_f1; +extern aNPC_Animation_c cKF_ba_r_npc_1_aseru_f2; +extern aNPC_Animation_c cKF_ba_r_npc_1_muuuuu_f1; +extern aNPC_Animation_c cKF_ba_r_npc_1_muuuuu_f2; +extern aNPC_Animation_c cKF_ba_r_npc_1_lovelove_f1; +extern aNPC_Animation_c cKF_ba_r_npc_1_lovelove_f2; +extern aNPC_Animation_c cKF_ba_r_npc_1_a_f1; +extern aNPC_Animation_c cKF_ba_r_npc_1_a_f2; +extern aNPC_Animation_c cKF_ba_r_npc_1_smile_f1; +extern aNPC_Animation_c cKF_ba_r_npc_1_smile_f2; +extern aNPC_Animation_c cKF_ba_r_npc_1_komari_f1; +extern aNPC_Animation_c cKF_ba_r_npc_1_niko_f1; +extern aNPC_Animation_c cKF_ba_r_npc_1_musu_f1; +extern aNPC_Animation_c cKF_ba_r_npc_1_hate_i1; +extern aNPC_Animation_c cKF_ba_r_npc_1_hate_i2; +extern aNPC_Animation_c cKF_ba_r_npc_1_ha_i1; +extern aNPC_Animation_c cKF_ba_r_npc_1_ha_i2; +extern aNPC_Animation_c cKF_ba_r_npc_1_happy_i1; +extern aNPC_Animation_c cKF_ba_r_npc_1_happy_i2; +extern aNPC_Animation_c cKF_ba_r_npc_1_aseru_i1; +extern aNPC_Animation_c cKF_ba_r_npc_1_aseru_i2; +extern aNPC_Animation_c cKF_ba_r_npc_1_muuuuu_i1; +extern aNPC_Animation_c cKF_ba_r_npc_1_muuuuu_i2; +extern aNPC_Animation_c cKF_ba_r_npc_1_love_i1; +extern aNPC_Animation_c cKF_ba_r_npc_1_love_i2; +extern aNPC_Animation_c cKF_ba_r_npc_1_shituren_i1; +extern aNPC_Animation_c cKF_ba_r_npc_1_shituren_i2; +extern aNPC_Animation_c cKF_ba_r_npc_1_komari_i1; +extern aNPC_Animation_c cKF_ba_r_npc_1_niko_i1; +extern aNPC_Animation_c cKF_ba_r_npc_1_musu_i1; +extern aNPC_Animation_c cKF_ba_r_npc_1_smile_d1; +extern aNPC_Animation_c cKF_ba_r_npc_1_smile_d2; +extern aNPC_Animation_c cKF_ba_r_npc_1_gaaan_d1; +extern aNPC_Animation_c cKF_ba_r_npc_1_gaaan_d2; +extern aNPC_Animation_c cKF_ba_r_npc_1_hirameki_d1; +extern aNPC_Animation_c cKF_ba_r_npc_1_hirameki_d2; +extern aNPC_Animation_c cKF_ba_r_npc_1_ha_d1; +extern aNPC_Animation_c cKF_ba_r_npc_1_ha_d2; +extern aNPC_Animation_c cKF_ba_r_npc_1_musu_d1; +extern aNPC_Animation_c cKF_ba_r_npc_1_niko_d1; +extern aNPC_Animation_c cKF_ba_r_npc_1_komari_d1; +extern aNPC_Animation_c cKF_ba_r_npc_1_hate_d1; +extern aNPC_Animation_c cKF_ba_r_npc_1_hate_d2; +extern aNPC_Animation_c cKF_ba_r_npc_1_punpun_r1; +extern aNPC_Animation_c cKF_ba_r_npc_1_punpun_r2; +extern aNPC_Animation_c cKF_ba_r_npc_1_musu_r1; +extern aNPC_Animation_c cKF_ba_r_npc_1_hyuuu_r1; +extern aNPC_Animation_c cKF_ba_r_npc_1_hyuuu_r2; +extern aNPC_Animation_c cKF_ba_r_npc_1_a_r1; +extern aNPC_Animation_c cKF_ba_r_npc_1_a_r2; +extern aNPC_Animation_c cKF_ba_r_npc_1_a2_r1; +extern aNPC_Animation_c cKF_ba_r_npc_1_akireru_r1; +extern aNPC_Animation_c cKF_ba_r_npc_1_akireru_r2; +extern aNPC_Animation_c cKF_ba_r_npc_1_matarou_r1; +extern aNPC_Animation_c cKF_ba_r_npc_1_matarou_r2; +extern aNPC_Animation_c cKF_ba_r_npc_1_gekido_r1; +extern aNPC_Animation_c cKF_ba_r_npc_1_gekido_r2; +extern aNPC_Animation_c cKF_ba_r_npc_1_ha_e1; +extern aNPC_Animation_c cKF_ba_r_npc_1_ha_e2; +extern aNPC_Animation_c cKF_ba_r_npc_1_keirei1; +extern aNPC_Animation_c cKF_ba_r_npc_1_kieeeei1; +extern aNPC_Animation_c cKF_ba_r_npc_1_kieeeei2; +extern aNPC_Animation_c cKF_ba_r_npc_1_umbrella1; +extern aNPC_Animation_c cKF_ba_r_npc_1_utiwa_wait1; +extern aNPC_Animation_c cKF_ba_r_npc_1_tue1; +extern aNPC_Animation_c cKF_ba_r_npc_1_kutipaku1; +extern aNPC_Animation_c cKF_ba_r_npc_1_kutipaku2; + +// clang-format off +static aNPC_anim_info_c aNPC_animeTable[aNPC_ANIM_NUM] = { + {&cKF_ba_r_npc_1_run1, 0x00}, + {&cKF_ba_r_npc_1_walk1, 0x01}, + {&cKF_ba_r_npc_1_walk_ki1, 0x02}, + {&cKF_ba_r_npc_1_walk_do1, 0x03}, + {&cKF_ba_r_npc_1_walk_ai1, 0x04}, + {&cKF_ba_r_npc_1_wait1, 0x05}, + {&cKF_ba_r_npc_1_wait_ki1, 0x06}, + {&cKF_ba_r_npc_1_wait_do1, 0x07}, + {&cKF_ba_r_npc_1_wait_ai1, 0x08}, + {&cKF_ba_r_npc_1_wait_nemu1, 0x09}, + {&cKF_ba_r_npc_1_aisatu1, 0x0A}, + {&cKF_ba_r_npc_1_aisatu2, 0x0B}, + {&cKF_ba_r_npc_1_aisatu3, 0x0C}, + {&cKF_ba_r_npc_1_aisatu4, 0x0D}, + {&cKF_ba_r_npc_1_guratuku1, 0x0E}, + {&cKF_ba_r_npc_1_otiru1, 0x0F}, + {&cKF_ba_r_npc_1_otiru2, 0x10}, + {&cKF_ba_r_npc_1_mogaku1, 0x11}, + {&cKF_ba_r_npc_1_deru1, 0x12}, + {&cKF_ba_r_npc_1_deru2, 0x13}, + {&cKF_ba_r_npc_1_walk1, 0x14}, + {&cKF_ba_r_npc_1_wait1, 0x15}, + {&cKF_ba_r_npc_1_open1, 0x16}, + {&cKF_ba_r_npc_1_go_out1, 0x17}, + {&cKF_ba_r_npc_1_umb_open1, 0x18}, + {&cKF_ba_r_npc_1_umb_close1, 0x19}, + {&cKF_ba_r_npc_1_transfer1, 0x1A}, + {&cKF_ba_r_npc_1_trans_wait1, 0x1B}, + {&cKF_ba_r_npc_1_get1, 0x1C}, + {&cKF_ba_r_npc_1_get_pull1, 0x1D}, + {&cKF_ba_r_npc_1_get_pull_wait1, 0x1E}, + {&cKF_ba_r_npc_1_get_putaway1, 0x1F}, + {&cKF_ba_r_npc_1_get_eat1, 0x20}, + {&cKF_ba_r_npc_1_get_change1, 0x21}, + {&cKF_ba_r_npc_1_get_return1, 0x22}, + {&cKF_ba_r_npc_1_transfer_f1, 0x23}, + {&cKF_ba_r_npc_1_trans_wait_f1, 0x24}, + {&cKF_ba_r_npc_1_get_f1, 0x25}, + {&cKF_ba_r_npc_1_get_pull_f1, 0x26}, + {&cKF_ba_r_npc_1_get_pull_wait_f1, 0x27}, + {&cKF_ba_r_npc_1_get_putaway_f1, 0x28}, + {&cKF_ba_r_npc_1_get_return_f1, 0x29}, + {&cKF_ba_r_npc_1_estimate_f1, 0x2A}, + {&cKF_ba_r_npc_1_contract1, 0x2B}, + {&cKF_ba_r_npc_1_contract2, 0x2C}, + {&cKF_ba_r_npc_1_contract3, 0x2D}, + {&cKF_ba_r_npc_1_not_contract1, 0x2E}, + {&cKF_ba_r_npc_1_fly1, 0x2F}, + {&cKF_ba_r_npc_1_flyaway1, 0x30}, + {&cKF_ba_r_npc_1_delivery1, 0x31}, + {&cKF_ba_r_npc_1_kyoro1, 0x32}, + {&cKF_ba_r_npc_1_landing1, 0x33}, + {&cKF_ba_r_npc_1_landing2, 0x34}, + {&cKF_ba_r_npc_1_landing3, 0x35}, + {&cKF_ba_r_npc_1_open_d1, 0x36}, + {&cKF_ba_r_npc_1_sitdown_d1, 0x37}, + {&cKF_ba_r_npc_1_sitdown_wait_d1, 0x38}, + {&cKF_ba_r_npc_1_standup_d1, 0x39}, + {&cKF_ba_r_npc_1_open_d2, 0x3A}, + {&cKF_ba_r_npc_1_to_deck_d1, 0x3B}, + {&cKF_ba_r_npc_1_keitai_on1, 0x3C}, + {&cKF_ba_r_npc_1_keitai_talk1, 0x3D}, + {&cKF_ba_r_npc_1_keitai_talk2, 0x3E}, + {&cKF_ba_r_npc_1_keitai_off1, 0x3F}, + {&cKF_ba_r_npc_1_wait_e1, 0x40}, + {&cKF_ba_r_npc_1_ensou_e1, 0x41}, + {&cKF_ba_r_npc_1_banzai1, 0x42}, + {&cKF_ba_r_npc_1_clap1, 0x43}, + {&cKF_ba_r_npc_1_kokkuri_d1, 0x44}, + {&cKF_ba_r_npc_1_kokkuri_d2, 0x45}, + {&cKF_ba_r_npc_1_saisen1, 0x46}, + {&cKF_ba_r_npc_1_omairi1, 0x47}, + {&cKF_ba_r_npc_1_sitdown_wait1, 0x48}, + {&cKF_ba_r_npc_1_sitdown_drink1, 0x49}, + {&cKF_ba_r_npc_1_sitdown_clap1, 0x4A}, + {&cKF_ba_r_npc_1_dance1, 0x4B}, + {&cKF_ba_r_npc_1_kuisinbo1, 0x4C}, + {&cKF_ba_r_npc_1_sanbasi1, 0x4D}, + {&cKF_ba_r_npc_1_wait_r1, 0x4E}, + {&cKF_ba_r_npc_1_appear1, 0x4F}, + {&cKF_ba_r_npc_1_go_ug1, 0x50}, + {&cKF_ba_r_npc_1_intro1_a, 0x51}, + {&cKF_ba_r_npc_1_intro1_b, 0x52}, + {&cKF_ba_r_npc_1_taisou1, 0x53}, + {&cKF_ba_r_npc_1_taisou2, 0x54}, + {&cKF_ba_r_npc_1_taisou3_a, 0x55}, + {&cKF_ba_r_npc_1_taisou3_b, 0x56}, + {&cKF_ba_r_npc_1_taisou4_a, 0x57}, + {&cKF_ba_r_npc_1_taisou4_b, 0x58}, + {&cKF_ba_r_npc_1_taisou5_a, 0x59}, + {&cKF_ba_r_npc_1_taisou5_b, 0x5A}, + {&cKF_ba_r_npc_1_taisou6_a, 0x5B}, + {&cKF_ba_r_npc_1_taisou6_b, 0x5C}, + {&cKF_ba_r_npc_1_taisou7, 0x5D}, + {&cKF_ba_r_npc_1_kiduku1, 0x5E}, + {&cKF_ba_r_npc_1_kiduku2, 0x5F}, + {&cKF_ba_r_npc_1_cracker_wait1, 0x60}, + {&cKF_ba_r_npc_1_cracker_fire1, 0x61}, + {&cKF_ba_r_npc_1_cracker_run1, 0x62}, + {&cKF_ba_r_npc_1_cracker_count1, 0x63}, + {&cKF_ba_r_npc_1_warmup1, 0x64}, + {&cKF_ba_r_npc_1_ready1, 0x65}, + {&cKF_ba_r_npc_1_asihumi1, 0x66}, + {&cKF_ba_r_npc_1_kokeru1, 0x67}, + {&cKF_ba_r_npc_1_kokeru_getup1, 0x68}, + {&cKF_ba_r_npc_1_tired1, 0x69}, + {&cKF_ba_r_npc_1_tamakome1, 0x6A}, + {&cKF_ba_r_npc_1_youi1, 0x6B}, + {&cKF_ba_r_npc_1_don1, 0x6C}, + {&cKF_ba_r_npc_1_tunahiki_aiko1, 0x6D}, + {&cKF_ba_r_npc_1_tunahiki_yuri1, 0x6E}, + {&cKF_ba_r_npc_1_tunahiki_furi1, 0x6F}, + {&cKF_ba_r_npc_1_hatafuri1, 0x70}, + {&cKF_ba_r_npc_1_tamahiroi1, 0x71}, + {&cKF_ba_r_npc_1_tamanage1, 0x72}, + {&cKF_ba_r_npc_1_getup_seg1, 0x73}, + {&cKF_ba_r_npc_1_getup_wait_seg1, 0x74}, + {&cKF_ba_r_npc_1_piku_seg1, 0x75}, + {&cKF_ba_r_npc_1_4haku_e1, 0x76}, + {&cKF_ba_r_npc_1_3haku_e1, 0x77}, + {&cKF_ba_r_npc_1_send_mail1, 0x78}, + {&cKF_ba_r_npc_1_turi_wait1, 0x79}, + {&cKF_ba_r_npc_1_misin1, 0x7A}, + {&cKF_ba_r_npc_1_wipkogu1, 0x7B}, + {&cKF_ba_r_npc_1_wipwait1, 0x7C}, + {&cKF_ba_r_npc_1_wipwait2, 0x7D}, + {&cKF_ba_r_npc_1_gstwait1, 0x7E}, + {&cKF_ba_r_npc_1_gyafun1, 0x7F}, + {&cKF_ba_r_npc_1_gyafun2, 0x80}, + {&cKF_ba_r_npc_1_tkykyoro1, 0x81}, + {&cKF_ba_r_npc_1_muka1, 0x82}, + {&cKF_ba_r_npc_1_muka2, 0x83}, + {&cKF_ba_r_npc_1_gaaan1, 0x84}, + {&cKF_ba_r_npc_1_gaaan2, 0x85}, + {&cKF_ba_r_npc_1_smile1, 0x86}, + {&cKF_ba_r_npc_1_smile2, 0x87}, + {&cKF_ba_r_npc_1_ha1, 0x88}, + {&cKF_ba_r_npc_1_ha2, 0x89}, + {&cKF_ba_r_npc_1_punpun1, 0x8A}, + {&cKF_ba_r_npc_1_punpun2, 0x8B}, + {&cKF_ba_r_npc_1_a1, 0x8C}, + {&cKF_ba_r_npc_1_a2, 0x8D}, + {&cKF_ba_r_npc_1_aseru1, 0x8E}, + {&cKF_ba_r_npc_1_aseru2, 0x8F}, + {&cKF_ba_r_npc_1_buruburu1, 0x90}, + {&cKF_ba_r_npc_1_buruburu2, 0x91}, + {&cKF_ba_r_npc_1_goukyu1, 0x92}, + {&cKF_ba_r_npc_1_goukyu2, 0x93}, + {&cKF_ba_r_npc_1_happy1, 0x94}, + {&cKF_ba_r_npc_1_happy2, 0x95}, + {&cKF_ba_r_npc_1_hate1, 0x96}, + {&cKF_ba_r_npc_1_hate2, 0x97}, + {&cKF_ba_r_npc_1_hirameki1, 0x98}, + {&cKF_ba_r_npc_1_hirameki2, 0x99}, + {&cKF_ba_r_npc_1_hyuuu1, 0x9A}, + {&cKF_ba_r_npc_1_hyuuu2, 0x9B}, + {&cKF_ba_r_npc_1_lovelove1, 0x9C}, + {&cKF_ba_r_npc_1_lovelove2, 0x9D}, + {&cKF_ba_r_npc_1_muuuuu1, 0x9E}, + {&cKF_ba_r_npc_1_muuuuu2, 0x9F}, + {&cKF_ba_r_npc_1_otikomu1, 0xA0}, + {&cKF_ba_r_npc_1_otikomu2, 0xA1}, + {&cKF_ba_r_npc_1_shituren1, 0xA2}, + {&cKF_ba_r_npc_1_shituren2, 0xA3}, + {&cKF_ba_r_npc_1_warudakumi1, 0xA4}, + {&cKF_ba_r_npc_1_warudakumi2, 0xA5}, + {&cKF_ba_r_npc_1_neboke1, 0xA6}, + {&cKF_ba_r_npc_1_neboke2, 0xA7}, + {&cKF_ba_r_npc_1_love1, 0xA8}, + {&cKF_ba_r_npc_1_love2, 0xA9}, + {&cKF_ba_r_npc_1_niko1, 0xAA}, + {&cKF_ba_r_npc_1_musu1, 0xAB}, + {&cKF_ba_r_npc_1_komari1, 0xAC}, + {&cKF_ba_r_npc_1_hate_f1, 0xAD}, + {&cKF_ba_r_npc_1_hate_f2, 0xAE}, + {&cKF_ba_r_npc_1_ha_f1, 0xAF}, + {&cKF_ba_r_npc_1_ha_f2, 0xB0}, + {&cKF_ba_r_npc_1_happy_f1, 0xB1}, + {&cKF_ba_r_npc_1_happy_f2, 0xB2}, + {&cKF_ba_r_npc_1_aseru_f1, 0xB3}, + {&cKF_ba_r_npc_1_aseru_f2, 0xB4}, + {&cKF_ba_r_npc_1_muuuuu_f1, 0xB5}, + {&cKF_ba_r_npc_1_muuuuu_f2, 0xB6}, + {&cKF_ba_r_npc_1_lovelove_f1, 0xB7}, + {&cKF_ba_r_npc_1_lovelove_f2, 0xB8}, + {&cKF_ba_r_npc_1_a_f1, 0xB9}, + {&cKF_ba_r_npc_1_a_f2, 0xBA}, + {&cKF_ba_r_npc_1_smile_f1, 0xBB}, + {&cKF_ba_r_npc_1_smile_f2, 0xBC}, + {&cKF_ba_r_npc_1_komari_f1, 0xBD}, + {&cKF_ba_r_npc_1_niko_f1, 0xBE}, + {&cKF_ba_r_npc_1_musu_f1, 0xBF}, + {&cKF_ba_r_npc_1_hate_i1, 0xC0}, + {&cKF_ba_r_npc_1_hate_i2, 0xC1}, + {&cKF_ba_r_npc_1_ha_i1, 0xC2}, + {&cKF_ba_r_npc_1_ha_i2, 0xC3}, + {&cKF_ba_r_npc_1_happy_i1, 0xC4}, + {&cKF_ba_r_npc_1_happy_i2, 0xC5}, + {&cKF_ba_r_npc_1_aseru_i1, 0xC6}, + {&cKF_ba_r_npc_1_aseru_i2, 0xC7}, + {&cKF_ba_r_npc_1_muuuuu_i1, 0xC8}, + {&cKF_ba_r_npc_1_muuuuu_i2, 0xC9}, + {&cKF_ba_r_npc_1_love_i1, 0xCA}, + {&cKF_ba_r_npc_1_love_i2, 0xCB}, + {&cKF_ba_r_npc_1_shituren_i1, 0xCC}, + {&cKF_ba_r_npc_1_shituren_i2, 0xCD}, + {&cKF_ba_r_npc_1_komari_i1, 0xCE}, + {&cKF_ba_r_npc_1_niko_i1, 0xCF}, + {&cKF_ba_r_npc_1_musu_i1, 0xD0}, + {&cKF_ba_r_npc_1_smile_d1, 0xD1}, + {&cKF_ba_r_npc_1_smile_d2, 0xD2}, + {&cKF_ba_r_npc_1_gaaan_d1, 0xD3}, + {&cKF_ba_r_npc_1_gaaan_d2, 0xD4}, + {&cKF_ba_r_npc_1_hirameki_d1, 0xD5}, + {&cKF_ba_r_npc_1_hirameki_d2, 0xD6}, + {&cKF_ba_r_npc_1_ha_d1, 0xD7}, + {&cKF_ba_r_npc_1_ha_d2, 0xD8}, + {&cKF_ba_r_npc_1_musu_d1, 0xD9}, + {&cKF_ba_r_npc_1_niko_d1, 0xDA}, + {&cKF_ba_r_npc_1_komari_d1, 0xDB}, + {&cKF_ba_r_npc_1_hate_d1, 0xDC}, + {&cKF_ba_r_npc_1_hate_d2, 0xDD}, + {&cKF_ba_r_npc_1_punpun_r1, 0xDE}, + {&cKF_ba_r_npc_1_punpun_r2, 0xDF}, + {&cKF_ba_r_npc_1_musu_r1, 0xE0}, + {&cKF_ba_r_npc_1_hyuuu_r1, 0xE1}, + {&cKF_ba_r_npc_1_hyuuu_r2, 0xE2}, + {&cKF_ba_r_npc_1_a_r1, 0xE3}, + {&cKF_ba_r_npc_1_a_r2, 0xE4}, + {&cKF_ba_r_npc_1_a2_r1, 0xE5}, + {&cKF_ba_r_npc_1_akireru_r1, 0xE6}, + {&cKF_ba_r_npc_1_akireru_r2, 0xE7}, + {&cKF_ba_r_npc_1_matarou_r1, 0xE8}, + {&cKF_ba_r_npc_1_matarou_r2, 0xE9}, + {&cKF_ba_r_npc_1_gekido_r1, 0xEA}, + {&cKF_ba_r_npc_1_gekido_r2, 0xEB}, + {&cKF_ba_r_npc_1_ha_e1, 0xEC}, + {&cKF_ba_r_npc_1_ha_e2, 0xED}, + {&cKF_ba_r_npc_1_keirei1, 0xEE}, + {&cKF_ba_r_npc_1_kieeeei1, 0xEF}, + {&cKF_ba_r_npc_1_kieeeei2, 0xF0}, + {&cKF_ba_r_npc_1_umbrella1, 0xF1}, + {&cKF_ba_r_npc_1_utiwa_wait1, 0xF2}, + {&cKF_ba_r_npc_1_tue1, 0xF3}, + {&cKF_ba_r_npc_1_kutipaku1, 0xF4}, + {&cKF_ba_r_npc_1_kutipaku2, 0xF5}, +}; +// clang-format on + +// clang-format off +static s16 aNPC_animeSeqNoTable[] = { + aNPC_ANIM_WAIT1, + aNPC_ANIM_WAIT_KI1, + aNPC_ANIM_WAIT_DO1, + aNPC_ANIM_WAIT_AI1, + aNPC_ANIM_WAIT_NEMU1, + aNPC_ANIM_WALK1, + aNPC_ANIM_WALK_KI1, + aNPC_ANIM_WALK_DO1, + aNPC_ANIM_WALK_AI1, + aNPC_ANIM_RUN1, + aNPC_ANIM_WALK_KI1, + aNPC_ANIM_WALK_DO1, + aNPC_ANIM_WALK_AI1, + aNPC_ANIM_WALK1, + aNPC_ANIM_WAIT1, + aNPC_ANIM_WAIT1, + aNPC_ANIM_AISATU1, + aNPC_ANIM_AISATU2, + aNPC_ANIM_AISATU3, + aNPC_ANIM_AISATU4, + aNPC_ANIM_GURATUKU1, + aNPC_ANIM_OTIRU1, + aNPC_ANIM_OTIRU2, + aNPC_ANIM_MOGAKU1, + aNPC_ANIM_DERU1, + aNPC_ANIM_DERU2, + aNPC_ANIM_TALK_TURN1, + aNPC_ANIM_TALK1, + aNPC_ANIM_OPEN1, + aNPC_ANIM_GO_OUT1, + aNPC_ANIM_UMB_OPEN1, + aNPC_ANIM_UMB_CLOSE1, + aNPC_ANIM_WALK1, + aNPC_ANIM_TRANSFER1, + aNPC_ANIM_TRANS_WAIT1, + aNPC_ANIM_TRANSFER_F1, + aNPC_ANIM_TRANS_WAIT_F1, + aNPC_ANIM_SEND_MAIL1, + aNPC_ANIM_WALK1, + aNPC_ANIM_GET1, + aNPC_ANIM_GET_PULL1, + aNPC_ANIM_GET_PULL_WAIT1, + aNPC_ANIM_GET_PUTAWAY1, + aNPC_ANIM_GET_EAT1, + aNPC_ANIM_GET_CHANGE1, + aNPC_ANIM_GET_RETURN1, + aNPC_ANIM_GET_F1, + aNPC_ANIM_GET_PULL_F1, + aNPC_ANIM_GET_PULL_WAIT_F1, + aNPC_ANIM_GET_PUTAWAY_F1, + aNPC_ANIM_GET_RETURN_F1, + aNPC_ANIM_ESTIMATE_F1, + aNPC_ANIM_ENSOU_E1, + aNPC_ANIM_WAIT_E1, + aNPC_ANIM_GYAFUN1, + aNPC_ANIM_GYAFUN2, + aNPC_ANIM_CLAP1, +}; +// clang-format on + +static s16 aNPC_sub_animeSeqNoTable[] = { -1, aNPC_ANIM_UMBRELLA1, aNPC_ANIM_UTIWA_WAIT1, aNPC_ANIM_TUE1 }; + +// clang-format off +static ClObjPipeData_c aNPC_CoInfoData = { + { 0x39, 0x20, 1 }, + { 0x01 }, + { 20, 30, 0, { 0, 0, 0 } }, +}; +// clang-format on + +// clang-format off +static StatusData_c aNPC_StatusData = { + 0, + 20, + 30, + 0, + 50, +}; +// clang-format on + +static s8 aNPC_part_tbl00[aNPC_JOINT_NUM + 1] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +static s8 aNPC_part_tbl01[aNPC_JOINT_NUM + 1] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, +}; + +static s8 aNPC_part_tbl10[aNPC_JOINT_NUM + 1] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +static s8 aNPC_part_tbl11[aNPC_JOINT_NUM + 1] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x00, 0x00, +}; + +// clang-format off +static s8* aNPC_part_tbl[][2] = { + {aNPC_part_tbl00, aNPC_part_tbl01}, + {aNPC_part_tbl10, aNPC_part_tbl11}, +}; +// clang-format on + +// clang-format off +static aNPC_spd_c aNPC_spd_data[] = { + { 0.0f, 0.0f, 0.0f }, + { 1.0f, 0.1f, 0.2f }, + { 3.0f, 0.3f, 0.6f }, +}; +// clang-format on + +// clang-format off +static int aNPC_uzai_feel[] = { + mNpc_FEEL_UZAI_0, + mNpc_FEEL_UZAI_1, + mNpc_FEEL_UZAI_0, + mNpc_FEEL_UZAI_1, + mNpc_FEEL_UZAI_1, + mNpc_FEEL_UZAI_1, +}; +// clang-format on diff --git a/src/actor/npc/ac_npc_draw.c_inc b/src/actor/npc/ac_npc_draw.c_inc new file mode 100644 index 00000000..52e33c36 --- /dev/null +++ b/src/actor/npc/ac_npc_draw.c_inc @@ -0,0 +1,345 @@ +// + +static int aNPC_check_mask_cat_type(ACTOR* actorx) { + NPC_ACTOR* nactorx = (NPC_ACTOR*)actorx; + int ret = aNPC_MASK_CAT_TYPE_NONE; + + switch (nactorx->actor_class.npc_id) { + case SP_NPC_MASK_CAT: + ret = aNPC_MASK_CAT_TYPE_MASKCAT; + break; + case SP_NPC_MASK_CAT2: + if (nactorx->npc_info.mask != NULL && nactorx->npc_info.mask->npc_id == SP_NPC_MASK_CAT2) { + ret = aNPC_MASK_CAT_TYPE_MASKCAT; + } + break; + } + + return ret; +} + +static void aNPC_set_shadow_pos(NPC_ACTOR* nactorx) { + xyz_t scale; + + scale.x = 0.01f; + scale.y = nactorx->actor_class.scale.y; + scale.z = 0.01f; + + cKF_SkeletonInfo_R_AnimationMove_CulcTransToWorld(&nactorx->draw.shadow_pos, &nactorx->actor_class.world.position, + 0.0f, 1000.0f, 0.0f, nactorx->actor_class.shape_info.rotation.y, + &scale, &nactorx->draw.main_animation.keyframe, + cKF_ANIMATION_TRANS_XZ | cKF_ANIMATION_TRANS_Y); + nactorx->actor_class.shape_info.shadow_position = &nactorx->draw.shadow_pos; +} + +static void aNPC_set_chn_base(GAME* game, NPC_ACTOR* nactorx, s_xyz* rot_p, xyz_t* trans_p) { + ACTOR* actorx = (ACTOR*)nactorx; + + if (nactorx->draw.chn_base_type == aNPC_CHN_BASE_TYPE_RELATIVE) { + Matrix_softcv3_load(&actorx->shape_info.rotation, actorx->world.position.x, + actorx->world.position.y + actorx->shape_info.ofs_y * actorx->scale.y, + actorx->world.position.z); + } + + Matrix_scale(0.01f, actorx->scale.y, 0.01f, 1); + Matrix_translate(trans_p->x, trans_p->y, trans_p->z, 1); + Matrix_scale(actorx->scale.x * 100.0f, 1.0f, actorx->scale.z * 100.0f, 1); + bzero(trans_p, sizeof(xyz_t)); +} + +static void aNPC_set_head_angl(GAME* game, NPC_ACTOR* nactorx, s_xyz* rot_p, xyz_t* trans_p) { + s_xyz world_rot; + + Matrix_to_rotate_new(get_Matrix_now(), &world_rot, 0); + aNPC_search_eye_target(nactorx, (GAME_PLAY*)game, &world_rot, rot_p); + rot_p->x = nactorx->head.angle_y; + rot_p->y = nactorx->head.angle_x; +} + +typedef void (*aNPC_DRAW_BEFORE_PROC)(GAME* game, NPC_ACTOR* nactorx, s_xyz* rot_p, xyz_t* trans_p); + +static int aNPC_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) { + // clang-format off + static aNPC_DRAW_BEFORE_PROC before_proc[] = { + &aNPC_set_chn_base, + (aNPC_DRAW_BEFORE_PROC)&none_proc1, + (aNPC_DRAW_BEFORE_PROC)&none_proc1, + (aNPC_DRAW_BEFORE_PROC)&none_proc1, + (aNPC_DRAW_BEFORE_PROC)&none_proc1, + (aNPC_DRAW_BEFORE_PROC)&none_proc1, + (aNPC_DRAW_BEFORE_PROC)&none_proc1, + (aNPC_DRAW_BEFORE_PROC)&none_proc1, + (aNPC_DRAW_BEFORE_PROC)&none_proc1, + (aNPC_DRAW_BEFORE_PROC)&none_proc1, + (aNPC_DRAW_BEFORE_PROC)&none_proc1, + (aNPC_DRAW_BEFORE_PROC)&none_proc1, + (aNPC_DRAW_BEFORE_PROC)&none_proc1, + (aNPC_DRAW_BEFORE_PROC)&none_proc1, + (aNPC_DRAW_BEFORE_PROC)&none_proc1, + (aNPC_DRAW_BEFORE_PROC)&none_proc1, + (aNPC_DRAW_BEFORE_PROC)&none_proc1, + (aNPC_DRAW_BEFORE_PROC)&none_proc1, + (aNPC_DRAW_BEFORE_PROC)&none_proc1, + (aNPC_DRAW_BEFORE_PROC)&none_proc1, + (aNPC_DRAW_BEFORE_PROC)&none_proc1, + &aNPC_set_head_angl, + (aNPC_DRAW_BEFORE_PROC)&none_proc1, + (aNPC_DRAW_BEFORE_PROC)&none_proc1, + (aNPC_DRAW_BEFORE_PROC)&none_proc1, + (aNPC_DRAW_BEFORE_PROC)&none_proc1, + }; + // clang-format on + + NPC_ACTOR* nactorx = (NPC_ACTOR*)arg; + + (*before_proc[joint_idx])(game, nactorx, joint_rot, joint_pos); + return TRUE; +} + +static void aNPC_set_right_hand_item(GAME* game, NPC_ACTOR* nactorx, int joint_idx) { + TOOLS_ACTOR* item_p; + + Matrix_Position_Zero(&nactorx->right_hand.pos); + item_p = (TOOLS_ACTOR*)nactorx->right_hand.item_actor_p; + if (item_p != NULL) { + f32 scale = 1.0f / (nactorx->actor_class.scale.x * 100.0f); + + Matrix_push(); + Matrix_scale(scale, scale, scale, 1); + Matrix_get(&item_p->matrix_work); + item_p->init_matrix = TRUE; + Matrix_pull(); + } +} + +static void aNPC_set_left_hand_item(GAME* game, NPC_ACTOR* nactorx, int joint_idx) { + TOOLS_ACTOR* item_p; + + Matrix_Position_Zero(&nactorx->left_hand.pos); + item_p = (TOOLS_ACTOR*)nactorx->left_hand.item_actor_p; + if (item_p != NULL) { + Matrix_push(); + Matrix_translate(nactorx->left_hand.pos.x, nactorx->left_hand.pos.y, nactorx->left_hand.pos.z, 0); + Matrix_scale(0.01f, 0.01f, 0.01f, 1); + Matrix_get(&item_p->matrix_work); + item_p->init_matrix = TRUE; + Matrix_pull(); + } +} + +static void aNPC_set_foot_eff(GAME* game, NPC_ACTOR* nactorx, int joint_idx) { + int idx; + + if (joint_idx == aNPC_JOINT_RFOOT3) { + idx = 1; + } else { + idx = 0; + } + + Matrix_Position_Zero(&nactorx->feet[idx]); +} + +static void aNPC_set_feel_eff(GAME* game, NPC_ACTOR* nactorx, int joint_idx) { + if (nactorx->draw.feel_effect != NULL) { + aNPC_set_feel_effect(game, nactorx); + } else { + aNPC_set_other_effect(game, nactorx); + } +} + +static void aNPC_set_accessory_mtx(NPC_ACTOR* nactorx, int joint_idx) { + if (joint_idx == nactorx->accessory.pos_joint_idx) { + TOOLS_ACTOR* accessory = (TOOLS_ACTOR*)nactorx->accessory.accessory; + + if (accessory != NULL) { + f32 scale = 1.0f / (nactorx->actor_class.scale.x * 100.0f); + + Matrix_push(); + Matrix_scale(scale, scale, scale, 1); + Matrix_get(&accessory->matrix_work); + accessory->init_matrix = TRUE; + Matrix_pull(); + } + } +} + +typedef void (*aNPC_DRAW_AFTER_PROC)(GAME* game, NPC_ACTOR* nactorx, int joint_idx); + +static int aNPC_actor_draw_after(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) { + // clang-format off + static aNPC_DRAW_AFTER_PROC after_proc[] = { + (aNPC_DRAW_AFTER_PROC)&none_proc1, + (aNPC_DRAW_AFTER_PROC)&none_proc1, + (aNPC_DRAW_AFTER_PROC)&none_proc1, + (aNPC_DRAW_AFTER_PROC)&none_proc1, + (aNPC_DRAW_AFTER_PROC)&none_proc1, + &aNPC_set_foot_eff, + (aNPC_DRAW_AFTER_PROC)&none_proc1, + (aNPC_DRAW_AFTER_PROC)&none_proc1, + (aNPC_DRAW_AFTER_PROC)&none_proc1, + &aNPC_set_foot_eff, + (aNPC_DRAW_AFTER_PROC)&none_proc1, + (aNPC_DRAW_AFTER_PROC)&none_proc1, + (aNPC_DRAW_AFTER_PROC)&none_proc1, + (aNPC_DRAW_AFTER_PROC)&none_proc1, + (aNPC_DRAW_AFTER_PROC)&none_proc1, + (aNPC_DRAW_AFTER_PROC)&none_proc1, + &aNPC_set_left_hand_item, + (aNPC_DRAW_AFTER_PROC)&none_proc1, + (aNPC_DRAW_AFTER_PROC)&none_proc1, + (aNPC_DRAW_AFTER_PROC)&none_proc1, + &aNPC_set_right_hand_item, + (aNPC_DRAW_AFTER_PROC)&none_proc1, + (aNPC_DRAW_AFTER_PROC)&none_proc1, + (aNPC_DRAW_AFTER_PROC)&none_proc1, + (aNPC_DRAW_AFTER_PROC)&none_proc1, + &aNPC_set_feel_eff, + }; + // clang-format on + + NPC_ACTOR* nactorx = (NPC_ACTOR*)arg; + + (*after_proc[joint_idx])(game, nactorx, joint_idx); + aNPC_set_accessory_mtx(nactorx, joint_idx); + return TRUE; +} + +static void aNPC_actor_draw_sub(ACTOR* actorx, GAME* game) { + // clang-format off + static Gfx xlu_env_disp[] = { + gsDPPipeSync(), + gsSPLoadGeometryMode(G_ZBUFFER | G_SHADE | G_FOG | G_LIGHTING | G_SHADING_SMOOTH), + gsDPSetOtherMode(G_AD_NOTPATTERN | G_CD_MAGICSQ | G_CK_NONE | G_TC_FILT | G_TF_BILERP | G_TT_RGBA16 | G_TL_TILE | G_TD_CLAMP | G_TP_PERSP | G_CYC_2CYCLE | G_PM_NPRIMITIVE, G_AC_NONE | G_ZS_PIXEL | G_RM_FOG_SHADE_A | G_RM_AA_ZB_XLU_SURF2), + gsSPTexture(65535, 65535, 0, 0, G_ON), + gsDPSetCombineLERP(TEXEL0, 0, SHADE, 0, PRIMITIVE, 0, ENVIRONMENT, 0, COMBINED, 0, PRIM_LOD_FRAC, COMBINED, 0, 0, 0, COMBINED), + gsSPEndDisplayList(), + }; + // clang-format on + + NPC_ACTOR* nactorx = (NPC_ACTOR*)actorx; + cKF_SkeletonInfo_R_c* kf_p = &nactorx->draw.main_animation.keyframe; + GRAPH* graph = game->graph; + Mtx* mtx = GRAPH_ALLOC_TYPE(graph, Mtx, kf_p->skeleton->num_shown_joints); + + if (mtx != NULL) { + aNPC_draw_tex_data_c* draw_tex_p = &nactorx->draw.draw_tex_data; + u8* eye_tex_p = draw_tex_p->eye_texture[nactorx->draw.tex_anim[aNPC_TEX_ANIM_EYE].pattern]; + u8* mouth_tex_p = draw_tex_p->mouth_texture[nactorx->draw.tex_anim[aNPC_TEX_ANIM_MOUTH].pattern]; + Gfx* gfx; // manually split out so we can handle wisp which uses XLU and others which use OPA + int xlu; + + OPEN_DISP(graph); + + switch (actorx->npc_id) { + case SP_NPC_EV_GHOST: { + EV_GHOST_ACTOR* ghost = (EV_GHOST_ACTOR*)nactorx; + + xlu = TRUE; + gfx = NOW_POLY_XLU_DISP; + + gSPDisplayList(gfx++, xlu_env_disp); + if (ghost->alpha > 127) { + gDPPipeSync(gfx++); + gDPSetRenderMode(gfx++, + Z_CMP | Z_UPD | IM_RD | CVG_DST_FULL | ZMODE_XLU | FORCE_BL | G_RM_FOG_SHADE_A, + Z_CMP | Z_UPD | IM_RD | CVG_DST_FULL | ZMODE_XLU | FORCE_BL | + GBL_c2(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)); + } + break; + } + + default: + xlu = FALSE; + _texture_z_light_fog_prim_npc(graph); + gfx = NOW_POLY_OPA_DISP; + } + + gDPSetTexEdgeAlpha(gfx++, 127); + gDPSetTextureAdjustMode(gfx++, G_TA_DOLPHIN); + + if (aNPC_check_mask_cat_type(actorx) == aNPC_MASK_CAT_TYPE_MASKCAT) { + MaskCat_c* mask_cat = Save_GetPointer(mask_cat); + + gSPSegment(gfx++, ANIME_1_TXT_SEG, mask_cat->design.design.data); + gDPLoadTLUT_Dolphin(gfx++, 13, 16, 1, mNW_PaletteIdx2Palette(mask_cat->palette_no)); + } else { + if (eye_tex_p != NULL) { + gSPSegment(gfx++, ANIME_1_TXT_SEG, eye_tex_p); + } + + if (mouth_tex_p != NULL) { + gSPSegment(gfx++, ANIME_2_TXT_SEG, mouth_tex_p); + } + } + + gSPSegment(gfx++, ANIME_4_TXT_SEG, draw_tex_p->texture); + gDPLoadTLUT_Dolphin(gfx++, 15, 16, 1, draw_tex_p->palette); + + if ((int)nactorx->draw.cloth_idx != aNPC_CLOTH_IDX_NONE) { + u8* tex_p; + u16* pal_p; + + if (nactorx->draw.cloth_idx == aNPC_CLOTH_IDX_ORG) { + int org_idx; + + if (nactorx->npc_info.animal == NULL) { + org_idx = 0; + } else { + org_idx = nactorx->npc_info.animal->cloth_original_id; + } + + tex_p = Save_Get(needlework).original_design[org_idx & 3].design.data; + pal_p = mNW_PaletteIdx2Palette(Save_Get(needlework).original_design[org_idx & 3].palette); + } else { + NPC_CONTROL_ACTOR* ctrl = (NPC_CONTROL_ACTOR*)aNPC_ctrlActor; + aNPC_cloth_c* cloth_p = ctrl->cloth + (int)nactorx->draw.cloth_idx - 1; + + tex_p = (u8*)cloth_p->texture_bank.ram_start; + pal_p = (u16*)cloth_p->palette_bank.ram_start; + } + + gSPSegment(gfx++, ANIME_3_TXT_SEG, tex_p); + gDPLoadTLUT_Dolphin(gfx++, 14, 16, 1, pal_p); + } + + if (xlu == TRUE) { + SET_POLY_XLU_DISP(gfx); + } else { + SET_POLY_OPA_DISP(gfx); + } + + CLOSE_DISP(graph); + + cKF_Si3_draw_R_SV(game, kf_p, mtx, &aNPC_actor_draw_before, &aNPC_actor_draw_after, actorx); + + OPEN_DISP(graph); + + if (xlu == TRUE) { + gfx = NOW_POLY_XLU_DISP; + } else { + gfx = NOW_POLY_OPA_DISP; + } + + gDPSetTexEdgeAlpha(gfx++, 144); + gDPSetTextureAdjustMode(gfx++, G_TA_N64); + + if (xlu == TRUE) { + SET_POLY_XLU_DISP(gfx); + } else { + SET_POLY_OPA_DISP(gfx); + } + + CLOSE_DISP(graph); + } +} + +static void aNPC_actor_draw(ACTOR* actorx, GAME* game) { + NPC_ACTOR* nactorx = (NPC_ACTOR*)actorx; + + if (nactorx->condition_info.hide_flg == FALSE) { + aNPC_actor_draw_sub(actorx, game); + aNPC_set_shadow_pos(nactorx); + } +} diff --git a/src/actor/npc/ac_npc_dt.c_inc b/src/actor/npc/ac_npc_dt.c_inc new file mode 100644 index 00000000..b4ca6728 --- /dev/null +++ b/src/actor/npc/ac_npc_dt.c_inc @@ -0,0 +1,41 @@ +static void aNPC_actor_dt(ACTOR* actorx, GAME* game) { + NPC_CONTROL_ACTOR* ctrl = (NPC_CONTROL_ACTOR*)aNPC_ctrlActor; + NPC_ACTOR* nactorx = (NPC_ACTOR*)actorx; + ACTOR* palActor = nactorx->palActor; + + aNPC_reset_out_of_door_flg(ctrl, actorx); + aNPC_reset_umb_open_flg(ctrl, actorx); + + if (eEC_CLIP != NULL) { + eEC_CLIP->effect_kill_all_proc(actorx->npc_id); + } + + if (nactorx->right_hand.item_actor_p != NULL) { + Actor_delete(nactorx->right_hand.item_actor_p); + nactorx->right_hand.item_actor_p = NULL; + } + + if (nactorx->accessory.accessory != NULL) { + Actor_delete(nactorx->accessory.accessory); + nactorx->accessory.accessory = NULL; + } + + if (palActor != NULL && palActor->part == ACTOR_PART_NPC) { + ((NPC_ACTOR*)palActor)->palActor = NULL; + } + + if (actorx->ct_proc == NULL) { + cKF_SkeletonInfo_R_dt(&nactorx->draw.main_animation.keyframe); + cKF_SkeletonInfo_R_dt(&nactorx->draw.sub_animation0.keyframe); + cKF_SkeletonInfo_R_dt(&nactorx->draw.sub_animation1.keyframe); + ClObjPipe_dt(game, &nactorx->collision.pipe); + } + + if (nactorx->npc_info.event != NULL) { + mNpc_UnRegistEventNpc(nactorx->npc_info.event); + } + + if (nactorx->npc_info.mask != NULL) { + mNpc_UnRegistMaskNpc(nactorx->npc_info.mask); + } +} diff --git a/src/actor/npc/ac_npc_effect.c_inc b/src/actor/npc/ac_npc_effect.c_inc new file mode 100644 index 00000000..277ee727 --- /dev/null +++ b/src/actor/npc/ac_npc_effect.c_inc @@ -0,0 +1,61 @@ +static void aNPC_set_eff(GAME* game, NPC_ACTOR* nactorx, int effect_id, s16 arg0, s16 arg1) { + ACTOR* actorx = (ACTOR*)nactorx; + xyz_t pos; + + Matrix_Position_Zero(&pos); + eEC_CLIP->effect_make_proc(effect_id, pos, 1, actorx->shape_info.rotation.y, game, actorx->npc_id, arg0, arg1); +} + +typedef struct { + int effect_id; + s16 arg0; + s16 arg1; +} aNPC_effect_data_c; + +static void aNPC_set_feel_effect(GAME* game, NPC_ACTOR* nactorx) { + // @BUG - this should've been marked static + aNPC_effect_data_c effect_data[mNpc_FEEL_ALL_NUM] = { + // clang-format off + {eEC_EFFECT_KONPU, 0, 0}, + {eEC_EFFECT_KONPU, 0, 0}, + {eEC_EFFECT_PUN_YUGE, 0, 0}, + {eEC_EFFECT_DOYON, 0, 0}, + {eEC_EFFECT_NEBOKE_AWA, 1, 1}, + {eEC_EFFECT_KONPU, 0, 0}, + {eEC_EFFECT_PUN_YUGE, 0, 0}, + {eEC_EFFECT_DOYON, 0, 0}, + {eEC_EFFECT_PUN_YUGE, 0, 0}, + // clang-format on + }; + + aNPC_feel_effect_c* feel_effect_p = nactorx->draw.feel_effect; + aNPC_effect_data_c* data_p = &effect_data[feel_effect_p->feel_type]; + f32 feel_counter = nactorx->draw.feel_effect_counter; + int set_num = feel_effect_p->set_num; + u32* set_p = (u32*)feel_effect_p->set_p; + + while (set_num != 0) { + f32 tmp = (f32)*set_p - feel_counter; + + if (tmp >= 0.0f && tmp < 0.5f) { + aNPC_set_eff(game, nactorx, data_p->effect_id, data_p->arg0, data_p->arg1); + } + + set_p++; + set_num--; + } + + feel_counter += 0.5f; + while (feel_counter > (f32)feel_effect_p->max) { + feel_counter -= (f32)feel_effect_p->max; + } + + nactorx->draw.feel_effect_counter = feel_counter; +} + +static void aNPC_set_other_effect(GAME* game, NPC_ACTOR* nactorx) { + if (cKF_FrameControl_passCheck_now(&nactorx->draw.main_animation.keyframe.frame_control, + (f32)nactorx->draw.effect_pattern) == TRUE) { + aNPC_set_eff(game, nactorx, nactorx->draw.effect_type, 0, 0); + } +} diff --git a/src/actor/npc/ac_npc_guide2_move.c_inc b/src/actor/npc/ac_npc_guide2_move.c_inc index b9fb762d..375ece6a 100644 --- a/src/actor/npc/ac_npc_guide2_move.c_inc +++ b/src/actor/npc/ac_npc_guide2_move.c_inc @@ -120,22 +120,22 @@ static void aNG2_set_camera_eyes(NPC_GUIDE2_ACTOR* guide2) { } static void aNG2_set_walk_spd(NPC_GUIDE2_ACTOR* guide2, GAME_PLAY* play) { - guide2->npc_class.movement.max_speed = 1.0f; - guide2->npc_class.movement.acceleration = 0.1f; - guide2->npc_class.movement.deceleration = 0.2f; + guide2->npc_class.movement.speed.max_speed = 1.0f; + guide2->npc_class.movement.speed.acceleration = 0.1f; + guide2->npc_class.movement.speed.deceleration = 0.2f; } static void aNG2_set_walk_spd2(NPC_GUIDE2_ACTOR* guide2, GAME_PLAY* play) { - guide2->npc_class.movement.max_speed = 1.5f; - guide2->npc_class.movement.acceleration = 0.15f; - guide2->npc_class.movement.deceleration = 0.3f; + guide2->npc_class.movement.speed.max_speed = 1.5f; + guide2->npc_class.movement.speed.acceleration = 0.15f; + guide2->npc_class.movement.speed.deceleration = 0.3f; } static void aNG2_set_stop_spd(NPC_GUIDE2_ACTOR* guide2, GAME_PLAY* play) { guide2->npc_class.actor_class.speed = 0.0f; - guide2->npc_class.movement.max_speed = 0.0f; - guide2->npc_class.movement.acceleration = 0.0f; - guide2->npc_class.movement.deceleration = 0.0f; + guide2->npc_class.movement.speed.max_speed = 0.0f; + guide2->npc_class.movement.speed.acceleration = 0.0f; + guide2->npc_class.movement.speed.deceleration = 0.0f; } static int aNG2_make_keitai(NPC_GUIDE2_ACTOR* guide2, GAME* game) { diff --git a/src/actor/npc/ac_npc_guide_move.c_inc b/src/actor/npc/ac_npc_guide_move.c_inc index 501839ba..78f02071 100644 --- a/src/actor/npc/ac_npc_guide_move.c_inc +++ b/src/actor/npc/ac_npc_guide_move.c_inc @@ -120,22 +120,22 @@ static void aNGD_set_camera_eyes(NPC_GUIDE_ACTOR* guide) { } static void aNGD_set_walk_spd(NPC_GUIDE_ACTOR* guide, GAME_PLAY* play) { - guide->npc_class.movement.max_speed = 1.0f; - guide->npc_class.movement.acceleration = 0.1f; - guide->npc_class.movement.deceleration = 0.2f; + guide->npc_class.movement.speed.max_speed = 1.0f; + guide->npc_class.movement.speed.acceleration = 0.1f; + guide->npc_class.movement.speed.deceleration = 0.2f; } static void aNGD_set_walk_spd2(NPC_GUIDE_ACTOR* guide, GAME_PLAY* play) { - guide->npc_class.movement.max_speed = 1.5f; - guide->npc_class.movement.acceleration = 0.15f; - guide->npc_class.movement.deceleration = 0.3f; + guide->npc_class.movement.speed.max_speed = 1.5f; + guide->npc_class.movement.speed.acceleration = 0.15f; + guide->npc_class.movement.speed.deceleration = 0.3f; } static void aNGD_set_stop_spd(NPC_GUIDE_ACTOR* guide, GAME_PLAY* play) { guide->npc_class.actor_class.speed = 0.0f; - guide->npc_class.movement.max_speed = 0.0f; - guide->npc_class.movement.acceleration = 0.0f; - guide->npc_class.movement.deceleration = 0.0f; + guide->npc_class.movement.speed.max_speed = 0.0f; + guide->npc_class.movement.speed.acceleration = 0.0f; + guide->npc_class.movement.speed.deceleration = 0.0f; } static int aNGD_make_keitai(NPC_GUIDE_ACTOR* guide, GAME* game) { diff --git a/src/actor/npc/ac_npc_hand.c_inc b/src/actor/npc/ac_npc_hand.c_inc new file mode 100644 index 00000000..248dc05b --- /dev/null +++ b/src/actor/npc/ac_npc_hand.c_inc @@ -0,0 +1,152 @@ +static int aNPC_change_umbrella(NPC_ACTOR* nactorx) { + int ret = FALSE; + + if (CLIP(tools_clip) != NULL) { + ACTOR* hand_actor; + int kind = nactorx->right_hand.umbrella_type; + int bank; + + hand_actor = CLIP(tools_clip)->aTOL_birth_proc(kind, aTOL_ACTION_S_TAKEOUT, (ACTOR*)nactorx, gamePT, -1, &bank); + if (hand_actor != NULL) { + nactorx->right_hand.prev_item_actor_p = nactorx->right_hand.item_actor_p; + nactorx->right_hand.item_actor_p = hand_actor; + nactorx->draw.sub_anim_type = aNPC_SUB_ANIM_UMBRELLA; + xyz_t_move(&hand_actor->world.position, &nactorx->actor_class.world.position); + ret = TRUE; + } + } + + return ret; +} + +static int aNPC_putaway_right_item(NPC_ACTOR* nactorx) { + static u8 next_act_idx[] = { aNPC_ACT_UMB_CLOSE, aNPC_ACT_NONE }; + int ret = TRUE; + + if (CLIP(tools_clip) != NULL && + CLIP(tools_clip) + ->aTOL_chg_request_mode_proc((ACTOR*)nactorx, nactorx->right_hand.item_actor_p, aTOL_ACTION_PUTAWAY) == + TRUE) { + int idx = nactorx->right_hand.item_type - aNPC_ITEM_TYPE_UMBRELLA; + + aNPC_set_request_act(nactorx, 4, next_act_idx[idx], aNPC_ACT_TYPE_DEFAULT, aNPC_req_default_data); + ret = FALSE; + } + + return ret; +} + +static int aNPC_takeout_right_item(NPC_ACTOR* nactorx) { + static u8 next_act_idx[] = { aNPC_ACT_UMB_OPEN, aNPC_ACT_NONE }; + static int itemIdx_table[] = { TOOL_UMBRELLA0, TOOL_KEITAI }; + int ret = TRUE; + + if (CLIP(tools_clip) != NULL) { + int requested = nactorx->right_hand.requested_item_type; + ACTOR* tool; + int kind; + int mode = aTOL_ACTION_TAKEOUT; + int bank; + + if (requested == aNPC_ITEM_TYPE_UMBRELLA) { + if (nactorx->condition_info.talk_condition != aNPC_TALK_TYPE_NONE) { + return TRUE; + } + + kind = nactorx->right_hand.umbrella_type; + if (nactorx->request.umb_flag == TRUE) { + mode = aTOL_ACTION_S_TAKEOUT; + } else { + mode = aTOL_ACTION_WAIT; + } + } else { + kind = itemIdx_table[requested - aNPC_ITEM_TYPE_UMBRELLA]; + } + + tool = CLIP(tools_clip)->aTOL_birth_proc(kind, mode, (ACTOR*)nactorx, gamePT, -1, &bank); + if (tool == NULL) { + if (bank != -1 && nactorx->request.umb_flag == TRUE) { + nactorx->request.umb_flag = FALSE; + } + } else { + nactorx->right_hand.item_type = requested; + nactorx->right_hand.requested_item_type = aNPC_ITEM_TYPE_NONE; + nactorx->right_hand.item_actor_p = tool; + if (mode == aTOL_ACTION_S_TAKEOUT) { + nactorx->draw.sub_anim_type = aNPC_SUB_ANIM_UMBRELLA; + } + + aNPC_set_request_act(nactorx, 4, next_act_idx[requested - aNPC_ITEM_TYPE_UMBRELLA], aNPC_ACT_TYPE_DEFAULT, + aNPC_req_default_data); + xyz_t_move(&tool->world.position, &nactorx->actor_class.world.position); + ret = FALSE; + } + } + + return ret; +} + +static int aNPC_chk_right_hand(NPC_ACTOR* nactorx) { + int requested = nactorx->right_hand.requested_item_type; + int ret = TRUE; + + switch (requested) { + case aNPC_ITEM_TYPE_NONE: + break; + case aNPC_ITEM_TYPE_PUTAWAY: + if (!aNPC_putaway_right_item(nactorx)) { + nactorx->right_hand.requested_item_type = aNPC_ITEM_TYPE_NONE; + ret = FALSE; + } + break; + default: + if (nactorx->right_hand.item_type == aNPC_ITEM_TYPE_NONE) { + ret = aNPC_takeout_right_item(nactorx); + } else { + ret = aNPC_putaway_right_item(nactorx); + } + break; + } + + return ret; +} + +static void aNPC_clear_left_hand_info(NPC_ACTOR* nactorx) { + nactorx->left_hand.item_type = aNPC_ITEM_TYPE_NONE; + nactorx->left_hand.item = EMPTY_NO; + nactorx->left_hand.after_mode = aHOI_REQUEST_NO_REQUEST; + nactorx->left_hand.present_flag = FALSE; + nactorx->left_hand.item_actor_p = NULL; +} + +static int aNPC_chk_left_hand(NPC_ACTOR* nactorx) { + int ret = TRUE; + + if (nactorx->left_hand.requested_item_type != aNPC_ITEM_TYPE_NONE) { + ACTOR* item_p; + + switch (nactorx->right_hand.item_type) { + case aNPC_ITEM_TYPE_NONE: + case aNPC_ITEM_TYPE_UMBRELLA: + item_p = CLIP(handOverItem_clip) + ->birth_proc(nactorx->left_hand.item, nactorx->left_hand.after_mode, + nactorx->left_hand.present_flag, (ACTOR*)nactorx); + if (item_p != NULL) { + CLIP(handOverItem_clip)->chg_request_mode_proc((ACTOR*)nactorx, aHOI_REQUEST_TRANSFER); + nactorx->left_hand.requested_item_type = aNPC_ITEM_TYPE_NONE; + nactorx->left_hand.item_type = aNPC_ITEM_TYPE_LEFT_HAND; + nactorx->left_hand.item_actor_p = item_p; + aNPC_set_request_act(nactorx, 4, aNPC_ACT_TRANS, aNPC_ACT_TYPE_DEFAULT, aNPC_req_default_data); + } + break; + default: + nactorx->right_hand.requested_item_type = aNPC_ITEM_TYPE_PUTAWAY; + aNPC_chk_right_hand(nactorx); + break; + } + + ret = FALSE; + } + + return ret; +} diff --git a/src/actor/npc/ac_npc_head.c_inc b/src/actor/npc/ac_npc_head.c_inc new file mode 100644 index 00000000..ad04c343 --- /dev/null +++ b/src/actor/npc/ac_npc_head.c_inc @@ -0,0 +1,214 @@ +static int aNPC_check_look_range(NPC_ACTOR* nactorx, xyz_t* pos_p) { + ACTOR* parent = nactorx->actor_class.parent_actor; + int ret = FALSE; + s16 angleY = search_position_angleY(&nactorx->actor_class.world.position, pos_p); + s16 actor_angleY = nactorx->actor_class.shape_info.rotation.y; + + if (parent != NULL) { + actor_angleY += parent->shape_info.rotation.y; + } + + angleY -= actor_angleY; + if (ABS(angleY) < DEG2SHORT_ANGLE2(67.5f)) { + ret = TRUE; + } + + return ret; +} + +static ACTOR* aNPC_check_look_player(NPC_ACTOR* nactorx, GAME_PLAY* play) { + s16 actor_angleY; + s16 angleY; + ACTOR* playerx = NULL; + + if (nactorx->actor_class.player_distance_xz < 120.0f) { + ACTOR* parent = nactorx->actor_class.parent_actor; + + actor_angleY = nactorx->actor_class.shape_info.rotation.y; + if (parent != NULL) { + actor_angleY += parent->shape_info.rotation.y; + } + + angleY = nactorx->actor_class.player_angle_y - actor_angleY; + if (ABS(angleY) < DEG2SHORT_ANGLE2(67.5f)) { + playerx = GET_PLAYER_ACTOR_ACTOR(play); + } + } + + return playerx; +} + +static void aNPC_check_attention(NPC_ACTOR* nactorx) { + aNPC_attention_c* att_p = &CLIP(npc_clip)->attention; + xyz_t pos; + + if (att_p->type == aNPC_ATT_TYPE_NONE) { + return; + } + + if (att_p->type == aNPC_ATT_TYPE_ACTOR) { + ACTOR* target = att_p->actor; + + if (target == (ACTOR*)nactorx) { + return; + } + + xyz_t_move(&pos, &target->world.position); + } else { + xyz_t_move(&pos, &att_p->pos); + } + + switch(nactorx->actor_class.npc_id) { + case SP_NPC_EV_SPEECH_SONCHO: + case SP_NPC_EV_GROUNDHOG_0: + case SP_NPC_EV_GROUNDHOG_1: + case SP_NPC_EV_GROUNDHOG_2: + case SP_NPC_EV_GROUNDHOG_3: + case SP_NPC_EV_GROUNDHOG_4: + aNPC_set_head_request(nactorx, 2, att_p->type, att_p->actor, &att_p->pos); + break; + default: + if (aNPC_check_look_range(nactorx, &pos) == TRUE) { + aNPC_set_head_request(nactorx, 2, att_p->type, att_p->actor, &att_p->pos); + } + break; + } +} + +static void aNPC_look_target(NPC_ACTOR* nactorx, GAME_PLAY* play) { + ACTOR* target = NULL; + u8 prio = 1; + + if (nactorx->palActor != NULL) { + switch (nactorx->action.idx) { + case aNPC_ACT_GREETING: + case aNPC_ACT_TALK: + if (nactorx->talk_info.turn != aNPC_TALK_TURN_NONE) { + target = nactorx->palActor; + prio = 4; + } + break; + } + } else { + switch (nactorx->action.act_obj) { + case aNPC_ACT_OBJ_BALL: + if (nactorx->movement.target != NULL) { + target = nactorx->movement.target; + } + break; + case aNPC_ACT_OBJ_INSECT: + case aNPC_ACT_OBJ_FISH: + if (nactorx->movement.target != NULL && nactorx->action.step == 0) { + target = nactorx->movement.target; + } + break; + } + + if (target == NULL) { + target = aNPC_check_look_player(nactorx, play); + } + } + + if (target != NULL) { + aNPC_set_head_request(nactorx, prio, aNPC_HEAD_TARGET_ACTOR, target, NULL); + } + + aNPC_check_attention(nactorx); +} + +static int aNPC_check_condition_search_eye(NPC_ACTOR* nactorx) { + return aNPC_get_feel_info(nactorx) != mNpc_FEEL_SLEEPY; +} + +static void aNPC_search_eye_target_sub(NPC_ACTOR* nactorx, xyz_t* target_eye, xyz_t* target_pos, s_xyz* angle) { + s16 angleX = -search_position_angleX(&nactorx->actor_class.eye.position, target_eye); + s16 angleY = search_position_angleY(&nactorx->actor_class.world.position, target_pos); + + angleX += angle->x; + angleY -= angle->y; + + if (angleX < DEG2SHORT_ANGLE2(-33.75f)) { + angleX = DEG2SHORT_ANGLE2(-33.75f); + } + + if (ABS(angleY) > DEG2SHORT_ANGLE2(67.5f)) { + if (angleY < 0) { + angleY = DEG2SHORT_ANGLE2(-67.5f); + } else { + angleY = DEG2SHORT_ANGLE2(67.5f); + } + } + + chase_angle(&nactorx->head.angle_x, angleX, nactorx->head.angle_add_x); + chase_angle(&nactorx->head.angle_y, angleY, nactorx->head.angle_add_y); +} + +static void aNPC_search_eye_target(NPC_ACTOR* nactorx, GAME_PLAY* play, s_xyz* world_angle, s_xyz* joint_angle) { + if (nactorx->head.lock_flag == FALSE) { + aNPC_look_target(nactorx, play); + } + + if (nactorx->request.head_priority != 0) { + nactorx->head.target_type = nactorx->request.head_type; + nactorx->head.target = nactorx->request.head_target; + xyz_t_move(&nactorx->head.pos, &nactorx->request.head_pos); + } else { + nactorx->head.target_type = aNPC_HEAD_TARGET_NONE; + } + + if (aNPC_check_condition_search_eye(nactorx) == TRUE) { + switch (nactorx->head.target_type) { + case aNPC_HEAD_TARGET_ACTOR: { + ACTOR* target = nactorx->head.target; + + aNPC_search_eye_target_sub(nactorx, &target->eye.position, &target->world.position, world_angle); + break; + } + + case aNPC_HEAD_TARGET_POS: { + xyz_t* pos = &nactorx->head.pos; + + aNPC_search_eye_target_sub(nactorx, pos, pos, world_angle); + break; + } + + default: { + chase_angle(&nactorx->head.angle_x, joint_angle->y, nactorx->head.angle_add_x); + chase_angle(&nactorx->head.angle_y, joint_angle->x, nactorx->head.angle_add_y); + break; + } + } + } + + nactorx->request.head_priority = 0; +} + +static void aNPC_set_head_request_sub(NPC_ACTOR* nactorx, u8 prio, u8 type, ACTOR* target_actor, xyz_t* target_pos) { + nactorx->request.head_priority = prio; + nactorx->request.head_type = type; + nactorx->request.head_target = target_actor; + + if (target_pos != NULL) { + xyz_t_move(&nactorx->request.head_pos, target_pos); + } else { + bzero(&nactorx->request.head_pos, sizeof(nactorx->request.head_pos)); + } +} + +static int aNPC_set_head_request(NPC_ACTOR* nactorx, u8 prio, u8 type, ACTOR* target_actor, xyz_t* target_pos) { + int ret = FALSE; + + if ((nactorx->condition_info.demo_flg & aNPC_COND_DEMO_SKIP_HEAD_LOOKAT) == 0 || prio == 4) { + if (nactorx->request.head_priority == prio) { + if (nactorx->request.head_type < type) { + aNPC_set_head_request_sub(nactorx, prio, type, target_actor, target_pos); + ret = TRUE; + } + } else if (nactorx->request.head_priority < prio) { + aNPC_set_head_request_sub(nactorx, prio, type, target_actor, target_pos); + ret = TRUE; + } + } + + return ret; +} diff --git a/src/actor/npc/ac_npc_init.c_inc b/src/actor/npc/ac_npc_init.c_inc new file mode 100644 index 00000000..578f5048 --- /dev/null +++ b/src/actor/npc/ac_npc_init.c_inc @@ -0,0 +1,78 @@ +static void aNPC_actor_init_common_proc(ACTOR* actorx, GAME* game) { + NPC_ACTOR* nactorx = (NPC_ACTOR*)actorx; + GAME_PLAY* play = (GAME_PLAY*)game; + + actorx->mv_proc = nactorx->move_proc; + actorx->dw_proc = nactorx->draw_proc; + if (nactorx->schedule.type != aNPC_SCHEDULE_NONE) { + aNPC_set_schedule(nactorx, play); + aNPC_action_proc(nactorx, play); + } + + aNPC_clear_all_morph_counter(nactorx); + aNPC_anime_proc(nactorx, game); +} + +static void aNPC_actor_init_for_normal(ACTOR* actorx, GAME* game) { + NPC_ACTOR* nactorx = (NPC_ACTOR*)actorx; + NPC_CONTROL_ACTOR* ctrl = (NPC_CONTROL_ACTOR*)aNPC_ctrlActor; + Animal_c* animal = aNPC_GET_ANM(nactorx); + + nactorx->draw.cloth_idx = aNPC_dma_cloth_data_check(ctrl->cloth, animal->cloth, nactorx); + aNPC_actor_init_common_proc(actorx, game); +} + +static void aNPC_actor_init_for_special(ACTOR* actorx, GAME* game) { + NPC_ACTOR* nactorx = (NPC_ACTOR*)actorx; + mNpc_EventNpc_c* event_npc = mNpc_GetSameEventNpc(actorx->npc_id); + + if (event_npc != NULL) { + mActor_name_t cloth = event_npc->cloth_id; + + if (cloth == EMPTY_NO) { + if (ITEM_NAME_GET_TYPE(event_npc->texture_id) == NAME_TYPE_NPC) { + int idx = mNpc_SearchAnimalinfo(Save_Get(animals), event_npc->texture_id, ANIMAL_NUM_MAX); + Animal_c* animal = Save_GetPointer(animals[idx]); + + cloth = animal->cloth; + } + } + + if (cloth != EMPTY_NO) { + NPC_CONTROL_ACTOR* ctrl = (NPC_CONTROL_ACTOR*)aNPC_ctrlActor; + + nactorx->draw.cloth_idx = aNPC_dma_cloth_data_check(ctrl->cloth, cloth, nactorx); + } + } else { + mNpc_MaskNpc_c* mask_npc = mNpc_GetSameMaskNpc(actorx->npc_id); + + if (mask_npc != NULL) { + mActor_name_t cloth = mask_npc->cloth_id; + + if (cloth != EMPTY_NO) { + NPC_CONTROL_ACTOR* ctrl = (NPC_CONTROL_ACTOR*)aNPC_ctrlActor; + + if (cloth == RSV_CLOTH && aNPC_GET_ANM(nactorx) == NULL) { + cloth = ITM_CLOTH_START; + } + + nactorx->draw.cloth_idx = aNPC_dma_cloth_data_check(ctrl->cloth, cloth, nactorx); + } + } + } + + + aNPC_set_request_act(nactorx, 1, aNPC_ACT_WAIT, aNPC_ACT_TYPE_DEFAULT, aNPC_req_default_data); + aNPC_actor_init_common_proc(actorx, game); +} + +static void aNPC_actor_init(ACTOR* actorx, GAME* game) { + switch (ITEM_NAME_GET_TYPE(actorx->npc_id)) { + case NAME_TYPE_NPC: + aNPC_actor_init_for_normal(actorx, game); + break; + case NAME_TYPE_SPNPC: + aNPC_actor_init_for_special(actorx, game); + break; + } +} diff --git a/src/actor/npc/ac_npc_move.c_inc b/src/actor/npc/ac_npc_move.c_inc new file mode 100644 index 00000000..cc18b38d --- /dev/null +++ b/src/actor/npc/ac_npc_move.c_inc @@ -0,0 +1,621 @@ +static void aNPC_BGcheck(NPC_ACTOR* nactorx, ACTOR* actorx) { + int flag = mCoBG_DIDNT_HIT_WALL; + + if ((nactorx->condition_info.demo_flg & aNPC_COND_DEMO_SKIP_BGCHECK) == 0) { + switch (nactorx->collision.check_kind) { + case aNPC_BG_CHECK_TYPE_NONE: + mCoBG_InitBgCheckResult(&actorx->bg_collision_check.result); + break; + case aNPC_BG_CHECK_TYPE_ONLY_GROUND: + mCoBG_GroundCheckOnly(NULL, actorx, nactorx->collision.BGcheck_radius, 0.0f, 0); + break; + case aNPC_BG_CHECK_TYPE_NORMAL: + mCoBG_BgCheckControll(NULL, actorx, nactorx->collision.BGcheck_radius, 0.0f, TRUE, FALSE, 1); + break; + case aNPC_BG_CHECK_TYPE_RANGE: + mCoBG_BgCheckControll(NULL, actorx, nactorx->collision.BGcheck_radius, 0.0f, TRUE, FALSE, 1); + mCoBG_UniqueWallCheck(actorx, nactorx->collision.BGcheck_radius, 0.0f); + break; + } + + if ((actorx->bg_collision_check.result.hit_wall & mCoBG_HIT_WALL_FRONT) || + (actorx->bg_collision_check.result.hit_attribute_wall & mCoBG_HIT_WALL_FRONT) || + actorx->bg_collision_check.result.unk_flag4) { + flag = mCoBG_HIT_WALL_FRONT | mCoBG_HIT_WALL; + } + } else { + mCoBG_InitBgCheckResult(&actorx->bg_collision_check.result); + } + + nactorx->collision.collision_flag = flag; +} + +static int aNPC_blockRangeCheck(NPC_ACTOR* nactorx, xyz_t pos) { + int bx; + int bz; + int ret = TRUE; + + if (mFI_Wpos2BlockNum(&bx, &bz, pos) == TRUE) { + if (bx != nactorx->actor_class.block_x || bz != nactorx->actor_class.block_z) { + ret = FALSE; + } else { + f32 dx = pos.x - bx * mFI_BK_WORLDSIZE_X_F; + f32 dz = pos.z - bz * mFI_BK_WORLDSIZE_Z_F; + f32 min = nactorx->collision.BGcheck_radius; + f32 max = mFI_BK_WORLDSIZE_BASE_F - min; + + if (dx <= min || dx >= max || dz <= min || dz >= max) { + ret = FALSE; + } + } + } else { + ret = FALSE; + } + + return ret; +} + +static int aNPC_circleRangeCheck(NPC_ACTOR* nactorx, xyz_t* rev_pos_p, xyz_t pos) { + f32 dx = pos.x - nactorx->movement.range_center_x; + f32 dz = pos.z - nactorx->movement.range_center_z; + xyz_t tmp; + f32 radius = nactorx->movement.range_radius; + f32 radiusSq = SQ(radius); + int ret = TRUE; + + if (SQ(dx) + SQ(dz) > radiusSq) { + s16 angle = atans_table(dz, dx); + + tmp.x = radius * sin_s(angle) - dx; + tmp.z = radius * cos_s(angle) - dz; + ret = FALSE; + } else { + tmp.x = 0.0f; + tmp.z = 0.0f; + } + + if (rev_pos_p != NULL) { + xyz_t_move(rev_pos_p, &tmp); + } + + return ret; +} + +// is this supposed to be 'Revise'? +static void aNPC_circleRangeRevice(NPC_ACTOR* nactorx) { + if ((nactorx->condition_info.demo_flg & aNPC_COND_DEMO_SKIP_MOVE_CIRCLE_REV) == 0 && + (nactorx->condition_info.demo_flg & aNPC_COND_DEMO_SKIP_LOVE_CHECK) == 0 && + nactorx->collision.check_kind == aNPC_BG_CHECK_TYPE_RANGE) { + xyz_t rev_pos; + int res = aNPC_circleRangeCheck(nactorx, &rev_pos, nactorx->actor_class.world.position); + + if (nactorx->movement.range_type == aNPC_MOVE_RANGE_TYPE_CIRCLE) { + if (nactorx->action.type != aNPC_ACT_TYPE_SEARCH || + (nactorx->movement.target != NULL && nactorx->movement.target->part != ACTOR_PART_PLAYER)) { + nactorx->actor_class.world.position.x += rev_pos.x; + nactorx->actor_class.world.position.z += rev_pos.z; + } + } else if (res == TRUE && nactorx->condition_info.entrance_flag == aNPC_ENTRANCE_TYPE_NONE) { + nactorx->movement.range_type = aNPC_MOVE_RANGE_TYPE_CIRCLE; + } + } +} + +static int aNPC_moveRangeCheck2(NPC_ACTOR* nactorx, xyz_t* rev_pos_p, xyz_t pos, u8 range_type) { + int ret = TRUE; + + if (rev_pos_p != NULL) { + bzero(rev_pos_p, sizeof(xyz_t)); + } + + switch (range_type) { + case aNPC_MOVE_RANGE_TYPE_BLOCK: + ret = aNPC_blockRangeCheck(nactorx, pos); + break; + case aNPC_MOVE_RANGE_TYPE_CIRCLE: + ret = aNPC_circleRangeCheck(nactorx, rev_pos_p, pos); + break; + } + + return ret; +} + +static int aNPC_moveRangeCheck(NPC_ACTOR* nactorx, xyz_t* rev_pos_p, xyz_t pos, u8 range_type) { + int ret = TRUE; + + if ((nactorx->condition_info.demo_flg & aNPC_COND_DEMO_SKIP_MOVE_RANGE_CHECK) == 0 && + nactorx->collision.check_kind == aNPC_BG_CHECK_TYPE_RANGE) { + ret = aNPC_moveRangeCheck2(nactorx, rev_pos_p, pos, range_type); + } + + return ret; +} + +static u8 aNPC_entranceCheck_sub(xyz_t* pos_p) { + static u8 ret_code[] = { aNPC_ENTRANCE_TYPE_AT, aNPC_ENTRANCE_TYPE_NEARBY, aNPC_ENTRANCE_TYPE_NONE }; + mActor_name_t* fg_p; + xyz_t pos; + int i; + + xyz_t_move(&pos, pos_p); + for (i = 0; i < 2; i++) { + pos.z -= mFI_UT_WORLDSIZE_Z_F; + fg_p = mFI_GetUnitFG(pos); + + if (fg_p != NULL && (ITEM_IS_DUMMY_NPC_HOUSE(*fg_p) || ITEM_IS_NPC_HOUSE(*fg_p) || *fg_p == COTTAGE_NPC || + *fg_p == DUMMY_COTTAGE_NPC)) { + break; + } + } + + return ret_code[i]; +} + +static void aNPC_entranceCheck(NPC_ACTOR* nactorx) { + u8 entrance_flag = aNPC_ENTRANCE_TYPE_NONE; + + if ((nactorx->condition_info.demo_flg & aNPC_COND_DEMO_SKIP_ENTRANCE_CHECK) == 0) { + entrance_flag = aNPC_entranceCheck_sub(&nactorx->actor_class.world.position); + } + + nactorx->condition_info.entrance_flag = entrance_flag; +} + +static int aNPC_check_entrance_pl(GAME_PLAY* play, int home_ux, int home_uz) { + ACTOR* playerx = GET_PLAYER_ACTOR_ACTOR(play); + int ret = FALSE; + + if (playerx == NULL) { + ret = TRUE; + } else { + int ux; + int uz; + + if (mFI_Wpos2UtNum(&ux, &uz, playerx->world.position) == TRUE) { + // if the player is on the house item or one unit below then count it + if (ux == home_ux && (uz == home_uz || uz == (home_uz + 1))) { + ret = TRUE; + } + } + } + + return ret; +} + +static int aNPC_check_entrance_npc(GAME_PLAY* play, NPC_ACTOR* owner, int home_ux, int home_uz) { + ACTOR* actorx = (ACTOR*)owner; + int n = play->actor_info.list[ACTOR_PART_NPC].num_actors; + ACTOR* chk_actorx = play->actor_info.list[ACTOR_PART_NPC].actor; + int ux; + int uz; + int ret = FALSE; + + while (n != 0) { + if (chk_actorx != actorx) { + if (mFI_Wpos2UtNum(&ux, &uz, chk_actorx->world.position) == TRUE) { + // if the npc is on the house item or one unit below then count it + if (ux == home_ux && (uz == home_uz || uz == (home_uz + 1))) { + ret = TRUE; + break; + } + } + } + + chk_actorx = chk_actorx->next_actor; + n--; + } + + return ret; +} + +static int aNPC_check_entrance_humanoid(NPC_ACTOR* nactorx, GAME_PLAY* play) { + Anmhome_c* home_p = &nactorx->npc_info.animal->home_info; + int home_ux = home_p->block_x * UT_X_NUM + home_p->ut_x; + int home_uz = home_p->block_z * UT_Z_NUM + home_p->ut_z; + int ret = aNPC_check_entrance_pl(play, home_ux, home_uz); + + if (!ret) { + ret = aNPC_check_entrance_npc(play, nactorx, home_ux, home_uz); + } + + return ret; +} + +static void aNPC_set_over_friendship(NPC_ACTOR* nactorx) { + if (ITEM_NAME_GET_TYPE(nactorx->actor_class.npc_id) != NAME_TYPE_SPNPC) { + int over_friendship = 0; + + switch (Now_Private->destiny.type) { + case mPr_DESTINY_UNPOPULAR: + over_friendship = -0x100; + break; + case mPr_DESTINY_POPULAR: + if (mNpc_GetLooks2Sex(nactorx->npc_info.animal->id.looks) != Now_Private->gender) { + over_friendship = 0x100; + } + break; + } + + nactorx->condition_info.over_friendship = over_friendship; + } +} + +static f32 aNPC_forward_check_sub(NPC_ACTOR* nactorx, int type) { + static f32 chk_x_table[] = { mFI_UT_WORLDSIZE_HALF_X_F, -mFI_UT_WORLDSIZE_HALF_X_F }; + f32 chk_x = chk_x_table[type]; + s16 angle = nactorx->actor_class.world.angle.y; + f32 sin = sin_s(angle); + f32 cos = cos_s(angle); + xyz_t pos; + xyz_t rev_pos; + f32 ret; + + pos.x = nactorx->actor_class.world.position.x + chk_x * cos; + pos.y = nactorx->actor_class.world.position.y; + pos.z = nactorx->actor_class.world.position.z - chk_x * sin; + + if (aNPC_moveRangeCheck(nactorx, &rev_pos, pos, nactorx->movement.range_type) == TRUE) { + ret = mCoBG_Wpos2GroundCheckOnly(&pos, 0.0f); + } else if (nactorx->collision.check_kind == aNPC_BG_CHECK_TYPE_RANGE) { + ret = mFI_UT_WORLDSIZE_HALF_Z_F; + } else { + ret = 0.0f; + } + + return ret; +} + +static void aNPC_forward_check(NPC_ACTOR* nactorx) { + static int crs_flg[] = { mCoBG_HIT_WALL, mCoBG_HIT_WALL_FRONT }; + int flg = nactorx->collision.collision_flag; + f32 res; + int i; + + for (i = 0; i < 2; i++) { + res = aNPC_forward_check_sub(nactorx, i); + if (ABS(res) >= mFI_UT_WORLDSIZE_HALF_X_F) { + flg |= crs_flg[i]; + } + } + + nactorx->collision.collision_flag = flg; +} + +static void aNPC_set_mv_angl(NPC_ACTOR* nactorx) { + s16 angle = atans_table(nactorx->movement.avoid_pos_z - nactorx->actor_class.world.position.z, + nactorx->movement.avoid_pos_x - nactorx->actor_class.world.position.x); + + nactorx->movement.mv_angl = angle; +} + +static void aNPC_set_avoid_pos(NPC_ACTOR* nactorx, f32 avoid_pos_x, f32 avoid_pos_z, u8 avoid_dir) { + nactorx->movement.avoid_pos_x = avoid_pos_x; + nactorx->movement.avoid_pos_z = avoid_pos_z; + nactorx->movement.avoid_direction = avoid_dir; + aNPC_set_mv_angl(nactorx); +} + +static void aNPC_set_dst_pos(NPC_ACTOR* nactorx, f32 dst_pos_x, f32 dst_pos_z) { + nactorx->movement.dst_pos_x = dst_pos_x; + nactorx->movement.dst_pos_z = dst_pos_z; + nactorx->movement.move_timer = 0; + aNPC_set_avoid_pos(nactorx, dst_pos_x, dst_pos_z, 0); +} + +static void aNPC_check_feel_tim(NPC_ACTOR* nactorx) { + Animal_c* animal_p = nactorx->npc_info.animal; + + if (animal_p != NULL) { + if ((nactorx->condition_info.demo_flg & aNPC_COND_DEMO_SKIP_FEEL_CHECK) == 0 && + nactorx->condition_info.feel_tim > 0) { + nactorx->condition_info.feel_tim--; + } + + if (nactorx->condition_info.feel_tim == 0) { + animal_p->mood = mNpc_FEEL_NORMAL; + } + } +} + +static void aNPC_calc_move_timer(NPC_ACTOR* nactorx) { + int move_timer = nactorx->movement.move_timer; + + move_timer++; + if (move_timer > 18000) { + move_timer = 18000; + } + + nactorx->movement.move_timer = move_timer; +} + +static void aNPC_calc_force_call_timer(NPC_ACTOR* nactorx) { + if (mDemo_Get_talk_actor() == NULL && nactorx->think.force_call_timer != 0) { + nactorx->think.force_call_timer--; + } +} + +static void aNPC_calc_act_timer(NPC_ACTOR* nactorx) { + if (nactorx->action.act_timer != 0) { + nactorx->action.act_timer--; + } +} + +static void aNPC_calc_timer(NPC_ACTOR* nactorx) { + aNPC_calc_move_timer(nactorx); + aNPC_calc_force_call_timer(nactorx); + aNPC_calc_act_timer(nactorx); +} + +static void aNPC_position_move(ACTOR* actorx) { + NPC_ACTOR* nactorx = (NPC_ACTOR*)actorx; + f32 accel; + + if (actorx->speed < nactorx->movement.speed.max_speed) { + accel = nactorx->movement.speed.acceleration; + } else { + accel = nactorx->movement.speed.deceleration; + } + + chase_f(&actorx->speed, nactorx->movement.speed.max_speed, accel * 0.5f); + Actor_position_speed_set(actorx); + if ((nactorx->condition_info.demo_flg & aNPC_COND_DEMO_SKIP_MOVE_Y) != 0) { + actorx->position_speed.y = 0.0f; + } + + Actor_position_move(actorx); +} + +static void aNPC_angle_calc(NPC_ACTOR* nactorx) { + chase_angle(&nactorx->actor_class.shape_info.rotation.y, nactorx->movement.mv_angl, nactorx->movement.mv_add_angl); + nactorx->actor_class.world.angle.y = nactorx->actor_class.shape_info.rotation.y; +} + +static void aNPC_set_body_angle(NPC_ACTOR* nactorx) { + s16 angle; + + if (nactorx->movement.override_body_angle_flag == TRUE) { + angle = nactorx->movement.body_angle; + } else { + angle = (nactorx->actor_class.speed * 3640.0f) / 3.0f; + } + + chase_angle(&nactorx->actor_class.shape_info.rotation.x, angle, 224); +} + +static void aNPC_around_obj_check(NPC_ACTOR* nactorx, ACTOR* actorx) { + if (ClObj_DID_COLLIDE(nactorx->collision.pipe.collision_obj)) { + ACTOR* collide_actor = nactorx->collision.pipe.collision_obj.collided_actor; + s16 angle; + + if (collide_actor != nactorx->movement.target) { + angle = search_position_angleY(&actorx->world.position, &collide_actor->world.position); + angle -= actorx->shape_info.rotation.y; + + if (ABS(angle) < DEG2SHORT_ANGLE2(90.0f)) { + int flag = nactorx->collision.collision_flag; + + if (ABS(angle) < DEG2SHORT_ANGLE2(22.5f)) { + flag |= mCoBG_HIT_WALL | mCoBG_HIT_WALL_FRONT; + } else if (angle < 0) { + flag |= mCoBG_HIT_WALL_FRONT; + } else { + flag |= mCoBG_HIT_WALL; + } + + nactorx->collision.collision_flag = flag; + } + } + } +} + +static int aNPC_chk_avoid_and_search(NPC_ACTOR* nactorx, GAME_PLAY* play) { + ACTOR* playerx = GET_PLAYER_ACTOR_ACTOR(play); + int ret = aNPC_FRIENDSHIP_NORMAL; + + if (playerx != NULL) { + int bx; + int bz; + + if (mFI_Wpos2BlockNum(&bx, &bz, playerx->world.position) == TRUE && bx == nactorx->actor_class.block_x && + bz == nactorx->actor_class.block_z) { + if (nactorx->condition_info.friendship != NULL) { + int friendship = *nactorx->condition_info.friendship + nactorx->condition_info.over_friendship; + + if (friendship < 0) { + ret = aNPC_FRIENDSHIP_AVOID; + } else if (friendship > 128) { + ret = aNPC_FRIENDSHIP_SEARCH; + } + } + } + } + + return ret; +} + +static void aNPC_calc_fatigue(NPC_ACTOR* nactorx, GAME_PLAY* play) { + static int fatigue_add_table[] = { + -2, -2, -2, -2, -2, 1, 1, 1, 1, 2, 2, 2, 2, 0, 0, -2, -2, -2, -2, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, + }; + + if (aNPC_chk_avoid_and_search(nactorx, play) == aNPC_FRIENDSHIP_NORMAL) { + int fatigue = nactorx->condition_info.fatigue; + + fatigue += fatigue_add_table[nactorx->condition_info.action]; + // fatigue = CLAMP(fatigue, 0, 1600); + if (fatigue < 0) { + fatigue = 0; + } else if (fatigue > 1600) { + fatigue = 1600; + } + + nactorx->condition_info.fatigue = fatigue; + } +} + +static void aNPC_set_condition_info(NPC_ACTOR* nactorx) { + nactorx->condition_info.under_fg_p = mFI_GetUnitFG(nactorx->actor_class.world.position); + mFI_Wpos2UtNum(&nactorx->condition_info.ut_x, &nactorx->condition_info.ut_z, nactorx->actor_class.world.position); +} + +typedef struct { + int talk_flag; + s16 mv_angl_add; + u8 speed_type; +} aNPC_setup_data_c; + +static void aNPC_setupAction(NPC_ACTOR* nactorx, u8 action) { + // clang-format off + static aNPC_setup_data_c setup_data[aNPC_ACTION_TYPE_NUM] = { + {FALSE, 0x0100, 0x00}, + {FALSE, 0x0100, 0x00}, + {FALSE, 0x0100, 0x00}, + {FALSE, 0x0100, 0x00}, + {FALSE, 0x0100, 0x00}, + {FALSE, 0x0200, 0x01}, + {FALSE, 0x0200, 0x01}, + {FALSE, 0x0200, 0x01}, + {FALSE, 0x0200, 0x01}, + {FALSE, 0x0400, 0x02}, + {FALSE, 0x0400, 0x02}, + {FALSE, 0x0400, 0x02}, + {FALSE, 0x0400, 0x02}, + {FALSE, 0x0800, 0x00}, + {FALSE, 0x0800, 0x00}, + {FALSE, 0x0200, 0x00}, + {FALSE, 0x0100, 0x00}, + {FALSE, 0x0100, 0x00}, + {FALSE, 0x0100, 0x00}, + {FALSE, 0x0100, 0x00}, + {FALSE, 0x0400, 0x00}, + {FALSE, 0x0400, 0x00}, + {FALSE, 0x0400, 0x00}, + {FALSE, 0x0400, 0x00}, + {FALSE, 0x0400, 0x00}, + {FALSE, 0x0400, 0x00}, + {FALSE, 0x0800, 0x00}, + { TRUE, 0x0400, 0x00}, + {FALSE, 0x0000, 0x00}, + {FALSE, 0x0000, 0x00}, + {FALSE, 0x0000, 0x00}, + {FALSE, 0x0000, 0x00}, + {FALSE, 0x0000, 0x00}, + {FALSE, 0x0000, 0x00}, + {FALSE, 0x0000, 0x00}, + {FALSE, 0x0000, 0x00}, + {FALSE, 0x0000, 0x00}, + {FALSE, 0x0000, 0x00}, + {FALSE, 0x0000, 0x00}, + {FALSE, 0x0000, 0x00}, + {FALSE, 0x0000, 0x00}, + {FALSE, 0x0000, 0x00}, + {FALSE, 0x0000, 0x00}, + {FALSE, 0x0000, 0x00}, + {FALSE, 0x0000, 0x00}, + {FALSE, 0x0000, 0x00}, + {FALSE, 0x0000, 0x00}, + {FALSE, 0x0000, 0x00}, + {FALSE, 0x0000, 0x00}, + {FALSE, 0x0000, 0x00}, + {FALSE, 0x0000, 0x00}, + {FALSE, 0x0000, 0x00}, + {FALSE, 0x0000, 0x00}, + { TRUE, 0x0000, 0x00}, + {FALSE, 0x0000, 0x00}, + {FALSE, 0x0000, 0x00}, + {FALSE, 0x0800, 0x00}, + }; + // clang-format on + + aNPC_setup_data_c* data_p = &setup_data[action]; + aNPC_spd_c* speed_p = &aNPC_spd_data[data_p->speed_type]; + + nactorx->condition_info.action = action; + nactorx->movement.mv_add_angl = data_p->mv_angl_add; + nactorx->movement.speed.max_speed = speed_p->max_speed; + nactorx->movement.speed.acceleration = speed_p->acceleration; + nactorx->movement.speed.deceleration = speed_p->deceleration; + + if (data_p->speed_type == 0) { + nactorx->actor_class.speed = 0.0f; + } + + nactorx->talk_info.demo_code = aNPC_MANPU_CODE_NONE; + aNPC_Animation_init((ACTOR*)nactorx, aNPC_animeSeqNoTable[(int)action], data_p->talk_flag); +} + +static void aNPC_actor_move_hide(ACTOR* actorx, GAME* game) { + NPC_ACTOR* nactorx = (NPC_ACTOR*)actorx; + GAME_PLAY* play = (GAME_PLAY*)game; + + aNPC_schedule_proc(nactorx, play); + aNPC_action_proc(nactorx, play); + aNPC_check_feel_tim(nactorx); +} + +static void aNPC_actor_move_show_before(ACTOR* actorx, GAME* game) { + NPC_ACTOR* nactorx = (NPC_ACTOR*)actorx; + + aNPC_anime_proc(nactorx, game); + aNPC_tex_anm_ctrl(nactorx); + aNPC_position_move(actorx); + aNPC_BGcheck(nactorx, actorx); + aNPC_entranceCheck(nactorx); + aNPC_circleRangeRevice(nactorx); + aNPC_set_condition_info(nactorx); +} + +static void aNPC_actor_move_show_after(ACTOR* actorx, GAME* game) { + NPC_ACTOR* nactorx = (NPC_ACTOR*)actorx; + GAME_PLAY* play = (GAME_PLAY*)game; + + aNPC_set_anime_speed(nactorx); + aNPC_set_body_angle(nactorx); + aNPC_check_feel_tim(nactorx); + aNPC_calc_timer(nactorx); + Actor_world_to_eye(actorx, nactorx->eye_y); + + if ((nactorx->condition_info.demo_flg & aNPC_COND_DEMO_SKIP_OBJ_COL_CHECK) == 0) { + CollisionCheck_Uty_ActorWorldPosSetPipeC(actorx, &nactorx->collision.pipe); + CollisionCheck_setOC(game, &play->collision_check, &nactorx->collision.pipe.collision_obj); + } +} + +static void aNPC_actor_move_show(ACTOR* actorx, GAME* game) { + NPC_ACTOR* nactorx = (NPC_ACTOR*)actorx; + GAME_PLAY* play = (GAME_PLAY*)game; + + aNPC_set_over_friendship(nactorx); + aNPC_actor_move_show_before(actorx, game); + + if ((nactorx->condition_info.demo_flg & aNPC_COND_DEMO_SKIP_FORWARD_CHECK) == 0) { + aNPC_forward_check(nactorx); + aNPC_around_obj_check(nactorx, actorx); + aNPC_talk_area_check(nactorx, play); + } + + aNPC_schedule_proc(nactorx, play); + aNPC_action_proc(nactorx, play); + aNPC_talk_request_check(actorx, game); + aNPC_angle_calc(nactorx); + aNPC_calc_fatigue(nactorx, play); + aNPC_actor_move_show_after(actorx, game); +} + +static void aNPC_actor_move(ACTOR* actorx, GAME* game) { + NPC_ACTOR* nactorx = (NPC_ACTOR*)actorx; + + if (nactorx->condition_info.hide_flg != nactorx->condition_info.hide_request) { + u8 hide_req = nactorx->condition_info.hide_request; + + nactorx->condition_info.hide_flg = hide_req; + actorx->shape_info.draw_shadow = hide_req ^ 1; + } + + if (nactorx->condition_info.hide_flg == TRUE) { + aNPC_actor_move_hide(actorx, game); + } else { + aNPC_actor_move_show(actorx, game); + } +} diff --git a/src/actor/npc/ac_npc_p_sel_schedule.c_inc b/src/actor/npc/ac_npc_p_sel_schedule.c_inc index 509a47f4..efd8e954 100644 --- a/src/actor/npc/ac_npc_p_sel_schedule.c_inc +++ b/src/actor/npc/ac_npc_p_sel_schedule.c_inc @@ -66,7 +66,7 @@ static void aNPS_think_proc(NPC_ACTOR* nactorx, GAME_PLAY* play, int type) { static void aNPS_schedule_init_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { NPC_P_SEL_ACTOR* p_sel = (NPC_P_SEL_ACTOR*)nactorx; - nactorx->draw._5BE = 1; + nactorx->draw.anim_speed_type = aNPC_ANIM_SPEED_TYPE_FREE; nactorx->think.think_proc = &aNPS_think_proc; nactorx->talk_info.default_animation = aNPC_ANIM_4HAKU_E1; p_sel->strum_timer = 440; diff --git a/src/actor/npc/ac_npc_rcn_guide.c b/src/actor/npc/ac_npc_rcn_guide.c index 176b6d22..15a198cf 100644 --- a/src/actor/npc/ac_npc_rcn_guide.c +++ b/src/actor/npc/ac_npc_rcn_guide.c @@ -112,7 +112,7 @@ static void aNRG_actor_ct(ACTOR* actorx, GAME* game) { if (Common_Get(clip).npc_clip->birth_check_proc(actorx, &play->game) == TRUE) { rcn_guide->npc_class.schedule.schedule_proc = &aNRG_schedule_proc; Common_Get(clip).npc_clip->ct_proc(actorx, &play->game, &ct_data); - rcn_guide->npc_class.collision.priority = 2; + rcn_guide->npc_class.collision.check_kind = aNPC_BG_CHECK_TYPE_NORMAL; rcn_guide->melody_copy = rcn_guide->npc_class.talk_info.melody_inst; /* Set shop acre */ diff --git a/src/actor/npc/ac_npc_rcn_guide_schedule.c_inc b/src/actor/npc/ac_npc_rcn_guide_schedule.c_inc index dcfd47e2..a79e65a0 100644 --- a/src/actor/npc/ac_npc_rcn_guide_schedule.c_inc +++ b/src/actor/npc/ac_npc_rcn_guide_schedule.c_inc @@ -27,7 +27,7 @@ static void aNRG_take_with(NPC_RCN_GUIDE_ACTOR* rcn_guide, GAME_PLAY* play) { if (path >= 1) { aNRG_setup_think_proc(rcn_guide, play, aNRC_THINK_EXPLAIN); } else { - aNRG_set_request_act(rcn_guide, 4, aNPC_ACT_WALK2, aNPC_ACT_TYPE_TO_POINT, aNPC_ACT_OBJ_DEFAULT, 2240, + aNRG_set_request_act(rcn_guide, 4, aNPC_ACT_RUN, aNPC_ACT_TYPE_TO_POINT, aNPC_ACT_OBJ_DEFAULT, 2240, 1500); path++; } @@ -116,7 +116,7 @@ static void aNRG_exit(NPC_RCN_GUIDE_ACTOR* rcn_guide, GAME_PLAY* play) { } } } else { - aNRG_set_request_act(rcn_guide, 4, aNPC_ACT_WALK2, aNPC_ACT_TYPE_TO_POINT, aNPC_ACT_OBJ_DEFAULT, moveX[idx], + aNRG_set_request_act(rcn_guide, 4, aNPC_ACT_RUN, aNPC_ACT_TYPE_TO_POINT, aNPC_ACT_OBJ_DEFAULT, moveX[idx], moveZ[idx]); } } @@ -192,7 +192,7 @@ static void aNRG_approach_init(NPC_RCN_GUIDE_ACTOR* rcn_guide, GAME_PLAY* play) } /* Request action to move to desired location */ - aNRG_set_request_act(rcn_guide, 4, aNPC_ACT_WALK2, aNPC_ACT_TYPE_TO_POINT, aNPC_ACT_OBJ_DEFAULT, x, z); + aNRG_set_request_act(rcn_guide, 4, aNPC_ACT_RUN, aNPC_ACT_TYPE_TO_POINT, aNPC_ACT_OBJ_DEFAULT, x, z); } static void aNRG_introduce_init(NPC_RCN_GUIDE_ACTOR* rcn_guide, GAME_PLAY* play) { @@ -215,7 +215,7 @@ static void aNRG_take_with_init(NPC_RCN_GUIDE_ACTOR* rcn_guide, GAME_PLAY* play) } } - aNRG_set_request_act(rcn_guide, 4, aNPC_ACT_WALK2, aNPC_ACT_TYPE_TO_POINT, aNPC_ACT_OBJ_DEFAULT, 2240, 1300); + aNRG_set_request_act(rcn_guide, 4, aNPC_ACT_RUN, aNPC_ACT_TYPE_TO_POINT, aNPC_ACT_OBJ_DEFAULT, 2240, 1300); } static void aNRG_before_open_door_talk2_init(NPC_RCN_GUIDE_ACTOR* rcn_guide, GAME_PLAY* play) { diff --git a/src/actor/npc/ac_npc_rtc_think.c.inc b/src/actor/npc/ac_npc_rtc_think.c.inc index f4b8fa58..c933240f 100644 --- a/src/actor/npc/ac_npc_rtc_think.c.inc +++ b/src/actor/npc/ac_npc_rtc_think.c.inc @@ -114,7 +114,7 @@ static void aNRTC_think_proc(NPC_ACTOR* actor, GAME_PLAY* play, int idx) { static void aNRTC_schedule_init_proc(NPC_ACTOR* actor, GAME_PLAY* play) { NPC_RTC_ACTOR* rtc = (NPC_RTC_ACTOR*)actor; - rtc->npc_class.draw._5BE = 1; + rtc->npc_class.draw.anim_speed_type = aNPC_ANIM_SPEED_TYPE_FREE; rtc->npc_class.talk_info.default_animation = aNPC_ANIM_4HAKU_E1; rtc->bgm_timer = -1; rtc->fade_timer = 0; diff --git a/src/actor/npc/ac_npc_save.c_inc b/src/actor/npc/ac_npc_save.c_inc new file mode 100644 index 00000000..2d7ae3d9 --- /dev/null +++ b/src/actor/npc/ac_npc_save.c_inc @@ -0,0 +1,78 @@ +static void aNPC_actor_save_for_normal(ACTOR* actorx) { + NPC_ACTOR* nactorx = (NPC_ACTOR*)actorx; + Animal_c* animal = aNPC_GET_ANM(nactorx); + + if (nactorx->action.idx == aNPC_ACT_INTO_HOUSE) { + int home_ux = animal->home_info.block_x * UT_X_NUM + animal->home_info.ut_x; + int home_uz = animal->home_info.block_z * UT_Z_NUM + animal->home_info.ut_z; + + if (nactorx->condition_info.ut_x == home_ux && nactorx->condition_info.ut_z == home_uz) { + aNPC_setup_stay_my_house(nactorx); + } + } + + aNPC_cancel_cloth_data(nactorx); + animal->cloth = nactorx->draw.next_cloth_no; + animal->cloth_original_id = nactorx->draw.next_org_idx; + + if (nactorx->condition_info.feel_tim == 0) { + animal->mood = mNpc_FEEL_NORMAL; + animal->mood_time = 0; + } else { + int feel_tim; + + switch (animal->mood) { + case mNpc_FEEL_PITFALL: + mFI_SetFG_common(EMPTY_NO, actorx->world.position, TRUE); + // fallthrough 5 -> 4, 7, & 8 + case mNpc_FEEL_SLEEPY: + case mNpc_FEEL_UZAI_0: + case mNpc_FEEL_UZAI_1: + animal->mood = mNpc_FEEL_NORMAL; + feel_tim = 0; + break; + default: + feel_tim = nactorx->condition_info.feel_tim / FRAMES_PER_MINUTE; + break; + } + + animal->mood_time = feel_tim; + } +} + +static void aNPC_actor_save_for_special(ACTOR* actorx) { + NPC_ACTOR* nactorx = (NPC_ACTOR*)actorx; + mNpc_EventNpc_c* event_npc = nactorx->npc_info.event; + + if (event_npc != NULL) { + if (event_npc->cloth_id != EMPTY_NO) { + aNPC_cancel_cloth_data(nactorx); + } + } else { + mNpc_MaskNpc_c* mask_npc = nactorx->npc_info.mask; + + if (mask_npc != NULL) { + if (mask_npc->cloth_id != EMPTY_NO) { + aNPC_cancel_cloth_data(nactorx); + } + } + } +} + +static void aNPC_actor_save(ACTOR* actorx, GAME* game) { + NPC_ACTOR* nactorx = (NPC_ACTOR*)actorx; + + if (mEv_CheckTitleDemo() <= 0) { + if (ITEM_NAME_GET_TYPE(actorx->npc_id) == NAME_TYPE_NPC) { + aNPC_actor_save_for_normal(actorx); + } else { + aNPC_actor_save_for_special(actorx); + } + + if (nactorx->movement.move_timer >= 18000 && nactorx->npc_info.list != NULL) { + xyz_t_move(&actorx->world.position, &nactorx->npc_info.list->position); + } + + mNpc_RenewalSetNpc(actorx); + } +} diff --git a/src/actor/npc/ac_npc_schedule.c_inc b/src/actor/npc/ac_npc_schedule.c_inc new file mode 100644 index 00000000..4677df54 --- /dev/null +++ b/src/actor/npc/ac_npc_schedule.c_inc @@ -0,0 +1,180 @@ +static void aNPC_set_hide_request(NPC_ACTOR* nactorx, u8 hide) { + nactorx->condition_info.hide_request = hide; + if (nactorx->condition_info.hide_flg != hide && hide != TRUE) { + aNPC_clear_all_morph_counter(nactorx); + nactorx->condition_info.fatigue = 0; + } +} + +static void aNPC_set_hide_flg(NPC_ACTOR* nactorx, u8 hide_flg) { + u8 inv = hide_flg ^ 1; + + nactorx->condition_info.hide_flg = inv; + aNPC_set_hide_request(nactorx, hide_flg); + nactorx->condition_info.hide_flg = hide_flg; + nactorx->actor_class.shape_info.draw_shadow = inv; +} + +static int aNPC_check_chg_schedule(NPC_ACTOR* nactorx, int step) { + int ret = FALSE; + + if (nactorx->schedule.step == step && nactorx->schedule.type != nactorx->npc_info.schedule->current_type && + nactorx->condition_info.talk_condition == aNPC_TALK_TYPE_NONE) { + ret = TRUE; + } + + return ret; +} + +static int aNPC_check_home_block(NPC_ACTOR* nactorx) { + int ret = FALSE; + + if (nactorx->actor_class.block_x == aNPC_GET_ANM(nactorx)->home_info.block_x && + nactorx->actor_class.block_z == aNPC_GET_ANM(nactorx)->home_info.block_z) { + ret = TRUE; + } + + return ret; +} + +#include "../src/actor/npc/ac_npc_schedule_field.c_inc" +#include "../src/actor/npc/ac_npc_schedule_in_house.c_inc" +#include "../src/actor/npc/ac_npc_schedule_sleep.c_inc" + +static void aNPC_stand_schedule_main_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + if (!aNPC_think_chk_interrupt_proc(nactorx, play) && nactorx->action.step == aNPC_ACTION_END_STEP) { + if (nactorx->action.idx == aNPC_ACT_WAIT) { + aNPC_think_main_proc(nactorx, play); + } else { + aNPC_think_init_proc(nactorx, play, aNPC_THINK_WAIT); + } + + nactorx->condition_info.demo_flg = aNPC_COND_DEMO_SKIP_FORWARD_CHECK | aNPC_COND_DEMO_SKIP_BGCHECK | + aNPC_COND_DEMO_SKIP_MOVE_Y | aNPC_COND_DEMO_SKIP_MOVE_CIRCLE_REV | + aNPC_COND_DEMO_SKIP_MOVE_RANGE_CHECK; + } +} + +static void aNPC_stand_schedule_init_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + aNPC_set_hide_flg(nactorx, FALSE); + aNPC_think_init_proc(nactorx, play, aNPC_THINK_WAIT); + nactorx->condition_info.demo_flg = aNPC_COND_DEMO_SKIP_FORWARD_CHECK | aNPC_COND_DEMO_SKIP_BGCHECK | + aNPC_COND_DEMO_SKIP_MOVE_Y | aNPC_COND_DEMO_SKIP_MOVE_CIRCLE_REV | + aNPC_COND_DEMO_SKIP_MOVE_RANGE_CHECK; +} + +static void aNPC_stand_schedule_proc(NPC_ACTOR* nactorx, GAME_PLAY* play, int proc_type) { + static aNPC_SUB_PROC sche_proc[] = { + &aNPC_stand_schedule_init_proc, + &aNPC_stand_schedule_main_proc, + }; + + (*sche_proc[proc_type])(nactorx, play); +} + +static void aNPC_wander_schedule_main_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + aNPC_think_main_proc(nactorx, play); + if (nactorx->think.end_flag == TRUE) { + aNPC_think_init_proc(nactorx, play, aNPC_THINK_PITFALL); + } +} + +static void aNPC_wander_schedule_init_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + aNPC_set_hide_flg(nactorx, FALSE); + aNPC_think_init_proc(nactorx, play, aNPC_THINK_WANDER); +} + +static void aNPC_wander_schedule_proc(NPC_ACTOR* nactorx, GAME_PLAY* play, int proc_type) { + static aNPC_SUB_PROC sche_proc[] = { + &aNPC_wander_schedule_init_proc, + &aNPC_wander_schedule_main_proc, + }; + + (*sche_proc[proc_type])(nactorx, play); +} + +static void aNPC_walk_wander_schedule_init_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + aNPC_set_hide_flg(nactorx, FALSE); + aNPC_think_init_proc(nactorx, play, aNPC_THINK_WALK_WANDER); +} + +static void aNPC_walk_wander_schedule_proc(NPC_ACTOR* nactorx, GAME_PLAY* play, int proc_type) { + static aNPC_SUB_PROC sche_proc[] = { + &aNPC_walk_wander_schedule_init_proc, + &aNPC_wander_schedule_main_proc, + }; + + (*sche_proc[proc_type])(nactorx, play); +} + +static void aNPC_special_schedule_proc(NPC_ACTOR* nactorx, GAME_PLAY* play, int proc_type) { + (*nactorx->schedule.schedule_proc)(nactorx, play, proc_type); +} + +static aNPC_SCHEDULE_PROC aNPC_sche_proc[] = { + &aNPC_field_schedule_proc, + &aNPC_in_house_schedule_proc, + &aNPC_sleep_schedule_proc, + &aNPC_stand_schedule_proc, + &aNPC_wander_schedule_proc, + &aNPC_walk_wander_schedule_proc, + &aNPC_special_schedule_proc, +}; + +static aNPC_SCHEDULE_PROC aNPC_island_sche_proc[] = { + &aNPC_field_schedule_proc, + &aNPC_in_house_schedule_proc, + &aNPC_in_house_schedule_proc, + &aNPC_stand_schedule_proc, + &aNPC_wander_schedule_proc, + &aNPC_walk_wander_schedule_proc, + &aNPC_special_schedule_proc, +}; + +static void aNPC_schedule_init(NPC_ACTOR* nactorx, GAME_PLAY* play) { + Animal_c* animal = aNPC_GET_ANM(nactorx); + int type = nactorx->schedule.type; + + if (animal != NULL && mNpc_CheckIslandAnimal(animal) == TRUE) { + (*aNPC_island_sche_proc[type])(nactorx, play, aNPC_SCHEDULE_PROC_INIT); + } else { + (*aNPC_sche_proc[type])(nactorx, play, aNPC_SCHEDULE_PROC_INIT); + } +} + +static void aNPC_chg_schedule(NPC_ACTOR* nactorx, GAME_PLAY* play, u8 type) { + nactorx->schedule.type = type; + aNPC_schedule_init(nactorx, play); +} + +static void aNPC_set_schedule(NPC_ACTOR* nactorx, GAME_PLAY* play) { + aNPC_chg_schedule(nactorx, play, nactorx->npc_info.schedule->current_type); +} + +static void aNPC_schedule_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + int type = nactorx->schedule.type; + + if (type != aNPC_SCHEDULE_NONE) { + Animal_c* animal = aNPC_GET_ANM(nactorx); + + if (animal != NULL && mNpc_CheckIslandAnimal(animal) == TRUE) { + (*aNPC_island_sche_proc[type])(nactorx, play, aNPC_SCHEDULE_PROC_MAIN); + } else { + (*aNPC_sche_proc[type])(nactorx, play, aNPC_SCHEDULE_PROC_MAIN); + } + } +} + +static void aNPC_first_set_schedule(NPC_ACTOR* nactorx) { + mNPS_schedule_c* sched_p = mNPS_get_schedule_area(&aNPC_GET_ANM(nactorx)->id); + + if (sched_p == NULL || (Common_Get(field_type) == mFI_FIELDTYPE2_FG && Save_Get(scene_no) != SCENE_FG)) { + sched_p = &nactorx->schedule.schedule; + sched_p->current_type = mNPS_SCHED_WANDER; + nactorx->schedule.type = aNPC_SCHEDULE_TYPE_WANDER; + } else { + nactorx->schedule.type = sched_p->current_type; + } + + nactorx->npc_info.schedule = sched_p; +} diff --git a/src/actor/npc/ac_npc_schedule_field.c_inc b/src/actor/npc/ac_npc_schedule_field.c_inc new file mode 100644 index 00000000..64851f58 --- /dev/null +++ b/src/actor/npc/ac_npc_schedule_field.c_inc @@ -0,0 +1,76 @@ +enum { + aNPC_SCHEDULE_FIELD_STEP_LEAVE_HOUSE, + aNPC_SCHEDULE_FIELD_STEP_WANDER, + aNPC_SCHEDULE_FIELD_STEP_IN_BLOCK, + aNPC_SCHEDULE_FIELD_STEP_PITFALL, + + aNPC_SCHEDULE_FIELD_STEP_NUM +}; + +static void aNPC_field_schedule_think_init(NPC_ACTOR* nactorx, GAME_PLAY* play, u8 step) { + static int think_idx[] = { aNPC_THINK_LEAVE_HOUSE, aNPC_THINK_WANDER, aNPC_THINK_IN_BLOCK, aNPC_THINK_PITFALL }; + static u8 hide_flg[] = { TRUE, FALSE, FALSE, FALSE }; + + nactorx->schedule.step = step; + aNPC_think_init_proc(nactorx, play, think_idx[step]); + aNPC_set_hide_flg(nactorx, hide_flg[step]); +} + +static void aNPC_field_schedule_main_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + aNPC_think_main_proc(nactorx, play); + if (nactorx->think.end_flag == TRUE) { + u8 step; + + switch (nactorx->schedule.step) { + case aNPC_SCHEDULE_FIELD_STEP_WANDER: + step = aNPC_SCHEDULE_FIELD_STEP_PITFALL; + break; + default: + step = aNPC_SCHEDULE_FIELD_STEP_WANDER; + break; + } + + aNPC_field_schedule_think_init(nactorx, play, step); + } else { + switch (nactorx->npc_info.schedule->current_type) { + case mNPS_SCHED_IN_HOUSE: + if (aNPC_check_home_block(nactorx) == TRUE && aNPC_check_chg_schedule(nactorx, aNPC_SCHEDULE_FIELD_STEP_WANDER) == TRUE) { + aNPC_set_schedule(nactorx, play); + } + break; + default: + if (aNPC_check_chg_schedule(nactorx, aNPC_SCHEDULE_FIELD_STEP_WANDER) == TRUE) { + aNPC_set_schedule(nactorx, play); + } + } + } +} + +static void aNPC_field_schedule_init_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + u8 step = aNPC_SCHEDULE_FIELD_STEP_LEAVE_HOUSE; + + if (nactorx->condition_info.appear_flag == 1) { + nactorx->condition_info.appear_flag = 0; + step = aNPC_SCHEDULE_FIELD_STEP_IN_BLOCK; + } else { + if (aNPC_GET_ANM(nactorx) != NULL) { + if (aNPC_GET_ANM(nactorx)->is_home == FALSE) { + step = aNPC_SCHEDULE_FIELD_STEP_WANDER; + } + } else { + step = aNPC_SCHEDULE_FIELD_STEP_WANDER; + } + } + + nactorx->schedule.step = step; + aNPC_field_schedule_think_init(nactorx, play, step); +} + +static void aNPC_field_schedule_proc(NPC_ACTOR* nactorx, GAME_PLAY* play, int proc_type) { + static aNPC_SUB_PROC sche_proc[] = { + &aNPC_field_schedule_init_proc, + &aNPC_field_schedule_main_proc, + }; + + (*sche_proc[proc_type])(nactorx, play); +} diff --git a/src/actor/npc/ac_npc_schedule_in_house.c_inc b/src/actor/npc/ac_npc_schedule_in_house.c_inc new file mode 100644 index 00000000..6b3ebeca --- /dev/null +++ b/src/actor/npc/ac_npc_schedule_in_house.c_inc @@ -0,0 +1,83 @@ +enum { + aNPC_SCHEDULE_IN_HOUSE_STEP_GO_HOME, + aNPC_SCHEDULE_IN_HOUSE_STEP_PITFALL, + aNPC_SCHEDULE_IN_HOUSE_STEP_INTO_HOUSE, + aNPC_SCHEDULE_IN_HOUSE_STEP_HIDE, + + aNPC_SCHEDULE_IN_HOUSE_STEP_NUM +}; + +static void aNPC_in_house_schedule_think_init(NPC_ACTOR* nactorx, GAME_PLAY* play) { + static int think_idx[] = { aNPC_THINK_GO_HOME, aNPC_THINK_PITFALL, aNPC_THINK_INTO_HOUSE, aNPC_THINK_WAIT }; + + aNPC_think_init_proc(nactorx, play, think_idx[nactorx->schedule.step]); +} + +static void aNPC_in_house_schedule_main_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + aNPC_think_main_proc(nactorx, play); + + if (nactorx->think.end_flag == TRUE) { + u8 step; + + switch (nactorx->schedule.step) { + case aNPC_SCHEDULE_IN_HOUSE_STEP_GO_HOME: + if (nactorx->condition_info.pitfall_flag == TRUE) { + step = aNPC_SCHEDULE_IN_HOUSE_STEP_PITFALL; + } else { + step = aNPC_SCHEDULE_IN_HOUSE_STEP_INTO_HOUSE; + } + break; + case aNPC_SCHEDULE_IN_HOUSE_STEP_PITFALL: + step = aNPC_SCHEDULE_IN_HOUSE_STEP_GO_HOME; + break; + default: + step = nactorx->schedule.step + 1; + break; + } + + nactorx->schedule.step = step; + aNPC_in_house_schedule_think_init(nactorx, play); + } else { + if (nactorx->schedule.type != nactorx->npc_info.schedule->current_type && nactorx->condition_info.talk_condition == aNPC_TALK_TYPE_NONE) { + switch (nactorx->schedule.step) { + case aNPC_SCHEDULE_IN_HOUSE_STEP_GO_HOME: + case aNPC_SCHEDULE_IN_HOUSE_STEP_HIDE: + if (nactorx->npc_info.schedule->current_type == mNPS_SCHED_SLEEP) { + if (!mNpc_CheckIslandAnimal(aNPC_GET_ANM(nactorx))) { + aNPC_set_schedule(nactorx, play); + } + } else { + aNPC_set_schedule(nactorx, play); + } + break; + } + } + } +} + +static void aNPC_in_house_schedule_init_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + u8 hide = FALSE; + u8 step = aNPC_SCHEDULE_IN_HOUSE_STEP_GO_HOME; + + if (aNPC_GET_ANM(nactorx)->is_home == TRUE) { + step = aNPC_SCHEDULE_IN_HOUSE_STEP_HIDE; + hide = TRUE; + nactorx->actor_class.world.position.x = nactorx->npc_info.list->house_position.x + mFI_UT_WORLDSIZE_HALF_X_F; + nactorx->actor_class.world.position.z = nactorx->npc_info.list->house_position.z + mFI_UT_WORLDSIZE_HALF_Z_F; + } else if (nactorx->condition_info.entrance_flag == aNPC_ENTRANCE_TYPE_AT) { + step = aNPC_SCHEDULE_IN_HOUSE_STEP_INTO_HOUSE; + } + + aNPC_set_hide_flg(nactorx, hide); + nactorx->schedule.step = step; + aNPC_in_house_schedule_think_init(nactorx, play); +} + +static void aNPC_in_house_schedule_proc(NPC_ACTOR* nactorx, GAME_PLAY* play, int proc_type) { + static aNPC_SUB_PROC sche_proc[] = { + &aNPC_in_house_schedule_init_proc, + &aNPC_in_house_schedule_main_proc, + }; + + (*sche_proc[proc_type])(nactorx, play); +} diff --git a/src/actor/npc/ac_npc_schedule_sleep.c_inc b/src/actor/npc/ac_npc_schedule_sleep.c_inc new file mode 100644 index 00000000..a5c72361 --- /dev/null +++ b/src/actor/npc/ac_npc_schedule_sleep.c_inc @@ -0,0 +1,79 @@ +enum { + aNPC_SCHEDULE_SLEEP_STEP_SLEEP, + aNPC_SCHEDULE_SLEEP_STEP_PITFALL, + + aNPC_SCHEDULE_SLEEP_STEP_NUM +}; + +static void aNPC_sleep_schedule_think_init(NPC_ACTOR* nactorx, GAME_PLAY* play, u8 step) { + static int think_idx[] = { aNPC_THINK_SLEEP, aNPC_THINK_PITFALL, aNPC_THINK_WAIT, aNPC_THINK_WAIT }; + + nactorx->schedule.step = step; + aNPC_think_init_proc(nactorx, play, think_idx[step]); +} + +static void aNPC_sleep_schedule_chg_schedule(NPC_ACTOR* nactorx, GAME_PLAY* play) { + int feel = aNPC_get_feel_info(nactorx); + + switch (feel) { + case mNpc_FEEL_UZAI_0: + case mNpc_FEEL_UZAI_1: + break; + default: + aNPC_set_feel_info(nactorx, mNpc_FEEL_NORMAL, 0); + break; + } + + nactorx->condition_info.demo_flg = 0; + nactorx->right_hand.umbrella_disabled_flag = FALSE; + aNPC_set_schedule(nactorx, play); +} + +static void aNPC_sleep_schedule_main_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + aNPC_think_main_proc(nactorx, play); + + if (nactorx->think.end_flag == TRUE) { + u8 step; + + switch (nactorx->schedule.step) { + case aNPC_SCHEDULE_SLEEP_STEP_SLEEP: + step = aNPC_SCHEDULE_SLEEP_STEP_PITFALL; + break; + default: + step = aNPC_SCHEDULE_SLEEP_STEP_SLEEP; + aNPC_think_sleep_set_force_schedule(nactorx); + break; + } + + aNPC_sleep_schedule_think_init(nactorx, play, step); + } else { + switch (nactorx->npc_info.schedule->current_type) { + case mNPS_SCHED_FIELD: + aNPC_sleep_schedule_chg_schedule(nactorx, play); + break; + case mNPS_SCHED_IN_HOUSE: + if (aNPC_check_home_block(nactorx) == TRUE) { + aNPC_sleep_schedule_chg_schedule(nactorx, play); + } + break; + + } + } +} + +static void aNPC_sleep_schedule_init_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + aNPC_set_hide_flg(nactorx, aNPC_GET_ANM(nactorx)->is_home); + nactorx->right_hand.umbrella_disabled_flag = aNPC_GET_ANM(nactorx)->is_home; + nactorx->palActorIgnoreTimer = -1; + nactorx->schedule.step = aNPC_SCHEDULE_SLEEP_STEP_SLEEP; + aNPC_sleep_schedule_think_init(nactorx, play, aNPC_SCHEDULE_SLEEP_STEP_SLEEP); +} + +static void aNPC_sleep_schedule_proc(NPC_ACTOR* nactorx, GAME_PLAY* play, int proc_type) { + static aNPC_SUB_PROC sche_proc[] = { + &aNPC_sleep_schedule_init_proc, + &aNPC_sleep_schedule_main_proc, + }; + + (*sche_proc[proc_type])(nactorx, play); +} diff --git a/src/actor/npc/ac_npc_sendo_move.c_inc b/src/actor/npc/ac_npc_sendo_move.c_inc index 8b62a29b..b6fa7d8f 100644 --- a/src/actor/npc/ac_npc_sendo_move.c_inc +++ b/src/actor/npc/ac_npc_sendo_move.c_inc @@ -230,7 +230,7 @@ static void aSEN_sing_start_wait_init(NPC_SENDO_ACTOR* sendo, GAME_PLAY* play) { boat_demo->demo_act = aBTD_DEMO_MOVE_BOAT_END; sendo->npc_class.talk_info.default_animation = 123; - sendo->npc_class.draw._5BE = 1; + sendo->npc_class.draw.anim_speed_type = aNPC_ANIM_SPEED_TYPE_FREE; } static void aSEN_touch_wharf_end_wait_init(NPC_SENDO_ACTOR* sendo, GAME_PLAY* play) { @@ -242,7 +242,7 @@ static void aSEN_arrive_call_init(NPC_SENDO_ACTOR* sendo, GAME_PLAY* play) { sendo->npc_class.head.angle_add_x = 512; sendo->npc_class.head.angle_add_y = 1024; sendo->npc_class.talk_info.default_animation = 124; - sendo->npc_class.draw._5BE = 0; + sendo->npc_class.draw.anim_speed_type = aNPC_ANIM_SPEED_TYPE_LOCKED; } static void aSEN_pl_ride_off_end_wait_init(NPC_SENDO_ACTOR* sendo, GAME_PLAY* play) { @@ -318,11 +318,11 @@ static void aSEN_schedule_init_proc(NPC_ACTOR* npc_actorx, GAME_PLAY* play) { npc_actorx->palActorIgnoreTimer = -1; npc_actorx->talk_info.default_animation = 124; npc_actorx->actor_class.talk_distance = 60.0f; - npc_actorx->collision.priority = 1; + npc_actorx->collision.check_kind = aNPC_BG_CHECK_TYPE_ONLY_GROUND; npc_actorx->actor_class.shape_info.draw_shadow = FALSE; npc_actorx->actor_class.state_bitfield |= ACTOR_STATE_NO_MOVE_WHILE_CULLED; - npc_actorx->actor_class.status_data.weight = 254; - npc_actorx->draw._5B9 = 1; + npc_actorx->actor_class.status_data.weight = MASSTYPE_HEAVY; + npc_actorx->draw.chn_base_type = aNPC_CHN_BASE_TYPE_WORLD; // base draw position is relative to world instead of actor position npc_actorx->actor_class.shape_info.rotation.y = DEG2SHORT_ANGLE(80.0f); npc_actorx->movement.mv_angl = DEG2SHORT_ANGLE(80.0f); @@ -1281,7 +1281,7 @@ static void aSEN_actor_move(ACTOR* actorx, GAME* game) { aSEN_set_matrix(sendo); - if (sendo->npc_class.draw._5BE == 1) { + if (sendo->npc_class.draw.anim_speed_type == aNPC_ANIM_SPEED_TYPE_FREE) { sAdos_GetKappaCounter(&sendo->kappa_counter); aSEN_set_anime_current(sendo); } diff --git a/src/actor/npc/ac_npc_shop_common.c b/src/actor/npc/ac_npc_shop_common.c index e4ea937c..17ee6e3b 100644 --- a/src/actor/npc/ac_npc_shop_common.c +++ b/src/actor/npc/ac_npc_shop_common.c @@ -439,21 +439,21 @@ static void aNSC_talk_demo_proc(ACTOR* actorx) { static void aNSC_set_stop_spd(NPC_SHOP_COMMON_ACTOR* shop_common) { shop_common->npc_class.actor_class.speed = 0.0; - shop_common->npc_class.movement.max_speed = 0.0; - shop_common->npc_class.movement.acceleration = 0.0; - shop_common->npc_class.movement.deceleration = 0.0; + shop_common->npc_class.movement.speed.max_speed = 0.0; + shop_common->npc_class.movement.speed.acceleration = 0.0; + shop_common->npc_class.movement.speed.deceleration = 0.0; } static void aNSC_set_walk_spd(NPC_SHOP_COMMON_ACTOR* shop_common) { - shop_common->npc_class.movement.max_speed = 1.0; - shop_common->npc_class.movement.acceleration = 0.1; - shop_common->npc_class.movement.deceleration = 0.2; + shop_common->npc_class.movement.speed.max_speed = 1.0; + shop_common->npc_class.movement.speed.acceleration = 0.1; + shop_common->npc_class.movement.speed.deceleration = 0.2; } static void aNSC_set_run_spd(NPC_SHOP_COMMON_ACTOR* shop_common) { - shop_common->npc_class.movement.max_speed = 4.0; - shop_common->npc_class.movement.acceleration = 0.4; - shop_common->npc_class.movement.deceleration = 0.8; + shop_common->npc_class.movement.speed.max_speed = 4.0; + shop_common->npc_class.movement.speed.acceleration = 0.4; + shop_common->npc_class.movement.speed.deceleration = 0.8; } #ifndef aNSC_MAMEDANUKI diff --git a/src/actor/npc/ac_npc_shop_mastersp_schedule.c_inc b/src/actor/npc/ac_npc_shop_mastersp_schedule.c_inc index cb9b344a..e09c8359 100644 --- a/src/actor/npc/ac_npc_shop_mastersp_schedule.c_inc +++ b/src/actor/npc/ac_npc_shop_mastersp_schedule.c_inc @@ -71,7 +71,7 @@ static void aSHM_normal_turn(NPC_SHOP_MASTERSP_ACTOR* shop_mastersp, GAME_PLAY* } static void aSHM_move(NPC_SHOP_MASTERSP_ACTOR* shop_mastersp, GAME_PLAY* play) { - if (shop_mastersp->npc_class.action.idx == aNPC_ACT_WALK2 || shop_mastersp->npc_class.action.idx == aNPC_ACT_WAIT) { + if (shop_mastersp->npc_class.action.idx == aNPC_ACT_RUN || shop_mastersp->npc_class.action.idx == aNPC_ACT_WAIT) { if (aSHM_set_next_avoid_pos(shop_mastersp)) { aSHM_setup_think_proc(shop_mastersp, play, shop_mastersp->move_think_idx); } else { @@ -170,7 +170,7 @@ static void aSHM_think_main_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { (*shop_mastersp->think_proc)(shop_mastersp, play); } else if (shop_mastersp->npc_class.action.step == aNPC_ACTION_END_STEP) { (*shop_mastersp->think_proc)(shop_mastersp, play); - } else if (shop_mastersp->npc_class.action.idx == aNPC_ACT_WALK2) { + } else if (shop_mastersp->npc_class.action.idx == aNPC_ACT_RUN) { shop_mastersp->npc_class.movement.mv_add_angl = DEG2SHORT_ANGLE2(22.5f); } } @@ -197,7 +197,7 @@ static void aSHM_normal_turn_init(NPC_SHOP_MASTERSP_ACTOR* shop_mastersp, GAME_P } static void aSHM_move_init(NPC_SHOP_MASTERSP_ACTOR* shop_mastersp, GAME_PLAY* play) { - aSHM_set_request_act(shop_mastersp, 4, aNPC_ACT_WALK2, aNPC_ACT_TYPE_TO_POINT, aNPC_ACT_OBJ_DEFAULT, + aSHM_set_request_act(shop_mastersp, 4, aNPC_ACT_RUN, aNPC_ACT_TYPE_TO_POINT, aNPC_ACT_OBJ_DEFAULT, shop_mastersp->base_pos[shop_mastersp->now_idx][0], shop_mastersp->base_pos[shop_mastersp->now_idx][1]); } diff --git a/src/actor/npc/ac_npc_sound.c_inc b/src/actor/npc/ac_npc_sound.c_inc new file mode 100644 index 00000000..a92ec6ef --- /dev/null +++ b/src/actor/npc/ac_npc_sound.c_inc @@ -0,0 +1,20 @@ +static void aNPC_OngenTrgStart(NPC_ACTOR* nactorx, u16 se_no) { + sAdo_OngenTrgStart(se_no, &nactorx->actor_class.world.position); +} + +static void aNPC_WalkSe(xyz_t* pos_p) { + u32 attr; + u16 se_no; + + attr = mCoBG_Wpos2Attribute(*pos_p, NULL); + se_no = sAdo_Get_WalkLabel(attr); + if (sAdo_CheckOnPlussBridge(pos_p, attr)) { + se_no = NA_SE_FOOTSTEP_PLUSSBRIDGE; + } + + sAdo_NpcWalkSe(se_no, pos_p); +} + +static void aNPC_TumbleSe(xyz_t* pos_p) { + sAdo_OngenTrgStart(sAdo_Get_KokeruLabel(mCoBG_Wpos2Attribute(*pos_p, NULL)), pos_p); +} diff --git a/src/actor/npc/ac_npc_talk.c_inc b/src/actor/npc/ac_npc_talk.c_inc new file mode 100644 index 00000000..3a26d554 --- /dev/null +++ b/src/actor/npc/ac_npc_talk.c_inc @@ -0,0 +1,593 @@ +static int aNPC_force_call_req_proc(NPC_ACTOR* nactorx, int msg_no) { + int ret = FALSE; + + if (nactorx->think.force_call_flag == aNPC_FORCE_CALL_NONE && + nactorx->condition_info.talk_condition == aNPC_TALK_TYPE_NONE && mDemo_CAN_ACTOR_TALK((ACTOR*)nactorx)) { + nactorx->think.force_call_flag = aNPC_FORCE_CALL_REQUEST; + nactorx->think.force_call_msg_no = msg_no; + ret = TRUE; + } + + return ret; +} + +static void aNPC_check_manpu_demoCode(ACTOR* actorx) { + // clang-format off + static s16 eff_idx[43] = { + -1, + aNPC_ANIM_MUKA1, + aNPC_ANIM_GAAAN1, + aNPC_ANIM_SMILE1, + aNPC_ANIM_HA1, + aNPC_ANIM_PUNPUN1, + aNPC_ANIM_A1, + aNPC_ANIM_ASERU1, + aNPC_ANIM_BURUBURU1, + aNPC_ANIM_GOUKYU1, + aNPC_ANIM_HAPPY1, + aNPC_ANIM_HATE1, + aNPC_ANIM_HIRAMEKI1, + aNPC_ANIM_HYUUU1, + aNPC_ANIM_LOVELOVE1, + aNPC_ANIM_MUUUUU1, + aNPC_ANIM_OTIKOMU1, + aNPC_ANIM_SHITUREN1, + aNPC_ANIM_WARUDAKUMI1, + aNPC_ANIM_NEBOKE1, + aNPC_ANIM_LOVE1, + aNPC_ANIM_NIKO1, + aNPC_ANIM_MUSU1, + aNPC_ANIM_KOMARI1, + aNPC_ANIM_SMILE_D1, + aNPC_ANIM_GAAAN_D1, + aNPC_ANIM_HIRAMEKI_D1, + aNPC_ANIM_HA_D1, + aNPC_ANIM_MUSU_D1, + aNPC_ANIM_NIKO_D1, + aNPC_ANIM_KOMARI_D1, + aNPC_ANIM_HATE_D1, + aNPC_ANIM_KEIREI1, + aNPC_ANIM_PUNPUN_R1, + aNPC_ANIM_MUSU_R1, + aNPC_ANIM_HYUUU_R1, + aNPC_ANIM_A_R1, + aNPC_ANIM_AKIRERU_R1, + aNPC_ANIM_MATAROU_R1, + aNPC_ANIM_GEKIDO_R1, + aNPC_ANIM_HA_E1, + aNPC_ANIM_KIEEEEI1, + aNPC_ANIM_A2_R1, + }; + // clang-format on + + // clang-format off + static s16 eff_idx2[43] = { + -1, + aNPC_ANIM_MUKA2, + aNPC_ANIM_GAAAN2, + aNPC_ANIM_SMILE2, + aNPC_ANIM_HA2, + aNPC_ANIM_PUNPUN2, + aNPC_ANIM_A2, + aNPC_ANIM_ASERU2, + aNPC_ANIM_BURUBURU2, + aNPC_ANIM_GOUKYU2, + aNPC_ANIM_HAPPY2, + aNPC_ANIM_HATE2, + aNPC_ANIM_HIRAMEKI2, + aNPC_ANIM_HYUUU2, + aNPC_ANIM_LOVELOVE2, + aNPC_ANIM_MUUUUU2, + aNPC_ANIM_OTIKOMU2, + aNPC_ANIM_SHITUREN2, + aNPC_ANIM_WARUDAKUMI2, + aNPC_ANIM_NEBOKE2, + aNPC_ANIM_LOVE2, + aNPC_ANIM_NIKO1, + aNPC_ANIM_MUSU1, + aNPC_ANIM_KOMARI1, + aNPC_ANIM_SMILE_D2, + aNPC_ANIM_GAAAN_D2, + aNPC_ANIM_HIRAMEKI_D2, + aNPC_ANIM_HA_D2, + aNPC_ANIM_MUSU_D1, + aNPC_ANIM_NIKO_D1, + aNPC_ANIM_KOMARI_D1, + aNPC_ANIM_HATE_D2, + aNPC_ANIM_KEIREI1, + aNPC_ANIM_PUNPUN_R2, + aNPC_ANIM_MUSU_R1, + aNPC_ANIM_HYUUU_R2, + aNPC_ANIM_A_R2, + aNPC_ANIM_AKIRERU_R2, + aNPC_ANIM_MATAROU_R2, + aNPC_ANIM_GEKIDO_R2, + aNPC_ANIM_HA_E2, + aNPC_ANIM_KIEEEEI2, + aNPC_ANIM_A_R2, + }; + // clang-format on + + // clang-format off + static s16 eff_idx_f[43] = { + -1, + aNPC_ANIM_MUKA1, + aNPC_ANIM_GAAAN1, + aNPC_ANIM_SMILE_F1, + aNPC_ANIM_HA_F1, + aNPC_ANIM_PUNPUN1, + aNPC_ANIM_A_F1, + aNPC_ANIM_ASERU_F1, + aNPC_ANIM_BURUBURU1, + aNPC_ANIM_GOUKYU1, + aNPC_ANIM_HAPPY_F1, + aNPC_ANIM_HATE_F1, + aNPC_ANIM_HIRAMEKI1, + aNPC_ANIM_HYUUU1, + aNPC_ANIM_LOVELOVE_F1, + aNPC_ANIM_MUUUUU_F1, + aNPC_ANIM_OTIKOMU1, + aNPC_ANIM_SHITUREN1, + aNPC_ANIM_WARUDAKUMI1, + aNPC_ANIM_NEBOKE1, + aNPC_ANIM_LOVE1, + aNPC_ANIM_NIKO_F1, + aNPC_ANIM_MUSU_F1, + aNPC_ANIM_KOMARI_F1, + aNPC_ANIM_SMILE_D1, + aNPC_ANIM_GAAAN_D1, + aNPC_ANIM_HIRAMEKI_D1, + aNPC_ANIM_HA_D1, + aNPC_ANIM_MUSU_D1, + aNPC_ANIM_NIKO_D1, + aNPC_ANIM_KOMARI_D1, + aNPC_ANIM_HATE_D1, + aNPC_ANIM_KEIREI1, + aNPC_ANIM_PUNPUN_R1, + aNPC_ANIM_MUSU_R1, + aNPC_ANIM_HYUUU_R1, + aNPC_ANIM_A_R1, + aNPC_ANIM_AKIRERU_R1, + aNPC_ANIM_MATAROU_R1, + aNPC_ANIM_GEKIDO_R1, + aNPC_ANIM_HA_E1, + aNPC_ANIM_KIEEEEI1, + aNPC_ANIM_A2_R1, + }; + // clang-format on + + // clang-format off + static s16 eff_idx_f2[43] = { + -1, + aNPC_ANIM_MUKA2, + aNPC_ANIM_GAAAN2, + aNPC_ANIM_SMILE_F2, + aNPC_ANIM_HA_F2, + aNPC_ANIM_PUNPUN2, + aNPC_ANIM_A_F2, + aNPC_ANIM_ASERU_F2, + aNPC_ANIM_BURUBURU2, + aNPC_ANIM_GOUKYU2, + aNPC_ANIM_HAPPY_F2, + aNPC_ANIM_HATE_F2, + aNPC_ANIM_HIRAMEKI2, + aNPC_ANIM_HYUUU2, + aNPC_ANIM_LOVELOVE_F2, + aNPC_ANIM_MUUUUU_F2, + aNPC_ANIM_OTIKOMU2, + aNPC_ANIM_SHITUREN2, + aNPC_ANIM_WARUDAKUMI2, + aNPC_ANIM_NEBOKE2, + aNPC_ANIM_LOVE2, + aNPC_ANIM_NIKO_F1, + aNPC_ANIM_MUSU_F1, + aNPC_ANIM_KOMARI_F1, + aNPC_ANIM_SMILE_D2, + aNPC_ANIM_GAAAN_D2, + aNPC_ANIM_HIRAMEKI_D2, + aNPC_ANIM_HA_D2, + aNPC_ANIM_MUSU_D1, + aNPC_ANIM_NIKO_D1, + aNPC_ANIM_KOMARI_D1, + aNPC_ANIM_HATE_D2, + aNPC_ANIM_KEIREI1, + aNPC_ANIM_PUNPUN_R2, + aNPC_ANIM_MUSU_R1, + aNPC_ANIM_HYUUU_R2, + aNPC_ANIM_A_R2, + aNPC_ANIM_AKIRERU_R2, + aNPC_ANIM_MATAROU_R2, + aNPC_ANIM_GEKIDO_R2, + aNPC_ANIM_HA_E2, + aNPC_ANIM_KIEEEEI2, + aNPC_ANIM_A_R2, + }; + // clang-format on + + // clang-format off + static s16 eff_idx_i[43] = { + -1, + aNPC_ANIM_MUKA1, + aNPC_ANIM_GAAAN1, + aNPC_ANIM_SMILE1, + aNPC_ANIM_HA_I1, + aNPC_ANIM_PUNPUN1, + aNPC_ANIM_A1, + aNPC_ANIM_ASERU_I1, + aNPC_ANIM_BURUBURU1, + aNPC_ANIM_GOUKYU1, + aNPC_ANIM_HAPPY_I1, + aNPC_ANIM_HATE_I1, + aNPC_ANIM_HIRAMEKI1, + aNPC_ANIM_HYUUU1, + aNPC_ANIM_LOVELOVE1, + aNPC_ANIM_MUUUUU_I1, + aNPC_ANIM_OTIKOMU1, + aNPC_ANIM_SHITUREN_I1, + aNPC_ANIM_WARUDAKUMI1, + aNPC_ANIM_NEBOKE1, + aNPC_ANIM_LOVE_I1, + aNPC_ANIM_NIKO_I1, + aNPC_ANIM_MUSU_I1, + aNPC_ANIM_KOMARI_I1, + aNPC_ANIM_SMILE_D1, + aNPC_ANIM_GAAAN_D1, + aNPC_ANIM_HIRAMEKI_D1, + aNPC_ANIM_HA_D1, + aNPC_ANIM_MUSU_D1, + aNPC_ANIM_NIKO_D1, + aNPC_ANIM_KOMARI_D1, + aNPC_ANIM_HATE_D1, + aNPC_ANIM_KEIREI1, + aNPC_ANIM_PUNPUN_R1, + aNPC_ANIM_MUSU_R1, + aNPC_ANIM_HYUUU_R1, + aNPC_ANIM_A_R1, + aNPC_ANIM_AKIRERU_R1, + aNPC_ANIM_MATAROU_R1, + aNPC_ANIM_GEKIDO_R1, + aNPC_ANIM_HA_E1, + aNPC_ANIM_KIEEEEI1, + aNPC_ANIM_A2_R1, + }; + // clang-format on + + // clang-format off + static s16 eff_idx_i2[43] = { + -1, + aNPC_ANIM_MUKA2, + aNPC_ANIM_GAAAN2, + aNPC_ANIM_SMILE2, + aNPC_ANIM_HA_I2, + aNPC_ANIM_PUNPUN2, + aNPC_ANIM_A2, + aNPC_ANIM_ASERU_I2, + aNPC_ANIM_BURUBURU2, + aNPC_ANIM_GOUKYU2, + aNPC_ANIM_HAPPY_I2, + aNPC_ANIM_HATE_I2, + aNPC_ANIM_HIRAMEKI2, + aNPC_ANIM_HYUUU2, + aNPC_ANIM_LOVELOVE2, + aNPC_ANIM_MUUUUU_I2, + aNPC_ANIM_OTIKOMU2, + aNPC_ANIM_SHITUREN_I2, + aNPC_ANIM_WARUDAKUMI2, + aNPC_ANIM_NEBOKE2, + aNPC_ANIM_LOVE_I2, + aNPC_ANIM_NIKO_I1, + aNPC_ANIM_MUSU_I1, + aNPC_ANIM_KOMARI_I1, + aNPC_ANIM_SMILE_D2, + aNPC_ANIM_GAAAN_D2, + aNPC_ANIM_HIRAMEKI_D2, + aNPC_ANIM_HA_D2, + aNPC_ANIM_MUSU_D1, + aNPC_ANIM_NIKO_D1, + aNPC_ANIM_KOMARI_D1, + aNPC_ANIM_HATE_D2, + aNPC_ANIM_KEIREI1, + aNPC_ANIM_PUNPUN_R2, + aNPC_ANIM_MUSU_R1, + aNPC_ANIM_HYUUU_R2, + aNPC_ANIM_A_R2, + aNPC_ANIM_AKIRERU_R2, + aNPC_ANIM_MATAROU_R2, + aNPC_ANIM_GEKIDO_R2, + aNPC_ANIM_HA_E2, + aNPC_ANIM_KIEEEEI2, + aNPC_ANIM_A_R2, + }; + // clang-format on + + NPC_ACTOR* nactorx = (NPC_ACTOR*)actorx; + int order = mDemo_Get_OrderValue(mDemo_ORDER_NPC0, 0); + int last_order = nactorx->talk_info.demo_code; + s16* eff_idx_p; + s16* eff_idx2_p; + + if (nactorx->left_hand.item == EMPTY_NO) { + eff_idx_p = eff_idx; + eff_idx2_p = eff_idx2; + } else if (ITEM_IS_FISH(nactorx->left_hand.item) == TRUE) { + eff_idx_p = eff_idx_f; + eff_idx2_p = eff_idx_f2; + } else { + eff_idx_p = eff_idx_i; + eff_idx2_p = eff_idx_i2; + } + + if (order != 0) { + int seqNo; + int talk = TRUE; + + if (order == aNPC_MANPU_CODE_RESET) { + seqNo = aNPC_ANIM_TALK1; + } else if (order == aNPC_MANPU_CODE_RESET_SIT) { + seqNo = aNPC_ANIM_SITDOWN_WAIT_D1; + } else if (order == aNPC_MANPU_CODE_RESET_KEKE) { + seqNo = aNPC_ANIM_WAIT_E1; + } else { + seqNo = eff_idx_p[order]; + talk = FALSE; + } + + aNPC_Animation_init(actorx, seqNo, talk); + nactorx->talk_info.demo_code = order; + } else if (last_order != aNPC_MANPU_CODE_NONE && nactorx->draw.animation_id == eff_idx_p[last_order] && + nactorx->draw.main_animation_state == cKF_STATE_STOPPED) { + aNPC_Animation_init(actorx, eff_idx2_p[last_order], FALSE); + } + + mDemo_Set_OrderValue(mDemo_ORDER_NPC0, 0, 0); +} + +static void aNPC_clear_timing_demoCode(int type) { + if (type == 0) { + mDemo_Set_OrderValue(mDemo_ORDER_NPC0, 1, 0); + } else { + mDemo_Set_OrderValue(mDemo_ORDER_NPC0, 3, 0); + } + + mDemo_Set_OrderValue(mDemo_ORDER_NPC1, 0, 0); + mDemo_Set_OrderValue(mDemo_ORDER_NPC1, 1, 0); + mDemo_Set_OrderValue(mDemo_ORDER_NPC1, 2, 0); +} + +static int aNPC_check_timing_demoCode(ACTOR* actorx) { + NPC_ACTOR* nactorx = (NPC_ACTOR*)actorx; + int order = mDemo_Get_OrderValue(mDemo_ORDER_NPC0, 3); + int type = 1; + int ret = TRUE; + + switch (order) { + default: + order = mDemo_Get_OrderValue(mDemo_ORDER_NPC0, 1); + type = 0; + break; + case 2: + case 3: + break; + } + + switch (order) { + case 3: + case 5: { + u16 args[aNPC_REQUEST_ARG_NUM]; + + bzero(args, sizeof(args)); + args[0] = mDemo_Get_OrderValue(mDemo_ORDER_NPC1, 0); + if (aNPC_set_request_act(nactorx, 4, aNPC_ACT_GET, aNPC_ACT_TYPE_DEFAULT, args) == TRUE) { + aNPC_clear_timing_demoCode(type); + ret = FALSE; + } + break; + } + case 2: + case 4: { + u16 args[aNPC_REQUEST_ARG_NUM]; + + bzero(args, sizeof(args)); + args[0] = mDemo_Get_OrderValue(mDemo_ORDER_NPC1, 0); + args[1] = mDemo_Get_OrderValue(mDemo_ORDER_NPC1, 1); + args[2] = mDemo_Get_OrderValue(mDemo_ORDER_NPC1, 2); + if (aNPC_set_request_act(nactorx, 4, aNPC_ACT_TRANS, aNPC_ACT_TYPE_DEFAULT, args) == TRUE) { + aNPC_clear_timing_demoCode(type); + ret = FALSE; + } + break; + } + case 15: { + if (aNPC_set_request_act(nactorx, 4, aNPC_ACT_CHANGE_CLOTH, aNPC_ACT_TYPE_DEFAULT, aNPC_req_default_data) == TRUE) { + Common_Set(npc_chg_cloth, Now_Private->cloth.item); + aNPC_clear_timing_demoCode(type); + ret = FALSE; + } + break; + } + } + + return ret; +} + +static void aNPC_check_feel_demoCode(ACTOR* actorx) { + int order = mDemo_Get_OrderValue(mDemo_ORDER_NPC0, 2); + NPC_ACTOR* nactorx = (NPC_ACTOR*)actorx; + + if (order != 0) { + int timer = mDemo_Get_OrderValue(mDemo_ORDER_NPC0, 8); + + if (order >= mNpc_FEEL_ALL_NUM) { + mDemo_Set_OrderValue(mDemo_ORDER_NPC0, 2, 0); + mDemo_Set_OrderValue(mDemo_ORDER_NPC0, 8, 0); + return; + } + + switch (order) { + case mNpc_FEEL_6: + break; + case mNpc_FEEL_PITFALL: + order = mNpc_FEEL_NORMAL; + break; + case mNpc_FEEL_UZAI_0: + order = aNPC_uzai_feel[mNpc_GetNpcLooks(actorx)]; + break; + } + + aNPC_set_feel_info(nactorx, order, timer); + mDemo_Set_OrderValue(mDemo_ORDER_NPC0, 2, 0); + mDemo_Set_OrderValue(mDemo_ORDER_NPC0, 8, 0); + } +} + +static void aNPC_setup_talk_start(NPC_ACTOR* nactorx, GAME* game) { + ACTOR* playerx = GET_PLAYER_ACTOR_GAME_ACTOR(game); + + nactorx->palActor = playerx; + if (nactorx->talk_info.turn == aNPC_TALK_TURN_NORMAL) { + aNPC_set_dst_pos(nactorx, playerx->world.position.x, playerx->world.position.z); + nactorx->movement.mv_angl -= nactorx->_174.y; + } + + nactorx->request.umb_flag = FALSE; + nactorx->condition_info.greeting_flag = FALSE; + nactorx->condition_info.talk_condition = aNPC_TALK_TYPE_START; + nactorx->condition_info.talk_demo_flg_save = nactorx->condition_info.demo_flg; +} + +static void aNPC_setup_talk_end(NPC_ACTOR* nactorx) { + nactorx->palActor = NULL; + if (nactorx->palActorIgnoreTimer >= 0) { + nactorx->palActorIgnoreTimer = 600; + } + nactorx->condition_info.talk_condition = aNPC_TALK_TYPE_NONE; + if (nactorx->think.force_call_flag != aNPC_FORCE_CALL_NONE) { + nactorx->think.force_call_timer = 300; + nactorx->think.force_call_flag = aNPC_FORCE_CALL_NONE; + } + nactorx->talk_info.feel = 0xFF; + nactorx->condition_info.demo_flg = nactorx->condition_info.talk_demo_flg_save; +} + +static void aNPC_set_talk_info_talk_request_check(ACTOR* actorx) { + NPC_ACTOR* nactorx = (NPC_ACTOR*)actorx; + int msg_no; + + if (mNpc_CheckIslandAnimal(nactorx->npc_info.animal) == TRUE) { + msg_no = 0x34AC + nactorx->npc_info.animal->id.looks * 3 + RANDOM(3); + } else { + msg_no = 0x075F + nactorx->npc_info.animal->id.looks * 3 + RANDOM(3); + } + + mDemo_Set_msg_num(msg_no); + nactorx->think.force_call_flag = aNPC_FORCE_CALL_SET; +} + +static void aNPC_talk_request_event_npc(ACTOR* actorx, GAME* game) { + NPC_ACTOR* nactorx = (NPC_ACTOR*)actorx; + + if ((mDemo_Check(mDemo_TYPE_SPEAK, actorx) == TRUE || mDemo_Check(mDemo_TYPE_SPEECH, actorx) == TRUE || + mDemo_Check(mDemo_TYPE_TALK, actorx) == TRUE) && + !mDemo_Check_ListenAble()) { + aNPC_setup_talk_start(nactorx, game); + } else { + GAME_PLAY* play = (GAME_PLAY*)game; + + if (play->submenu.process_status == mSM_PROCESS_WAIT && play->submenu.wait_timer == 0) { + if (nactorx->talk_info.talk_request_proc != NULL) { + (*nactorx->talk_info.talk_request_proc)(actorx, game); + } else { + mDemo_Request(mDemo_TYPE_TALK, actorx, NULL); + } + } + } +} + +static int aNPC_normal_talk_request(ACTOR* actorx, GAME* game) { + NPC_ACTOR* nactorx = (NPC_ACTOR*)actorx; + int ret = FALSE; + + if (CLIP(quest_manager_clip)->talk_request_proc != NULL && + CLIP(quest_manager_clip)->talk_request_proc(actorx) == TRUE) { + nactorx->think.force_call_flag = aNPC_FORCE_CALL_NONE; + aNPC_setup_talk_start(nactorx, game); + ret = TRUE; + } + + return ret; +} + +static void aNPC_set_talk_info_force_call(ACTOR* actorx) { + NPC_ACTOR* nactorx = (NPC_ACTOR*)actorx; + + mDemo_Set_msg_num(nactorx->think.force_call_msg_no); + mDemo_Set_camera(nactorx->think.force_call_camera_type); + nactorx->think.force_call_msg_no = -1; + nactorx->think.force_call_camera_type = CAMERA2_PROCESS_NORMAL; + nactorx->think.force_call_flag = aNPC_FORCE_CALL_SET; +} + +static int aNPC_force_talk_request(ACTOR* actorx) { + NPC_ACTOR* nactorx = (NPC_ACTOR*)actorx; + s8* friendship_p = nactorx->condition_info.friendship; + int ret = FALSE; + + if (nactorx->think.force_call_msg_no != -1) { + mDemo_Request(mDemo_TYPE_SPEAK, actorx, &aNPC_set_talk_info_force_call); + ret = TRUE; + } else if (friendship_p != NULL) { + int friendship = *friendship_p + nactorx->condition_info.over_friendship; + + if (friendship > 0x80 && nactorx->action.type == aNPC_ACT_TYPE_SEARCH && + nactorx->action.act_obj == aNPC_ACT_OBJ_PLAYER && nactorx->think.force_call_timer == 0 && + actorx->player_distance_xz < 80.0f && ABS(actorx->player_distance_y) < 60.0f) { + mDemo_Request(mDemo_TYPE_SPEAK, actorx, &aNPC_set_talk_info_talk_request_check); + ret = TRUE; + } + } + + return ret; +} + +static void aNPC_talk_request_normal_npc(ACTOR* actorx, GAME* game) { + NPC_ACTOR* nactorx = (NPC_ACTOR*)actorx; + + if (mDemo_Check(mDemo_TYPE_TALK, actorx) == TRUE) { + nactorx->think.force_call_flag = aNPC_FORCE_CALL_NONE; + } + + switch (nactorx->think.force_call_flag) { + case aNPC_FORCE_CALL_NONE: + aNPC_normal_talk_request(actorx, game); + break; + case aNPC_FORCE_CALL_REQUEST: + if (!aNPC_force_talk_request(actorx) && aNPC_normal_talk_request(actorx, game) == TRUE) { + nactorx->think.force_call_flag = aNPC_FORCE_CALL_NONE; + } + break; + case aNPC_FORCE_CALL_SET: + if (mDemo_Check(mDemo_TYPE_SPEAK, actorx) == TRUE) { + aNPC_setup_talk_start(nactorx, game); + nactorx->think.force_call_flag = aNPC_FORCE_CALL_START; + } + break; + } +} + +static void aNPC_talk_request_check(ACTOR* actorx, GAME* game) { + NPC_ACTOR* nactorx = (NPC_ACTOR*)actorx; + + if ((nactorx->condition_info.demo_flg & aNPC_COND_DEMO_SKIP_TALK_CHECK) == 0 && + nactorx->condition_info.talk_condition == aNPC_TALK_TYPE_NONE && !nactorx->condition_info.hide_flg) { + if (mEv_CheckTitleDemo() == 0 || mEv_CheckTitleDemo() == -9) { + if (nactorx->action.idx != aNPC_ACT_TALK) { + if (ITEM_NAME_GET_TYPE(actorx->npc_id) == NAME_TYPE_SPNPC && + (nactorx->npc_info.animal == NULL || nactorx->npc_info.animal->mood != mNpc_FEEL_PITFALL)) { + aNPC_talk_request_event_npc(actorx, game); + } else { + aNPC_talk_request_normal_npc(actorx, game); + } + } + } + } +} diff --git a/src/actor/npc/ac_npc_think.c_inc b/src/actor/npc/ac_npc_think.c_inc new file mode 100644 index 00000000..f0ffc514 --- /dev/null +++ b/src/actor/npc/ac_npc_think.c_inc @@ -0,0 +1,757 @@ +static int aNPC_check_uzai_cross(NPC_ACTOR* nactorx, GAME_PLAY* play) { + int ret = FALSE; + + if (nactorx->actor_class.player_distance_xz < mFI_UNIT_BASE_SIZE_F && + ABS(nactorx->actor_class.player_distance_y) < mFI_UNIT_BASE_SIZE_F) { + if (!F32_IS_ZERO(gamePT->mcon.adjusted_pR)) { + ACTOR* playerx = GET_PLAYER_ACTOR_ACTOR(play); + + if (playerx != NULL) { + s16 npc_angleY = nactorx->actor_class.player_angle_y + DEG2SHORT_ANGLE2(180.0f); + s16 d_angleY = npc_angleY - playerx->world.angle.y; + + if (ABS(d_angleY) < DEG2SHORT_ANGLE2(135.0f)) { + ret = TRUE; + } + } + } + } + + return ret; +} + +static int aNPC_check_uzai(NPC_ACTOR* nactorx, GAME_PLAY* play) { + static int max_uzai_cross[] = { 600, 240 }; + static int max_uzai_tool[] = { 3, 1 }; + // clang-format off + static int base_msg_no_table[][mNpc_LOOKS_NUM][2] = { + { + {0x2E47, 0x2E11}, + {0x2E52, 0x2E1C}, + {0x2E42, 0x2E0C}, + {0x2E5D, 0x2E27}, + {0x2E62, 0x2E2C}, + {0x2E6D, 0x2E37}, + }, + { + {0x358B, 0x3579}, + {0x358E, 0x357C}, + {0x3591, 0x357F}, + {0x3594, 0x3582}, + {0x3597, 0x3585}, + {0x359A, 0x3588}, + }, + }; + // clang-format on + int ret = FALSE; + + if (mEv_CheckTitleDemo() > 0 || (nactorx->condition_info.demo_flg & aNPC_COND_DEMO_SKIP_UZAI_CHECK)) { + nactorx->uzai.flag = 0; + return FALSE; + } + + if (nactorx->uzai.flag == 1) { + ret = TRUE; + } + + if (aNPC_IS_NRM_NPC(nactorx)) { + int mem_idx = + mNpc_GetAnimalMemoryIdx(&Now_Private->player_ID, nactorx->npc_info.animal->memories, ANIMAL_MEMORY_NUM); + + if (mem_idx != -1 && (nactorx->condition_info.demo_flg & aNPC_COND_DEMO_SKIP_LOVE_CHECK) == 0) { + int step = nactorx->uzai.step; + int type; + int flag_state; + + if (nactorx->uzai.flag != 1 && mDemo_Get_talk_actor() == NULL) { + if (aNPC_check_uzai_cross(nactorx, play) == TRUE) { + step += 2; + } else { + step -= 1; + } + } + + if (step > max_uzai_cross[nactorx->uzai.cross == 1] || + nactorx->uzai.tool == max_uzai_tool[nactorx->uzai.cross == 1]) { + Animal_c* animal = nactorx->npc_info.animal; + int msg_no; + f32 msg_max = 5; + int pushed = FALSE; + int islander = FALSE; + + if (mNpc_CheckIslandAnimal(animal) == TRUE) { + msg_max = 3; + islander = TRUE; + } + + if (nactorx->uzai.flag == 1) { + mISL_SetNowPlayerAction(mISL_PLAYER_ACTION_UZAI_HIT_NET); + mISL_SetNowPlayerAction(mISL_PLAYER_ACTION_UZAI_HIT); + } else { + mISL_SetNowPlayerAction(mISL_PLAYER_ACTION_UZAI_PUSHED); + nactorx->uzai.flag = 2; + pushed = TRUE; + } + + msg_no = base_msg_no_table[islander][animal->id.looks][pushed]; + if (aNPC_force_call_req_proc(nactorx, msg_no + (int)RANDOM_F(msg_max)) == TRUE) { + nactorx->uzai.tool = 0; + nactorx->uzai.cross = 1; + step = 0; + aNPC_set_feel_info(nactorx, aNPC_uzai_feel[mNpc_GetNpcLooks((ACTOR*)nactorx)], 1); + nactorx->think.force_call_camera_type = CAMERA2_PROCESS_TALK; + nactorx->uzai.flag = 0; + } + } else { + if (step < 0) { + step = 0; + } + + nactorx->uzai.flag = 0; + } + + nactorx->uzai.step = step; + } + } + + return ret; +} + +static void aNPC_ctrl_umbrella(NPC_ACTOR* nactorx) { + NPC_CONTROL_ACTOR* ctrl; + + if (nactorx->condition_info.talk_condition != aNPC_TALK_TYPE_NONE) { + return; + } + + if ((nactorx->condition_info.demo_flg & aNPC_COND_DEMO_SKIP_ITEM) != 0) { + return; + } + + ctrl = (NPC_CONTROL_ACTOR*)aNPC_ctrlActor; + switch (Common_Get(weather)) { + case mEnv_WEATHER_RAIN: + if (nactorx->right_hand.item_type == aNPC_ITEM_TYPE_UMBRELLA) { + return; + } + + if (nactorx->think.force_call_flag != aNPC_FORCE_CALL_NONE) { + return; + } + + if (nactorx->right_hand.umbrella_disabled_flag) { + return; + } + + if (nactorx->request.umb_flag == TRUE) { + nactorx->right_hand.requested_item_type = aNPC_ITEM_TYPE_UMBRELLA; + return; + } + + if (ctrl->umbrella_open_actor != NULL) { + return; + } + + if (ctrl->umbrella_open_timer != 0) { + return; + } + + nactorx->right_hand.requested_item_type = aNPC_ITEM_TYPE_UMBRELLA; + ctrl->umbrella_open_actor = (ACTOR*)nactorx; + nactorx->request.umb_flag = FALSE; + break; + + default: + if (nactorx->schedule.type == aNPC_SCHEDULE_TYPE_SLEEP) { + return; + } + + if (nactorx->right_hand.item_type == aNPC_ITEM_TYPE_UMBRELLA) { + nactorx->right_hand.requested_item_type = aNPC_ITEM_TYPE_PUTAWAY; + } + + nactorx->request.umb_flag = FALSE; + break; + } +} + +static int aNPC_check_obj_crs_player(NPC_ACTOR* nactorx) { + int ret = FALSE; + + if (ClObj_DID_COLLIDE(nactorx->collision.pipe.collision_obj)) { + if (nactorx->collision.pipe.collision_obj.collided_actor->part == ACTOR_PART_PLAYER) { + ret = TRUE; + } + } + + return ret; +} + +static int aNPC_check_entrance(NPC_ACTOR* nactorx) { + Anmhome_c* home_p; + int ret; + + ret = FALSE; + if ((nactorx->think.interrupt_flags & aNPC_THINK_INTERRUPT_ENTRANCE) != 0 && + nactorx->condition_info.entrance_flag == aNPC_ENTRANCE_TYPE_AT) { + if (!aNPC_check_obj_crs_player(nactorx)) { + u8 act = aNPC_ACT_WALK; + u16 arg_data[aNPC_REQUEST_ARG_NUM]; + xyz_t pos; + + bzero(arg_data, sizeof(arg_data)); + mFI_UtNum2CenterWpos(&pos, nactorx->condition_info.ut_x, nactorx->condition_info.ut_z + 1); + arg_data[2] = pos.x; + arg_data[3] = pos.z; + if (ABS(nactorx->actor_class.shape_info.rotation.y) >= DEG2SHORT_ANGLE2(22.5f)) { + act = aNPC_ACT_TURN; + } + + aNPC_set_request_act(nactorx, 2, act, aNPC_ACT_TYPE_TO_POINT, arg_data); + nactorx->movement.range_type = aNPC_MOVE_RANGE_TYPE_BLOCK; + } else { + aNPC_set_request_act(nactorx, 2, aNPC_ACT_WAIT, aNPC_ACT_TYPE_DEFAULT, aNPC_req_default_data); + } + + ret = TRUE; + } + + return ret; +} + +static void aNPC_turn_to_backward(NPC_ACTOR* nactorx, int angle) { + if (nactorx->action.idx != aNPC_ACT_TURN || nactorx->action.step == aNPC_ACTION_END_STEP) { + u16 arg_data[aNPC_REQUEST_ARG_NUM]; + ACTOR* actorx = (ACTOR*)nactorx; + s16 angleY = actorx->world.angle.y; + xyz_t pos; + u8 prio = 1; + + bzero(arg_data, sizeof(arg_data)); + angleY += angle; + pos.x = (int)(actorx->world.position.x + mFI_UT_WORLDSIZE_X_F * sin_s(angleY)); + pos.z = (int)(actorx->world.position.z + mFI_UT_WORLDSIZE_Z_F * cos_s(angleY)); + arg_data[2] = (int)pos.x; + arg_data[3] = (int)pos.z; + arg_data[4] = 0; + + if (nactorx->action.priority >= 1) { + prio = nactorx->action.priority; + } + + aNPC_set_request_act(nactorx, prio, aNPC_ACT_TURN, aNPC_ACT_TYPE_AVOID, arg_data); + } +} + +static int aNPC_avoid_wall(NPC_ACTOR* nactorx, int direction, int n) { + // clang-format off + static int add_angl[][2] = { + { DEG2SHORT_ANGLE2(22.5f), DEG2SHORT_ANGLE2(-22.5f) }, + { DEG2SHORT_ANGLE2(45.0f), DEG2SHORT_ANGLE2(-45.0f) }, + { DEG2SHORT_ANGLE2(90.0f), DEG2SHORT_ANGLE2(-90.0f) }, + }; + // clang-format on + + static u8 drt_data[] = { 1, 2 }; + ACTOR* actorx = (ACTOR*)nactorx; + s16 angle = actorx->world.angle.y + add_angl[n][direction]; + xyz_t pos; + int ret = FALSE; + + pos.x = (int)(actorx->world.position.x + sin_s(angle) * (2 * mFI_UT_WORLDSIZE_X_F)); + pos.z = (int)(actorx->world.position.z + cos_s(angle) * (2 * mFI_UT_WORLDSIZE_Z_F)); + + if (aNPC_moveRangeCheck(nactorx, NULL, pos, nactorx->movement.range_type) == TRUE && + (pos.x != nactorx->movement.avoid_pos_x || pos.z != nactorx->movement.avoid_pos_z)) { + if (n > 0) { + u16 arg_data[aNPC_REQUEST_ARG_NUM]; + u8 prio = 1; + + bzero(arg_data, sizeof(arg_data)); + arg_data[2] = (int)pos.x; + arg_data[3] = (int)pos.z; + arg_data[4] = drt_data[direction]; + + if (nactorx->action.priority >= 1) { + prio = nactorx->action.priority; + } + + aNPC_set_request_act(nactorx, prio, aNPC_ACT_TURN, aNPC_ACT_TYPE_AVOID, arg_data); + ret = TRUE; + } else { + aNPC_set_avoid_pos(nactorx, pos.x, pos.z, drt_data[direction]); + } + } else if (n < 2) { + ret = aNPC_avoid_wall(nactorx, direction, n + 1); + } else { + aNPC_turn_to_backward(nactorx, DEG2SHORT_ANGLE2(180.0f)); + ret = TRUE; + } + + return ret; +} + +static int aNPC_avoid_obstacle(NPC_ACTOR* nactorx) { + static int turn_angl_table[] = { DEG2SHORT_ANGLE2(112.5f), DEG2SHORT_ANGLE2(-112.5f) }; + int ret = FALSE; + + if ((nactorx->think.interrupt_flags & aNPC_THINK_INTERRUPT_OBSTACLE) != 0) { + switch (nactorx->collision.collision_flag) { + // case 0: + case 3: + switch (nactorx->movement.avoid_direction) { + case 0: + aNPC_turn_to_backward(nactorx, turn_angl_table[RANDOM(ARRAY_COUNT(turn_angl_table))]); + ret = TRUE; + break; + case 1: + ret = aNPC_avoid_wall(nactorx, 0, 0); + break; + case 2: + ret = aNPC_avoid_wall(nactorx, 1, 0); + break; + } + break; + case 1: + if (nactorx->movement.avoid_direction != 3) { + ret = aNPC_avoid_wall(nactorx, 1, 0); + } + break; + case 2: + if (nactorx->movement.avoid_direction != 3) { + ret = aNPC_avoid_wall(nactorx, 0, 0); + } + break; + } + } + + return ret; +} + +static int aNPC_chk_talk_start(NPC_ACTOR* nactorx) { + ACTOR* palActor = nactorx->palActor; + int ret = FALSE; + + if (palActor != NULL) { + switch (nactorx->condition_info.talk_condition) { + case aNPC_TALK_TYPE_NONE: { + ACTOR* actorx = (ACTOR*)nactorx; + + if (mDemo_IS_ACTOR_TALKING(actorx) || mDemo_IS_ACTOR_TALKING(palActor)) { + NPC_ACTOR* pal_nactorx = (NPC_ACTOR*)palActor; + + if (nactorx->palActor == palActor) { + nactorx->palActor = NULL; + } + + if (pal_nactorx->palActor == actorx) { + pal_nactorx->palActor = NULL; + } + } else { + aNPC_set_request_act(nactorx, 4, aNPC_ACT_GREETING, aNPC_ACT_TYPE_SEARCH, aNPC_req_default_data); + ret = TRUE; + } + } break; + case aNPC_TALK_TYPE_START: + aNPC_set_request_act(nactorx, 4, nactorx->talk_info.default_act, aNPC_ACT_TYPE_DEFAULT, + aNPC_req_default_data); + ret = TRUE; + break; + case aNPC_TALK_TYPE_CONTINUE: + if (aNPC_chk_right_hand(nactorx) == TRUE) { + aNPC_chk_left_hand(nactorx); + } + + ret = TRUE; + break; + } + } + + return ret; +} + +static int aNPC_check_clap(NPC_ACTOR* nactorx, GAME_PLAY* play) { + int ret = FALSE; + + if (aNPC_IS_NRM_NPC(nactorx) && aNPC_get_feel_info(nactorx) == mNpc_FEEL_NORMAL) { + if (mPlib_check_player_actor_main_index_catch_insect((GAME*)play) || + mPlib_check_player_actor_main_index_catch_fish((GAME*)play)) { + if (nactorx->actor_class.player_distance_xz < (3 * mFI_UNIT_BASE_SIZE_F)) { + s16 d_angle = nactorx->actor_class.shape_info.rotation.y - nactorx->actor_class.player_angle_y; + + if (ABS(d_angle) < DEG2SHORT_ANGLE2(67.5f)) { + ret = TRUE; + } + } + } + } + + return ret; +} + +static int aNPC_check_ball(NPC_ACTOR* nactorx, GAME_PLAY* play) { + int ret = FALSE; + + if (aNPC_IS_NRM_NPC(nactorx)) { + BALL_ACTOR* ball = (BALL_ACTOR*)Actor_info_name_search(&play->actor_info, mAc_PROFILE_BALL, ACTOR_PART_BG); + + if (ball != NULL && (ball->state_flags & aBALL_STATE_IN_HOLE) == 0) { + f32 dx = ball->actor_class.world.position.x - nactorx->actor_class.world.position.x; + f32 dz = ball->actor_class.world.position.z - nactorx->actor_class.world.position.z; + f32 dist = SQ(dx) + SQ(dz); + + if (dist < SQ(200.0f)) { + s16 angle = atans_table(dz, dx); + + if (ABS(angle) < DEG2SHORT_ANGLE2(67.5f)) { + ret = TRUE; + } + } + } + } + + return ret; +} + +static int aNPC_check_insect_and_gyoei(NPC_ACTOR* nactorx, GAME_PLAY* play) { + static u16 req_gyo_data[aNPC_REQUEST_ARG_NUM] = { aNPC_ACT_OBJ_FISH, 0, 0, 0, 0, 0 }; + static u16 req_ins_data[aNPC_REQUEST_ARG_NUM] = { aNPC_ACT_OBJ_INSECT, 0, 0, 0, 0, 0 }; + int ret = FALSE; + + if (aNPC_IS_NRM_NPC(nactorx) && aNPC_get_feel_info(nactorx) == mNpc_FEEL_NORMAL) { + f32 x = nactorx->actor_class.world.position.x; + f32 z = nactorx->actor_class.world.position.z; + f32 dx; + f32 dz; + f32 dist; + ACTOR* target = NULL; + + if (CLIP(gyo_clip) != NULL) { + target = CLIP(gyo_clip)->search_near_gyoei_proc(x, z); + } + + if (target != NULL) { + dx = target->world.position.x - x; + dz = target->world.position.z - z; + dist = SQ(dx) + SQ(dz); + + if (dist < SQ(140.0f)) { + aNPC_set_request_act(nactorx, 1, aNPC_ACT_CHASE_GYOEI, aNPC_ACT_TYPE_SEARCH, req_gyo_data); + ret = TRUE; + } + } else if (CLIP(insect_clip) != NULL) { + target = CLIP(insect_clip)->search_near_insect_proc(x, z, (GAME*)play); + + if (target != NULL) { + dx = target->world.position.x - x; + dz = target->world.position.z - z; + dist = SQ(dx) + SQ(dz); + + if (dist < SQ(100.0f)) { + aNPC_set_request_act(nactorx, 1, aNPC_ACT_CHASE_INSECT, aNPC_ACT_TYPE_SEARCH, req_ins_data); + ret = TRUE; + } + } + } + } + + return ret; +} + +static int aNPC_check_fatigue(NPC_ACTOR* nactorx) { + int ret = FALSE; + + if (aNPC_IS_NRM_NPC(nactorx)) { + switch (nactorx->action.type) { + case aNPC_ACT_TYPE_DEFAULT: + case aNPC_ACT_TYPE_TO_POINT: + if ((nactorx->think.interrupt_flags & aNPC_THINK_INTERRUPT_FATIGUE) != 0 && + nactorx->condition_info.fatigue >= 1600) { + ret = TRUE; + } + break; + } + } + + return ret; +} + +static void aNPC_think_demo_allways(NPC_ACTOR* nactorx, GAME_PLAY* play) { + if (nactorx->action.step == aNPC_ACTION_END_STEP) { + nactorx->condition_info.demo_flg = 0; + nactorx->think.end_flag = TRUE; + } +} + +static int aNPC_chk_pitfall(NPC_ACTOR* nactorx) { + mActor_name_t* fg_p = nactorx->condition_info.under_fg_p; + int ret = FALSE; + + if (fg_p != NULL) { + if (ITEM_IS_BURIED_PITFALL_HOLE(*fg_p) && aNPC_IS_NRM_NPC(nactorx)) { + CLIP(bg_item_clip) + ->pit_fall_proc(*fg_p, nactorx->condition_info.ut_x, nactorx->condition_info.ut_z, + nactorx->actor_class.npc_id); + nactorx->condition_info.pitfall_flag = 1; + nactorx->think.end_flag = TRUE; + ret = TRUE; + } + } + + return ret; +} + +static int aNPC_hate_player(NPC_ACTOR* nactorx) { + u16 arg_data[aNPC_REQUEST_ARG_NUM]; + int ret = FALSE; + + bzero(arg_data, sizeof(arg_data)); + arg_data[0] = aNPC_ACT_OBJ_PLAYER; + + if (nactorx->actor_class.player_distance_xz < (3 * mFI_UNIT_BASE_SIZE_F)) { + aNPC_set_request_act(nactorx, 1, aNPC_ACT_RUN, aNPC_ACT_TYPE_AVOID, arg_data); + ret = TRUE; + } else if (nactorx->actor_class.player_distance_xz < (4 * mFI_UNIT_BASE_SIZE_F)) { + aNPC_set_request_act(nactorx, 1, aNPC_ACT_WALK, aNPC_ACT_TYPE_AVOID, arg_data); + ret = TRUE; + } + + return ret; +} + +static int aNPC_love_player(NPC_ACTOR* nactorx, GAME_PLAY* play) { + int ret = FALSE; + + if (Now_Private->gender != mNpc_GetLooks2Sex(aNPC_GET_LOOKS(nactorx))) { + u8 next_act = aNPC_ACT_WAIT; + u8 act_type; + u16 arg_data[aNPC_REQUEST_ARG_NUM]; + + if (nactorx->think.force_call_flag == aNPC_FORCE_CALL_NONE && nactorx->think.force_call_timer == 0) { + nactorx->think.force_call_flag = aNPC_FORCE_CALL_REQUEST; + } + + if (nactorx->actor_class.player_distance_xz > (3 * mFI_UNIT_BASE_SIZE_F)) { + next_act = aNPC_ACT_RUN; + } else if (nactorx->actor_class.player_distance_xz > (1.5f * mFI_UNIT_BASE_SIZE_F)) { + next_act = aNPC_ACT_WALK; + } + + act_type = aNPC_ACT_TYPE_SEARCH; + bzero(arg_data, sizeof(arg_data)); + arg_data[0] = aNPC_ACT_OBJ_PLAYER; + + if (nactorx->movement.dst_pos_x != nactorx->movement.avoid_pos_x && + nactorx->movement.dst_pos_z != nactorx->movement.avoid_pos_z) { + xyz_t pos; + + pos.x = nactorx->movement.avoid_pos_x; + pos.z = nactorx->movement.avoid_pos_z; + if (aNPC_moveRangeCheck(nactorx, NULL, pos, nactorx->movement.range_type) == TRUE) { + arg_data[2] = (int)nactorx->movement.avoid_pos_x; + arg_data[3] = (int)nactorx->movement.avoid_pos_z; + act_type = aNPC_ACT_TYPE_TO_POINT; + } + } + + aNPC_set_request_act(nactorx, 1, next_act, act_type, arg_data); + nactorx->condition_info.demo_flg |= aNPC_COND_DEMO_SKIP_LOVE_CHECK; + ret = TRUE; + } + + return ret; +} + +static int aNPC_chk_friendship_lv(NPC_ACTOR* nactorx, GAME_PLAY* play) { + int ret = FALSE; + + switch (aNPC_chk_avoid_and_search(nactorx, play)) { + case aNPC_FRIENDSHIP_AVOID: + ret = aNPC_hate_player(nactorx); + break; + case aNPC_FRIENDSHIP_SEARCH: + ret = aNPC_love_player(nactorx, play); + break; + } + + return ret; +} + +static int aNPC_chk_friendship_sub(NPC_ACTOR* nactorx, GAME_PLAY* play) { + s8* friendship_p = nactorx->condition_info.friendship; + int ret = FALSE; + + nactorx->condition_info.demo_flg &= ~aNPC_COND_DEMO_SKIP_LOVE_CHECK; + if (friendship_p == NULL) { + if (aNPC_IS_NRM_NPC(nactorx) && aNPC_setP_friendship(nactorx) == TRUE) { + ret = aNPC_chk_friendship_lv(nactorx, play); + } + } else { + ret = aNPC_chk_friendship_lv(nactorx, play); + } + + return ret; +} + +static int aNPC_chk_friendship(NPC_ACTOR* nactorx, GAME_PLAY* play) { + int skip_flag = FALSE; + int ret = FALSE; + mNPS_schedule_c* sched_p = nactorx->npc_info.schedule; + + if (sched_p != NULL && sched_p->current_type == mNPS_SCHED_FIELD && sched_p->current_type != sched_p->saved_type && + !mNpc_CheckIslandAnimal(aNPC_GET_ANM(nactorx))) { + skip_flag = TRUE; + } + + if ((nactorx->think.interrupt_flags & aNPC_THINK_INTERRUPT_FRIENDSHIP) != 0 && !aNPC_IS_SP_NPC(nactorx) && + !skip_flag) { + switch (nactorx->action.idx) { + case aNPC_ACT_WAIT: + case aNPC_ACT_WALK: + case aNPC_ACT_RUN: + ret = aNPC_chk_friendship_sub(nactorx, play); + break; + default: + if (nactorx->action.step == aNPC_ACTION_END_STEP) { + ret = aNPC_chk_friendship_sub(nactorx, play); + } + break; + } + } + + return ret; +} + +static int aNPC_think_chk_interrupt_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + // clang-format off + static u16 aNPC_req_ball_search_data[aNPC_REQUEST_ARG_NUM] = { aNPC_ACT_OBJ_BALL, 0, 0, 0, 0, 0 }; + // clang-format on + int ret = FALSE; + + if (aNPC_chk_talk_start(nactorx) == TRUE) { + ret = TRUE; + } else { + aNPC_ctrl_umbrella(nactorx); + + if (aNPC_chk_pitfall(nactorx) == TRUE) { + ret = TRUE; + } else if (aNPC_chk_right_hand(nactorx) == FALSE) { + ret = TRUE; + } else if (aNPC_chk_left_hand(nactorx) == FALSE) { + ret = TRUE; + } else { + if (aNPC_check_uzai(nactorx, play) == TRUE) { + aNPC_set_request_act(nactorx, 2, aNPC_ACT_REACT_TOOL, aNPC_ACT_TYPE_DEFAULT, aNPC_req_default_data); + ret = TRUE; + } else if (aNPC_check_entrance(nactorx) == TRUE) { + ret = TRUE; + } else if (!F32_IS_ZERO(nactorx->actor_class.speed)) { + if (aNPC_check_clap(nactorx, play) == TRUE) { + aNPC_set_request_act(nactorx, 1, aNPC_ACT_CLAP, aNPC_ACT_TYPE_DEFAULT, aNPC_req_default_data); + ret = TRUE; + } else if (aNPC_check_fatigue(nactorx) == TRUE) { + aNPC_set_request_act(nactorx, 1, aNPC_ACT_WAIT, aNPC_ACT_TYPE_DEFAULT, aNPC_req_default_data); + ret = TRUE; + } else if (nactorx->collision.turn_flag == TRUE) { + s16 angle = nactorx->collision.turn_angle; + u16 arg_data[aNPC_REQUEST_ARG_NUM]; + f32 dx; + f32 dz; + + bzero(arg_data, sizeof(arg_data)); + dx = nactorx->actor_class.world.position.x + mFI_UT_WORLDSIZE_X_F * sin_s(angle); + dz = nactorx->actor_class.world.position.z + mFI_UT_WORLDSIZE_Z_F * cos_s(angle); + arg_data[2] = (int)dx; + arg_data[3] = (int)dz; + aNPC_set_dst_pos(nactorx, dx, dz); + aNPC_set_request_act(nactorx, 1, aNPC_ACT_TURN, aNPC_ACT_TYPE_TO_POINT, arg_data); + ret = TRUE; + } else if (aNPC_avoid_obstacle(nactorx) == TRUE) { + ret = TRUE; + } else if (aNPC_check_ball(nactorx, play) == TRUE) { + aNPC_set_request_act(nactorx, 1, aNPC_ACT_RUN, aNPC_ACT_TYPE_SEARCH, aNPC_req_ball_search_data); + ret = TRUE; + } else if (aNPC_check_insect_and_gyoei(nactorx, play) == TRUE) { + ret = TRUE; + } + } else { + if (aNPC_check_clap(nactorx, play) == TRUE) { + aNPC_set_request_act(nactorx, 1, aNPC_ACT_CLAP, aNPC_ACT_TYPE_DEFAULT, aNPC_req_default_data); + ret = TRUE; + } + } + + if (ret == FALSE) { + ret = aNPC_chk_friendship(nactorx, play); + } + } + } + + return ret; +} + +static void aNPC_think_wait_init_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + aNPC_set_request_act(nactorx, 1, aNPC_ACT_WAIT, aNPC_ACT_TYPE_DEFAULT, aNPC_req_default_data); +} + +static void aNPC_think_wait_proc(NPC_ACTOR* nactorx, GAME_PLAY* play, int proc_type) { + if (proc_type == aNPC_THINK_PROC_INIT) { + aNPC_think_wait_init_proc(nactorx, play); + } +} + +static void aNPC_think_special_proc(NPC_ACTOR* nactorx, GAME_PLAY* play, int proc_type) { + (*nactorx->think.think_proc)(nactorx, play, proc_type); +} + +#include "../src/actor/npc/ac_npc_think_wander.c_inc" +#include "../src/actor/npc/ac_npc_think_go_home.c_inc" +#include "../src/actor/npc/ac_npc_think_into_house.c_inc" +#include "../src/actor/npc/ac_npc_think_leave_house.c_inc" +#include "../src/actor/npc/ac_npc_think_in_block.c_inc" +#include "../src/actor/npc/ac_npc_think_pitfall.c_inc" +#include "../src/actor/npc/ac_npc_think_sleep.c_inc" + +static aNPC_THINK_PROC aNPC_think_proc_tbl[] = { + &aNPC_think_wait_proc, + &aNPC_think_wander_proc, + &aNPC_think_wander_proc, + &aNPC_think_go_home_proc, + &aNPC_think_into_house_proc, + &aNPC_think_leave_house_proc, + &aNPC_think_in_block_proc, + &aNPC_think_pitfall_proc, + &aNPC_think_sleep_proc, + &aNPC_think_special_proc, +}; + +static void aNPC_think_init_proc(NPC_ACTOR* nactorx, GAME_PLAY* play, int think_idx) { + nactorx->think.interrupt_flags = aNPC_THINK_INTERRUPT_ENTRANCE | aNPC_THINK_INTERRUPT_OBSTACLE | aNPC_THINK_INTERRUPT_FATIGUE | aNPC_THINK_INTERRUPT_FRIENDSHIP; + nactorx->think.idx = think_idx; + (*aNPC_think_proc_tbl[think_idx])(nactorx, play, aNPC_THINK_PROC_INIT); + nactorx->think.end_flag = FALSE; +} + +static void aNPC_think_main_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + int think_idx = nactorx->think.idx; + + (*aNPC_think_proc_tbl[think_idx])(nactorx, play, aNPC_THINK_PROC_MAIN); +} + +static int aNPC_think_proc(NPC_ACTOR* nactorx, GAME_PLAY* play, int think_idx, int proc_type) { + int ret = FALSE; + + switch (proc_type) { + case aNPC_THINK_TYPE_INIT: + aNPC_think_init_proc(nactorx, play, think_idx); + break; + case aNPC_THINK_TYPE_CHK_INTERRUPT: + ret = aNPC_think_chk_interrupt_proc(nactorx, play); + break; + case aNPC_THINK_TYPE_MAIN: + aNPC_think_main_proc(nactorx, play); + break; + } + + return ret; +} diff --git a/src/actor/npc/ac_npc_think_go_home.c_inc b/src/actor/npc/ac_npc_think_go_home.c_inc new file mode 100644 index 00000000..522106e6 --- /dev/null +++ b/src/actor/npc/ac_npc_think_go_home.c_inc @@ -0,0 +1,61 @@ +static void aNPC_set_request_go_home_act(NPC_ACTOR* nactorx) { + u16 arg_data[aNPC_REQUEST_ARG_NUM]; + f32 pos_x; + f32 pos_z; + + bzero(arg_data, sizeof(arg_data)); + pos_x = nactorx->npc_info.list->house_position.x + 20.0f; + pos_z = nactorx->npc_info.list->house_position.z + 60.0f; + aNPC_set_dst_pos(nactorx, pos_x, pos_z); + arg_data[2] = (int)pos_x; + arg_data[3] = (int)pos_z; + aNPC_set_request_act(nactorx, 1, aNPC_ACT_WALK, aNPC_ACT_TYPE_DEFAULT, arg_data); +} + +static int aNPC_think_go_home_check_entrance(NPC_ACTOR* nactorx, GAME_PLAY* play) { + int ret = FALSE; + + if (aNPC_check_entrance_humanoid(nactorx, play) == TRUE) { + aNPC_set_request_act(nactorx, 1, aNPC_ACT_WAIT, aNPC_ACT_TYPE_DEFAULT, aNPC_req_default_data); + ret = TRUE; + } + + return ret; +} + +static void aNPC_think_go_home_next_act(NPC_ACTOR* nactorx, GAME_PLAY* play) { + if (nactorx->condition_info.entrance_flag) { + if (nactorx->action.step == aNPC_ACTION_END_STEP && aNPC_think_go_home_check_entrance(nactorx, play) == FALSE) { + if (nactorx->action.idx == aNPC_ACT_WALK) { + nactorx->think.end_flag = TRUE; + } else { + aNPC_set_request_go_home_act(nactorx); + } + } + } else { + if (nactorx->action.step == aNPC_ACTION_END_STEP && nactorx->action.idx != aNPC_ACT_WALK) { + aNPC_set_request_go_home_act(nactorx); + } + } +} + +static void aNPC_think_go_home_main_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + if (!aNPC_think_chk_interrupt_proc(nactorx, play) && mDemo_CAN_ACTOR_TALK((ACTOR*)nactorx)) { + aNPC_think_go_home_next_act(nactorx, play); + } +} + +static void aNPC_think_go_home_init_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + nactorx->movement.range_type = aNPC_MOVE_RANGE_TYPE_BLOCK; + nactorx->think.interrupt_flags = aNPC_THINK_INTERRUPT_OBSTACLE; + aNPC_set_request_go_home_act(nactorx); +} + +static void aNPC_think_go_home_proc(NPC_ACTOR* nactorx, GAME_PLAY* play, int proc_type) { + static aNPC_SUB_PROC think_proc[] = { + &aNPC_think_go_home_init_proc, + &aNPC_think_go_home_main_proc, + }; + + (*think_proc[proc_type])(nactorx, play); +} diff --git a/src/actor/npc/ac_npc_think_in_block.c_inc b/src/actor/npc/ac_npc_think_in_block.c_inc new file mode 100644 index 00000000..400f2212 --- /dev/null +++ b/src/actor/npc/ac_npc_think_in_block.c_inc @@ -0,0 +1,130 @@ +static void aNPC_think_in_block_chg_native_info(ACTOR* actorx, f32 pos_x, f32 pos_z) { + int bx; + int bz; + + actorx->home.position.x = pos_x; + actorx->home.position.z = pos_z; + mFI_Wpos2BlockNum(&bx, &bz, actorx->home.position); + actorx->block_x = bx; + actorx->block_z = bz; +} + +static void aNPC_think_in_block_setup_end(NPC_ACTOR* nactorx) { + nactorx->condition_info.demo_flg = 0; + nactorx->think.end_flag = TRUE; + nactorx->collision.check_kind = aNPC_BG_CHECK_TYPE_RANGE; + nactorx->palActorIgnoreTimer = 0; + nactorx->action.step = aNPC_ACTION_END_STEP; + aNPC_think_in_block_chg_native_info((ACTOR*)nactorx, nactorx->actor_class.world.position.x, + nactorx->actor_class.world.position.z); + nactorx->movement.range_center_x = ((nactorx->actor_class.block_x + 0.5f) * mFI_BK_WORLDSIZE_X_F); + nactorx->movement.range_center_z = ((nactorx->actor_class.block_z + 0.5f) * mFI_BK_WORLDSIZE_Z_F); +} + +static int aNPC_think_in_block_chk_interrupt_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + int ret = FALSE; + + if (aNPC_chk_talk_start(nactorx) == TRUE) { + ret = TRUE; + } else { + aNPC_ctrl_umbrella(nactorx); + if (aNPC_chk_pitfall(nactorx) == TRUE) { + ret = TRUE; + } else if (!aNPC_chk_right_hand(nactorx)) { + ret = TRUE; + } else if (!aNPC_chk_left_hand(nactorx)) { + ret = TRUE; + } else if (aNPC_check_uzai(nactorx, play) == TRUE) { + aNPC_set_request_act(nactorx, 2, aNPC_ACT_REACT_TOOL, aNPC_ACT_TYPE_DEFAULT, aNPC_req_default_data); + ret = TRUE; + } + } + + return ret; +} + +static int aNPC_think_in_block_check_humanoid(NPC_ACTOR* nactorx) { + int ret = FALSE; + + if (ClObj_DID_COLLIDE(nactorx->collision.pipe.collision_obj)) { + switch (nactorx->collision.pipe.collision_obj.collided_actor->part) { + case ACTOR_PART_PLAYER: + case ACTOR_PART_NPC: + ret = TRUE; + break; + } + } + + return ret; +} + +static void aNPC_think_in_block_next_act(NPC_ACTOR* nactorx) { + if (nactorx->action.step == aNPC_ACTION_END_STEP) { + if (aNPC_check_arrive_destination(nactorx) == TRUE) { + aNPC_think_in_block_setup_end(nactorx); + } else { + nactorx->condition_info.demo_flg = aNPC_COND_DEMO_SKIP_UZAI_CHECK | aNPC_COND_DEMO_SKIP_LOVE_CHECK | + aNPC_COND_DEMO_SKIP_ITEM | aNPC_COND_DEMO_SKIP_FORWARD_CHECK | + aNPC_COND_DEMO_SKIP_MOVE_CIRCLE_REV | + aNPC_COND_DEMO_SKIP_MOVE_RANGE_CHECK; + aNPC_set_request_act(nactorx, 4, aNPC_ACT_WALK, aNPC_ACT_TYPE_DEFAULT, aNPC_req_default_data); + } + } +} + +static void aNPC_think_in_block_main_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + if (nactorx->condition_info.talk_condition == aNPC_TALK_TYPE_NONE && nactorx->right_hand.item_type != aNPC_ITEM_TYPE_UMBRELLA && nactorx->request.umb_flag == TRUE) { + nactorx->right_hand.requested_item_type = aNPC_ITEM_TYPE_UMBRELLA; + } + + if (!aNPC_think_in_block_chk_interrupt_proc(nactorx, play)) { + if (aNPC_think_in_block_check_humanoid(nactorx) == TRUE) { + aNPC_think_in_block_setup_end(nactorx); + } else if (nactorx->collision.collision_flag) { + int bx; + int bz; + + mFI_Wpos2BlockNum(&bx, &bz, nactorx->actor_class.world.position); + if (nactorx->actor_class.block_x == bx && nactorx->actor_class.block_z == bz && !ClObj_DID_COLLIDE(nactorx->collision.pipe.collision_obj)) { + aNPC_think_in_block_setup_end(nactorx); + } + } else { + aNPC_think_in_block_next_act(nactorx); + } + } +} + +static void aNPC_think_in_block_init_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + static s16 angle_table[] = { DEG2SHORT_ANGLE2(180.0f), DEG2SHORT_ANGLE2(0.0f), DEG2SHORT_ANGLE2(-90.0f), DEG2SHORT_ANGLE2(90.0f) }; + static f32 mv_posX[] = { 0.0f, 0.0f, -120.0f, 120.0f }; + static f32 mv_posZ[] = { -120.0f, 120.0f, 0.0f, 0.0f }; + ACTOR* actorx = (ACTOR*)nactorx; + int appear = nactorx->condition_info.appear_rotation; + f32 x; + f32 z; + s16 angle; + + nactorx->condition_info.demo_flg = aNPC_COND_DEMO_SKIP_UZAI_CHECK | aNPC_COND_DEMO_SKIP_LOVE_CHECK | + aNPC_COND_DEMO_SKIP_ITEM | aNPC_COND_DEMO_SKIP_FORWARD_CHECK | + aNPC_COND_DEMO_SKIP_MOVE_CIRCLE_REV | + aNPC_COND_DEMO_SKIP_MOVE_RANGE_CHECK; + nactorx->think.interrupt_flags = aNPC_THINK_INTERRUPT_ENTRANCE | aNPC_THINK_INTERRUPT_OBSTACLE; + nactorx->actor_class.shape_info.rotation.y = angle_table[(int)appear]; + nactorx->palActorIgnoreTimer = -1; + x = mv_posX[appear] + actorx->home.position.x; + z = mv_posZ[appear] + actorx->home.position.z; + aNPC_set_dst_pos(nactorx, x, z); + aNPC_think_in_block_chg_native_info(actorx, x, z); + nactorx->movement.range_type = aNPC_MOVE_RANGE_TYPE_BLOCK; + nactorx->collision.check_kind = aNPC_BG_CHECK_TYPE_NORMAL; + aNPC_set_request_act(nactorx, 4, aNPC_ACT_WALK, aNPC_ACT_TYPE_DEFAULT, aNPC_req_default_data); +} + +static void aNPC_think_in_block_proc(NPC_ACTOR* nactorx, GAME_PLAY* play, int proc_type) { + static aNPC_SUB_PROC think_proc[] = { + &aNPC_think_in_block_init_proc, + &aNPC_think_in_block_main_proc, + }; + + (*think_proc[proc_type])(nactorx, play); +} diff --git a/src/actor/npc/ac_npc_think_into_house.c_inc b/src/actor/npc/ac_npc_think_into_house.c_inc new file mode 100644 index 00000000..a00809ce --- /dev/null +++ b/src/actor/npc/ac_npc_think_into_house.c_inc @@ -0,0 +1,13 @@ +static void aNPC_think_into_house_init_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + aNPC_set_dst_pos(nactorx, nactorx->npc_info.list->house_position.x + 20.0f, nactorx->npc_info.list->house_position.z + 20.0f); + aNPC_set_request_act(nactorx, 4, aNPC_ACT_INTO_HOUSE, aNPC_ACT_TYPE_DEFAULT, aNPC_req_default_data); +} + +static void aNPC_think_into_house_proc(NPC_ACTOR* nactorx, GAME_PLAY* play, int proc_type) { + static aNPC_SUB_PROC think_proc[] = { + &aNPC_think_into_house_init_proc, + &aNPC_think_demo_allways, + }; + + (*think_proc[proc_type])(nactorx, play); +} diff --git a/src/actor/npc/ac_npc_think_leave_house.c_inc b/src/actor/npc/ac_npc_think_leave_house.c_inc new file mode 100644 index 00000000..5c35ece2 --- /dev/null +++ b/src/actor/npc/ac_npc_think_leave_house.c_inc @@ -0,0 +1,22 @@ +static void aNPC_think_leave_house_init_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + f32 x = nactorx->npc_info.list->house_position.x + 20.0f; + f32 z = nactorx->npc_info.list->house_position.z + 40.0f; + + nactorx->actor_class.shape_info.rotation.y = 0; + nactorx->actor_class.world.angle.y = 0; + nactorx->actor_class.world.position.x = x; + nactorx->actor_class.world.position.z = z; + nactorx->actor_class.world.position.y = mCoBG_GetBgY_OnlyCenter_FromWpos(nactorx->actor_class.world.position, 0.0f); + aNPC_set_dst_pos(nactorx, x, z + 40.0f); + nactorx->movement.range_type = aNPC_MOVE_RANGE_TYPE_BLOCK; + aNPC_set_request_act(nactorx, 4, aNPC_ACT_LEAVE_HOUSE, aNPC_ACT_TYPE_DEFAULT, aNPC_req_default_data); +} + +static void aNPC_think_leave_house_proc(NPC_ACTOR* nactorx, GAME_PLAY* play, int proc_type) { + static aNPC_SUB_PROC think_proc[] = { + &aNPC_think_leave_house_init_proc, + &aNPC_think_demo_allways, + }; + + (*think_proc[proc_type])(nactorx, play); +} diff --git a/src/actor/npc/ac_npc_think_pitfall.c_inc b/src/actor/npc/ac_npc_think_pitfall.c_inc new file mode 100644 index 00000000..0bd9fe92 --- /dev/null +++ b/src/actor/npc/ac_npc_think_pitfall.c_inc @@ -0,0 +1,49 @@ +static void aNPC_think_pitfall_main_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + if (!aNPC_chk_talk_start(nactorx) && nactorx->action.step == aNPC_ACTION_END_STEP) { + if (nactorx->action.idx == aNPC_ACT_TALK) { + aNPC_set_request_act(nactorx, 4, aNPC_ACT_REVIVE, aNPC_ACT_TYPE_DEFAULT, aNPC_req_default_data); + } else { + nactorx->actor_class.status_data.weight = 50; + nactorx->palActorIgnoreTimer = 0; + aNPC_set_feel_info(nactorx, mNpc_FEEL_NORMAL, 0); + nactorx->talk_info.turn = aNPC_TALK_TURN_NORMAL; + nactorx->talk_info.default_animation = -1; + nactorx->condition_info.demo_flg = 0; + if (nactorx->right_hand.item_type == aNPC_ITEM_TYPE_UMBRELLA) { + nactorx->draw.sub_anim_type = aNPC_SUB_ANIM_UMBRELLA; + } + + nactorx->condition_info.pitfall_flag = 0; + nactorx->think.end_flag = TRUE; + } + } +} + +static void aNPC_think_pitfall_init_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + ACTOR* palActor = nactorx->palActor; + + if (palActor != NULL && palActor->part == ACTOR_PART_NPC) { + ((NPC_ACTOR*)palActor)->palActor = NULL; + } + nactorx->actor_class.status_data.weight = MASSTYPE_IMMOVABLE; + nactorx->palActorIgnoreTimer = -1; + aNPC_set_feel_info(nactorx, mNpc_FEEL_PITFALL, -1); + + { + xyz_t pos; + + mFI_UtNum2CenterWpos(&pos, nactorx->condition_info.ut_x, nactorx->condition_info.ut_z); + aNPC_set_dst_pos(nactorx, pos.x, pos.z); + } + + aNPC_set_request_act(nactorx, 4, aNPC_ACT_PITFALL, aNPC_ACT_TYPE_DEFAULT, aNPC_req_default_data); +} + +static void aNPC_think_pitfall_proc(NPC_ACTOR* nactorx, GAME_PLAY* play, int proc_type) { + static aNPC_SUB_PROC think_proc[] = { + &aNPC_think_pitfall_init_proc, + &aNPC_think_pitfall_main_proc, + }; + + (*think_proc[proc_type])(nactorx, play); +} diff --git a/src/actor/npc/ac_npc_think_sleep.c_inc b/src/actor/npc/ac_npc_think_sleep.c_inc new file mode 100644 index 00000000..ad25b778 --- /dev/null +++ b/src/actor/npc/ac_npc_think_sleep.c_inc @@ -0,0 +1,48 @@ +static void aNPC_think_sleep_set_force_schedule(NPC_ACTOR* nactorx) { + mNPS_schedule_c* sched_p = nactorx->npc_info.schedule; + u8 type = mNPS_SCHED_FIELD; + + if (aNPC_check_home_block(nactorx) == TRUE) { + type = mNPS_SCHED_IN_HOUSE; + } + + sched_p->forced_type = type; + sched_p->forced_timer = 7200; +} + +static void aNPC_think_sleep_main_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + if (!aNPC_think_chk_interrupt_proc(nactorx, play) && nactorx->action.step == aNPC_ACTION_END_STEP) { + switch (nactorx->action.idx) { + case aNPC_ACT_TALK: + case aNPC_ACT_UMB_OPEN: + aNPC_think_sleep_set_force_schedule(nactorx); + break; + default: + switch(aNPC_get_feel_info(nactorx)) { + case mNpc_FEEL_UZAI_0: + case mNpc_FEEL_UZAI_1: + break; + default: + aNPC_set_feel_info(nactorx, mNpc_FEEL_SLEEPY, -1); + aNPC_set_request_act(nactorx, 4, aNPC_ACT_WAIT, aNPC_ACT_TYPE_DEFAULT, aNPC_req_default_data); + break; + } + } + } +} + +static void aNPC_think_sleep_init_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + aNPC_set_feel_info(nactorx, mNpc_FEEL_SLEEPY, -1); + nactorx->think.interrupt_flags = aNPC_THINK_INTERRUPT_ENTRANCE | aNPC_THINK_INTERRUPT_OBSTACLE | aNPC_THINK_INTERRUPT_FATIGUE; + nactorx->condition_info.demo_flg = aNPC_COND_DEMO_SKIP_ENTRANCE_CHECK | aNPC_COND_DEMO_SKIP_HEAD_LOOKAT | aNPC_COND_DEMO_SKIP_FORWARD_CHECK; + aNPC_set_request_act(nactorx, 4, aNPC_ACT_WAIT, aNPC_ACT_TYPE_DEFAULT, aNPC_req_default_data); +} + +static void aNPC_think_sleep_proc(NPC_ACTOR* nactorx, GAME_PLAY* play, int proc_type) { + static aNPC_SUB_PROC think_proc[] = { + &aNPC_think_sleep_init_proc, + &aNPC_think_sleep_main_proc, + }; + + (*think_proc[proc_type])(nactorx, play); +} diff --git a/src/actor/npc/ac_npc_think_wander.c_inc b/src/actor/npc/ac_npc_think_wander.c_inc new file mode 100644 index 00000000..48869937 --- /dev/null +++ b/src/actor/npc/ac_npc_think_wander.c_inc @@ -0,0 +1,214 @@ +static int aNPC_think_wander_check_ones_way(NPC_ACTOR* nactorx, u16* arg_data) { + s16 angle; + s16 d_angle; + xyz_t dst_pos; + int ret = FALSE; + + dst_pos.x = arg_data[2]; + dst_pos.y = 0.0f; + dst_pos.z = arg_data[3]; + angle = search_position_angleY(&nactorx->actor_class.world.position, &dst_pos); + d_angle = angle - nactorx->actor_class.shape_info.rotation.y; + + if (ABS(d_angle) > DEG2SHORT_ANGLE2(90.0f)) { + ret = TRUE; + } + + return ret; +} + +static int aNPC_think_wander_move_next(u16* arg_data, NPC_ACTOR* nactorx) { + xyz_t dst_pos; + int sum = 0; + int ret = TRUE; + mActor_name_t* fg_p; + int bx; + int bz; + + mFI_Wpos2BlockNum(&bx, &bz, nactorx->actor_class.world.position); + fg_p = mFI_BkNumtoUtFGTop(bx, bz); + if (fg_p == NULL) { + sum = 5; + } else { + mActor_name_t item; + f32 center_x = nactorx->movement.range_center_x; + f32 center_z = nactorx->movement.range_center_z; + f32 radius = nactorx->movement.range_radius; + int ux; + int uz; + s16 angle; + + while (TRUE) { + // 0xFFFF, should've just been 0x10000 since fqrand upper bound is exclusive. + angle = (s16)RANDOM_F(DEG2SHORT_ANGLE2(360.0f) - 1); + dst_pos.x = center_x + sin_s(angle) * radius; + dst_pos.z = center_z + cos_s(angle) * radius; + mFI_Wpos2UtNum_inBlock(&ux, &uz, dst_pos); + item = *(fg_p + ux + uz * UT_X_NUM); + if ((item == EMPTY_NO || ITEM_IS_ITEM1(item) || ITEM_IS_FTR(item)) && + mCoBG_Wpos2CheckNpc(dst_pos) == TRUE && + aNPC_moveRangeCheck2(nactorx, NULL, dst_pos, nactorx->movement.range_type) == TRUE) { + s16 angleY; + + if (nactorx->action.idx != aNPC_ACT_TURN) { + break; + } + + angleY = search_position_angleY(&nactorx->actor_class.world.position, &dst_pos); + if (ABS(angleY - nactorx->actor_class.shape_info.rotation.y) < DEG2SHORT_ANGLE2(22.5f)) { + break; + } + } else if (sum > 4) { + break; + } + + sum++; + } + } + + if (sum <= 4) { + arg_data[2] = (int)dst_pos.x; + arg_data[3] = (int)dst_pos.z; + } else { + ret = FALSE; + } + + return ret; +} + +static void aNPC_think_wander_decide_next(NPC_ACTOR* nactorx) { + static int girl_decide_boarder[] = { 3, 6 }; // 40% wait, 30% walk, 30% run + static int ko_girl_decide_boarder[] = { 6, 8 }; // 70% wait, 20% walk, 10% run + static int boy_decide_boarder[] = { 5, 7 }; // 60% wait, 20% walk, 20% run + static int sport_man_decide_boarder[] = { 2, 4 }; // 30% wait, 20% walk, 50% run + static int grim_man_decide_boarder[] = { 3, 6 }; // 40% wait, 30% walk, 30% run + static int naniwa_lady_decide_boarder[] = { 4, 8 }; // 50% wait, 40% walk, 10% run + static int s_npc_decide_boarder[] = { 4, 8 }; // 50% wait, 40% walk, 10% run + + // clang-format off + static int* decide_boarder[] = { + girl_decide_boarder, + ko_girl_decide_boarder, + boy_decide_boarder, + sport_man_decide_boarder, + grim_man_decide_boarder, + naniwa_lady_decide_boarder, + }; + // clang-format on + + u8 act_type; + u16 arg_data[aNPC_REQUEST_ARG_NUM]; + u8 act_idx; + + act_type = aNPC_ACT_TYPE_DEFAULT; + bzero(arg_data, sizeof(arg_data)); + + if (aNPC_check_fatigue(nactorx) == TRUE || aNPC_get_feel_info(nactorx) == mNpc_FEEL_SLEEPY) { + act_idx = aNPC_ACT_WAIT; + } else if (nactorx->action.idx == aNPC_ACT_TURN) { + act_idx = aNPC_ACT_WAIT; + if (nactorx->collision.collision_flag == 0) { + xyz_t pos; + + pos.x = (int)nactorx->action.move_x; + pos.z = (int)nactorx->action.move_z; + if (aNPC_moveRangeCheck2(nactorx, NULL, pos, nactorx->movement.range_type) == TRUE) { + arg_data[2] = nactorx->action.move_x; + arg_data[3] = nactorx->action.move_z; + act_idx = aNPC_ACT_WALK; + act_type = aNPC_ACT_TYPE_TO_POINT; + } + } + } else { + int rng = RANDOM(10); + int* boarder_p; + + if (aNPC_IS_NRM_NPC(nactorx)) { + boarder_p = decide_boarder[mNpc_GetNpcLooks((ACTOR*)nactorx)]; + } else { + boarder_p = s_npc_decide_boarder; + } + + if (nactorx->think.idx == aNPC_THINK_WALK_WANDER) { + if (rng > 5) { + act_idx = aNPC_ACT_WAIT; + } else { + act_idx = aNPC_ACT_WALK; + } + } else { + for (act_idx = aNPC_ACT_WAIT; act_idx < aNPC_ACT_RUN; act_idx++) { + if (rng <= *boarder_p) { + break; + } + + boarder_p++; + } + } + + switch (act_idx) { + case aNPC_ACT_WAIT: + break; + case aNPC_ACT_RUN: { + mNPS_schedule_c* sched_p = nactorx->npc_info.schedule; + + if (sched_p != NULL && sched_p->current_type == mNPS_SCHED_FIELD && sched_p->current_type != sched_p->saved_type) { + act_idx = aNPC_ACT_WALK; + } + } + // fallthrough 2 -> 1 + case aNPC_ACT_WALK: + if (aNPC_think_wander_move_next(arg_data, nactorx) == FALSE) { + act_idx = aNPC_ACT_WAIT; + } else { + if (aNPC_think_wander_check_ones_way(nactorx, arg_data) == TRUE) { + act_idx = aNPC_ACT_TURN; + } + + act_type = aNPC_ACT_TYPE_TO_POINT; + } + break; + } + } + + aNPC_set_request_act(nactorx, 1, act_idx, act_type, arg_data); +} + +static void aNPC_think_wander_next_act(NPC_ACTOR* nactorx) { + if (nactorx->action.step == aNPC_ACTION_END_STEP) { + aNPC_think_wander_decide_next(nactorx); + } +} + +static void aNPC_think_wander_main_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + if (aNPC_think_chk_interrupt_proc(nactorx, play) == FALSE) { + aNPC_think_wander_next_act(nactorx); + } +} + +static void aNPC_think_wander_init_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + int ux; + int uz; + + mFI_Wpos2UtNum_inBlock(&ux, &uz, nactorx->actor_class.world.position); + if (ux == 0 || ux == (UT_X_NUM - 1) || uz == 0 || uz == (UT_Z_NUM - 1)) { + aNPC_think_in_block_chg_native_info((ACTOR*)nactorx, nactorx->actor_class.world.position.x, nactorx->actor_class.world.position.z); + nactorx->movement.range_type = aNPC_MOVE_RANGE_TYPE_BLOCK; + nactorx->movement.range_center_x = (0.5f + nactorx->actor_class.block_x) * mFI_BK_WORLDSIZE_X_F; + nactorx->movement.range_center_z = (0.5f + nactorx->actor_class.block_z) * mFI_BK_WORLDSIZE_Z_F; + } + + nactorx->condition_info.demo_flg = 0; + nactorx->think.force_call_flag = aNPC_FORCE_CALL_NONE; + aNPC_set_request_act(nactorx, 1, aNPC_ACT_WAIT, aNPC_ACT_TYPE_DEFAULT, aNPC_req_default_data); +} + +static void aNPC_think_wander_proc(NPC_ACTOR* nactorx, GAME_PLAY* play, int proc_type) { + // clang-format off + static aNPC_SUB_PROC think_proc[] = { + &aNPC_think_wander_init_proc, + &aNPC_think_wander_main_proc, + }; + // clang-format on + + (*think_proc[proc_type])(nactorx, play); +} diff --git a/src/actor/npc/event/ac_ev_broker_move.c_inc b/src/actor/npc/event/ac_ev_broker_move.c_inc index da0178bf..b410f0cc 100644 --- a/src/actor/npc/event/ac_ev_broker_move.c_inc +++ b/src/actor/npc/event/ac_ev_broker_move.c_inc @@ -128,14 +128,14 @@ static void aEBRK_enter(EV_BROKER_ACTOR* broker) { static void aEBRK_set_spd_info(EV_BROKER_ACTOR* broker, int action) { if (action == aEBRK_ACTION_ENTER) { - broker->npc_class.movement.max_speed = 1.0f; - broker->npc_class.movement.acceleration = 0.1f; - broker->npc_class.movement.deceleration = 0.1f; + broker->npc_class.movement.speed.max_speed = 1.0f; + broker->npc_class.movement.speed.acceleration = 0.1f; + broker->npc_class.movement.speed.deceleration = 0.1f; } else { broker->npc_class.actor_class.speed = 0.0f; - broker->npc_class.movement.max_speed = 0.0f; - broker->npc_class.movement.acceleration = 0.0f; - broker->npc_class.movement.deceleration = 0.0f; + broker->npc_class.movement.speed.max_speed = 0.0f; + broker->npc_class.movement.speed.acceleration = 0.0f; + broker->npc_class.movement.speed.deceleration = 0.0f; } } diff --git a/src/actor/npc/event/ac_ev_ghost.c b/src/actor/npc/event/ac_ev_ghost.c index 30a09822..a9227d78 100644 --- a/src/actor/npc/event/ac_ev_ghost.c +++ b/src/actor/npc/event/ac_ev_ghost.c @@ -237,8 +237,8 @@ static void aEGH_actor_move(ACTOR* actorx, GAME* game) { step = 1; if (mDemo_Get_talk_actor() == actorx) { - ghost->npc_class.draw._5BE = 0; - ghost->npc_class.draw.animation_speed = 0.5f; + ghost->npc_class.draw.anim_speed_type = aNPC_ANIM_SPEED_TYPE_LOCKED; + ghost->npc_class.draw.frame_speed = 0.5f; target_alpha = 190; } else { @@ -253,8 +253,8 @@ static void aEGH_actor_move(ACTOR* actorx, GAME* game) { step = 1; } - ghost->npc_class.draw._5BE = 1; - ghost->npc_class.draw.animation_speed = 0.25f; + ghost->npc_class.draw.anim_speed_type = aNPC_ANIM_SPEED_TYPE_FREE; + ghost->npc_class.draw.frame_speed = 0.25f; } delta_alpha = alpha - target_alpha; diff --git a/src/actor/npc/event/ac_ev_soncho.c b/src/actor/npc/event/ac_ev_soncho.c index da15e494..333b3def 100644 --- a/src/actor/npc/event/ac_ev_soncho.c +++ b/src/actor/npc/event/ac_ev_soncho.c @@ -49,7 +49,7 @@ static void aESC_actor_ct(ACTOR* actorx, GAME* game) { if ((*Common_Get(clip).npc_clip->birth_check_proc)(actorx, game) == TRUE) { (*Common_Get(clip).npc_clip->ct_proc)(actorx, game, &ct_data); soncho_actor->npc_class.palActorIgnoreTimer = -1; - soncho_actor->npc_class.draw._5BD = 3; + soncho_actor->npc_class.draw.sub_anim_type = aNPC_SUB_ANIM_TUE; if (soncho_event == NULL) { soncho_event = (aESC_event_save_c*)mEv_reserve_save_area(mEv_EVENT_SONCHO_BRIDGE_MAKE, 34); diff --git a/src/audio.c b/src/audio.c index 615f901c..7b26f6b3 100644 --- a/src/audio.c +++ b/src/audio.c @@ -78,22 +78,22 @@ extern void sAdo_PlyWalkSeRoom(u8 walk, const xyz_t* pos) { Na_PlyWalkSeRoom(walk, scalc, fcalc); } -extern void sAdo_NpcWalkSe(int walk, const xyz_t* pos) { +extern void sAdo_NpcWalkSe(u16 se_no, const xyz_t* pos) { f32 fcalc; u16 scalc; sAdo_Calc_MicPosition_forTrig(&fcalc, &scalc, pos); - Na_NpcWalkSe(walk, scalc, fcalc); + Na_NpcWalkSe(se_no, scalc, fcalc); } -extern void sAdo_NpcWalkSeRoom(int walk, const xyz_t* pos) { +extern void sAdo_NpcWalkSeRoom(u16 se_no, const xyz_t* pos) { f32 fcalc; u16 scalc; sAdo_Calc_MicPosition_forTrig(&fcalc, &scalc, pos); - Na_NpcWalkSeRoom(walk, scalc, fcalc); + Na_NpcWalkSeRoom(se_no, scalc, fcalc); } extern void sAdo_PlayerStatusLevel(f32 speed, int p) { @@ -360,41 +360,41 @@ extern void sAdo_SoftReset() { Na_SoftReset(); } -u16 sAdo_Get_WalkLabel(int type) { +u16 sAdo_Get_WalkLabel(int attr) { u16 ret; - switch (type) { - case 0: - case 1: - case 2: - if (Common_Get(time.season) != 3) { - ret = 0x4201; + switch (attr) { + case mCoBG_ATTRIBUTE_GRASS0: + case mCoBG_ATTRIBUTE_GRASS1: + case mCoBG_ATTRIBUTE_GRASS2: + if (Common_Get(time.season) != mTM_SEASON_WINTER) { + ret = NA_SE_FOOTSTEP_GRASS; } else { - ret = 0x4206; + ret = NA_SE_FOOTSTEP_SNOW; } break; - case 4: - case 5: - case 6: - ret = 0x4202; + case mCoBG_ATTRIBUTE_SOIL0: + case mCoBG_ATTRIBUTE_SOIL1: + case mCoBG_ATTRIBUTE_SOIL2: + ret = NA_SE_FOOTSTEP_SOIL; break; - case 7: - ret = 0x4203; + case mCoBG_ATTRIBUTE_STONE: + ret = NA_SE_FOOTSTEP_STONE; break; - case 23: - ret = 0x4204; + case mCoBG_ATTRIBUTE_WOOD: + ret = NA_SE_FOOTSTEP_WOOD; break; - case 9: - ret = 0x4205; + case mCoBG_ATTRIBUTE_BUSH: + ret = NA_SE_FOOTSTEP_BUSH; break; - case 22: - ret = 0x4208; + case mCoBG_ATTRIBUTE_SAND: + ret = NA_SE_FOOTSTEP_SAND; break; - case 11: - ret = 0x4209; + case mCoBG_ATTRIBUTE_WAVE: + ret = NA_SE_FOOTSTEP_WAVE; break; default: - ret = 0x4202; + ret = NA_SE_FOOTSTEP_SOIL; break; } return ret; @@ -406,32 +406,32 @@ u16 sAdo_Get_KokeruLabel(int type) { u16 ret; switch (label) { - case 0x4201: - ret = 0xe; + case NA_SE_FOOTSTEP_GRASS: + ret = NA_SE_TUMBLE_GRASS; break; - case 0x4206: - ret = 0x13; + case NA_SE_FOOTSTEP_SNOW: + ret = NA_SE_TUMBLE_SNOW; break; - case 0x4202: - ret = 0xf; + case NA_SE_FOOTSTEP_SOIL: + ret = NA_SE_TUMBLE_SOIL; break; - case 0x4203: - ret = 0x10; + case NA_SE_FOOTSTEP_STONE: + ret = NA_SE_TUMBLE_STONE; break; - case 0x4204: - ret = 0x11; + case NA_SE_FOOTSTEP_WOOD: + ret = NA_SE_TUMBLE_WOOD; break; - case 0x4205: - ret = 0x12; + case NA_SE_FOOTSTEP_BUSH: + ret = NA_SE_TUMBLE_BUSH; break; - case 0x4208: - ret = 0x156; + case NA_SE_FOOTSTEP_SAND: + ret = NA_SE_TUMBLE_SAND; break; - case 0x4209: - ret = 0x157; + case NA_SE_FOOTSTEP_WAVE: + ret = NA_SE_TUMBLE_WAVE; break; default: - ret = 15; + ret = NA_SE_TUMBLE_SOIL; break; } return ret; diff --git a/src/effect/ef_clacker.c b/src/effect/ef_clacker.c index 870e661a..39752595 100644 --- a/src/effect/ef_clacker.c +++ b/src/effect/ef_clacker.c @@ -18,7 +18,7 @@ eEC_PROFILE_c iam_ef_clacker = { // clang-format on }; -void eClacker_Make_Effect(eEC_Effect_c* effect, GAME* game) { +static void eClacker_Make_Effect(eEC_Effect_c* effect, GAME* game) { static s16 angle_tbl[] = {0x071C, 0x58E3, 0xAAAB}; int i; @@ -82,4 +82,4 @@ static void eClacker_mv(eEC_Effect_c* effect, GAME* game) { static void eClacker_dw(eEC_Effect_c* effect, GAME* game) { -} \ No newline at end of file +} diff --git a/src/game/m_actor.c b/src/game/m_actor.c index 0ea2c35d..347156ce 100644 --- a/src/game/m_actor.c +++ b/src/game/m_actor.c @@ -620,14 +620,14 @@ static int Actor_data_bank_regist_check(int* bank_id, ACTOR_PROFILE* profile, AC return res; } -static int Actor_malloc_actor_class(ACTOR** actor_pp, ACTOR_PROFILE* profile, ACTOR_DLFTBL* dlftbl, const char* unk, +static int Actor_malloc_actor_class(ACTOR** actor_pp, ACTOR_PROFILE* profile, ACTOR_DLFTBL* dlftbl, const char* name, mActor_name_t id) { aNPC_draw_data_c draw_data; switch (ITEM_NAME_GET_TYPE(id)) { case NAME_TYPE_SPNPC: case NAME_TYPE_NPC: { - *actor_pp = (*Common_Get(clip).npc_clip->get_actor_area_proc)(profile->class_size, unk, 1); + *actor_pp = CLIP(npc_clip)->get_actor_area_proc(profile->class_size, name, 1); (*Common_Get(clip).npc_clip->dma_draw_data_proc)(&draw_data, id); // leftover? break; } diff --git a/src/game/m_npc.c b/src/game/m_npc.c index 0ef68f92..1829fb8e 100644 --- a/src/game/m_npc.c +++ b/src/game/m_npc.c @@ -14,6 +14,7 @@ #include "m_mail_password_check.h" #include "libultra/libultra.h" #include "jsyswrap.h" +#include "ac_npc.h" static int mNpc_CheckIslandAnimalID(AnmPersonalID_c* anm_id); @@ -2071,10 +2072,9 @@ extern u8* mNpc_GetWordEnding(ACTOR* actor) { return word_ending; } -extern void mNpc_ResetWordEnding(ACTOR* actor) { - if (actor != NULL && actor->part == ACTOR_PART_NPC) { - NPC_ACTOR* npc = (NPC_ACTOR*)actor; - Animal_c* animal = npc->npc_info.animal; +extern void mNpc_ResetWordEnding(NPC_ACTOR* nactorx) { + if (nactorx != NULL && nactorx->actor_class.part == ACTOR_PART_NPC) { + Animal_c* animal = nactorx->npc_info.animal; if (animal != NULL) { mString_Load_StringFromRom(animal->catchphrase, ANIMAL_CATCHPHRASE_LEN, diff --git a/src/game/m_player_common.c_inc b/src/game/m_player_common.c_inc index fc82545c..6a61f554 100644 --- a/src/game/m_player_common.c_inc +++ b/src/game/m_player_common.c_inc @@ -7788,7 +7788,7 @@ static int Player_actor_CheckAndSet_UZAI_forNpc(ACTOR* actorx) { mNpc_GetAnimalMemoryIdx(&Now_Private->player_ID, animal->memories, ANIMAL_MEMORY_NUM) != -1) { if (ITEM_NAME_GET_TYPE(actorx->npc_id) == NAME_TYPE_NPC && (npc_actor->condition_info.demo_flg & aNPC_COND_DEMO_SKIP_UZAI_CHECK) == 0) { - npc_actor->uzai.counter++; + npc_actor->uzai.tool++; npc_actor->uzai.flag = TRUE; } } diff --git a/src/game/m_player_main_reflect_axe.c_inc b/src/game/m_player_main_reflect_axe.c_inc index 09c8cc68..713c04a7 100644 --- a/src/game/m_player_main_reflect_axe.c_inc +++ b/src/game/m_player_main_reflect_axe.c_inc @@ -98,7 +98,7 @@ static void Player_actor_SetOrderNPC_Reflect_axe(ACTOR* actor, mPlayer_main_refl return; case mAc_PROFILE_BALL: - ((BALL_ACTOR*)reflect_actor)->unk208 |= 8; + ((BALL_ACTOR*)reflect_actor)->state_flags |= aBALL_STATE_PLAYER_HIT_AXE; return; default: diff --git a/src/game/m_player_main_reflect_scoop.c_inc b/src/game/m_player_main_reflect_scoop.c_inc index 0dedb324..2a1db529 100644 --- a/src/game/m_player_main_reflect_scoop.c_inc +++ b/src/game/m_player_main_reflect_scoop.c_inc @@ -108,7 +108,7 @@ static void Player_actor_SetEffectHit_Reflect_scoop(ACTOR* actor, GAME* game) { break; case mAc_PROFILE_BALL: - ((BALL_ACTOR*)reflected)->unk208 |= 4; + ((BALL_ACTOR*)reflected)->state_flags |= aBALL_STATE_PLAYER_HIT_SCOOP; break; } }