diff --git a/configure.py b/configure.py index f4cbf3e3..c8c05ed0 100644 --- a/configure.py +++ b/configure.py @@ -1179,7 +1179,7 @@ config.libs = [ Object(Matching, "actor/npc/event/ac_ev_soncho.c"), Object(Matching, "actor/npc/event/ac_ev_soncho2.c"), Object(Matching, "actor/npc/event/ac_ev_speech_soncho.c"), - Object(NonMatching, "actor/npc/event/ac_ev_turkey.c"), + Object(Matching, "actor/npc/event/ac_ev_turkey.c"), Object(NonMatching, "actor/npc/event/ac_ev_yomise.c"), ], ), diff --git a/include/ac_ev_turkey.h b/include/ac_ev_turkey.h index 4ac1241d..47449f4e 100644 --- a/include/ac_ev_turkey.h +++ b/include/ac_ev_turkey.h @@ -3,11 +3,46 @@ #include "types.h" #include "m_actor.h" +#include "ac_npc.h" #ifdef __cplusplus extern "C" { #endif +typedef struct { + PersonalID_c pid; + u16 given_present_bitfield; +} aEv_turkey_save_c; + +typedef struct { + u8 _00; + u8 _01; + u8 _02; +} aEv_turkey_common_c; + +typedef struct ev_turkey_actor_s EV_TURKEY_ACTOR; + +typedef void (*aETKY_ACT_PROC)(EV_TURKEY_ACTOR* turkey); +typedef void (*aETKY_TALK_PROC)(EV_TURKEY_ACTOR* turkey, GAME_PLAY* play); +typedef void (*aETKY_TALK_SETUP_STATUS_PROC)(EV_TURKEY_ACTOR* turkey, GAME_PLAY* play, int talk_act); + +struct ev_turkey_actor_s { + NPC_ACTOR npc_class; + int talk_action; + aETKY_TALK_PROC talk_proc; + aETKY_TALK_SETUP_STATUS_PROC talk_setup_proc; + int talk_msg_no; + int next_talk_action; + aEv_turkey_save_c* ev_save_p; + aEv_turkey_common_c* ev_common_p; + u8 present_idx; + u8 _9B1; + aETKY_ACT_PROC act_proc; + int action; + int _9BC; + xyz_t _9C0; +}; + extern ACTOR_PROFILE Ev_Turkey_Profile; #ifdef __cplusplus @@ -15,4 +50,3 @@ extern ACTOR_PROFILE Ev_Turkey_Profile; #endif #endif - diff --git a/include/ac_npc.h b/include/ac_npc.h index 87edd8b9..3aeaa94a 100644 --- a/include/ac_npc.h +++ b/include/ac_npc.h @@ -26,6 +26,9 @@ extern "C" { #define aNPC_SPNPC_BIT_SET(field, bit) ((field) |= (1 << (bit))) #define aNPC_SPNPC_BIT_CLR(field, bit) ((field) &= ~(1 << (bit))) +// To use this enum, make sure that m_common_data.h is included! +#define NPC_CLIP CLIP(npc_clip) + enum { aNPC_JOINT_BASE_ROOT, aNPC_JOINT_BASE, diff --git a/include/m_name_table.h b/include/m_name_table.h index 694f89c2..c863fb89 100644 --- a/include/m_name_table.h +++ b/include/m_name_table.h @@ -2475,7 +2475,55 @@ extern int mNT_check_unknown(mActor_name_t item_no); #define FTR_SPRING_MEDAL 0x32A8 #define FTR_AUTUMN_MEDAL 0x32AC - +#define FTR_TUMBLEWEED 0x32B0 +#define FTR_COW_SKULL 0x32B4 +#define FTR_OIL_DRUM 0x32B8 +#define FTR_SADDLE_FENCE 0x32BC +#define FTR_WESTERN_FENCE 0x32C0 +#define FTR_WATERING_TROUGH 0x32C4 +#define FTR_LUIGI_TROPHY 0x32C8 +#define FTR_MARIO_TROPHY 0x32CC +#define FTR_HARVEST_LAMP 0x32D0 +#define FTR_COVERED_WAGON 0x32D4 +#define FTR_STOREFRONT 0x32D8 +#define FTR_PICNIC_TABLE 0x32DC +#define FTR_HARVEST_TABLE 0x32E0 +#define FTR_HARVEST_TV 0x32E4 +#define FTR_HARVEST_BED 0x32E8 +#define FTR_HARVEST_CHAIR 0x32EC +#define FTR_HARVEST_CLOCK 0x32F0 +#define FTR_HARVEST_SOFA 0x32F4 +#define FTR_GREEN_PIPE 0x32F8 +#define FTR_BRICK_BLOCK 0x32FC +#define FTR_HARVEST_BUREAU 0x3300 +#define FTR_FLAGPOLE 0x3304 +#define FTR_HARVEST_DRESSER 0x3308 +#define FTR_SUPER_MUSHROOM 0x330C +#define FTR_HARVEST_MIRROR 0x3310 +#define FTR_COIN 0x3314 +#define FTR_Q_BLOCK 0x3318 +#define FTR_STARMAN 0x331C +#define FTR_KOOPA_SHELL 0x3320 +#define FTR_CANNON 0x3324 +#define FTR_DESERT_CACTUS 0x3328 +#define FTR_FIRE_FLOWER 0x332C +#define FTR_WAGON_WHEEL 0x3330 +#define FTR_WELL 0x3334 +#define FTR_BOXING_BARRICADE 0x3338 +#define FTR_NEUTRAL_CORNER 0x333C +#define FTR_RED_CORNER 0x3340 +#define FTR_BLUE_CORNER 0x3344 +#define FTR_BOXING_MAT 0x3348 +#define FTR_RINGSIDE_TABLE 0x334C +#define FTR_SPEED_BAG 0x3350 +#define FTR_SANDBAG 0x3354 +#define FTR_WEIGHT_BENCH 0x3358 +#define FTR_CAMPFIRE 0x335C +#define FTR_BONFIRE 0x3360 +#define FTR_KAYAK 0x3364 +#define FTR_SPRINKLER 0x3368 +#define FTR_TENT_MODEL 0x336C +#define FTR_BACKPACK 0x3370 #define FTR_ANGLER_TROPHY 0x3374 #define FTR_PANSY_MODEL1 0x3378 #define FTR_PANSY_MODEL2 0x337C @@ -2486,7 +2534,12 @@ extern int mNT_check_unknown(mActor_name_t item_no); #define FTR_TULIP_MODEL1 0x3390 #define FTR_TULIP_MODEL2 0x3394 #define FTR_TULIP_MODEL3 0x3398 - +#define FTR_LANTERN 0x339C +#define FTR_LAWN_MOWER 0x33A0 +#define FTR_COOLER 0x33A4 +#define FTR_MOUNTAIN_BIKE 0x33A8 +#define FTR_SLEEPING_BAG 0x33AC +#define FTR_PROPANE_STOVE 0x33B0 #define FTR_CORNUCOPIA 0x33B4 #define FTR_JUDGES_BELL 0x33B8 #define FTR_NOISEMAKER 0x33BC diff --git a/src/actor/npc/event/ac_ev_turkey.c b/src/actor/npc/event/ac_ev_turkey.c new file mode 100644 index 00000000..eb4762a4 --- /dev/null +++ b/src/actor/npc/event/ac_ev_turkey.c @@ -0,0 +1,564 @@ +#include "ac_ev_turkey.h" + +#include "m_common_data.h" +#include "m_msg.h" +#include "m_player_lib.h" +#include "libultra/libultra.h" + +#define aETKY_PRESENT_NUM 12 +#define aETKY_ALL_BITS ((1 << aETKY_PRESENT_NUM) - 1) + +enum { + aETKY_ACTION_WAIT, + aETKY_ACTION_KYORO, + + aETKY_ACTION_NUM +}; + +enum { + aETKY_TALK_WAIT_END, + aETKY_TALK_EXPLAIN_ENV0, + aETKY_TALK_EXPLAIN_ENV1, + aETKY_TALK_EXPLAIN_ENV2, + aETKY_TALK_EXPLAIN_ENV3, + aETKY_TALK_FIND_REAC, + aETKY_TALK_GIVE_ME_FORK, + aETKY_TALK_GIVE_YOU_PRESENT, + + aETKY_TALK_NUM +}; + +static void aETKY_actor_ct(ACTOR* actorx, GAME* game); +static void aETKY_actor_dt(ACTOR* actorx, GAME* game); +static void aETKY_actor_init(ACTOR* actorx, GAME* game); +static void aETKY_actor_save(ACTOR* actorx, GAME* game); +static void aETKY_actor_move(ACTOR* actorx, GAME* game); +static void aETKY_actor_draw(ACTOR* actorx, GAME* game); + +ACTOR_PROFILE Ev_Turkey_Profile = { + // clang-format off + mAc_PROFILE_EV_TURKEY, + ACTOR_PART_NPC, + ACTOR_STATE_NONE, + SP_NPC_TURKEY, + ACTOR_OBJ_BANK_KEEP, + sizeof(EV_TURKEY_ACTOR), + aETKY_actor_ct, + aETKY_actor_dt, + aETKY_actor_init, + mActor_NONE_PROC1, + aETKY_actor_save, + // clang-format on +}; + +static const mActor_name_t aETKY_present_table[] = { + // clang-format off + FTR_HARVEST_LAMP, + FTR_HARVEST_TABLE, + FTR_HARVEST_TV, + FTR_HARVEST_BED, + FTR_HARVEST_CHAIR, + FTR_HARVEST_CLOCK, + FTR_HARVEST_SOFA, + FTR_HARVEST_BUREAU, + FTR_HARVEST_DRESSER, + FTR_HARVEST_MIRROR, + ITM_CARPET66, + ITM_WALL66, + // clang-format on +}; + +static int aETKY_DecidePresent(u16* given_bitfield) { + int dont_have_count = 0; + int check_count = 0; + int selected; + int i; + + if ((*given_bitfield & aETKY_ALL_BITS) == aETKY_ALL_BITS) { + *given_bitfield = 0; + } + + for (i = 0; i < aETKY_PRESENT_NUM; i++) { + if (((*given_bitfield >> i) & 1) == 0) { + dont_have_count++; + } + } + + selected = RANDOM(dont_have_count); + for (i = 0; i < aETKY_PRESENT_NUM; i++) { + if (((*given_bitfield >> i) & 1) == 0) { + if (check_count == selected) { + return i; + } + + check_count++; + } + } + + return 0; +} + +static void aETKY_ReportPresent(u16* given_bitfield, int idx) { + if (given_bitfield != NULL) { + *given_bitfield |= (u16)(1 << idx); + } +} + +static void aETKY_ActionWait(EV_TURKEY_ACTOR* turkey) { + if (turkey->npc_class.draw.main_animation_state == cKF_STATE_CONTINUE) { + if (turkey->npc_class.draw.loop_flag == FALSE) { + turkey->npc_class.action.step = aNPC_ACTION_END_STEP; + } else { + turkey->npc_class.draw.loop_flag--; + } + } +} + +static void aETKY_ActionKyoro(EV_TURKEY_ACTOR* turkey) { + if (turkey->npc_class.draw.main_animation_state == cKF_STATE_CONTINUE) { + if (turkey->npc_class.draw.loop_flag == FALSE) { + turkey->npc_class.action.step = aNPC_ACTION_END_STEP; + } else { + turkey->npc_class.draw.loop_flag--; + } + } +} + +static void aETKY_setupAction(EV_TURKEY_ACTOR* turkey, int action) { + static aETKY_ACT_PROC process[] = { aETKY_ActionWait, aETKY_ActionKyoro }; + static int animeSeqNo[] = { aNPC_ANIM_WAIT1, aNPC_ANIM_TKYKYORO1 }; + + turkey->npc_class.action.step = 0; + turkey->action = action; + turkey->act_proc = process[action]; + + if (action == aETKY_ACTION_WAIT) { + turkey->npc_class.draw.loop_flag = RANDOM(2); + } else { + turkey->npc_class.draw.loop_flag = RANDOM(2); + } + + NPC_CLIP->animation_init_proc((ACTOR*)turkey, animeSeqNo[action], FALSE); +} + +static void aETKY_act_chg_data_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + nactorx->action.act_obj = aNPC_ACT_OBJ_PLAYER; +} + +static void aETKY_act_init_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + EV_TURKEY_ACTOR* turkey = (EV_TURKEY_ACTOR*)nactorx; + + if (turkey->_9B1 == 1) { + aETKY_setupAction(turkey, aETKY_ACTION_WAIT); + } else { + aETKY_setupAction(turkey, aETKY_ACTION_KYORO); + } +} + +static void aETKY_act_main_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + EV_TURKEY_ACTOR* turkey = (EV_TURKEY_ACTOR*)nactorx; + + (*turkey->act_proc)(turkey); +} + +static void aETKY_act_proc(NPC_ACTOR* nactorx, GAME_PLAY* play, int proc_type) { + static aNPC_SUB_PROC act_proc[] = { + // clang-format off + aETKY_act_init_proc, + aETKY_act_chg_data_proc, + aETKY_act_main_proc, + // clang-format on + }; + + (*act_proc[proc_type])(nactorx, play); +} + +static void aETKY_set_request_act(NPC_ACTOR* nactorx) { + nactorx->request.act_priority = 4; + nactorx->request.act_idx = aNPC_ACT_SPECIAL; + nactorx->request.act_type = aNPC_ACT_TYPE_SEARCH; +} + +static void aETKY_think_init_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + nactorx->think.interrupt_flags = 0; + nactorx->action.act_proc = aETKY_act_proc; + aETKY_set_request_act(nactorx); +} + +static void aETKY_think_main_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + EV_TURKEY_ACTOR* turkey = (EV_TURKEY_ACTOR*)nactorx; + + if (nactorx->action.step == aNPC_ACTION_END_STEP) { + switch (nactorx->action.idx) { + case aNPC_ACT_SPECIAL: + if (turkey->_9BC != -1) { + aETKY_setupAction(turkey, turkey->_9BC); + turkey->_9BC = -1; + } else if (turkey->_9B1 == 1) { + aETKY_setupAction(turkey, aETKY_ACTION_WAIT); + } else { + aETKY_setupAction(turkey, (turkey->action + 1) & 1); + } + + nactorx->condition_info.demo_flg = aNPC_COND_DEMO_SKIP_HEAD_LOOKAT; + nactorx->collision.check_kind = aNPC_BG_CHECK_TYPE_ONLY_GROUND; + + if (turkey->_9C0.x != nactorx->actor_class.world.position.x) { + add_calc(&turkey->_9C0.x, nactorx->actor_class.world.position.x, 1.0f - sqrtf(0.7f), 0.25f, 0.05f); + } else if (turkey->_9C0.y != nactorx->actor_class.world.position.y) { + add_calc(&turkey->_9C0.y, nactorx->actor_class.world.position.y, 1.0f - sqrtf(0.7f), 0.25f, 0.05f); + } else if (turkey->_9C0.z != nactorx->actor_class.world.position.z) { + add_calc(&turkey->_9C0.z, nactorx->actor_class.world.position.z, 1.0f - sqrtf(0.7f), 0.25f, 0.05f); + } + + break; + case aNPC_ACT_TALK: + nactorx->condition_info.demo_flg = aNPC_COND_DEMO_SKIP_HEAD_LOOKAT; + nactorx->movement.mv_angl = 0; + aETKY_set_request_act(nactorx); + break; + } + } +} + +static void aETKY_think_proc(NPC_ACTOR* nactorx, GAME_PLAY* play, int proc_type) { + static aNPC_SUB_PROC think_proc[] = { aETKY_think_init_proc, aETKY_think_main_proc }; + + (*think_proc[proc_type & 1])(nactorx, play); +} + +static void aETKY_schedule_init_proc(NPC_ACTOR* nactorx, GAME_PLAY* play) { + EV_TURKEY_ACTOR* turkey = (EV_TURKEY_ACTOR*)nactorx; + + nactorx->think.think_proc = aETKY_think_proc; + nactorx->condition_info.hide_request = FALSE; + nactorx->palActorIgnoreTimer = -1; + nactorx->talk_info.default_animation = aNPC_ANIM_WAIT1; + turkey->_9BC = -1; + NPC_CLIP->think_proc(nactorx, play, aNPC_THINK_SPECIAL, aNPC_THINK_TYPE_INIT); +} + +static void aETKY_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 aETKY_schedule_proc(NPC_ACTOR* nactorx, GAME_PLAY* play, int proc_type) { + static aNPC_SUB_PROC sche_proc[] = { aETKY_schedule_init_proc, aETKY_schedule_main_proc }; + + (*sche_proc[proc_type & 1])(nactorx, play); +} + +static void aETKY_SetupSaveData(ACTOR* actorx) { + EV_TURKEY_ACTOR* turkey = (EV_TURKEY_ACTOR*)actorx; + aEv_turkey_save_c* save_p = (aEv_turkey_save_c*)mEv_get_save_area(mEv_EVENT_HARVEST_FESTIVAL_FRANKLIN, 0); + + if (save_p == NULL) { + save_p = (aEv_turkey_save_c*)mEv_reserve_save_area(mEv_EVENT_HARVEST_FESTIVAL_FRANKLIN, 0); + bzero(save_p, sizeof(aEv_turkey_save_c)); + mPr_ClearPersonalID(&save_p->pid); + turkey->ev_save_p = save_p; + } else { + turkey->ev_save_p = save_p; + } +} + +static void aETKY_SetupCommonData(ACTOR* actorx) { + EV_TURKEY_ACTOR* turkey = (EV_TURKEY_ACTOR*)actorx; + aEv_turkey_common_c* common_p = (aEv_turkey_common_c*)mEv_get_common_area(mEv_EVENT_HARVEST_FESTIVAL_FRANKLIN, 0); + + if (common_p == NULL) { + common_p = (aEv_turkey_common_c*)mEv_reserve_common_area(mEv_EVENT_HARVEST_FESTIVAL_FRANKLIN, 0); + turkey->ev_common_p = common_p; + common_p->_01 = 0; + common_p->_02 = 0; + common_p->_00 = 0; + } else { + turkey->ev_common_p = common_p; + } +} + +static void aETKY_TalkRequest(ACTOR* actorx, GAME* game); +static int aETKY_TalkInit(ACTOR* actorx, GAME* game); +static int aETKY_TalkEndCheck(ACTOR* actorx, GAME* game); + +static void aETKY_SetupTalkStat(EV_TURKEY_ACTOR* turkey, GAME_PLAY* play, int talk_action); + +static void aETKY_actor_ct(ACTOR* actorx, GAME* game) { + static aNPC_ct_data_c ct_data = { + // clang-format off + aETKY_actor_move, + aETKY_actor_draw, + aNPC_CT_SCHED_TYPE_SPECIAL, + aETKY_TalkRequest, + aETKY_TalkInit, + aETKY_TalkEndCheck, + 0, + // clang-format on + }; + + EV_TURKEY_ACTOR* turkey = (EV_TURKEY_ACTOR*)actorx; + + if (NPC_CLIP->birth_check_proc(actorx, game) == TRUE) { + turkey->npc_class.schedule.schedule_proc = aETKY_schedule_proc; + NPC_CLIP->ct_proc(actorx, game, &ct_data); + turkey->talk_setup_proc = aETKY_SetupTalkStat; + aETKY_SetupSaveData(actorx); + aETKY_SetupCommonData(actorx); + turkey->present_idx = aETKY_DecidePresent(&turkey->ev_save_p->given_present_bitfield); + turkey->npc_class.actor_class.status_data.weight = MASSTYPE_HEAVY; + } + + turkey->_9C0 = turkey->npc_class.actor_class.world.position; +} + +static void aETKY_Give_Me_Fork_Init(EV_TURKEY_ACTOR* turkey, GAME_PLAY* play) { + // nothing +} + +static void aETKY_Give_You_Present_Init(EV_TURKEY_ACTOR* turkey, GAME_PLAY* play) { + // nothing +} + +typedef void (*aETKY_TALK_INIT_PROC)(EV_TURKEY_ACTOR* turkey, GAME_PLAY* play); + +static void aETKY_init_proc(EV_TURKEY_ACTOR* turkey, GAME_PLAY* play, int talk_act) { + static aETKY_TALK_INIT_PROC init_proc[] = { + // clang-format off + (aETKY_TALK_INIT_PROC)none_proc1, + (aETKY_TALK_INIT_PROC)none_proc1, + (aETKY_TALK_INIT_PROC)none_proc1, + (aETKY_TALK_INIT_PROC)none_proc1, + (aETKY_TALK_INIT_PROC)none_proc1, + (aETKY_TALK_INIT_PROC)none_proc1, + aETKY_Give_Me_Fork_Init, + aETKY_Give_You_Present_Init, + // clang-format on + }; + + (*init_proc[talk_act])(turkey, play); +} + +static void aETKY_DeleteKnifeInPlayerBag(void) { + int idx = mPr_GetPossessionItemIdxWithCond(Now_Private, ITM_KNIFE_AND_FORK, mPr_ITEM_COND_NORMAL); + + if (idx != -1) { + mPr_SetPossessionItem(Now_Private, idx, EMPTY_NO, mPr_ITEM_COND_NORMAL); + } +} + +static void aETKY_SetKnifeForkSequence(EV_TURKEY_ACTOR* turkey, GAME_PLAY* play) { + int item_idx = mPr_GetPossessionItemIdxWithCond(Now_Private, ITM_KNIFE_AND_FORK, mPr_ITEM_COND_NORMAL); + u8 present_idx; + mActor_name_t present; + u8 item_name[mIN_ITEM_NAME_LEN]; + + if (item_idx == -1) { + mMsg_SET_CONTINUE_MSG_NUM(0x3C02 + RANDOM(3)); + aETKY_SetupTalkStat(turkey, play, aETKY_TALK_WAIT_END); + } else { + present_idx = turkey->present_idx; + present = aETKY_present_table[present_idx]; + mIN_copy_name_str(item_name, present); + mMsg_SET_CONTINUE_MSG_NUM(0x3C11 + present_idx); + mMsg_SET_ITEM_STR_ART(mMsg_ITEM_STR0, item_name, mIN_ITEM_NAME_LEN, present); + aETKY_SetupTalkStat(turkey, play, aETKY_TALK_GIVE_ME_FORK); + } +} + +static void aETKY_Explain_Env0123(EV_TURKEY_ACTOR* turkey, GAME_PLAY* play) { + int talk_action = turkey->talk_action; + int msg_no = mMsg_GET_MSG_NUM(); + + if (mMsg_CHECK_MAINNORMALCONTINUE() && msg_no == 0x3BFD + talk_action) { + if (turkey->talk_action == aETKY_TALK_EXPLAIN_ENV3) { + aETKY_SetKnifeForkSequence(turkey, play); + } else { + mMsg_SET_CONTINUE_MSG_NUM(0x3BFD + talk_action + 1); + aETKY_SetupTalkStat(turkey, play, turkey->talk_action + 1); + } + } +} + +static void aETKY_Find_Reac(EV_TURKEY_ACTOR* turkey, GAME_PLAY* play) { + if (mMsg_CHECK_MAINNORMALCONTINUE()) { + aETKY_SetKnifeForkSequence(turkey, play); + } +} + +static void aETKY_Give_Me_Fork(EV_TURKEY_ACTOR* turkey, GAME_PLAY* play) { + int order = mDemo_Get_OrderValue(mDemo_ORDER_NPC0, 9); + int msg_no = mMsg_GET_MSG_NUM(); // @unused + + switch (order) { + case 1: + // Wait for give_type1 to succeed, and then move over to waiting for give to finish + if (mPlib_request_main_give_type1((GAME*)play, ITM_KNIFE_AND_FORK, aHOI_REQUEST_PUTAWAY, FALSE, FALSE)) { + mDemo_Set_OrderValue(mDemo_ORDER_NPC0, 9, 2); + mMsg_SET_LOCKCONTINUE(); + mDemo_Set_OrderValue(mDemo_ORDER_NPC0, 1, 3); + aETKY_DeleteKnifeInPlayerBag(); + } + break; + case 2: + // Wait for hand over item sequence to finish, then clear order + if (CLIP(handOverItem_clip)->master_actor == NULL) { + mMsg_UNSET_LOCKCONTINUE(); + mDemo_Set_OrderValue(mDemo_ORDER_NPC0, 9, 0); + aETKY_SetupTalkStat(turkey, play, aETKY_TALK_GIVE_YOU_PRESENT); + } + break; + } +} + +static void aETKY_Give_You_Present(EV_TURKEY_ACTOR* turkey, GAME_PLAY* play) { + int order = mDemo_Get_OrderValue(mDemo_ORDER_NPC0, 1); + + if (order == 2) { + mActor_name_t present = aETKY_present_table[turkey->present_idx]; + + aNPC_DEMO_GIVE_ITEM(present, aHOI_REQUEST_PUTAWAY, FALSE); + mPr_SetFreePossessionItem(Now_Private, present, mPr_ITEM_COND_NORMAL); + aETKY_ReportPresent(&turkey->ev_save_p->given_present_bitfield, turkey->present_idx); + aETKY_SetupTalkStat(turkey, play, aETKY_TALK_WAIT_END); + } +} + +static void aETKY_SetupTalkStat(EV_TURKEY_ACTOR* turkey, GAME_PLAY* play, int talk_act) { + static aETKY_TALK_PROC process[] = { + // clang-format off + (aETKY_TALK_PROC)none_proc1, + aETKY_Explain_Env0123, + aETKY_Explain_Env0123, + aETKY_Explain_Env0123, + aETKY_Explain_Env0123, + aETKY_Find_Reac, + aETKY_Give_Me_Fork, + aETKY_Give_You_Present, + // clang-format on + }; + + turkey->talk_action = talk_act; + turkey->talk_proc = process[talk_act]; + aETKY_init_proc(turkey, play, talk_act); +} + +static void aETKY_actor_save(ACTOR* actorx, GAME* game) { + NPC_CLIP->save_proc(actorx, game); +} + +static void aETKY_actor_dt(ACTOR* actorx, GAME* game) { + NPC_CLIP->dt_proc(actorx, game); + mEv_actor_dying_message(mEv_EVENT_HARVEST_FESTIVAL_FRANKLIN, actorx); +} + +static void aETKY_actor_init(ACTOR* actorx, GAME* game) { + NPC_CLIP->init_proc(actorx, game); +} + +static void aETKY_GetTalkStartStatus(int* msg_no, int* next_talk_act, ACTOR* actorx) { + EV_TURKEY_ACTOR* turkey = (EV_TURKEY_ACTOR*)actorx; + aEv_turkey_common_c* common_p = turkey->ev_common_p; + + if (turkey->_9B1 == 1) { + *msg_no = 0x3C1D + gamePT->frame_counter % 5; + *next_talk_act = aETKY_TALK_WAIT_END; + } else { + *msg_no = 0x3BFE; + *next_talk_act = aETKY_TALK_EXPLAIN_ENV0; + + if (common_p != NULL && common_p->_00 != 0) { + *msg_no = 0x3C05 + turkey->present_idx; + *next_talk_act = aETKY_TALK_FIND_REAC; + } + } +} + +static void aETKY_SetTalkInfo(ACTOR* actorx) { + EV_TURKEY_ACTOR* turkey = (EV_TURKEY_ACTOR*)actorx; + int msg_no; + int next_talk_act; + + aETKY_GetTalkStartStatus(&msg_no, &next_talk_act, actorx); + turkey->talk_msg_no = msg_no; + turkey->next_talk_action = next_talk_act; + mEv_set_status(mEv_EVENT_HARVEST_FESTIVAL_FRANKLIN, mEv_STATUS_TALK); + mDemo_Set_msg_num(msg_no); + turkey->ev_common_p->_00++; + turkey->_9B1 = 1; +} + +static void aETKY_TalkRequest(ACTOR* actorx, GAME* game) { + EV_TURKEY_ACTOR* turkey = (EV_TURKEY_ACTOR*)actorx; + + if (turkey->_9B1 == 0) { + ACTOR* playerx = GET_PLAYER_ACTOR_GAME_ACTOR(game); + xyz_t delta; + + delta.x = playerx->world.position.x - actorx->world.position.x; + delta.y = ABS(playerx->world.position.y - actorx->world.position.y); + delta.z = playerx->world.position.z - actorx->world.position.z; + + if (delta.y <= 10.0f) { + if (SQ(delta.x) + SQ(delta.z) <= SQ(55.0f)) { + if (mDemo_Check(mDemo_TYPE_SPEAK, actorx) == TRUE) { + if (mDemo_Check_ListenAble() == FALSE) { + mDemo_Set_ListenAble(); + turkey->_9B1 = 1; + } + } else { + mDemo_Request(mDemo_TYPE_SPEAK, actorx, aETKY_SetTalkInfo); + } + } + } + } else { + mDemo_Request(mDemo_TYPE_TALK, actorx, aETKY_SetTalkInfo); + } +} + +static int aETKY_TalkInit(ACTOR* actorx, GAME* game) { + EV_TURKEY_ACTOR* turkey = (EV_TURKEY_ACTOR*)actorx; + GAME_PLAY* play = (GAME_PLAY*)game; + + (*turkey->talk_setup_proc)(turkey, play, turkey->next_talk_action); + mDemo_Set_ListenAble(); + return TRUE; +} + +static int aETKY_TalkEndCheck(ACTOR* actorx, GAME* game) { + EV_TURKEY_ACTOR* turkey = (EV_TURKEY_ACTOR*)actorx; + GAME_PLAY* play = (GAME_PLAY*)game; + + (*turkey->talk_proc)(turkey, play); + + if (!mDemo_Check(mDemo_TYPE_TALK, actorx) && !mDemo_Check(mDemo_TYPE_SPEAK, actorx)) { + return TRUE; + } + + if (mDemo_Check(mDemo_TYPE_SPEAK, actorx) == TRUE) { + ACTOR* playerx = GET_PLAYER_ACTOR_GAME_ACTOR(game); + s16 actor_look_angle = actorx->shape_info.rotation.y + DEG2SHORT_ANGLE2(180.0f); + s_xyz pl_angle = playerx->shape_info.rotation; + + if (actor_look_angle != pl_angle.y) { + add_calc_short_angle2(&pl_angle.y, actor_look_angle, 0.2f, DEG2SHORT_ANGLE(22.5f), 0); + GET_PLAYER_ACTOR_NOW()->Set_force_position_angle_proc(gamePT, NULL, &pl_angle, mPlayer_FORCE_POSITION_ANGLE_ROTY); + } + } + + return FALSE; +} + +static void aETKY_actor_move(ACTOR* actorx, GAME* game) { + EV_TURKEY_ACTOR* turkey = (EV_TURKEY_ACTOR*)actorx; + ACTOR* playerx = GET_PLAYER_ACTOR_GAME_ACTOR(game); // @unused + + turkey->npc_class.palActorIgnoreTimer = -1; + NPC_CLIP->move_proc(actorx, game); + turkey->npc_class.palActorIgnoreTimer = -1; +} + +static void aETKY_actor_draw(ACTOR* actorx, GAME* game) { + NPC_CLIP->draw_proc(actorx, game); +}