From ff88594f7f6dff4f9dd919aeabe72d7013944f1c Mon Sep 17 00:00:00 2001 From: Cuyler36 Date: Thu, 21 Dec 2023 17:52:57 -0500 Subject: [PATCH] Implement & link ac_npc_curator --- config/rel_slices.yml | 4 + include/ac_npc.h | 56 +- include/ac_npc_curator.h | 15 +- include/m_name_table.h | 29 +- src/ac_npc_curator.c | 126 ++++ src/ac_npc_curator_move.c_inc | 1177 +++++++++++++++++++++++++++++++++ 6 files changed, 1401 insertions(+), 6 deletions(-) create mode 100644 src/ac_npc_curator.c create mode 100644 src/ac_npc_curator_move.c_inc diff --git a/config/rel_slices.yml b/config/rel_slices.yml index 0d2e2ee4..58dfe84e 100644 --- a/config/rel_slices.yml +++ b/config/rel_slices.yml @@ -555,6 +555,10 @@ ac_ev_soncho.c: .text: [0x8052400C, 0x8052475C] .rodata: [0x80649270, 0x80649278] .data: [0x806A0D38, 0x806A0D88] +ac_npc_curator.c: + .text: [0x8054B06C, 0x8054CF28] + .rodata: [0x806495B0, 0x806495B8] + .data: [0x806A4FB0, 0x806A5530] ac_douzou.c: .text: [0x805AD6D8, 0x805AE704] .rodata: [0x8064A7C0, 0x8064A7E8] diff --git a/include/ac_npc.h b/include/ac_npc.h index 990f8a90..7e1405df 100644 --- a/include/ac_npc.h +++ b/include/ac_npc.h @@ -13,8 +13,13 @@ extern "C" { #endif +#define aNPC_SPNPC_BIT_CURATOR 0 #define aNPC_SPNPC_BIT_EV_SONCHO 5 +#define aNPC_SPNPC_BIT_GET(field, bit) (((field) >> (bit)) & 1) +#define aNPC_SPNPC_BIT_SET(field, bit) ((field) |= (1 << (bit))) +#define aNPC_SPNPC_BIT_CLR(field, bit) ((field) &= ~(1 << (bit))) + typedef struct ac_npc_clip_s aNPC_Clip_c; typedef struct npc_draw_data_s { @@ -31,6 +36,29 @@ enum { aNPC_ATTENTION_TYPE_NUM }; +enum { + aNPC_THINK_WAIT, + aNPC_THINK_WANDER, + aNPC_THINK_WANDER2, + aNPC_THINK_GO_HOME, + aNPC_THINK_INTO_HOUSE, + aNPC_THINK_LEAVE_HOUSE, + aNPC_THINK_IN_BLOCK, + aNPC_THINK_PITFALL, + aNPC_THINK_SLEEP, + aNPC_THINK_SPECIAL, + + aNPC_THINK_NUM +}; + +enum { + aNPC_THINK_TYPE_INIT, + aNPC_THINK_TYPE_CHK_INTERRUPT, + aNPC_THINK_TYPE_MAIN, + + aNPC_THINK_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*); @@ -62,6 +90,8 @@ typedef void (*aNPC_MOVE_AFTER_PROC)(ACTOR*, GAME*); typedef void (*aNPC_DRAW_PROC)(ACTOR*, GAME*); typedef void (*aNPC_REBUILD_DMA_PROC)(); +typedef void (*aNPC_ANIMATION_INIT_PROC)(ACTOR*, int, int); +typedef int (*aNPC_CLIP_THINK_PROC)(NPC_ACTOR*, GAME_PLAY*, int, int); typedef int (*aNPC_FORCE_CALL_REQ_PROC)(NPC_ACTOR*, int); @@ -86,7 +116,11 @@ 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[(0x124 - 0x0FC) / sizeof(void*)]; + /* 0x0FC */ void* _0FC[(0x114 - 0x0FC) / sizeof(void*)]; + /* 0x114 */ aNPC_ANIMATION_INIT_PROC animation_init_proc; + /* 0x118 */ void* _118; + /* 0x11C */ void* _11C; + /* 0x120 */ aNPC_CLIP_THINK_PROC think_proc; /* 0x124 */ aNPC_FORCE_CALL_REQ_PROC force_call_req_proc; /* 0x128 */ void* _128; }; @@ -151,6 +185,8 @@ enum { typedef void (*aNPC_ACTION_PROC)(NPC_ACTOR*, GAME_PLAY*, int); +#define aNPC_ACTION_END_STEP 0xFF + typedef struct npc_action_s { u8 priority; u8 idx; @@ -180,6 +216,23 @@ typedef struct npc_request_s { xyz_t head_pos; } aNPC_request_c; +#define aNPC_COND_DEMO_SKIP_MOVE_RANGE_CHECK (1 << 0) /* 0x0001 */ +#define aNPC_COND_DEMO_SKIP_MOVE_CIRCLE_REV (1 << 1) /* 0x0002 */ +#define aNPC_COND_DEMO_SKIP_MOVE_Y (1 << 2) /* 0x0004 */ +#define aNPC_COND_DEMO_SKIP_OBJ_COL_CHECK (1 << 3) /* 0x0008 */ +#define aNPC_COND_DEMO_SKIP_BGCHECK (1 << 4) /* 0x0010 */ +#define aNPC_COND_DEMO_SKIP_FORWARD_CHECK (1 << 5) /* 0x0020 */ +#define aNPC_COND_DEMO_SKIP_ITEM (1 << 6) /* 0x0040 */ +#define aNPC_COND_DEMO_SKIP_TALK_CHECK (1 << 7) /* 0x0080 */ +#define aNPC_COND_DEMO_SKIP_HEAD_LOOKAT (1 << 8) /* 0x0100 */ +#define aNPC_COND_DEMO_SKIP_ENTRANCE_CHECK (1 << 9) /* 0x0200 */ +#define aNPC_COND_DEMO_SKIP_KUTIPAKU (1 << 10) /* 0x0400 */ +#define aNPC_COND_DEMO_SKIP_FOOTSTEPS (1 << 11) /* 0x0800 */ +#define aNPC_COND_DEMO_SKIP_FEEL_CHECK (1 << 12) /* 0x1000 */ +#define aNPC_COND_DEMO_SKIP_LOVE_CHECK (1 << 13) /* 0x2000 */ +#define aNPC_COND_DEMO_SKIP_FOOTSTEPS_VFX (1 << 14) /* 0x4000 */ +#define aNPC_COND_DEMO_SKIP_UZAI_CHECK (1 << 15) /* 0x8000 */ + typedef struct npc_condition_s { u8 hide_flg; u8 hide_request; @@ -296,6 +349,7 @@ typedef struct npc_actor_talk_info_s { s16 npc_voice_id; u8 feel; u8 memory; + u8 kutipaku_timer; // frames of mouth movement animation } aNPC_talk_info_c; typedef struct npc_accessory_s { diff --git a/include/ac_npc_curator.h b/include/ac_npc_curator.h index f6860c1a..d1480270 100644 --- a/include/ac_npc_curator.h +++ b/include/ac_npc_curator.h @@ -9,16 +9,25 @@ extern "C" { #endif +#define aCR_SLEEP_WAIT_TIMER (6 * 60) // 6 seconds (calculated in frames frames) +#define aCR_SLEEP_TIME_START ( 6 * mTM_SECONDS_IN_HOUR) +#define aCR_SLEEP_TIME_END (18 * mTM_SECONDS_IN_HOUR) + typedef struct npc_curator_actor_s NPC_CURATOR_ACTOR; +typedef void (*aCR_SETUPTALKACTION_PROC)(NPC_CURATOR_ACTOR*, GAME_PLAY*, int); +typedef void (*aCR_ACTION_PROC)(NPC_ACTOR*, GAME_PLAY*); +typedef void (*aCR_ACT_PROC)(NPC_CURATOR_ACTOR*, GAME_PLAY*); +typedef void (*aCR_TALK_ACT_PROC)(NPC_CURATOR_ACTOR*, GAME_PLAY*); + struct npc_curator_actor_s { NPC_ACTOR npc_class; int action; - aNPC_SUB_PROC action_proc; + aCR_ACT_PROC action_proc; int sleep_wait_timer; int talk_act_idx; - aNPC_SUB_PROC talk_proc; - aNPC_PROC setupTalkAction_proc; + aCR_TALK_ACT_PROC talk_proc; + aCR_SETUPTALKACTION_PROC setupTalkAction_proc; int msg_no; int _9B0; // might be unused 'awake' state mActor_name_t donated_item; diff --git a/include/m_name_table.h b/include/m_name_table.h index 111a6e69..51bd9944 100644 --- a/include/m_name_table.h +++ b/include/m_name_table.h @@ -637,9 +637,31 @@ extern int mNT_check_unknown(mActor_name_t item_no); #define FTR_DINO_START 0x1EEC #define FTR_DINO_TRICERA_SKULL FTR_DINO_START - +#define FTR_DINO_TRICERA_TAIL 0x1EF0 +#define FTR_DINO_TRICERA_BODY 0x1EF4 #define FTR_DINO_TREX_SKULL 0x1EF8 - +#define FTR_DINO_TREX_TAIL 0x1EFC +#define FTR_DINO_TREX_BODY 0x1F00 +#define FTR_DINO_APATO_SKULL 0x1F04 +#define FTR_DINO_APATO_TAIL 0x1F08 +#define FTR_DINO_APATO_BODY 0x1F0C +#define FTR_DINO_STEGO_SKULL 0x1F10 +#define FTR_DINO_STEGO_TAIL 0x1F14 +#define FTR_DINO_STEGO_BODY 0x1F18 +#define FTR_DINO_PTERA_SKULL 0x1F1C +#define FTR_DINO_PTERA_RIGHT_WING 0x1F20 +#define FTR_DINO_PTERA_LEFT_WING 0x1F24 +#define FTR_DINO_PLESIO_SKULL 0x1F28 +#define FTR_DINO_PLESIO_NECK 0x1F2C +#define FTR_DINO_PLESIO_TORSO 0x1F30 +#define FTR_DINO_MAMMOTH_SKULL 0x1F34 +#define FTR_DINO_MAMMOTH_TORSO 0x1F38 +#define FTR_FOSSIL_AMBER 0x1F3C +#define FTR_FOSSIL_TRACK 0x1F40 +#define FTR_FOSSIL_AMMONITE 0x1F44 +#define FTR_FOSSIL_EGG 0x1F48 +#define FTR_FOSSIL_TRILOBITE 0x1F4C +// #define FTR_DINO_TRILOBITE_WEST 0x1F4F #define FTR_DINO_END FTR_DINO_TRILOBITE_WEST @@ -1556,6 +1578,9 @@ extern int mNT_check_unknown(mActor_name_t item_no); #define FTR_AXE 0x3190 +#define FTR_PAINTING15_UNUSED 0x31D8 +#define FTR_PAINTING16_UNUSED 0x31DC + #define FTR_BOTTLE_ROCKET 0x31F0 #define FTR_FISHING_TROPHY 0x3210 diff --git a/src/ac_npc_curator.c b/src/ac_npc_curator.c new file mode 100644 index 00000000..cf916c33 --- /dev/null +++ b/src/ac_npc_curator.c @@ -0,0 +1,126 @@ +#include "ac_npc_curator.h" + +#include "m_common_data.h" +#include "m_item_name.h" +#include "m_msg.h" + +enum { + aCR_ACTION_WAIT, + aCR_ACTION_SLEEP_WAIT, + aCR_ACTION_SLEEP, + + aCR_ACTION_NUM +}; + +enum { + aCR_TALK_END_WAIT, + aCR_TALK_AFTER_TALK_START_WAIT, + aCR_TALK_CHK_REQUEST, + aCR_TALK_CHK_DECIDE_TO_DONATE, + aCR_TALK_CHK_DECIDE_TO_DONATE2, + aCR_TALK_MENU_OPEN_WAIT, + aCR_TALK_MSG_WIN_CLOSE_WAIT, + aCR_TALK_MENU_CLOSE_WAIT, + aCR_TALK_GET_DEMO_START_WAIT, + aCR_TALK_GET_DEMO_END_WAIT, + aCR_TALK_MSG_WIN_OPEN_WAIT, + aCR_TALK_RETURN_DEMO_START_WAIT, + aCR_TALK_RETURN_DEMO_START_WAIT2, + aCR_TALK_RETURN_DEMO_END_WAIT, + aCR_TALK_RETURN_DEMO_END_WAIT2, + aCR_TALK_CHK_CONTINUE_TO_DONATE, + aCR_TALK_CHK_CONTINUE_TO_DONATE2, + aCR_TALK_CHK_CONTINUE_TO_DONATE3, + aCR_TALK_PUTAWAY_DEMO_START_WAIT, + aCR_TALK_PUTAWAY_DEMO_START_WAIT2, + aCR_TALK_PUTAWAY_DEMO_START_WAIT3, + aCR_TALK_PUTAWAY_DEMO_START_WAIT4, + aCR_TALK_PUTAWAY_DEMO_START_WAIT5, + aCR_TALK_PUTAWAY_DEMO_START_WAIT6, + aCR_TALK_PUTAWAY_DEMO_START_WAIT5_2, + aCR_TALK_PUTAWAY_DEMO_END_WAIT, + aCR_TALK_PUTAWAY_DEMO_END_WAIT2, + aCR_TALK_PUTAWAY_DEMO_END_WAIT3, + aCR_TALK_PUTAWAY_DEMO_END_WAIT4, + aCR_TALK_PUTAWAY_DEMO_END_WAIT5, + aCR_TALK_PUTAWAY_DEMO_END_WAIT6, + aCR_TALK_AFTER_EXPLAIN_INSECT, + aCR_TALK_THANKS_FOSSIL_MSG_END_WAIT, + aCR_TALK_CHK_ALL_COMPLETE, + + aCR_TALK_NUM +}; + +static void aCR_actor_ct(ACTOR* actorx, GAME* game); +static void aCR_actor_dt(ACTOR* actorx, GAME* game); +static void aCR_actor_move(ACTOR* actorx, GAME* game); +static void aCR_actor_draw(ACTOR* actorx, GAME* game); +static void aCR_actor_init(ACTOR* actorx, GAME* game); +static void aCR_actor_save(ACTOR* actorx, GAME* game); + +ACTOR_PROFILE Npc_Curator_Profile = { + mAc_PROFILE_NPC_CURATOR, + ACTOR_PART_NPC, + ACTOR_STATE_NONE, + SP_NPC_CURATOR, + ACTOR_OBJ_BANK_KEEP, + sizeof(NPC_CURATOR_ACTOR), + &aCR_actor_ct, + &aCR_actor_dt, + &aCR_actor_init, + mActor_NONE_PROC1, + &aCR_actor_save +}; + +static void aCR_talk_request(ACTOR* actorx, GAME* game); +static int aCR_talk_init(ACTOR* actorx, GAME* game); +static int aCR_talk_end_chk(ACTOR* actorx, GAME* game); + +static void aCR_schedule_proc(NPC_ACTOR* actorx, GAME_PLAY* play, int sched_idx); +static void aCR_setupTalkAction(NPC_CURATOR_ACTOR* curator, GAME_PLAY* play, int talk_act_idx); +static void aCR_setupAction(NPC_CURATOR_ACTOR* curator, GAME_PLAY* play, int action); + +static void aCR_actor_ct(ACTOR* actorx, GAME* game) { + static aNPC_ct_data_c ct_data = { + &aCR_actor_move, + &aCR_actor_draw, + 5, + &aCR_talk_request, + &aCR_talk_init, + &aCR_talk_end_chk, + 0 + }; + + NPC_CURATOR_ACTOR* curator = (NPC_CURATOR_ACTOR*)actorx; + + if ((*Common_Get(clip).npc_clip->birth_check_proc)(actorx, game) == TRUE) { + curator->npc_class.schedule.schedule_proc = &aCR_schedule_proc; + (*Common_Get(clip).npc_clip->ct_proc)(actorx, game, &ct_data); + actorx->status_data.weight = 255; + actorx->world.position.x += 20.0f; + curator->setupTalkAction_proc = &aCR_setupTalkAction; + + /* Clear 'first talk' flag if entering from a scene outside the museum */ + if (Common_Get(last_scene_no) >= SCENE_MY_ROOM_LL1 || Common_Get(last_scene_no) < SCENE_MUSEUM_ROOM_PAINTING) { + aNPC_SPNPC_BIT_CLR(Common_Get(spnpc_first_talk_flags), aNPC_SPNPC_BIT_CURATOR); + } + } +} + +static void aCR_actor_save(ACTOR* actorx, GAME* game) { + (*Common_Get(clip).npc_clip->save_proc)(actorx, game); +} + +static void aCR_actor_dt(ACTOR* actorx, GAME* game) { + (*Common_Get(clip).npc_clip->dt_proc)(actorx, game); +} + +static void aCR_actor_init(ACTOR* actorx, GAME* game) { + (*Common_Get(clip).npc_clip->init_proc)(actorx, game); +} + +static void aCR_actor_draw(ACTOR* actorx, GAME* game) { + (*Common_Get(clip).npc_clip->draw_proc)(actorx, game); +} + +#include "../src/ac_npc_curator_move.c_inc" diff --git a/src/ac_npc_curator_move.c_inc b/src/ac_npc_curator_move.c_inc new file mode 100644 index 00000000..47f8d33b --- /dev/null +++ b/src/ac_npc_curator_move.c_inc @@ -0,0 +1,1177 @@ +static void aCR_set_animation(NPC_CURATOR_ACTOR* curator, int action) { + static int animeSeqNo[] = { 5, 5, 9 }; + + (*Common_Get(clip).npc_clip->animation_init_proc)((ACTOR*)curator, animeSeqNo[action], FALSE); +} + +static void aCR_set_request_act(NPC_CURATOR_ACTOR* curator) { + curator->npc_class.request.act_priority = 4; + curator->npc_class.request.act_idx = 16; + curator->npc_class.request.act_type = 2; +} + +static int aCR_check_sleep_time() { + int res = FALSE; + + if (Common_Get(time.now_sec) >= aCR_SLEEP_TIME_START && Common_Get(time.now_sec) < aCR_SLEEP_TIME_END) { + res = TRUE; + } + + return res; +} + +static void aCR_sleep_wait(NPC_CURATOR_ACTOR* curator, GAME_PLAY* play) { + curator->sleep_wait_timer--; + + if (curator->sleep_wait_timer <= 0) { + aCR_setupAction(curator, play, aCR_ACTION_SLEEP); // Go back to sleep + } +} + +static void aCR_wait_init(NPC_CURATOR_ACTOR* curator) { + curator->npc_class.condition_info.demo_flg = 0; + curator->npc_class.head.angle_add_y = DEG2SHORT_ANGLE(5.625f); + curator->npc_class.movement.mv_angl = DEG2SHORT_ANGLE(0.0f); + curator->npc_class.movement.mv_add_angl = DEG2SHORT_ANGLE(5.625f); +} + +static void aCR_sleep_wait_init(NPC_CURATOR_ACTOR* curator) { + aCR_wait_init(curator); + curator->sleep_wait_timer = aCR_SLEEP_WAIT_TIMER; +} + +static void aCR_sleep_init(NPC_CURATOR_ACTOR* curator) { + curator->npc_class.condition_info.demo_flg = aNPC_COND_DEMO_SKIP_HEAD_LOOKAT; + curator->npc_class.head.angle_add_y = DEG2SHORT_ANGLE(1.40625f); + curator->_9B0 = 0; +} + +typedef void (*aCR_INIT_PROC)(NPC_CURATOR_ACTOR*); + +static void aCR_setupAction(NPC_CURATOR_ACTOR* curator, GAME_PLAY* play, int action) { + static aCR_ACT_PROC process[aCR_ACTION_NUM] = { + (aCR_ACT_PROC)&none_proc1, + &aCR_sleep_wait, + (aCR_ACT_PROC)&none_proc1 + }; + + static aCR_INIT_PROC init_proc[aCR_ACTION_NUM] = { + &aCR_wait_init, + &aCR_sleep_wait_init, + &aCR_sleep_init + }; + + aCR_set_animation(curator, action); + curator->action = action; + curator->action_proc = process[action]; + (*init_proc[action])(curator); +} + +static void aCR_act_chg_data_proc(NPC_ACTOR* actorx, GAME_PLAY* play) { + NPC_CURATOR_ACTOR* curator = (NPC_CURATOR_ACTOR*)actorx; + + curator->npc_class.action.act_obj = aNPC_ACT_OBJ_PLAYER; +} + +static void aCR_act_init_proc(NPC_ACTOR* actorx, GAME_PLAY* play) { + NPC_CURATOR_ACTOR* curator = (NPC_CURATOR_ACTOR*)actorx; + int action; + + if (curator->action == aCR_ACTION_WAIT) { + if (aCR_check_sleep_time() == TRUE) { + action = aCR_ACTION_SLEEP_WAIT; + } + else { + action = aCR_ACTION_WAIT; + } + } + else { + if (aCR_check_sleep_time() == TRUE) { + action = aCR_ACTION_SLEEP; + } + else { + action = aCR_ACTION_WAIT; + } + } + + actorx->action.step = 0; + aCR_setupAction(curator, play, action); +} + +static void aCR_act_main_proc(NPC_ACTOR* actorx, GAME_PLAY* play) { + NPC_CURATOR_ACTOR* curator = (NPC_CURATOR_ACTOR*)actorx; + + (*curator->action_proc)(curator, play); +} + +static void aCR_act_proc(NPC_ACTOR* actorx, GAME_PLAY* play, int action) { + static aCR_ACTION_PROC act_proc[aCR_ACTION_NUM] = { + &aCR_act_init_proc, + &aCR_act_chg_data_proc, + &aCR_act_main_proc + }; + + (*act_proc[action])(actorx, play); +} + +static void aCR_think_main_proc(NPC_ACTOR* actorx, GAME_PLAY* play) { + NPC_CURATOR_ACTOR* curator = (NPC_CURATOR_ACTOR*)actorx; + + if (curator->npc_class.action.step == aNPC_ACTION_END_STEP) { + aCR_set_request_act(curator); + } + else if (curator->npc_class.action.idx == 16) { + if (aCR_check_sleep_time() == TRUE) { + if (curator->action == aCR_ACTION_WAIT) { + aCR_setupAction(curator, play, aCR_ACTION_SLEEP_WAIT); + } + } + else if (curator->action == aCR_ACTION_SLEEP) { + aCR_setupAction(curator, play, aCR_ACTION_WAIT); + } + } +} + +static void aCR_think_init_proc(NPC_ACTOR* actorx, GAME_PLAY* play) { + NPC_CURATOR_ACTOR* curator = (NPC_CURATOR_ACTOR*)actorx; + int action; + + if (aCR_check_sleep_time() == TRUE) { + action = aCR_ACTION_SLEEP; + } + else { + action = aCR_ACTION_WAIT; + } + + curator->action = action; + curator->npc_class.action.act_proc = &aCR_act_proc; + aCR_set_request_act(curator); +} + +typedef void (*aCR_THINK_PROC)(NPC_ACTOR*, GAME_PLAY*); + +static void aCR_think_proc(NPC_ACTOR* actorx, GAME_PLAY* play, int think_idx) { + static aCR_THINK_PROC think_proc[2] = { + &aCR_think_init_proc, + &aCR_think_main_proc + }; + + (*think_proc[think_idx])(actorx, play); +} + +static void aCR_schedule_init_proc(NPC_ACTOR* actorx, GAME_PLAY* play) { + actorx->think.think_proc = &aCR_think_proc; + actorx->condition_info.hide_request = FALSE; + (*Common_Get(clip).npc_clip->think_proc)(actorx, play, aNPC_THINK_IN_BLOCK, aNPC_THINK_TYPE_INIT); +} + +static void aCR_schedule_main_proc(NPC_ACTOR* actorx, GAME_PLAY* play) { + if ((*Common_Get(clip).npc_clip->think_proc)(actorx, play, -1, aNPC_THINK_TYPE_CHK_INTERRUPT) == FALSE) { + (*Common_Get(clip).npc_clip->think_proc)(actorx, play, -1, aNPC_THINK_TYPE_MAIN); + } +} + +typedef void (*aCR_SCHEDULE_PROC)(NPC_ACTOR*, GAME_PLAY*); + +static void aCR_schedule_proc(NPC_ACTOR* actorx, GAME_PLAY* play, int proc_idx) { + static aCR_SCHEDULE_PROC sched_proc[] = { + &aCR_schedule_init_proc, + &aCR_schedule_main_proc + }; + + (*sched_proc[proc_idx])(actorx, play); +} + +enum { + aCR_FOSSIL_TYPE_TRICERA, + aCR_FOSSIL_TYPE_TREX, + aCR_FOSSIL_TYPE_APATO, + aCR_FOSSIL_TYPE_STEGO, + aCR_FOSSIL_TYPE_PTERA, + aCR_FOSSIL_TYPE_PLESIO, + aCR_FOSSIL_TYPE_MAMMOTH, + + aCR_FOSSIL_TYPE_NUM +}; + +static int aCR_get_fossil_type(mActor_name_t item) { + static int fossil_ftr_start[aCR_FOSSIL_TYPE_NUM] = { + FTR_DINO_TRICERA_SKULL, + FTR_DINO_TREX_SKULL, + FTR_DINO_APATO_SKULL, + FTR_DINO_STEGO_SKULL, + FTR_DINO_PTERA_SKULL, + FTR_DINO_PLESIO_SKULL, + FTR_DINO_MAMMOTH_SKULL + }; + + static int fossil_ftr_end[aCR_FOSSIL_TYPE_NUM] = { + FTR_DINO_TRICERA_BODY+3, + FTR_DINO_TREX_BODY+3, + FTR_DINO_APATO_BODY+3, + FTR_DINO_STEGO_BODY+3, + FTR_DINO_PTERA_LEFT_WING+3, + FTR_DINO_PLESIO_TORSO+3, + FTR_DINO_MAMMOTH_TORSO+3 + }; + + int res = -1; + int i; + + for (i = 0; i < aCR_FOSSIL_TYPE_NUM; i++) { + if (item >= fossil_ftr_start[i] && item <= fossil_ftr_end[i]) { + res = i; + break; + } + } + + return res; +} + +typedef struct { + int count; + mActor_name_t* parts; +} aCR_fossil_part_c; + +#define aCR_GetFossilPartDonator(item_no) \ + mMmd_FossilInfo(((item_no) >= FTR_DINO_START && (item_no) <= FTR_DINO_END) ? FTR_IDX_2_NO((item_no - FTR_DINO_START)) : 0) +#define aCR_GetArtDonator(item_no) \ + mMmd_ArtInfo(((item_no) >= FTR_PAINTING0 && (item_no) <= FTR_PAINTING14_WEST) ? FTR_IDX_2_NO((item_no - FTR_PAINTING0)) : 0) +#define aCR_GetInsectDonator(item_no) \ + mMmd_InsectInfo(((item_no) >= ITM_INSECT_START && (item_no) < ITM_INSECT_END) ? (item_no - ITM_INSECT_START) : 0) +#define aCR_GetFishDonator(item_no) \ + mMmd_FishInfo(((item_no) >= ITM_FISH_START && (item_no) <= ITM_FISH_END) ? (item_no - ITM_FISH_START) : 0) + +static int aCR_chk_fossil_parts_complete_sub(int type) { + static mActor_name_t trikera_parts[] = { FTR_DINO_TRICERA_SKULL, FTR_DINO_TRICERA_TAIL, FTR_DINO_TRICERA_BODY }; + static mActor_name_t trex_parts[] = { FTR_DINO_TREX_SKULL, FTR_DINO_TREX_TAIL, FTR_DINO_TREX_BODY }; + static mActor_name_t bront_parts[] = { FTR_DINO_APATO_SKULL, FTR_DINO_APATO_TAIL, FTR_DINO_APATO_BODY }; + static mActor_name_t stego_parts[] = { FTR_DINO_STEGO_SKULL, FTR_DINO_STEGO_TAIL, FTR_DINO_STEGO_BODY }; + static mActor_name_t ptera_parts[] = { FTR_DINO_PTERA_SKULL, FTR_DINO_PTERA_RIGHT_WING, FTR_DINO_PTERA_LEFT_WING }; + static mActor_name_t hutaba_parts[] = { FTR_DINO_PLESIO_SKULL, FTR_DINO_PLESIO_NECK, FTR_DINO_PLESIO_TORSO }; + static mActor_name_t mammoth_parts[] = { FTR_DINO_MAMMOTH_SKULL, FTR_DINO_MAMMOTH_TORSO }; + static aCR_fossil_part_c fossil_parts[aCR_FOSSIL_TYPE_NUM] = { + { ARRAY_COUNT(trikera_parts), trikera_parts }, + { ARRAY_COUNT(trex_parts), trex_parts }, + { ARRAY_COUNT(bront_parts), bront_parts }, + { ARRAY_COUNT(stego_parts), stego_parts }, + { ARRAY_COUNT(ptera_parts), ptera_parts }, + { ARRAY_COUNT(hutaba_parts), hutaba_parts }, + { ARRAY_COUNT(mammoth_parts), mammoth_parts } + }; + + aCR_fossil_part_c* fossil_part = &fossil_parts[type]; + int i = fossil_part->count; + mActor_name_t* fossil_part_p = fossil_part->parts; + int res = TRUE; + + while (i != 0) { + int valid = aCR_GetFossilPartDonator(*fossil_part_p) >= mMmd_DONATOR_PLAYER1 + && aCR_GetFossilPartDonator(*fossil_part_p) <= mMmd_DONATOR_DELETED_PLAYER; + + if (!valid) { + res = FALSE; + break; + } + + fossil_part_p++; + i--; + } + + return res; +} + +static void aCR_chk_fossil_parts_complete(NPC_CURATOR_ACTOR* curator, GAME_PLAY* play) { + static int msg_no_table[aCR_FOSSIL_TYPE_NUM] = { + 0x2F78, + 0x2F79, + 0x2F7A, + 0x2F7B, + 0x2F7C, + 0x2F7D, + 0x2F7E + }; + + int fossil_type = aCR_get_fossil_type(play->submenu.item_p->item); + int msg_no = 0x2F84; + + if (fossil_type != -1 && aCR_chk_fossil_parts_complete_sub(fossil_type) == TRUE) { + msg_no = msg_no_table[fossil_type]; + } + + mMsg_Set_continue_msg_num(mMsg_Get_base_window_p(), msg_no); + curator->msg_no = msg_no; + (*curator->setupTalkAction_proc)(curator, play, aCR_TALK_THANKS_FOSSIL_MSG_END_WAIT); +} + +static void aCR_chk_fossil_complete(NPC_CURATOR_ACTOR* curator, GAME_PLAY* play) { + static int msg_no[] = { 0x2F73, 0x2F85 }; + static int next_act_idx[] = { aCR_TALK_CHK_CONTINUE_TO_DONATE3, aCR_TALK_CHK_ALL_COMPLETE }; + + mMsg_Window_c* msg_p = mMsg_Get_base_window_p(); + int complete = FALSE; + + if (mMmd_CountDisplayedFossil() == mMmd_FOSSIL_NUM) { + complete = TRUE; + } + + mMsg_Set_continue_msg_num(msg_p, msg_no[complete]); + curator->msg_no = msg_no[complete]; + (*curator->setupTalkAction_proc)(curator, play, next_act_idx[complete]); +} + +static void aCR_chk_art_complete(NPC_CURATOR_ACTOR* curator, GAME_PLAY* play) { + static int msg_no[] = { 0x2F73, 0x2F75 }; + static int next_act_idx[] = { aCR_TALK_CHK_CONTINUE_TO_DONATE3, aCR_TALK_CHK_ALL_COMPLETE }; + + int complete = FALSE; + + if (mMmd_CountDisplayedArt() == mMmd_ART_NUM) { + complete = TRUE; + } + + mMsg_Set_continue_msg_num(mMsg_Get_base_window_p(), msg_no[complete]); + curator->msg_no = msg_no[complete]; + (*curator->setupTalkAction_proc)(curator, play, next_act_idx[complete]); +} + +static void aCR_chk_fish_complete(NPC_CURATOR_ACTOR* curator, GAME_PLAY* play) { + static int msg_no[] = { 0x2F73, 0x2F8A }; + static int next_act_idx[] = { aCR_TALK_CHK_CONTINUE_TO_DONATE3, aCR_TALK_CHK_ALL_COMPLETE }; + + int complete = FALSE; + + if (mMmd_CountDisplayedFish() == mMmd_FISH_NUM) { + complete = TRUE; + } + + mMsg_Set_continue_msg_num(mMsg_Get_base_window_p(), msg_no[complete]); + curator->msg_no = msg_no[complete]; + (*curator->setupTalkAction_proc)(curator, play, next_act_idx[complete]); +} + +static void aCR_chk_insect_complete(NPC_CURATOR_ACTOR* curator, GAME_PLAY* play) { + static int msg_no[] = { 0x2F73, 0x2F88 }; + static int next_act_idx[] = { aCR_TALK_CHK_CONTINUE_TO_DONATE3, aCR_TALK_CHK_ALL_COMPLETE }; + + int complete = FALSE; + + if (mMmd_CountDisplayedInsect() == mMmd_INSECT_NUM) { + complete = TRUE; + } + + mMsg_Set_continue_msg_num(mMsg_Get_base_window_p(), msg_no[complete]); + curator->msg_no = msg_no[complete]; + (*curator->setupTalkAction_proc)(curator, play, next_act_idx[complete]); +} + +static void aCR_set_after_explain_insect(NPC_CURATOR_ACTOR* curator, GAME_PLAY* play) { + static int msg_no[] = { + 0x3A56, + 0x3A56, + 0x3A56, + 0x3A56, + 0x3A57, + 0x3A57, + 0x3A5D, + 0x3A57, + 0x3A5E, + 0x3A58, + 0x3A58, + 0x3A58, + 0x3A5F, + 0x3A59, + 0x3A59, + 0x3A5A, + 0x3A5A, + 0x3A5A, + 0x3A5A, + 0x3A5B, + 0x3A5B, + 0x3A5B, + 0x3A61, + 0x3A62, + 0x3A5C, + 0x3A5C, + 0x3A63, + 0x3A64, + 0x3A56, + 0x3A5B, + 0x3A5B, + 0x3A60, + 0x3A6B, + 0x3A69, + 0x3A65, + 0x3A6C, + 0x3A68, + 0x3A6A, + 0x3A66, + 0x3A67 + }; + + int insect_type = curator->donated_item - ITM_INSECT_START; + + if (insect_type < 0 || insect_type >= INSECT_ONLY_NUM) { + insect_type = 0; + } + + mMsg_Set_continue_msg_num(mMsg_Get_base_window_p(), msg_no[insect_type]); + curator->msg_no = msg_no[insect_type]; + (*curator->setupTalkAction_proc)(curator, play, aCR_TALK_AFTER_EXPLAIN_INSECT); +} + +static void aCR_set_item_name_str(mActor_name_t item) { + u8 item_str[mIN_ITEM_NAME_LEN]; + + mIN_copy_name_str(item_str, item); + mMsg_Set_item_str_art(mMsg_Get_base_window_p(), mMsg_FREE_STR0, item_str, sizeof(item_str), mIN_get_item_article(item)); +} + +static void aCR_set_other_player_name_str(int player_no) { + mMsg_Set_free_str(mMsg_Get_base_window_p(), mMsg_FREE_STR0, Save_Get(private[player_no]).player_ID.player_name, PLAYER_NAME_LEN); +} + +static int aCR_countDisplayed() { + return mMmd_CountDisplayedFossil() + mMmd_CountDisplayedArt() + mMmd_CountDisplayedInsect() + mMmd_CountDisplayedFish(); +} + +static int aCR_get_msg_no_after_talk() { + static int msg_no[] = { 0x2F58, 0x2F59, 0x2F5A, 0x2F5B }; + int displayed = aCR_countDisplayed(); + int idx; + + if (displayed == 0) { + idx = 0; + } + else if (displayed <= 36) { + idx = 1; + } + else if (displayed <= 84) { + idx = 2; + } + else { + idx = 3; + } + + return msg_no[idx]; +} + +static int aCR_get_idx_to_donate_fossil(mActor_name_t item) { + int donator = aCR_GetFossilPartDonator(item); + + if (donator == (Common_Get(player_no) + 1)) { + return 4; + } + + switch (donator) { + case mMmd_DONATOR_NONE: + { + switch (item) { + case FTR_FOSSIL_TRILOBITE: + return 17; + case FTR_FOSSIL_AMMONITE: + return 18; + case FTR_FOSSIL_EGG: + return 19; + case FTR_FOSSIL_TRACK: + return 20; + case FTR_FOSSIL_AMBER: + return 21; + default: + return 16; + } + } + + case mMmd_DONATOR_DELETED_PLAYER: + return 12; + } + + aCR_set_other_player_name_str(donator - 1); + return 8; +} + +static int aCR_get_idx_to_donate_art(mActor_name_t item) { + int donator = aCR_GetArtDonator(item); + + switch (item) { + case FTR_PAINTING15_UNUSED: + case FTR_PAINTING16_UNUSED: + return 1; + } + + if (donator == (Common_Get(player_no) + 1)) { + return 5; + } + + switch (donator) { + case mMmd_DONATOR_NONE: + return 22 + RANDOM(3); + case mMmd_DONATOR_DELETED_PLAYER: + return 13; + } + + aCR_set_other_player_name_str(donator - 1); + return 9; +} + +static int aCR_get_idx_to_donate_insect(mActor_name_t item) { + int donator = aCR_GetInsectDonator(item); + int res; + + if (donator == (Common_Get(player_no) + 1)) { + res = 7; + } + else { + switch (donator) { + case mMmd_DONATOR_NONE: + { + /* Is it a cockroach? */ + if (item == ITM_INSECT28) { + res = 26; + } + else { + res = 25; + } + break; + } + + case mMmd_DONATOR_DELETED_PLAYER: + res = 15; + break; + + default: + aCR_set_other_player_name_str(donator - 1); + res = 11; + break; + } + } + + return res; +} + +static int aCR_get_idx_to_donate_fish(mActor_name_t item) { + int donator = aCR_GetFishDonator(item); + + if (donator == (Common_Get(player_no) + 1)) { + return 6; + } + + switch (donator) { + case mMmd_DONATOR_NONE: + return 27; + + case mMmd_DONATOR_DELETED_PLAYER: + return 14; + } + + aCR_set_other_player_name_str(donator - 1); + return 10; +} + +static void aCR_after_talk_start_wait(NPC_CURATOR_ACTOR* curator, GAME_PLAY* play) { + mMsg_Window_c* msg_p = mMsg_Get_base_window_p(); + + if (mMsg_Check_MainNormalContinue(msg_p) == TRUE) { + int msg_no = aCR_get_msg_no_after_talk(); + + mMsg_Set_continue_msg_num(msg_p, msg_no); + (*curator->setupTalkAction_proc)(curator, play, aCR_TALK_END_WAIT); + } +} + +static void aCR_chk_request(NPC_CURATOR_ACTOR* curator, GAME_PLAY* play) { + mMsg_Window_c* msg_p = mMsg_Get_base_window_p(); + int talk_act; + + if (mMsg_Get_msg_num(msg_p) == 0x2F50 && mMsg_Check_MainNormalContinue(msg_p) == TRUE) { + switch (mChoice_Get_ChoseNum(mChoice_Get_base_window_p())) { + case mChoice_CHOICE0: + talk_act = aCR_TALK_MENU_OPEN_WAIT; + break; + case mChoice_CHOICE1: + talk_act = aCR_TALK_CHK_DECIDE_TO_DONATE; + break; + case mChoice_CHOICE2: + talk_act = aCR_TALK_AFTER_TALK_START_WAIT; + break; + default: + talk_act = aCR_TALK_END_WAIT; + break; + } + + (*curator->setupTalkAction_proc)(curator, play, talk_act); + } +} + +static void aCR_chk_decide_to_donate(NPC_CURATOR_ACTOR* curator, GAME_PLAY* play) { + mMsg_Window_c* msg_p = mMsg_Get_base_window_p(); + int talk_act; + + if (mMsg_Get_msg_num(msg_p) == 0x2F5F && mMsg_Check_MainNormalContinue(msg_p) == TRUE) { + switch (mChoice_Get_ChoseNum(mChoice_Get_base_window_p())) { + case mChoice_CHOICE0: + talk_act = aCR_TALK_CHK_DECIDE_TO_DONATE2; + break; + case mChoice_CHOICE1: + talk_act = aCR_TALK_END_WAIT; + break; + default: + talk_act = aCR_TALK_END_WAIT; + break; + } + + (*curator->setupTalkAction_proc)(curator, play, talk_act); + } +} + +static void aCR_chk_decide_to_donate2(NPC_CURATOR_ACTOR* curator, GAME_PLAY* play) { + mMsg_Window_c* msg_p = mMsg_Get_base_window_p(); + int talk_act; + + if (mMsg_Get_msg_num(msg_p) == 0x2F60 && mMsg_Check_MainNormalContinue(msg_p) == TRUE) { + switch (mChoice_Get_ChoseNum(mChoice_Get_base_window_p())) { + case mChoice_CHOICE0: + talk_act = aCR_TALK_MENU_OPEN_WAIT; + break; + case mChoice_CHOICE1: + talk_act = aCR_TALK_END_WAIT; + break; + default: + talk_act = aCR_TALK_END_WAIT; + break; + } + + (*curator->setupTalkAction_proc)(curator, play, talk_act); + } +} + +static void aCR_menu_open_wait(NPC_CURATOR_ACTOR* curator, GAME_PLAY* play) { + if (mMsg_Check_MainNormalContinue(mMsg_Get_base_window_p()) == TRUE) { + (*curator->setupTalkAction_proc)(curator, play, aCR_TALK_MSG_WIN_CLOSE_WAIT); + } +} + +static void aCR_msg_win_close_wait(NPC_CURATOR_ACTOR* curator, GAME_PLAY* play) { + if (mMsg_Check_main_wait(mMsg_Get_base_window_p()) == TRUE) { + (*curator->setupTalkAction_proc)(curator, play, aCR_TALK_MENU_CLOSE_WAIT); + } +} + +static void aCR_menu_close_wait(NPC_CURATOR_ACTOR* curator, GAME_PLAY* play) { + int talk_act; + + if (play->submenu.flag == FALSE) { + talk_act = aCR_TALK_GET_DEMO_START_WAIT; + + if (play->submenu.item_p->item == EMPTY_NO) { + talk_act = aCR_TALK_MSG_WIN_OPEN_WAIT; + } + + (*curator->setupTalkAction_proc)(curator, play, talk_act); + } +} + +static void aCR_get_demo_start_wait(NPC_CURATOR_ACTOR* curator, GAME_PLAY* play) { + if (Common_Get(clip).handOverItem_clip->request_mode == aHOI_REQUEST_TRANS_WAIT) { + (*curator->setupTalkAction_proc)(curator, play, aCR_TALK_GET_DEMO_END_WAIT); + } +} + +static void aCR_get_demo_end_wait(NPC_CURATOR_ACTOR* curator, GAME_PLAY* play) { + if (Common_Get(clip).handOverItem_clip->request_mode == aHOI_REQUEST_GET_PULL_WAIT) { + curator->npc_class.talk_info.default_animation = 30; + (*curator->setupTalkAction_proc)(curator, play, aCR_TALK_MSG_WIN_OPEN_WAIT); + } +} + +#define aCR_IS_FOSSIL(item) \ + ((item) >= FTR_DINO_START && (item) <= FTR_DINO_END) + +#define aCR_IS_ART(item) \ + ((item) >= FTR_PAINTING0 && (item) <= FTR_PAINTING14_WEST) + +#define aCR_IS_INSECT(item) \ + ((item) >= ITM_INSECT_START && (item) < ITM_INSECT_END) + +#define aCR_IS_FISH(item) \ + ((item) >= ITM_FISH_START && (item) <= ITM_FISH_END) + +typedef struct { + int msg_no; + int talk_act; +} aCR_donate_act_c; + +static void aCR_msg_win_open_wait(NPC_CURATOR_ACTOR* curator, GAME_PLAY* play) { + static aCR_donate_act_c donate_act[] = { + { 0x2F63, aCR_TALK_END_WAIT }, + { 0x3A83, aCR_TALK_RETURN_DEMO_START_WAIT }, + { 0x2F64, aCR_TALK_RETURN_DEMO_START_WAIT }, + { 0x2F65, aCR_TALK_RETURN_DEMO_START_WAIT }, + { 0x2F6B, aCR_TALK_RETURN_DEMO_START_WAIT2 }, + { 0x2F6C, aCR_TALK_RETURN_DEMO_START_WAIT2 }, + { 0x2F6D, aCR_TALK_RETURN_DEMO_START_WAIT2 }, + { 0x2F6E, aCR_TALK_RETURN_DEMO_START_WAIT2 }, + { 0x2F67, aCR_TALK_RETURN_DEMO_START_WAIT2 }, + { 0x2F68, aCR_TALK_RETURN_DEMO_START_WAIT2 }, + { 0x2F69, aCR_TALK_RETURN_DEMO_START_WAIT2 }, + { 0x2F6A, aCR_TALK_RETURN_DEMO_START_WAIT2 }, + { 0x2F90, aCR_TALK_RETURN_DEMO_START_WAIT2 }, + { 0x2F91, aCR_TALK_RETURN_DEMO_START_WAIT2 }, + { 0x2F92, aCR_TALK_RETURN_DEMO_START_WAIT2 }, + { 0x2F93, aCR_TALK_RETURN_DEMO_START_WAIT2 }, + { 0x2F8F, aCR_TALK_PUTAWAY_DEMO_START_WAIT2 }, + { 0x2F7F, aCR_TALK_PUTAWAY_DEMO_START_WAIT3 }, + { 0x2F80, aCR_TALK_PUTAWAY_DEMO_START_WAIT3 }, + { 0x2F81, aCR_TALK_PUTAWAY_DEMO_START_WAIT3 }, + { 0x2F82, aCR_TALK_PUTAWAY_DEMO_START_WAIT3 }, + { 0x2F83, aCR_TALK_PUTAWAY_DEMO_START_WAIT3 }, + { 0x2F70, aCR_TALK_PUTAWAY_DEMO_START_WAIT }, + { 0x2F71, aCR_TALK_PUTAWAY_DEMO_START_WAIT }, + { 0x2F72, aCR_TALK_PUTAWAY_DEMO_START_WAIT }, + { 0x2F86, aCR_TALK_PUTAWAY_DEMO_START_WAIT5 }, + { 0x2F87, aCR_TALK_PUTAWAY_DEMO_START_WAIT4 }, + { 0x2F89, aCR_TALK_PUTAWAY_DEMO_START_WAIT5_2 } + }; + + mMsg_Window_c* msg_p = mMsg_Get_base_window_p(); + mActor_name_t item; + int act_idx; + aCR_donate_act_c* donate_act_p; + + if (mMsg_Check_not_series_main_wait(msg_p) == TRUE) { + act_idx = 0; + item = play->submenu.item_p->item; + + if (item != EMPTY_NO) { + if (aCR_IS_FOSSIL(item) == TRUE) { + act_idx = aCR_get_idx_to_donate_fossil(item); + } + else if (aCR_IS_ART(item) == TRUE) { + act_idx = aCR_get_idx_to_donate_art(item); + } + else if (aCR_IS_INSECT(item) == TRUE) { + act_idx = aCR_get_idx_to_donate_insect(item); + } + else if (aCR_IS_FISH(item) == TRUE) { + act_idx = aCR_get_idx_to_donate_fish(item); + } + else if (item == ITM_FOSSIL) { + act_idx = 3; + } + else { + act_idx = 2; + } + + aCR_set_item_name_str(item); + } + + donate_act_p = &donate_act[act_idx]; + curator->donated_item = item; + mMsg_Set_continue_msg_num(msg_p, donate_act_p->msg_no); + mMsg_Set_ForceNext(msg_p); + (*curator->setupTalkAction_proc)(curator, play, donate_act_p->talk_act); + } +} + +static void aCR_return_demo_start_wait(NPC_CURATOR_ACTOR* curator, GAME_PLAY* play) { + int order = mDemo_Get_OrderValue(mDemo_ORDER_NPC0, 1); + + if (order == 10) { + int talk_act = aCR_TALK_RETURN_DEMO_END_WAIT; + + if (curator->talk_act_idx != aCR_TALK_RETURN_DEMO_START_WAIT) { + talk_act = aCR_TALK_RETURN_DEMO_END_WAIT2; + } + + (*curator->setupTalkAction_proc)(curator, play, talk_act); + } +} + +static void aCR_return_demo_end_wait(NPC_CURATOR_ACTOR* curator, GAME_PLAY* play) { + if (Common_Get(clip).handOverItem_clip->master_actor == NULL) { + mMsg_Window_c* msg_p = mMsg_Get_base_window_p(); + int talk_act = aCR_TALK_CHK_CONTINUE_TO_DONATE; + + if (curator->talk_act_idx != aCR_TALK_RETURN_DEMO_END_WAIT) { + talk_act = aCR_TALK_CHK_CONTINUE_TO_DONATE2; + } + + curator->npc_class.talk_info.default_animation = -1; + mMsg_Unset_LockContinue(msg_p); + (*curator->setupTalkAction_proc)(curator, play, talk_act); + } +} + +static void aCR_chk_continue_to_donate(NPC_CURATOR_ACTOR* curator, GAME_PLAY* play) { + static int chk_msg_num[] = { 0x2F66, 0x2F6F, 0x2F73 }; + + mMsg_Window_c* msg_p = mMsg_Get_base_window_p(); + int donate_idx = curator->talk_act_idx - aCR_TALK_CHK_CONTINUE_TO_DONATE; + + if (chk_msg_num[donate_idx] == mMsg_Get_msg_num(msg_p) && mMsg_Check_MainNormalContinue(msg_p)) { + int talk_act = aCR_TALK_END_WAIT; + int msg_no; + + if (mChoice_Get_ChoseNum(mChoice_Get_base_window_p()) == mChoice_CHOICE0) { + talk_act = aCR_TALK_MENU_OPEN_WAIT; + msg_no = 0x2F62; + } + else { + msg_no = aCR_get_msg_no_after_talk(); + } + + if (curator->talk_act_idx != aCR_TALK_CHK_CONTINUE_TO_DONATE3) { + mMsg_Set_continue_msg_num(msg_p, msg_no); + } + + (*curator->setupTalkAction_proc)(curator, play, talk_act); + } +} + +static void aCR_putaway_demo_start_wait(NPC_CURATOR_ACTOR* curator, GAME_PLAY* play) { + int order = mDemo_Get_OrderValue(mDemo_ORDER_NPC0, 1); + + if (order == 14) { + (*curator->setupTalkAction_proc)(curator, play, curator->talk_act_idx + (aCR_TALK_PUTAWAY_DEMO_END_WAIT - aCR_TALK_PUTAWAY_DEMO_START_WAIT)); + } +} + +static void aCR_putaway_demo_start_wait5_2(NPC_CURATOR_ACTOR* curator, GAME_PLAY* play) { + static int msg_no[FISH_NUM + 1] = { + 0x3A6D, + 0x3A6E, + 0x3A6D, + 0x3A80, + 0x3A6D, + 0x3A6D, + 0x3A6E, + 0x3A6F, + 0x3A6D, + 0x3A70, + 0x3A71, + 0x3A6D, + 0x3A6E, + 0x3A72, + 0x3A6D, + 0x3A6D, + 0x3A6D, + 0x3A73, + 0x3A6E, + 0x3A81, + 0x3A6E, + 0x3A74, + 0x3A6D, + 0x3A7D, + 0x3A75, + 0x3A76, + 0x3A6E, + 0x3A6E, + 0x3A7E, + 0x3A77, + 0x3A7D, + 0x3A79, + 0x3A7C, + 0x3A82, + 0x3A77, + 0x3A7F, + 0x3A6D, + 0x3A7A, + 0x3A7B, + 0x3A78 + // uninitialized entry here + }; + + mMsg_Window_c* msg_p = mMsg_Get_base_window_p(); + + if (mMsg_Get_msg_num(msg_p) == 0x2F89) { + int fish_type = curator->donated_item - ITM_FISH_START; + + if (fish_type < 0 || fish_type >= (FISH_NUM + 1)) { + fish_type = 0; + } + + mMsg_Set_continue_msg_num(msg_p, msg_no[fish_type]); + (*curator->setupTalkAction_proc)(curator, play, aCR_TALK_PUTAWAY_DEMO_START_WAIT6); + } +} + +static void aCR_putaway_demo_end_wait(NPC_CURATOR_ACTOR* curator, GAME_PLAY* play) { + if (Common_Get(clip).handOverItem_clip->master_actor == NULL) { + curator->npc_class.talk_info.default_animation = -1; + mMsg_Unset_LockContinue(mMsg_Get_base_window_p()); + + switch (curator->talk_act_idx) { + case aCR_TALK_PUTAWAY_DEMO_END_WAIT: + aCR_chk_art_complete(curator, play); + break; + case aCR_TALK_PUTAWAY_DEMO_END_WAIT2: + aCR_chk_fossil_parts_complete(curator, play); + break; + case aCR_TALK_PUTAWAY_DEMO_END_WAIT3: + aCR_chk_fossil_complete(curator, play); + break; + case aCR_TALK_PUTAWAY_DEMO_END_WAIT4: + aCR_chk_insect_complete(curator, play); + break; + case aCR_TALK_PUTAWAY_DEMO_END_WAIT5: + aCR_set_after_explain_insect(curator, play); + break; + case aCR_TALK_PUTAWAY_DEMO_END_WAIT6: + aCR_chk_fish_complete(curator, play); + break; + } + } +} + +static void aCR_after_explain_insect(NPC_CURATOR_ACTOR* curator, GAME_PLAY* play) { + mMsg_Window_c* msg_p = mMsg_Get_base_window_p(); + + if (curator->msg_no == mMsg_Get_msg_num(msg_p) && mMsg_Check_MainNormalContinue(msg_p)) { + aCR_chk_insect_complete(curator, play); + } +} + +static void aCR_thanks_fossil_msg_end_wait(NPC_CURATOR_ACTOR* curator, GAME_PLAY* play) { + mMsg_Window_c* msg_p = mMsg_Get_base_window_p(); + + if (curator->msg_no == mMsg_Get_msg_num(msg_p) && mMsg_Check_MainNormalContinue(msg_p)) { + aCR_chk_fossil_complete(curator, play); + } +} + +static void aCR_chk_all_complete(NPC_CURATOR_ACTOR* curator, GAME_PLAY* play) { + static int msg_no[] = { 0x2F76, 0x2F77 }; + mMsg_Window_c* msg_p = mMsg_Get_base_window_p(); + + if (curator->msg_no == mMsg_Get_msg_num(msg_p) && mMsg_Check_MainNormalContinue(msg_p) == TRUE) { + int msg_idx = 0; + + if (aCR_countDisplayed() == (mMmd_FOSSIL_NUM + mMmd_ART_NUM + mMmd_INSECT_NUM + mMmd_FISH_NUM)) { + mMsm_SetCompMail(); + msg_idx = 1; + } + + mMsg_Set_continue_msg_num(msg_p, msg_no[msg_idx]); + (*curator->setupTalkAction_proc)(curator, play, aCR_TALK_END_WAIT); + } +} + +static void aCR_msg_win_close_wait_init(NPC_CURATOR_ACTOR* curator, GAME_PLAY* play) { + mMsg_request_main_disappear_wait_type1(mMsg_Get_base_window_p()); +} + +static void aCR_menu_close_wait_init(NPC_CURATOR_ACTOR* curator, GAME_PLAY* play) { + mSM_open_submenu(&play->submenu, mSM_OVL_INVENTORY, mSM_IV_OPEN_CURATOR, 0); +} + +static void aCR_get_demo_end_wait_init(NPC_CURATOR_ACTOR* curator, GAME_PLAY* play) { + mDemo_Set_OrderValue(mDemo_ORDER_NPC0, 1, 3); + Common_Get(clip).handOverItem_clip->player_after_mode = 8; +} + +static void aCR_msg_win_open_wait_init(NPC_CURATOR_ACTOR* curator, GAME_PLAY* play) { + mMsg_Window_c* msg_p = mMsg_Get_base_window_p(); + + mMsg_request_main_appear_wait_type1(msg_p); + mMsg_Unset_LockContinue(msg_p); +} + +static void aCR_return_demo_end_wait_init(NPC_CURATOR_ACTOR* curator, GAME_PLAY* play) { + mMsg_Set_LockContinue(mMsg_Get_base_window_p()); +} + +static void aCR_putaway_demo_end_wait_init(NPC_CURATOR_ACTOR* curator, GAME_PLAY* play) { + Submenu_Item_c* sm_item_p = play->submenu.item_p; + + if (mMmd_RequestMuseumDisplay(sm_item_p->item) == TRUE) { + mPr_SetPossessionItem(Common_Get(now_private), sm_item_p->slot_no, EMPTY_NO, mPr_ITEM_COND_NORMAL); + } + + mMsg_Set_LockContinue(mMsg_Get_base_window_p()); +} + +typedef void (*aCR_TALK_INIT_PROC)(NPC_CURATOR_ACTOR*, GAME_PLAY*); + +static void aCR_talk_init_proc(NPC_CURATOR_ACTOR* curator, GAME_PLAY* play, int talk_act) { + static aCR_TALK_INIT_PROC init_proc[aCR_TALK_NUM] = { + (aCR_TALK_INIT_PROC)none_proc1, + (aCR_TALK_INIT_PROC)none_proc1, + (aCR_TALK_INIT_PROC)none_proc1, + (aCR_TALK_INIT_PROC)none_proc1, + (aCR_TALK_INIT_PROC)none_proc1, + (aCR_TALK_INIT_PROC)none_proc1, + &aCR_msg_win_close_wait_init, + &aCR_menu_close_wait_init, + (aCR_TALK_INIT_PROC)none_proc1, + &aCR_get_demo_end_wait_init, + &aCR_msg_win_open_wait_init, + (aCR_TALK_INIT_PROC)none_proc1, + (aCR_TALK_INIT_PROC)none_proc1, + &aCR_return_demo_end_wait_init, + &aCR_return_demo_end_wait_init, + (aCR_TALK_INIT_PROC)none_proc1, + (aCR_TALK_INIT_PROC)none_proc1, + (aCR_TALK_INIT_PROC)none_proc1, + (aCR_TALK_INIT_PROC)none_proc1, + (aCR_TALK_INIT_PROC)none_proc1, + (aCR_TALK_INIT_PROC)none_proc1, + (aCR_TALK_INIT_PROC)none_proc1, + (aCR_TALK_INIT_PROC)none_proc1, + (aCR_TALK_INIT_PROC)none_proc1, + (aCR_TALK_INIT_PROC)none_proc1, + &aCR_putaway_demo_end_wait_init, + &aCR_putaway_demo_end_wait_init, + &aCR_putaway_demo_end_wait_init, + &aCR_putaway_demo_end_wait_init, + &aCR_putaway_demo_end_wait_init, + &aCR_putaway_demo_end_wait_init, + (aCR_TALK_INIT_PROC)none_proc1, + (aCR_TALK_INIT_PROC)none_proc1, + (aCR_TALK_INIT_PROC)none_proc1 + }; + + (*init_proc[talk_act])(curator, play); +} + +static void aCR_setupTalkAction(NPC_CURATOR_ACTOR* curator, GAME_PLAY* play, int talk_act) { + static aCR_TALK_ACT_PROC process[aCR_TALK_NUM] = { + (aCR_TALK_INIT_PROC)&none_proc1, + &aCR_after_talk_start_wait, + &aCR_chk_request, + &aCR_chk_decide_to_donate, + &aCR_chk_decide_to_donate2, + &aCR_menu_open_wait, + &aCR_msg_win_close_wait, + &aCR_menu_close_wait, + &aCR_get_demo_start_wait, + &aCR_get_demo_end_wait, + &aCR_msg_win_open_wait, + &aCR_return_demo_start_wait, + &aCR_return_demo_start_wait, + &aCR_return_demo_end_wait, + &aCR_return_demo_end_wait, + &aCR_chk_continue_to_donate, + &aCR_chk_continue_to_donate, + &aCR_chk_continue_to_donate, + &aCR_putaway_demo_start_wait, + &aCR_putaway_demo_start_wait, + &aCR_putaway_demo_start_wait, + &aCR_putaway_demo_start_wait, + &aCR_putaway_demo_start_wait, + &aCR_putaway_demo_start_wait, + &aCR_putaway_demo_start_wait5_2, + &aCR_putaway_demo_end_wait, + &aCR_putaway_demo_end_wait, + &aCR_putaway_demo_end_wait, + &aCR_putaway_demo_end_wait, + &aCR_putaway_demo_end_wait, + &aCR_putaway_demo_end_wait, + &aCR_after_explain_insect, + &aCR_thanks_fossil_msg_end_wait, + &aCR_chk_all_complete + }; + + curator->talk_act_idx = talk_act; + curator->talk_proc = process[talk_act]; + aCR_talk_init_proc(curator, play, talk_act); +} + +static void aCR_set_talk_info(ACTOR* actorx) { + static int msg_no[2][2][2][3] = { + { + { { 0x2F8B, 0x2F8C, 0x2F8C }, { 0x2F8D, 0x2F95, 0x2F8E } }, + { { 0x2F4E, 0x2F4F, 0x2F4F }, { 0x2F51, 0x2F96, 0x2F52 } } + }, + { + { { 0x2F53, 0x2F54, 0x2F54 }, { 0x2F55, 0x2F94, 0x2F56 } }, + { { 0x2F53, 0x2F54, 0x2F54 }, { 0x2F55, 0x2F94, 0x2F56 } } + } + }; + + NPC_CURATOR_ACTOR* curator = (NPC_CURATOR_ACTOR*)actorx; + + int talk_act = aCR_TALK_END_WAIT; + int sel_msg_no; + + if (Common_Get(clip).aprilfool_control_clip != NULL && Common_Get(clip).aprilfool_control_clip->talk_chk_proc(SP_NPC_CURATOR) == FALSE) { + sel_msg_no = (*Common_Get(clip).aprilfool_control_clip->get_msg_num_proc)(SP_NPC_CURATOR, TRUE); + } + else { + int completed = FALSE; + int not_foreigner = FALSE; + int not_first_talk = FALSE; + int action_idx = 0; + + if (aCR_countDisplayed() == (mMmd_FOSSIL_NUM + mMmd_ART_NUM + mMmd_INSECT_NUM + mMmd_FISH_NUM)) { + completed = TRUE; + } + + if (mLd_PlayerManKindCheck() == FALSE) { + not_foreigner = TRUE; + } + + if (aNPC_SPNPC_BIT_GET(Common_Get(spnpc_first_talk_flags), aNPC_SPNPC_BIT_CURATOR)) { + not_first_talk = TRUE; + } + + if (aCR_check_sleep_time() == TRUE) { + if (curator->action == aCR_ACTION_SLEEP_WAIT) { + action_idx = 1; + } + } + else { + action_idx = 2; + } + + if (completed == FALSE) { + if (not_foreigner == FALSE) { + if (not_first_talk == FALSE) { + talk_act = aCR_TALK_AFTER_TALK_START_WAIT; + } + } + else { + talk_act = aCR_TALK_CHK_REQUEST; + } + } + + sel_msg_no = msg_no[completed][not_foreigner][not_first_talk][action_idx]; + } + + mDemo_Set_msg_num(sel_msg_no); + curator->talk_act_idx = talk_act; +} + +static void aCR_talk_request(ACTOR* actorx, GAME* game) { + mDemo_Request(mDemo_TYPE_TALK, actorx, &aCR_set_talk_info); +} + +static int aCR_talk_init(ACTOR* actorx, GAME* game) { + NPC_CURATOR_ACTOR* curator = (NPC_CURATOR_ACTOR*)actorx; + GAME_PLAY* play = (GAME_PLAY*)game; + + (*curator->setupTalkAction_proc)(curator, play, curator->talk_act_idx); + mDemo_Set_ListenAble(); + aNPC_SPNPC_BIT_SET(Common_Get(spnpc_first_talk_flags), aNPC_SPNPC_BIT_CURATOR); + curator->npc_class.head.angle_add_y = DEG2SHORT_ANGLE(5.625f); + curator->action = aCR_ACTION_WAIT; + + return TRUE; +} + +static int aCR_talk_end_chk(ACTOR* actorx, GAME* game) { + NPC_CURATOR_ACTOR* curator = (NPC_CURATOR_ACTOR*)actorx; + GAME_PLAY* play = (GAME_PLAY*)game; + int res = FALSE; + + (*curator->talk_proc)(curator, play); + + if (mDemo_Check(mDemo_TYPE_TALK, actorx) == FALSE) { + res = TRUE; + } + + return res; +} + +static void aCR_actor_move(ACTOR* actorx, GAME* game) { + (*Common_Get(clip).npc_clip->move_proc)(actorx, game); +}