diff --git a/configure.py b/configure.py index 9c547222..5b1a4f95 100644 --- a/configure.py +++ b/configure.py @@ -1141,7 +1141,7 @@ config.libs = [ Object(Matching, "actor/npc/ac_npc_shop_master.c"), Object(Matching, "actor/npc/ac_npc_shop_mastersp.c"), Object(Matching, "actor/npc/ac_npc_sleep_obaba.c"), - Object(NonMatching, "actor/npc/ac_npc_soncho.c"), + Object(Matching, "actor/npc/ac_npc_soncho.c"), Object(NonMatching, "actor/npc/ac_npc_station_master.c"), Object(Matching, "actor/npc/ac_npc_super_master.c"), Object(Matching, "actor/npc/ac_npc_totakeke.c"), diff --git a/include/ac_npc_soncho.h b/include/ac_npc_soncho.h index 03b7f966..3e84ef26 100644 --- a/include/ac_npc_soncho.h +++ b/include/ac_npc_soncho.h @@ -3,11 +3,29 @@ #include "types.h" #include "m_actor.h" +#include "ac_npc.h" #ifdef __cplusplus extern "C" { #endif +typedef struct npc_soncho_actor_s NPC_SONCHO_ACTOR; + +typedef void (*aNS_PROC)(NPC_SONCHO_ACTOR* actor); + +struct npc_soncho_actor_s { + NPC_ACTOR npc_class; + aNS_PROC think_proc; + int _998; + u16 _99C; + u8 think_idx; + u8 think_after_talk_idx; + u8 _9A0; + u8 talk_idx; + u8 think_chg_flag; + u8 _9A3; +}; + extern ACTOR_PROFILE Npc_Soncho_Profile; #ifdef __cplusplus @@ -15,4 +33,3 @@ extern ACTOR_PROFILE Npc_Soncho_Profile; #endif #endif - diff --git a/include/m_soncho.h b/include/m_soncho.h index 0509e3f6..024726b8 100644 --- a/include/m_soncho.h +++ b/include/m_soncho.h @@ -61,6 +61,8 @@ enum { mSC_EVENT_NUM = mSC_EVENT_PLAYER_BIRTHDAY, + mSC_SPECIAL_EVENT_ARBEIT = 32, + mSC_SPECIAL_EVENT_JAN_VACATION = 101, mSC_SPECIAL_EVENT_FEB_VACATION = 102, mSC_SPECIAL_EVENT_MORNING_AEROBICS = 103 diff --git a/src/actor/npc/ac_npc_soncho.c b/src/actor/npc/ac_npc_soncho.c new file mode 100644 index 00000000..d50044a2 --- /dev/null +++ b/src/actor/npc/ac_npc_soncho.c @@ -0,0 +1,126 @@ +#include "ac_npc_soncho.h" +#include "ac_npc.h" +#include "libultra/libultra.h" +#include "m_actor.h" +#include "m_actor_type.h" +#include "m_common_data.h" +#include "m_name_table.h" +#include "m_npc.h" +#include "m_soncho.h" + +enum { + aNS_TALK_END_WAIT, + + aNS_TALK_NUM +}; + +enum { + aNS_THINK_WAIT, + aNS_THINK_NORMAL_WAIT, + aNS_THINK_WANDER, + + aNS_THINK_NUM +}; + +static void aNS_actor_ct(ACTOR* actorx, GAME* game); +static void aNS_actor_dt(ACTOR* actorx, GAME* game); +static void aNS_actor_init(ACTOR* actorx, GAME* game); +static void aNS_actor_move(ACTOR* actorx, GAME* game); +static void aNS_actor_draw(ACTOR* actorx, GAME* game); +static void aNS_actor_save(ACTOR* actorx, GAME* game); + +// clang-format off +ACTOR_PROFILE Npc_Soncho_Profile = { + mAc_PROFILE_NPC_SONCHO, + ACTOR_PART_NPC, + ACTOR_STATE_NONE, + SP_NPC_SONCHO, + ACTOR_OBJ_BANK_KEEP, + sizeof(NPC_SONCHO_ACTOR), + aNS_actor_ct, + aNS_actor_dt, + aNS_actor_init, + mActor_NONE_PROC1, + aNS_actor_save, +}; +// clang-format on + +static int aNS_talk_init(ACTOR* actorx, GAME* game); +static int aNS_talk_end_chk(ACTOR* actorx, GAME* game); +static void aNS_schedule_proc(NPC_ACTOR* nactorx, GAME_PLAY* play, int type); +static void aNS_setup_think_proc(NPC_SONCHO_ACTOR* actor, GAME_PLAY* play, u8 think_idx); + +static void aNS_actor_ct(ACTOR* actorx, GAME* game) { + // clang-format off + static aNPC_ct_data_c ct_data = { + aNS_actor_move, + aNS_actor_draw, + aNPC_CT_SCHED_TYPE_SPECIAL, + (aNPC_TALK_REQUEST_PROC)none_proc1, + aNS_talk_init, + aNS_talk_end_chk, + 0, + }; + // clang-format on + + if (NPC_CLIP->birth_check_proc(actorx, game) == TRUE) { + NPC_SONCHO_ACTOR* actor = (NPC_SONCHO_ACTOR*)actorx; + + actor->npc_class.schedule.schedule_proc = aNS_schedule_proc; + NPC_CLIP->ct_proc(actorx, game, &ct_data); + actor->npc_class.palActorIgnoreTimer = -1; + actor->npc_class.draw.sub_anim_type = aNPC_SUB_ANIM_TUE; // cane + actor->think_chg_flag = FALSE; + actor->_9A3 = 0; + } +} + +static void aNS_actor_save(ACTOR* actorx, GAME* game) { + mNpc_RenewalSetNpc(actorx); +} + +static void aNS_actor_dt(ACTOR* actorx, GAME* game) { + NPC_CLIP->dt_proc(actorx, game); +} + +static void aNS_actor_init(ACTOR* actorx, GAME* game) { + NPC_CLIP->init_proc(actorx, game); +} + +static int aNS_set_request_act(NPC_SONCHO_ACTOR* actor, u8 prio, u8 idx, u8 type, u16 obj, s16 move_x, s16 move_z) { + int ret = FALSE; + + if (prio >= actor->npc_class.request.act_priority) { + u16 arg_data[aNPC_REQUEST_ARG_NUM]; + + bzero(arg_data, sizeof(arg_data)); + arg_data[0] = obj; + arg_data[2] = move_x; + arg_data[3] = move_z; + + actor->npc_class.request.act_priority = prio; + actor->npc_class.request.act_idx = idx; + actor->npc_class.request.act_type = type; + mem_copy((u8*)actor->npc_class.request.act_args, (u8*)arg_data, sizeof(arg_data)); + ret = TRUE; + } + + return ret; +} + +static void aNS_actor_move(ACTOR* actorx, GAME* game) { + NPC_SONCHO_ACTOR* actor = (NPC_SONCHO_ACTOR*)actorx; + + actor->npc_class.movement.range_center_x = actorx->home.position.x; + actor->npc_class.movement.range_center_z = actorx->home.position.z; + actor->npc_class.movement.range_radius = 60.0f; + actor->npc_class.movement.range_type = aNPC_MOVE_RANGE_TYPE_CIRCLE; + NPC_CLIP->move_proc(actorx, game); +} + +static void aNS_actor_draw(ACTOR* actorx, GAME* game) { + NPC_CLIP->draw_proc(actorx, game); +} + +#include "../src/actor/npc/ac_npc_soncho_talk.c_inc" +#include "../src/actor/npc/ac_npc_soncho_schedule.c_inc" diff --git a/src/actor/npc/ac_npc_soncho_schedule.c_inc b/src/actor/npc/ac_npc_soncho_schedule.c_inc new file mode 100644 index 00000000..d2aace5f --- /dev/null +++ b/src/actor/npc/ac_npc_soncho_schedule.c_inc @@ -0,0 +1,100 @@ +static void aNS_think_main_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + NPC_SONCHO_ACTOR* actor = (NPC_SONCHO_ACTOR*)nactorx; + + (*actor->think_proc)(actor); +} + +static void aNS_think_init_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + NPC_SONCHO_ACTOR* actor = (NPC_SONCHO_ACTOR*)nactorx; + + nactorx->actor_class.status_data.weight = MASSTYPE_IMMOVABLE; + nactorx->condition_info.hide_request = FALSE; + aNS_setup_think_proc(actor, play, aNS_THINK_WAIT); +} + +static void aNS_normal_wait_init(NPC_SONCHO_ACTOR* actor, GAME_PLAY* play) { + aNS_set_request_act(actor, 4, aNPC_ACT_WAIT, aNPC_ACT_TYPE_DEFAULT, aNPC_ACT_OBJ_DEFAULT, 0, 0); +} + +static void aNS_wander_init(NPC_SONCHO_ACTOR* actor, GAME_PLAY* play) { + NPC_CLIP->chg_schedule_proc((NPC_ACTOR*)actor, play, aNPC_SCHEDULE_TYPE_WALK_WANDER); + actor->npc_class.actor_class.status_data.weight = 80; +} + +typedef struct { + u8 think_proc_idx; + u8 think_init_proc_idx; + u8 talk_request_type; + u8 talk_idx; + u8 think_after_talk_idx; +} aNS_think_data_c; + +// clnag-format off + static aNS_think_data_c dt_tbl[] = { + { 0, aNS_THINK_WANDER, 1, 0, aNS_THINK_WAIT }, + }; + // clang-format on + +static aNS_PROC proc_table[] = { (aNS_PROC)none_proc1 }; + +typedef void (*aNS_INIT_PROC)(NPC_SONCHO_ACTOR* actor, GAME_PLAY* play); + +// clang-format off +static aNS_INIT_PROC init_table[] = { + (aNS_INIT_PROC)none_proc1, + aNS_normal_wait_init, + aNS_wander_init, +}; +// clang-format on + +static void aNS_setup_think_proc(NPC_SONCHO_ACTOR* actor, GAME_PLAY* play, u8 think_idx) { + // clang-format off + static aNPC_TALK_REQUEST_PROC talk_request_table[] = { + (aNPC_TALK_REQUEST_PROC)none_proc1, + aNS_norm_talk_request, + (aNPC_TALK_REQUEST_PROC)none_proc1, + }; + // clang-format on + aNS_think_data_c* data_p = &dt_tbl[think_idx]; + + actor->think_idx = think_idx; + actor->think_proc = proc_table[data_p->think_proc_idx]; + actor->npc_class.talk_info.talk_request_proc = talk_request_table[data_p->talk_request_type]; + actor->talk_idx = data_p->talk_idx; + actor->think_after_talk_idx = data_p->think_after_talk_idx; + (*init_table[data_p->think_init_proc_idx])(actor, play); + actor->think_chg_flag = TRUE; +} + +static void aNS_think_proc(NPC_ACTOR* nactorx, GAME_PLAY* play, int type) { + switch (type) { + case aNPC_THINK_PROC_INIT: + aNS_think_init_proc(nactorx, play); + break; + case aNPC_THINK_PROC_MAIN: + aNS_think_main_proc(nactorx, play); + break; + } +} + +static void aNS_schedule_init_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + nactorx->think.think_proc = aNS_think_proc; + NPC_CLIP->think_proc(nactorx, play, aNPC_THINK_SPECIAL, aNPC_THINK_TYPE_INIT); +} + +static void aNS_schedule_main_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + if (NPC_CLIP->think_proc(nactorx, play, -1, aNPC_THINK_TYPE_CHK_INTERRUPT) == FALSE) { + NPC_CLIP->think_proc(nactorx, play, -1, aNPC_THINK_TYPE_MAIN); + } +} + +static void aNS_schedule_proc(NPC_ACTOR* nactorx, GAME_PLAY* play, int type) { + switch (type) { + case aNPC_SCHEDULE_PROC_INIT: + aNS_schedule_init_proc(nactorx, play); + break; + case aNPC_SCHEDULE_PROC_MAIN: + aNS_schedule_main_proc(nactorx, play); + break; + } +} diff --git a/src/actor/npc/ac_npc_soncho_talk.c_inc b/src/actor/npc/ac_npc_soncho_talk.c_inc new file mode 100644 index 00000000..a47e7ea0 --- /dev/null +++ b/src/actor/npc/ac_npc_soncho_talk.c_inc @@ -0,0 +1,58 @@ +static int aNS_change_talk_proc(NPC_SONCHO_ACTOR* actor, u8 talk_idx) { + actor->talk_idx = talk_idx; + return TRUE; +} + +static void aNS_set_norm_talk_info(ACTOR* actorx) { + NPC_SONCHO_ACTOR* actor = (NPC_SONCHO_ACTOR*)actorx; + + mDemo_Set_talk_turn(TRUE); + mDemo_Set_camera(CAMERA2_PROCESS_TALK); + aNS_change_talk_proc(actor, aNS_TALK_END_WAIT); + + if (mSC_check_ArbeitPlayer()) { + mDemo_Set_msg_num(0x3AFF + RANDOM(3)); + } else if (mSC_LightHouse_travel_check()) { + mDemo_Set_msg_num(0x3B02); + } else { + mDemo_Set_msg_num(0x3AFC); + } +} + +static void aNS_norm_talk_request(ACTOR* actorx, GAME* game) { + NPC_SONCHO_ACTOR* actor = (NPC_SONCHO_ACTOR*)actorx; + + if (!actor->think_chg_flag) { + mDemo_Request(mDemo_TYPE_TALK, actorx, aNS_set_norm_talk_info); + } else { + actor->think_chg_flag = FALSE; + } +} + +static int aNS_talk_init(ACTOR* actorx, GAME* game) { + static aNS_PROC proc[] = { (aNS_PROC)none_proc1 }; // ?? unused somewhere here or above (inside a function) + NPC_SONCHO_ACTOR* actor = (NPC_SONCHO_ACTOR*)actorx; + + actor->npc_class.talk_info.talk_request_proc = (aNPC_TALK_REQUEST_PROC)none_proc1; + mDemo_Set_ListenAble(); + mDemo_Start(actorx); + mSC_trophy_set(mSC_SPECIAL_EVENT_ARBEIT); + return TRUE; +} + +static int aNS_talk_end_chk(ACTOR* actorx, GAME* game) { + static aNS_PROC proc[] = { (aNS_PROC)none_proc1 }; + + NPC_SONCHO_ACTOR* actor = (NPC_SONCHO_ACTOR*)actorx; + GAME_PLAY* play = (GAME_PLAY*)game; + int ret = FALSE; + + (*proc[actor->talk_idx])(actor); + + if (mDemo_CAN_ACTOR_TALK(actorx)) { + aNS_setup_think_proc(actor, play, actor->think_after_talk_idx); + ret = TRUE; + } + + return ret; +}