diff --git a/config/rel_slices.yml b/config/rel_slices.yml index b10355f1..c212b9e4 100644 --- a/config/rel_slices.yml +++ b/config/rel_slices.yml @@ -443,6 +443,10 @@ ac_quest_talk_greeting.c: .rodata: [0x80644CA0, 0x80644CA8] .data: [0x8068AE40, 0x8068B048] .bss: [0x812FCA68, 0x812FCAA8] +ac_quest_talk_init.c: + .text: [0x80489A34, 0x8048D768] + .rodata: [0x80644CA8, 0x80644D10] + .data: [0x8068B048, 0x8068B310] ac_rope.c: .text: [0x804967A4, 0x80496AB8] .rodata: [0x80644DB0, 0x80644DB8] diff --git a/include/ac_quest_manager.h b/include/ac_quest_manager.h index e514e812..93721792 100644 --- a/include/ac_quest_manager.h +++ b/include/ac_quest_manager.h @@ -75,7 +75,7 @@ enum { aQMgr_MSG_KIND_FULL_ITEM, // pockets are full so can't give quests aQMgr_MSG_KIND_AFTER_REWARD, aQMgr_MSG_KIND_AFTER_REWARD_THANKS, - aQMgr_MSG_KIND_REWARD_FULL_ITEM, // pockets are full so can't give reward + aQMgr_MSG_KIND_REWARD_FULL_ITEM, // pockets are full so can't give reward aQMgr_MSG_KIND_REWARD_FULL_ITEM2, // pockets are still full aQMgr_MSG_KIND_NONE, @@ -141,11 +141,11 @@ typedef struct quest_manager_order_s { } aQMgr_order_c; typedef struct quest_manager_set_data_s { - u32 to_type:3; - u32 day_limit:6; - u32 last_step:4; - u32 handover_item:1; - u32 src_item_type:3; + u32 to_type : 3; + u32 day_limit : 6; + u32 last_step : 4; + u32 handover_item : 1; + u32 src_item_type : 3; mActor_name_t item; u8 reward_percentages[aQMgr_QUEST_REWARD_NUM]; u32 max_pay; @@ -153,8 +153,8 @@ typedef struct quest_manager_set_data_s { } aQMgr_set_data_c; typedef struct quest_manager_flower_work_data_s { - int exist_num; int goal_num; + int exist_num; int remain_num; } aQMgr_flower_data_c; @@ -175,7 +175,7 @@ typedef struct quest_manager_target_s { aQMgr_set_data_c* set_data_p; int free_data_idx; mQst_base_c* free_data_p; - u8 errand_type; + s8 errand_type; aQMgr_work_data_c work; } aQMgr_target_c; @@ -199,8 +199,8 @@ typedef struct quest_manager_normal_info_s { Anmmem_c* memory; Anmplmail_c* anmplmail; u32 pay; - int player_num_items; // valid items to trade - int player_give_item_idx; // index to give item away + int player_num_items; // valid items to trade + int player_give_item_idx; // index to give item away mActor_name_t player_items[4]; // items which the player has in their inventory which match 'player_num_items' mActor_name_t selected_item; } aQMgr_normal_info_c; @@ -253,7 +253,7 @@ struct quest_manager_actor { /* 0x958 */ mActor_name_t cloth; /* 0x95A */ u8 talk_type; /* 0x95B */ u8 talk_change_type; - /* 0x95C */ u8 errand_next[5]; + /* 0x95C */ u8 errand_next[mPr_ERRAND_QUEST_NUM]; /* 0x962 */ Mail_c mail; /* 0xA8C */ Anmmem_c* mail_memory; /* 0xA90 */ u8 last_strings[7]; @@ -261,6 +261,9 @@ struct quest_manager_actor { /* 0xA9C */ int _A9C; }; +#define aQMgr_GET_CLIENT(manager) ((NPC_ACTOR*)*manager->client) +#define aQMgr_GET_CLIENT_ANIMAL(manager) aQMgr_GET_CLIENT(manager)->npc_info.animal + extern ACTOR_PROFILE Quest_Manager_Profile; #ifdef __cplusplus @@ -268,4 +271,3 @@ extern ACTOR_PROFILE Quest_Manager_Profile; #endif #endif - diff --git a/include/ac_quest_talk_init.h b/include/ac_quest_talk_init.h index 2be4ffab..ac2f5e49 100644 --- a/include/ac_quest_talk_init.h +++ b/include/ac_quest_talk_init.h @@ -8,6 +8,14 @@ extern "C" { #endif +#define aQMgr_NEW_QUEST_SUCCESS 1 +#define aQMgr_NEW_QUEST_NO_SPACE -1 +#define aQMgr_NEW_QUEST_NO_FOREIGN_ID -2 +#define aQMgr_NEW_QUEST_NO_REMOVE_ANIMAL_ID -3 +#define aQMgr_NEW_QUEST_ERROR -4 + +#define aQMgr_FLOWER_GOAL_NUM 4 + extern void aQMgr_actor_move_talk_init(QUEST_MANAGER_ACTOR* manager); #ifdef __cplusplus diff --git a/include/m_common_data.h b/include/m_common_data.h index ba7edd38..79f4de6c 100644 --- a/include/m_common_data.h +++ b/include/m_common_data.h @@ -41,279 +41,289 @@ extern "C" { #define SCHEDULE_NUM ANIMAL_NUM_MAX + mISL_ISLANDER_NUM typedef struct time_s { - u32 season; - u32 term_idx; - s16 bgitem_profile; - s16 bgitem_bank; - int now_sec; - lbRTC_time_c rtc_time; - s16 rad_min; /* clock hand radial position for mins */ - s16 rad_hour; /* clock hand radial position for hours */ - u8 time_signal; - u8 under_sec; - u8 disp; - u8 rtc_crashed; - int rtc_enabled; - int add_sec; - int add_idx; + u32 season; + u32 term_idx; + s16 bgitem_profile; + s16 bgitem_bank; + int now_sec; + lbRTC_time_c rtc_time; + s16 rad_min; /* clock hand radial position for mins */ + s16 rad_hour; /* clock hand radial position for hours */ + u8 time_signal; + u8 under_sec; + u8 disp; + u8 rtc_crashed; + int rtc_enabled; + int add_sec; + int add_idx; } Time_c; /* sizeof(PlusBridge_c) == 8 */ typedef struct bridge_s { - /* 0x00 */ u8 block_x; - /* 0x01 */ u8 block_z; - /* 0x02 */ struct { - u8 exists:1; - u8 pending:1; - u8 pad:6; - }; - /* 0x04 */ lbRTC_ymd_c build_date; + /* 0x00 */ u8 block_x; + /* 0x01 */ u8 block_z; + /* 0x02 */ struct { + u8 exists : 1; + u8 pending : 1; + u8 pad : 6; + }; + /* 0x04 */ lbRTC_ymd_c build_date; } PlusBridge_c; typedef struct lighthouse_s { - lbRTC_ymd_c renew_time; - u8 days_switched_on; - u8 players_quest_started; - u8 players_completed; + lbRTC_ymd_c renew_time; + u8 days_switched_on; + u8 players_quest_started; + u8 players_completed; } LightHouse_c; typedef struct Save_s { - /* 0x000000 */ mFRm_chk_t save_check; /* save information */ - /* 0x000014 */ int scene_no; /* current 'scene' id */ - /* 0x000018 */ u8 now_npc_max; /* current number of villagers living in town (see (Add/Sub)NowNpcMax) */ - /* 0x000019 */ u8 remove_animal_idx; /* index of the villager which is scheduled to leave town, 0xFF when none selected */ - /* 0x00001A */ u16 copy_protect; /* 'unique' value between [1, 65520] used for copy protection (see mCD_get_land_copyProtect) */ - /* 0x00001C */ u8 pad_1C[4]; - /* 0x000020 */ Private_c private[PLAYER_NUM]; /* player data */ - /* 0x009120 */ mLd_land_info_c land_info; /* town name & id */ - /* 0x00912C */ mNtc_board_post_c noticeboard[mNtc_BOARD_POST_COUNT]; /* noticeboard posts */ - /* 0x009CE4 */ u8 pad_9CE4[4]; - /* 0x009CE8 */ mHm_hs_c homes[PLAYER_NUM]; /* player house data */ - /* 0x0137A8 */ mFM_fg_c fg[FG_BLOCK_Z_NUM][FG_BLOCK_X_NUM]; /* fg items (fg = foreground?) */ - /* 0x0173A8 */ mFM_combination_c combi_table[BLOCK_Z_NUM][BLOCK_X_NUM]; /* acre 'combination' data */ - /* 0x017438 */ Animal_c animals[ANIMAL_NUM_MAX]; /* villagers in town */ - /* 0x020330 */ AnmPersonalID_c last_removed_animal_id; /* ID of last villager who left town */ - /* 0x020340 */ Shop_c shop; /* Nook's shop */ - /* 0x020480 */ Kabu_price_c kabu_price_schedule; /* Stalk Market info */ - /* 0x020498 */ mEv_event_save_c event_save_data; - /* 0x020554 */ mEv_save_common_data_c event_save_common; - /* 0x020688 */ mActor_name_t fruit; /* town fruit type */ - /* 0x02068A */ u8 house_arrangement; /* 2 bits for each player for the # of house they own */ - /* 0x02068B */ u8 num_statues; /* number of statues built for players who have paid off their debts */ - /* 0x02068C */ lbRTC_time_c all_grow_renew_time; /* renewal time for fg items handled by mAgrw_RenewalFgItem_ovl */ - /* 0x020694 */ PostOffice_c post_office; /* post office data */ - /* 0x020ED0 */ PoliceBox_c police_box; /* police station lost & found */ - /* 0x020EF8 */ mSN_snowman_save_c snowmen; /* saved snowmen data */ - /* 0x020F08 */ u64 melody; /* town tune, each nibble is a note (16 notes) */ - /* 0x020F10 */ Config_c config; /* saved config for sound mode, voice mode, and vibration */ - /* 0x020F14 */ lbRTC_ymd_c renew_time; /* next renew date */ - /* 0x020F18 */ u8 station_type; /* train station type */ - /* 0x020F19 */ u8 weather; /* upper nibble is intensity, lower nibble is type */ - /* 0x020F1A */ u8 save_exist; /* unsure, set in mCD_SaveHome_bg_set_data (1) & mCD_SaveHome_bg (bss) */ - /* 0x020F1B */ u8 npc_force_go_home; /* when set to 1, forces the 'm_go_home' code to activate */ - /* 0x020F1C */ u16 deposit[FG_BLOCK_X_NUM * FG_BLOCK_Z_NUM][UT_Z_NUM]; /* flags for which items are buried around town */ - /* 0x0212DC */ lbRTC_time_c last_grow_time; /* last time that a new villager moved into town */ - /* 0x0212E4 */ mPr_mother_mail_info_c mother_mail[PLAYER_NUM]; /* info on when mom sent player letters and what event was sent */ - /* 0x02131C */ mMsr_time_c mushroom_time; /* last time mushroom season info was updated */ - /* 0x021322 */ lbRTC_ymd_c _021322; - /* 0x021326 */ u16 _021326[20]; - /* 0x02134E */ u8 npc_used_tbl[32]; - /* 0x02136E */ lbRTC_time_c _02136E; - /* 0x021376 */ u8 cheated_flag; - /* 0x021377 */ u8 _021377[7]; - /* 0x02137E */ lbRTC_time_c treasure_buried_time; /* last time treasure was actually buried */ - /* 0x021386 */ lbRTC_time_c treasure_checked_time; /* last time check to bury treasure was executed */ - /* 0x02138E */ u8 saved_rom_debug; /* flag to set save to 'debug rom' mode */ - /* 0x02138F */ u8 snowman_year; /* year last snowman was built */ - /* 0x021390 */ u8 snowman_month; /* month last snowman was built */ - /* 0x021391 */ u8 snowman_day; /* day last snowman was built */ - /* 0x021392 */ u8 snowman_hour; /* hour last snowman was built */ - /* 0x021393 */ u8 haniwa_scheduled; /* when set, gyroids will be spwaned */ - /* 0x021394 */ u8 dust_flag; /* set by field assessment for too much 'dust' (garbage) around town, causes immediate fail of town ranking */ - /* 0x021395 */ u8 clear_grass; /* set by Wisp, removes all weeds */ - /* 0x021396 */ u8 _021396[2]; - /* 0x021398 */ lbRTC_year_t event_year; /* might not exist and just be lbRTC_year_t */ - /* 0x02139A */ u8 unused_2139C[6]; - /* 0x0213A0 */ u8 keep_house_size[PLAYER_NUM]; /* saved flags for house sizes */ - /* 0x0213A4 */ lbRTC_ymd_c force_remove_date; /* last time the NPC force remove timer was updated */ - /* 0x0213A8 */ mMmd_info_c museum_display; /* museum display bits */ - /* 0x0213E7 */ u8 _tmp6[0x213F0 - 0x213E7]; - /* 0x0213F0 */ PlusBridge_c bridge; /* additional bridge info */ - /* 0x021400 */ mNW_needlework_c needlework; /* Able Sisters' designs */ - /* 0x022500 */ u8 _tmp7[0x22528 - 0x22500]; - /* 0x022528 */ OSTime time_delta; /* time delta against GC RTC */ - /* 0x022540 */ Island_c island; /* island data */ - /* 0x023E40 */ mAGrw_AllGrow_c allgrow_ss_pos_info; - /* 0x023E68 */ mFR_record_c fishRecord[mFR_RECORD_NUM]; - /* 0x023F20 */ MaskCat_c mask_cat; - /* 0x024160 */ Anmret_c return_animal; /* information about villager which moved back in to your town after moving to someone else's town */ - /* 0x02416C */ LightHouse_c LightHouse; /* info for tracking the light house quest */ - /* 0x024174 */ u8 insect_term; /* current insect term idx */ - /* 0x024175 */ u8 insect_term_transition_offset; /* days offset from end of term to begin transition */ - /* 0x024176 */ u8 gyoei_term; /* current fish term idx */ - /* 0x024177 */ u8 gyoei_term_transition_offset; /* days offset from end of term to begin transition */ - /* 0x024178 */ mFAs_GoodField_c good_field; /* field assessment last info */ - /* 0x024184 */ u8 bg_tex_idx; /* Grass type */ - /* 0x024185 */ lbRTC_month_t rainbow_month; - /* 0x024186 */ lbRTC_day_t rainbow_day; - /* 0x024187 */ u8 rainbow_reserved; - /* 0x024188 */ u8 _24188; - /* 0x024189 */ u8 _24189; - /* 0x02418A */ u8 town_day; - /* 0x02418B */ u8 _2418B[0x241A0 - 0x2418B]; - /* 0x0241A0 */ lbRTC_time_c saved_auto_nwrite_time; /* save data notice time used for fishing tourney results? */ - /* 0x0241A8 */ u8 _241A8[0x26000 - 0x241A8]; + /* 0x000000 */ mFRm_chk_t save_check; /* save information */ + /* 0x000014 */ int scene_no; /* current 'scene' id */ + /* 0x000018 */ u8 now_npc_max; /* current number of villagers living in town (see (Add/Sub)NowNpcMax) */ + /* 0x000019 */ u8 + remove_animal_idx; /* index of the villager which is scheduled to leave town, 0xFF when none selected */ + /* 0x00001A */ u16 + copy_protect; /* 'unique' value between [1, 65520] used for copy protection (see mCD_get_land_copyProtect) */ + /* 0x00001C */ u8 pad_1C[4]; + /* 0x000020 */ Private_c private[PLAYER_NUM]; /* player data */ + /* 0x009120 */ mLd_land_info_c land_info; /* town name & id */ + /* 0x00912C */ mNtc_board_post_c noticeboard[mNtc_BOARD_POST_COUNT]; /* noticeboard posts */ + /* 0x009CE4 */ u8 pad_9CE4[4]; + /* 0x009CE8 */ mHm_hs_c homes[PLAYER_NUM]; /* player house data */ + /* 0x0137A8 */ mFM_fg_c fg[FG_BLOCK_Z_NUM][FG_BLOCK_X_NUM]; /* fg items (fg = foreground?) */ + /* 0x0173A8 */ mFM_combination_c combi_table[BLOCK_Z_NUM][BLOCK_X_NUM]; /* acre 'combination' data */ + /* 0x017438 */ Animal_c animals[ANIMAL_NUM_MAX]; /* villagers in town */ + /* 0x020330 */ AnmPersonalID_c last_removed_animal_id; /* ID of last villager who left town */ + /* 0x020340 */ Shop_c shop; /* Nook's shop */ + /* 0x020480 */ Kabu_price_c kabu_price_schedule; /* Stalk Market info */ + /* 0x020498 */ mEv_event_save_c event_save_data; + /* 0x020554 */ mEv_save_common_data_c event_save_common; + /* 0x020688 */ mActor_name_t fruit; /* town fruit type */ + /* 0x02068A */ u8 house_arrangement; /* 2 bits for each player for the # of house they own */ + /* 0x02068B */ u8 num_statues; /* number of statues built for players who have paid off their debts */ + /* 0x02068C */ lbRTC_time_c all_grow_renew_time; /* renewal time for fg items handled by mAgrw_RenewalFgItem_ovl */ + /* 0x020694 */ PostOffice_c post_office; /* post office data */ + /* 0x020ED0 */ PoliceBox_c police_box; /* police station lost & found */ + /* 0x020EF8 */ mSN_snowman_save_c snowmen; /* saved snowmen data */ + /* 0x020F08 */ u64 melody; /* town tune, each nibble is a note (16 notes) */ + /* 0x020F10 */ Config_c config; /* saved config for sound mode, voice mode, and vibration */ + /* 0x020F14 */ lbRTC_ymd_c renew_time; /* next renew date */ + /* 0x020F18 */ u8 station_type; /* train station type */ + /* 0x020F19 */ u8 weather; /* upper nibble is intensity, lower nibble is type */ + /* 0x020F1A */ u8 save_exist; /* unsure, set in mCD_SaveHome_bg_set_data (1) & mCD_SaveHome_bg (bss) */ + /* 0x020F1B */ u8 npc_force_go_home; /* when set to 1, forces the 'm_go_home' code to activate */ + /* 0x020F1C */ u16 deposit[FG_BLOCK_X_NUM * FG_BLOCK_Z_NUM] + [UT_Z_NUM]; /* flags for which items are buried around town */ + /* 0x0212DC */ lbRTC_time_c last_grow_time; /* last time that a new villager moved into town */ + /* 0x0212E4 */ mPr_mother_mail_info_c + mother_mail[PLAYER_NUM]; /* info on when mom sent player letters and what event was sent */ + /* 0x02131C */ mMsr_time_c mushroom_time; /* last time mushroom season info was updated */ + /* 0x021322 */ lbRTC_ymd_c _021322; + /* 0x021326 */ u16 _021326[20]; + /* 0x02134E */ u8 npc_used_tbl[32]; + /* 0x02136E */ lbRTC_time_c _02136E; + /* 0x021376 */ u8 cheated_flag; + /* 0x021377 */ u8 _021377[7]; + /* 0x02137E */ lbRTC_time_c treasure_buried_time; /* last time treasure was actually buried */ + /* 0x021386 */ lbRTC_time_c treasure_checked_time; /* last time check to bury treasure was executed */ + /* 0x02138E */ u8 saved_rom_debug; /* flag to set save to 'debug rom' mode */ + /* 0x02138F */ u8 snowman_year; /* year last snowman was built */ + /* 0x021390 */ u8 snowman_month; /* month last snowman was built */ + /* 0x021391 */ u8 snowman_day; /* day last snowman was built */ + /* 0x021392 */ u8 snowman_hour; /* hour last snowman was built */ + /* 0x021393 */ u8 haniwa_scheduled; /* when set, gyroids will be spwaned */ + /* 0x021394 */ u8 dust_flag; /* set by field assessment for too much 'dust' (garbage) around town, causes immediate + fail of town ranking */ + /* 0x021395 */ u8 clear_grass; /* set by Wisp, removes all weeds */ + /* 0x021396 */ u8 _021396[2]; + /* 0x021398 */ lbRTC_year_t event_year; /* might not exist and just be lbRTC_year_t */ + /* 0x02139A */ u8 unused_2139C[6]; + /* 0x0213A0 */ u8 keep_house_size[PLAYER_NUM]; /* saved flags for house sizes */ + /* 0x0213A4 */ lbRTC_ymd_c force_remove_date; /* last time the NPC force remove timer was updated */ + /* 0x0213A8 */ mMmd_info_c museum_display; /* museum display bits */ + /* 0x0213E7 */ u8 _tmp6[0x213F0 - 0x213E7]; + /* 0x0213F0 */ PlusBridge_c bridge; /* additional bridge info */ + /* 0x021400 */ mNW_needlework_c needlework; /* Able Sisters' designs */ + /* 0x022500 */ u8 _tmp7[0x22528 - 0x22500]; + /* 0x022528 */ OSTime time_delta; /* time delta against GC RTC */ + /* 0x022540 */ Island_c island; /* island data */ + /* 0x023E40 */ mAGrw_AllGrow_c allgrow_ss_pos_info; + /* 0x023E68 */ mFR_record_c fishRecord[mFR_RECORD_NUM]; + /* 0x023F20 */ MaskCat_c mask_cat; + /* 0x024160 */ Anmret_c return_animal; /* information about villager which moved back in to your town after moving + to someone else's town */ + /* 0x02416C */ LightHouse_c LightHouse; /* info for tracking the light house quest */ + /* 0x024174 */ u8 insect_term; /* current insect term idx */ + /* 0x024175 */ u8 insect_term_transition_offset; /* days offset from end of term to begin transition */ + /* 0x024176 */ u8 gyoei_term; /* current fish term idx */ + /* 0x024177 */ u8 gyoei_term_transition_offset; /* days offset from end of term to begin transition */ + /* 0x024178 */ mFAs_GoodField_c good_field; /* field assessment last info */ + /* 0x024184 */ u8 bg_tex_idx; /* Grass type */ + /* 0x024185 */ lbRTC_month_t rainbow_month; + /* 0x024186 */ lbRTC_day_t rainbow_day; + /* 0x024187 */ u8 rainbow_reserved; + /* 0x024188 */ u8 _24188; + /* 0x024189 */ u8 _24189; + /* 0x02418A */ u8 town_day; + /* 0x02418B */ u8 _2418B[0x241A0 - 0x2418B]; + /* 0x0241A0 */ lbRTC_time_c saved_auto_nwrite_time; /* save data notice time used for fishing tourney results? */ + /* 0x0241A8 */ u8 _241A8[0x26000 - 0x241A8]; } Save_t; typedef union save_u { - Save_t save; - //u8 raw[0x26000]; /* Temp to force length */ + Save_t save; + // u8 raw[0x26000]; /* Temp to force length */ } Save; typedef struct transition_s { - u8 _00; // only set in Global_kankyo_ct? - u8 fade_rate; - u8 wipe_rate; - u8 wipe_type; + u8 _00; // only set in Global_kankyo_ct? + u8 fade_rate; + u8 wipe_rate; + u8 wipe_type; } Transition_c; /* sizeof(common_data_t) == 0x2DC00 */ typedef struct common_data_s { - /* 0x000000 */ Save save; - /* 0x026000 */ u8 game_started; - /* 0x026001 */ u8 field_type; - /* 0x026002 */ u8 field_draw_type; - /* 0x026003 */ u8 player_no; - /* 0x026004 */ int last_scene_no; - /* 0x026008 */ int player_data_mode; - /* 0x02600C */ Clip_c clip; - /* 0x026110 */ Time_c time; - /* 0x02613C */ Private_c* now_private; - /* 0x026140 */ mHm_hs_c* now_home; - /* 0x026144 */ u8 map_flag; - /* 0x026145 */ u8 fish_location; - /* 0x026146 */ u8 npc_is_summercamper; - /* 0x026147 */ u8 player_select_animal_no; - /* 0x026148 */ u8 _26148[0x2614C - 0x26148]; - /* 0x02614C */ Transition_c transition; - /* 0x026150 */ s16 bg_item_type; - /* 0x026152 */ s16 bg_item_profile; - /* 0x026154 */ u8 _26154[0x26164 - 0x26154]; - /* 0x026164 */ mNpc_NpcList_c npclist[ANIMAL_NUM_MAX + 1]; - /* 0x0264E4 */ mNpc_NpcList_c island_npclist[1]; // TODO: define for island npc count - /* 0x02651C */ mActor_name_t house_owner_name; - /* 0x02651E */ mActor_name_t last_field_id; - /* 0x026520 */ u8 in_initial_block; /* when TRUE, the player is in the acre which they exited a building. FALSE otherwise. */ - /* 0x026521 */ u8 submenu_disabled; /* when set, submenus cannot be accessed from start button */ - /* 0x026522 */ u8 sunlight_flag; - /* 0x026523 */ u8 train_flag; - /* 0x026522 */ u8 _26524[0x2666C - 0x26524]; - /* 0x02666C */ s16 weather; - /* 0x02666E */ s16 weather_intensity; - /* 0x026670 */ lbRTC_time_c weather_time; - /* 0x026678 */ s_xyz wind; - /* 0x026680 */ f32 wind_speed; - /* 0x026684 */ mEv_event_common_u special_event_common; - /* 0x02669C */ mQst_not_saved_c quest; - /* 0x0266A4 */ int scene_from_title_demo; /* next scene to be loaded when title demo finishes */ - /* 0x0266A8 */ mNPS_schedule_c npc_schedule[SCHEDULE_NUM]; - /* 0x0267A8 */ mNpc_walk_c npc_walk; - /* 0x026838 */ mNpc_EventNpc_c event_npc[mNpc_EVENT_NPC_NUM]; - /* 0x026878 */ mNpc_MaskNpc_c mask_npc[mNpc_MASK_NPC_NUM]; - /* 0x028528 */ int snowman_msg_id; - /* 0x02852C */ s16 money_power; - /* 0x02852E */ s16 goods_power; - /* 0x028530 */ Door_data_c door_data; /* misc door data */ - /* 0x028544 */ Door_data_c structure_exit_door_data; /* door data for when exiting a building */ - /* 0x028558 */ mDemo_Request_c start_demo_request; - /* 0x028568 */ Door_data_c event_door_data; - /* 0x02857C */ Door_data_c famicom_emu_exit_door_data; - /* 0x028590 */ u8 remove_cut_tree_info_bitfield; /* resets the cut tree states for trees in a visible acre */ - /* 0x028591 */ u8 floor_idx; - /* 0x028592 */ s16 demo_profiles[2]; /* demo_profiles[0] is for demo_clip, demo_profiles[1] is for demo_clip2 */ - /* 0x028596 */ u16 copy_protect_code; - /* 0x028598 */ int event_keep_flags[4]; - /* 0x0285A8 */ u8 _285A8[0x0285BE - 0x0285A8]; - /* 0x0285BE */ s8 player_actor_exists; - /* 0x0285BF */ s8 payment_completed_type; - /* 0x0285C0 */ s8 player_decoy_flag; - /* 0x0285C1 */ u8 _285C1; - /* 0x0285C2 */ u8 make_npc2_actor; - /* 0x0285C4 */ s16 event_id; - /* 0x0285C6 */ u8 event_title_flags; - /* 0x0285C7 */ u8 event_title_fade_in_progress; - /* 0x0285C8 */ mEv_common_data_c event_common; - /* 0x0287F8 */ s8 current_famicom_rom; - /* 0x0287F9 */ s8 famicom_287F9; - /* 0x0287FA */ u8 _287FA[0x28838 - 0x0287FA]; - /* 0x028838 */ s8 player_bee_swell_flag; - /* 0x028839 */ s8 player_bee_chase_flag; - /* 0x02883A */ u8 goki_shocked_flag; - /* 0x02883B */ u8 time_changed_flag; - /* 0x02883C */ u8 unable_to_wade_flag; - /* 0x02883D */ u8 _02883D; - /* 0x02883E */ u8 train_coming_flag; /* state tracker for when train is going to spawn/has spawned */ - /* 0x02883F */ u8 train_exists_flag; /* state tracker for when train exists */ - /* 0x028840 */ u8 train_control_state; /* current train state */ - /* 0x028841 */ u8 train_last_control_state; /* previous train state */ - /* 0x028842 */ u8 train_signal; - /* 0x028843 */ u8 train_day; - /* 0x028844 */ u8 train_action; - /* 0x028845 */ u8 train_timer; - /* 0x028848 */ u32 train_start_timer; - /* 0x02884C */ f32 train_speed; - /* 0x028850 */ xyz_t train_position; - /* 0x02885C */ f32 unused_02885C; - /* 0x028860 */ f32 unused_028860; - /* 0x028864 */ u16 unused_028864; - /* 0x028866 */ u16 unused_028866; - /* 0x028868 */ u8 reset_flag; - /* 0x028869 */ u8 reset_type; - /* 0x02886A */ u8 force_mail_delivery_flag; - /* 0x02886B */ u8 post_girl_npc_type; - /* 0x02886C */ xyz_t ball_pos; - /* 0x028878 */ u8 ball_type; - /* 0x028879 */ u8 auto_nwrite_count; - /* 0x02887A */ lbRTC_year_t auto_nwrite_year; - /* 0x02887C */ u8 save_error_type; /* set to one of the mFRm_ERROR_* states when save is invalid */ - /* 0x02887D */ u8 train_approaching_flag; /* set when the train is coming */ - /* 0x02887E */ u8 buried_treasure_flag; /* when set, treasure cannot be buried */ - /* 0x02887F */ u8 spnpc_first_talk_flags; - /* 0x028880 */ u8 needlework_first_talk_flags; - /* 0x028882 */ u16 event_notification_active; - /* 0x028884 */ lbRTC_time_c newly_set_time; /* time set by player in time adjust menu */ - /* 0x02888C */ lbRTC_time_c old_time; /* time before being changed by the player */ - /* 0x028894 */ s16 balloon_state; /* balloon's current state */ - /* 0x028896 */ s16 balloon_last_spawn_min; /* last minute the balloon was spawned */ - /* 0x028898 */ f32 balloon_spawn_percent; /* chance that a balloon will spawn */ - /* 0x02889C */ int tanuki_shop_status; /* adjusted based on any current events happening to Nook's shop */ - /* 0x0288A0 */ u8 pad_connected; /* is gamepad 0 connected? */ - /* 0x0288A1 */ u8 unk288A1; - /* 0x0288A2 */ s16 current_sound_effect; - /* 0x0288A4 */ u8 _288a4[0x0288C0 - 0x0288A4]; - /* 0x0288C0 */ Island_c transfer_island; /* used when transferring islands with the GBA */ - /* 0x02A1C0 */ Island_agb_c agb_island; /* converted island data sent over to the GBA */ - /* 0x02DB40 */ u8 auto_nwrite_set; /* when true, saved nwrite time will be utilized. Seems to be used to keep same date for fishing tourney stuff. */ - /* 0x02DB42 */ u16 select_last_select_no; - /* 0x02DB44 */ u16 select_last_top_no; - /* 0x02DB46 */ mCD_persistent_data_c travel_persistent_data; /* used for checking if travelling back to town */ - /* 0x02DBA2 */ s16 island_weather; - /* 0x02DBA4 */ s16 island_weather_intensity; - /* 0x02DBA6 */ s16 _2DBA6; - /* 0x02DBA8 */ u8 memcard_slot; - /* 0X02DBAC */ int famicom_2DBAC; - /* 0x02DBB0 */ s16 can_look_goki_count; - /* 0x02DBB4 */ f32 rainbow_opacity; /* current opacity of rainbow (0.0f - 1.0f) */ - /* 0x02DBB8 */ u32 event_flags[mEv_EVENT_TYPE_NUM]; - /* 0x02DBD4 */ xyz_t* pluss_bridge_pos; /* position of extra bridge */ - /* 0x02DBD8 */ lbRTC_time_c auto_nwrite_time; /* cached notice time used for fishing tourney results? */ - /* 0x02DBE0 */ u8 rhythym_updated; - /* 0x02DBE1 */ u8 _2dbe1; - /* 0x02DBE2 */ u8 hem_visible; /* controls farley's visiblilty during cutscene? */ - /* 0x02DBE4 */ u8* carde_program_p; /* pointer to current e-Reader program data */ - /* 0x02DBE8 */ size_t carde_program_size; /* size of current e-Reader program data */ - /* 0x02DBEC */ int unk_nook_present_count; /* something possibly to do withhanding over password present? */ - /* 0x02DBF0 */ u8 pad[16]; + /* 0x000000 */ Save save; + /* 0x026000 */ u8 game_started; + /* 0x026001 */ u8 field_type; + /* 0x026002 */ u8 field_draw_type; + /* 0x026003 */ u8 player_no; + /* 0x026004 */ int last_scene_no; + /* 0x026008 */ int player_data_mode; + /* 0x02600C */ Clip_c clip; + /* 0x026110 */ Time_c time; + /* 0x02613C */ Private_c* now_private; + /* 0x026140 */ mHm_hs_c* now_home; + /* 0x026144 */ u8 map_flag; + /* 0x026145 */ u8 fish_location; + /* 0x026146 */ u8 npc_is_summercamper; + /* 0x026147 */ u8 player_select_animal_no; + /* 0x026148 */ u8 _26148[0x2614C - 0x26148]; + /* 0x02614C */ Transition_c transition; + /* 0x026150 */ s16 bg_item_type; + /* 0x026152 */ s16 bg_item_profile; + /* 0x026154 */ u8 _26154[0x26164 - 0x26154]; + /* 0x026164 */ mNpc_NpcList_c npclist[ANIMAL_NUM_MAX + 1]; + /* 0x0264E4 */ mNpc_NpcList_c island_npclist[1]; // TODO: define for island npc count + /* 0x02651C */ mActor_name_t house_owner_name; + /* 0x02651E */ mActor_name_t last_field_id; + /* 0x026520 */ u8 + in_initial_block; /* when TRUE, the player is in the acre which they exited a building. FALSE otherwise. */ + /* 0x026521 */ u8 submenu_disabled; /* when set, submenus cannot be accessed from start button */ + /* 0x026522 */ u8 sunlight_flag; + /* 0x026523 */ u8 train_flag; + /* 0x026522 */ u8 _26524[0x26668 - 0x26524]; + /* 0x026668 */ mActor_name_t npc_chg_cloth; + /* 0x02666A */ u16 _pad_2666A; // weather data is probably a struct aligned to 4 bytes + /* 0x02666C */ s16 weather; + /* 0x02666E */ s16 weather_intensity; + /* 0x026670 */ lbRTC_time_c weather_time; + /* 0x026678 */ s_xyz wind; + /* 0x026680 */ f32 wind_speed; + /* 0x026684 */ mEv_event_common_u special_event_common; + /* 0x02669C */ mQst_not_saved_c quest; + /* 0x0266A4 */ int scene_from_title_demo; /* next scene to be loaded when title demo finishes */ + /* 0x0266A8 */ mNPS_schedule_c npc_schedule[SCHEDULE_NUM]; + /* 0x0267A8 */ mNpc_walk_c npc_walk; + /* 0x026838 */ mNpc_EventNpc_c event_npc[mNpc_EVENT_NPC_NUM]; + /* 0x026878 */ mNpc_MaskNpc_c mask_npc[mNpc_MASK_NPC_NUM]; + /* 0x028528 */ int snowman_msg_id; + /* 0x02852C */ s16 money_power; + /* 0x02852E */ s16 goods_power; + /* 0x028530 */ Door_data_c door_data; /* misc door data */ + /* 0x028544 */ Door_data_c structure_exit_door_data; /* door data for when exiting a building */ + /* 0x028558 */ mDemo_Request_c start_demo_request; + /* 0x028568 */ Door_data_c event_door_data; + /* 0x02857C */ Door_data_c famicom_emu_exit_door_data; + /* 0x028590 */ u8 remove_cut_tree_info_bitfield; /* resets the cut tree states for trees in a visible acre */ + /* 0x028591 */ u8 floor_idx; + /* 0x028592 */ s16 demo_profiles[2]; /* demo_profiles[0] is for demo_clip, demo_profiles[1] is for demo_clip2 */ + /* 0x028596 */ u16 copy_protect_code; + /* 0x028598 */ int event_keep_flags[4]; + /* 0x0285A8 */ u8 _285A8[0x0285BE - 0x0285A8]; + /* 0x0285BE */ s8 player_actor_exists; + /* 0x0285BF */ s8 payment_completed_type; + /* 0x0285C0 */ s8 player_decoy_flag; + /* 0x0285C1 */ u8 _285C1; + /* 0x0285C2 */ u8 make_npc2_actor; + /* 0x0285C4 */ s16 event_id; + /* 0x0285C6 */ u8 event_title_flags; + /* 0x0285C7 */ u8 event_title_fade_in_progress; + /* 0x0285C8 */ mEv_common_data_c event_common; + /* 0x0287F8 */ s8 current_famicom_rom; + /* 0x0287F9 */ s8 famicom_287F9; + /* 0x0287FA */ u8 _287FA[0x28838 - 0x0287FA]; + /* 0x028838 */ s8 player_bee_swell_flag; + /* 0x028839 */ s8 player_bee_chase_flag; + /* 0x02883A */ u8 goki_shocked_flag; + /* 0x02883B */ u8 time_changed_flag; + /* 0x02883C */ u8 unable_to_wade_flag; + /* 0x02883D */ u8 _02883D; + /* 0x02883E */ u8 train_coming_flag; /* state tracker for when train is going to spawn/has spawned */ + /* 0x02883F */ u8 train_exists_flag; /* state tracker for when train exists */ + /* 0x028840 */ u8 train_control_state; /* current train state */ + /* 0x028841 */ u8 train_last_control_state; /* previous train state */ + /* 0x028842 */ u8 train_signal; + /* 0x028843 */ u8 train_day; + /* 0x028844 */ u8 train_action; + /* 0x028845 */ u8 train_timer; + /* 0x028848 */ u32 train_start_timer; + /* 0x02884C */ f32 train_speed; + /* 0x028850 */ xyz_t train_position; + /* 0x02885C */ f32 unused_02885C; + /* 0x028860 */ f32 unused_028860; + /* 0x028864 */ u16 unused_028864; + /* 0x028866 */ u16 unused_028866; + /* 0x028868 */ u8 reset_flag; + /* 0x028869 */ u8 reset_type; + /* 0x02886A */ u8 force_mail_delivery_flag; + /* 0x02886B */ u8 post_girl_npc_type; + /* 0x02886C */ xyz_t ball_pos; + /* 0x028878 */ u8 ball_type; + /* 0x028879 */ u8 auto_nwrite_count; + /* 0x02887A */ lbRTC_year_t auto_nwrite_year; + /* 0x02887C */ u8 save_error_type; /* set to one of the mFRm_ERROR_* states when save is invalid */ + /* 0x02887D */ u8 train_approaching_flag; /* set when the train is coming */ + /* 0x02887E */ u8 buried_treasure_flag; /* when set, treasure cannot be buried */ + /* 0x02887F */ u8 spnpc_first_talk_flags; + /* 0x028880 */ u8 needlework_first_talk_flags; + /* 0x028882 */ u16 event_notification_active; + /* 0x028884 */ lbRTC_time_c newly_set_time; /* time set by player in time adjust menu */ + /* 0x02888C */ lbRTC_time_c old_time; /* time before being changed by the player */ + /* 0x028894 */ s16 balloon_state; /* balloon's current state */ + /* 0x028896 */ s16 balloon_last_spawn_min; /* last minute the balloon was spawned */ + /* 0x028898 */ f32 balloon_spawn_percent; /* chance that a balloon will spawn */ + /* 0x02889C */ int tanuki_shop_status; /* adjusted based on any current events happening to Nook's shop */ + /* 0x0288A0 */ u8 pad_connected; /* is gamepad 0 connected? */ + /* 0x0288A1 */ u8 unk288A1; + /* 0x0288A2 */ s16 current_sound_effect; + /* 0x0288A4 */ u8 _288a4[0x0288C0 - 0x0288A4]; + /* 0x0288C0 */ Island_c transfer_island; /* used when transferring islands with the GBA */ + /* 0x02A1C0 */ Island_agb_c agb_island; /* converted island data sent over to the GBA */ + /* 0x02DB40 */ u8 auto_nwrite_set; /* when true, saved nwrite time will be utilized. Seems to be used to keep same + date for fishing tourney stuff. */ + /* 0x02DB42 */ u16 select_last_select_no; + /* 0x02DB44 */ u16 select_last_top_no; + /* 0x02DB46 */ mCD_persistent_data_c travel_persistent_data; /* used for checking if travelling back to town */ + /* 0x02DBA2 */ s16 island_weather; + /* 0x02DBA4 */ s16 island_weather_intensity; + /* 0x02DBA6 */ s16 _2DBA6; + /* 0x02DBA8 */ u8 memcard_slot; + /* 0X02DBAC */ int famicom_2DBAC; + /* 0x02DBB0 */ s16 can_look_goki_count; + /* 0x02DBB4 */ f32 rainbow_opacity; /* current opacity of rainbow (0.0f - 1.0f) */ + /* 0x02DBB8 */ u32 event_flags[mEv_EVENT_TYPE_NUM]; + /* 0x02DBD4 */ xyz_t* pluss_bridge_pos; /* position of extra bridge */ + /* 0x02DBD8 */ lbRTC_time_c auto_nwrite_time; /* cached notice time used for fishing tourney results? */ + /* 0x02DBE0 */ u8 rhythym_updated; + /* 0x02DBE1 */ u8 _2dbe1; + /* 0x02DBE2 */ u8 hem_visible; /* controls farley's visiblilty during cutscene? */ + /* 0x02DBE4 */ u8* carde_program_p; /* pointer to current e-Reader program data */ + /* 0x02DBE8 */ size_t carde_program_size; /* size of current e-Reader program data */ + /* 0x02DBEC */ int unk_nook_present_count; /* something possibly to do withhanding over password present? */ + /* 0x02DBF0 */ u8 pad[16]; } common_data_t; extern common_data_t common_data; @@ -343,6 +353,8 @@ extern void common_data_reinit(); extern void common_data_init(); extern void common_data_clear(); +//clang-format on + #ifdef __cplusplus } #endif diff --git a/include/m_name_table.h b/include/m_name_table.h index 89a7743e..5644302b 100644 --- a/include/m_name_table.h +++ b/include/m_name_table.h @@ -1684,57 +1684,57 @@ extern int mNT_check_unknown(mActor_name_t item_no); #define ITM_CLOTH_END (ITM_CLOTH_START + 255) #define ITM_ETC_START 0x2500 -#define ITM_QST_LETTER ITM_ETC_START -#define ITM_QST_CLOTH (ITM_QST_LETTER + 1) -#define ITM_QST_MONEY (ITM_QST_CLOTH + 1) -#define ITM_QST_VIDEOTAPE (ITM_QST_MONEY + 1) -#define ITM_QST_ORGANIZER (ITM_QST_VIDEOTAPE + 1) -#define ITM_QST_POKEMON_PIKACHU (ITM_QST_ORGANIZER + 1) -#define ITM_QST_COMIC_BOOK (ITM_QST_POKEMON_PIKACHU + 1) -#define ITM_QST_PICTURE_BOOK (ITM_QST_COMIC_BOOK + 1) -#define ITM_QST_GAME_BOY (ITM_QST_PICTURE_BOOK + 1) -#define ITM_QST_CAMREA (ITM_QST_GAME_BOY + 1) -#define ITM_QST_WATCH (ITM_QST_CAMREA + 1) -#define ITM_QST_HANDKERCHIEF (ITM_QST_WATCH + 1) -#define ITM_QST_GLASSES_CASE (ITM_QST_HANDKERCHIEF + 1) -#define ITM_MONEY1000BELL (ITM_QST_GLASSES_CASE + 1) -#define ITM_DUST0_EMPTY_CAN (ITM_MONEY1000BELL + 1) -#define ITM_DUST1_BOOT (ITM_DUST0_EMPTY_CAN + 1) -#define ITM_DUST2_OLD_TIRE (ITM_DUST1_BOOT + 1) -#define ITM_FOSSIL (ITM_DUST2_OLD_TIRE + 1) -#define ITM_PITFALL (ITM_FOSSIL + 1) -#define ITM_FORTUNE_SLIP (ITM_PITFALL + 1) +#define ITM_QST_LETTER (ITM_ETC_START + 0) +#define ITM_QST_CLOTH (ITM_ETC_START + 1) +#define ITM_QST_MONEY (ITM_ETC_START + 2) +#define ITM_QST_VIDEOTAPE (ITM_ETC_START + 3) +#define ITM_QST_ORGANIZER (ITM_ETC_START + 4) +#define ITM_QST_POKEMON_PIKACHU (ITM_ETC_START + 5) +#define ITM_QST_COMIC_BOOK (ITM_ETC_START + 6) +#define ITM_QST_PICTURE_BOOK (ITM_ETC_START + 7) +#define ITM_QST_GAME_BOY (ITM_ETC_START + 8) +#define ITM_QST_CAMREA (ITM_ETC_START + 9) +#define ITM_QST_WATCH (ITM_ETC_START + 10) +#define ITM_QST_HANDKERCHIEF (ITM_ETC_START + 11) +#define ITM_QST_GLASSES_CASE (ITM_ETC_START + 12) +#define ITM_MONEY1000BELL (ITM_ETC_START + 13) +#define ITM_DUST0_EMPTY_CAN (ITM_ETC_START + 14) +#define ITM_DUST1_BOOT (ITM_ETC_START + 15) +#define ITM_DUST2_OLD_TIRE (ITM_ETC_START + 16) +#define ITM_FOSSIL (ITM_ETC_START + 17) +#define ITM_PITFALL (ITM_ETC_START + 18) +#define ITM_FORTUNE_SLIP (ITM_ETC_START + 19) #define ITM_SHELL_START (ITM_ETC_START + 20) -#define ITM_SHELL0 (ITM_SHELL_START + 0) -#define ITM_SHELL1 (ITM_SHELL_START + 1) -#define ITM_SHELL2 (ITM_SHELL_START + 2) -#define ITM_SHELL3 (ITM_SHELL_START + 3) -#define ITM_SHELL4 (ITM_SHELL_START + 4) -#define ITM_SHELL5 (ITM_SHELL_START + 5) -#define ITM_SHELL6 (ITM_SHELL_START + 6) -#define ITM_SHELL7 (ITM_SHELL_START + 7) -#define ITM_SHELL_END (ITM_SHELL_START + 8) +#define ITM_SHELL0 (ITM_ETC_START + 20) +#define ITM_SHELL1 (ITM_ETC_START + 21) +#define ITM_SHELL2 (ITM_ETC_START + 22) +#define ITM_SHELL3 (ITM_ETC_START + 23) +#define ITM_SHELL4 (ITM_ETC_START + 24) +#define ITM_SHELL5 (ITM_ETC_START + 25) +#define ITM_SHELL6 (ITM_ETC_START + 26) +#define ITM_SHELL7 (ITM_ETC_START + 27) +#define ITM_SHELL_END (ITM_ETC_START + 28) #define ITM_PRESENT (ITM_ETC_START + 28) -#define ITM_TOWN_MAP (ITM_PRESENT + 1) -#define ITM_SIGNBOARD (ITM_TOWN_MAP + 1) -#define ITM_GOLDEN_NET_PRESENT (ITM_SIGNBOARD + 1) -#define ITM_GOLDEN_AXE_PRESENT (ITM_GOLDEN_NET_PRESENT + 1) -#define ITM_GOLDEN_SHOVEL_PRESENT (ITM_GOLDEN_AXE_PRESENT + 1) -#define ITM_GOLDEN_ROD_PRESENT (ITM_GOLDEN_SHOVEL_PRESENT + 1) -#define ITM_EXCERCISE_CARD00 (ITM_GOLDEN_ROD_PRESENT + 1) -#define ITM_EXCERCISE_CARD01 (ITM_EXCERCISE_CARD00 + 1) -#define ITM_EXCERCISE_CARD02 (ITM_EXCERCISE_CARD01 + 1) -#define ITM_EXCERCISE_CARD03 (ITM_EXCERCISE_CARD02 + 1) -#define ITM_EXCERCISE_CARD04 (ITM_EXCERCISE_CARD03 + 1) -#define ITM_EXCERCISE_CARD05 (ITM_EXCERCISE_CARD04 + 1) -#define ITM_EXCERCISE_CARD06 (ITM_EXCERCISE_CARD05 + 1) -#define ITM_EXCERCISE_CARD07 (ITM_EXCERCISE_CARD06 + 1) -#define ITM_EXCERCISE_CARD08 (ITM_EXCERCISE_CARD07 + 1) -#define ITM_EXCERCISE_CARD09 (ITM_EXCERCISE_CARD08 + 1) -#define ITM_EXCERCISE_CARD10 (ITM_EXCERCISE_CARD09 + 1) -#define ITM_EXCERCISE_CARD11 (ITM_EXCERCISE_CARD10 + 1) -#define ITM_EXCERCISE_CARD12 (ITM_EXCERCISE_CARD11 + 1) -#define ITM_KNIFE_AND_FORK (ITM_EXCERCISE_CARD12 + 1) +#define ITM_TOWN_MAP (ITM_ETC_START + 29) +#define ITM_SIGNBOARD (ITM_ETC_START + 30) +#define ITM_GOLDEN_NET_PRESENT (ITM_ETC_START + 31) +#define ITM_GOLDEN_AXE_PRESENT (ITM_ETC_START + 32) +#define ITM_GOLDEN_SHOVEL_PRESENT (ITM_ETC_START + 33) +#define ITM_GOLDEN_ROD_PRESENT (ITM_ETC_START + 34) +#define ITM_EXCERCISE_CARD00 (ITM_ETC_START + 35) +#define ITM_EXCERCISE_CARD01 (ITM_ETC_START + 36) +#define ITM_EXCERCISE_CARD02 (ITM_ETC_START + 37) +#define ITM_EXCERCISE_CARD03 (ITM_ETC_START + 38) +#define ITM_EXCERCISE_CARD04 (ITM_ETC_START + 39) +#define ITM_EXCERCISE_CARD05 (ITM_ETC_START + 40) +#define ITM_EXCERCISE_CARD06 (ITM_ETC_START + 41) +#define ITM_EXCERCISE_CARD07 (ITM_ETC_START + 42) +#define ITM_EXCERCISE_CARD08 (ITM_ETC_START + 43) +#define ITM_EXCERCISE_CARD09 (ITM_ETC_START + 44) +#define ITM_EXCERCISE_CARD10 (ITM_ETC_START + 45) +#define ITM_EXCERCISE_CARD11 (ITM_ETC_START + 46) +#define ITM_EXCERCISE_CARD12 (ITM_ETC_START + 47) +#define ITM_KNIFE_AND_FORK (ITM_ETC_START + 48) #define ITM_ETC_END 0x2531 #define ITM_CARPET_START 0x2600 diff --git a/include/m_npc.h b/include/m_npc.h index 5fb4ffcb..9343c3d3 100644 --- a/include/m_npc.h +++ b/include/m_npc.h @@ -434,7 +434,7 @@ extern void mNpc_ClearTalkInfo(); extern int mNpc_CheckOverImpatient(int animal_idx, int looks); extern int mNpc_GetOverImpatient(int animal_idx, int looks); extern int mNpc_CheckQuestRequest(int animal_idx); -extern void mNpc_SetQuestRequestOFF(int animal_idx, int feel); +extern void mNpc_SetQuestRequestOFF(int animal_idx, int looks); extern void mNpc_TalkInfoMove(); extern void mNpc_TalkEndMove(int animal_idx, int feel); extern int mNpc_GetNpcFloorNo(); diff --git a/include/m_private.h b/include/m_private.h index f85ddf45..a6d4d029 100644 --- a/include/m_private.h +++ b/include/m_private.h @@ -19,13 +19,17 @@ extern "C" { #define mPr_DEPOSIT_MAX 999999999 #define mPr_FLAG_MASK_CAT_SCHEDULED (1 << 0) // Blanca appears when travelling +#define mPr_FLAG_1 (1 << 1) // unused? #define mPr_FLAG_POSTOFFICE_GIFT0 (1 << 2) // 1,000,000 Bells #define mPr_FLAG_POSTOFFICE_GIFT1 (1 << 3) // 10,000,000 Bells #define mPr_FLAG_POSTOFFICE_GIFT2 (1 << 4) // 100,000,000 Bells #define mPr_FLAG_POSTOFFICE_GIFT3 (1 << 5) // 999,999,999 Bells #define mPr_FLAG_MUSEUM_COMP_HANDBILL_SCHEDULED (1 << 6) // player is scheduled to receive completion letter & reward #define mPr_FLAG_MUSEUM_COMP_HANDBILL_RECEIVED (1 << 7) // player has received the completion letter & reward +#define mPr_FLAG_8 (1 << 8) // unused? #define mPr_FLAG_UPDATE_OUTLOOK_PENDING (1 << 9) // player bought a new coat of roof paint to be repainted +#define mPr_FLAG_BIRTHDAY_ACTIVE (1 << 10) // player's birthday is active and a villager can give them a gift +#define mPr_FLAG_TOTAKEKE_INTRODUCTION (1 << 11) // player has spoken to K.K. Slider before #define mPr_MONEY_POWER_MIN -80 diff --git a/include/m_quest.h b/include/m_quest.h index d798ddf7..4074d193 100644 --- a/include/m_quest.h +++ b/include/m_quest.h @@ -31,77 +31,92 @@ extern "C" { #define mQst_LETTER_RANK_11 11 #define mQst_LETTER_RANK_MAX mQst_LETTER_RANK_11 + 1 -#define mQst_LETTER_SCORE_BONUS 3 /* Given when the raw score of the letter has passed the threshold */ +#define mQst_LETTER_SCORE_BONUS 3 /* Given when the raw score of the letter has passed the threshold */ #define mQst_LETTER_PRESENT_BONUS 6 /* Given when a present is attached */ #define mQst_LETTER_OKAY_LENGTH 17 #define mQst_LETTER_GOOD_LENGTH 49 -#define mQst_DELIVERY_KIND_NUM 4 - enum { - mQst_QUEST_TYPE_DELIVERY, /* Deliver item quest */ - mQst_QUEST_TYPE_ERRAND, /* Villager 'can I help' quests */ - mQst_QUEST_TYPE_CONTEST, /* Villager send letter, plant flowers, bring ball, etc */ - mQst_QUEST_TYPE_NONE, - - mQst_QUEST_TYPE_NUM = mQst_QUEST_TYPE_NONE + mQst_QUEST_TYPE_DELIVERY, /* Deliver item quest */ + mQst_QUEST_TYPE_ERRAND, /* Villager 'can I help' quests */ + mQst_QUEST_TYPE_CONTEST, /* Villager send letter, plant flowers, bring ball, etc */ + mQst_QUEST_TYPE_NONE, + + mQst_QUEST_TYPE_NUM = mQst_QUEST_TYPE_NONE }; /* sizeof(mQst_base_c) == 0xC */ typedef struct quest_base_s { - /* 0x00 */ u32 quest_type:2; /* type, 0 = delivery, 1 = errand, 2 = contest, 3 = none */ - /* 0x00 */ u32 quest_kind:6; /* kind, differs by type */ - /* 0x01 */ u32 time_limit_enabled:1; /* when set, the time limit will be utilized */ - /* 0x01 */ u32 progress:4; /* progress towards quest goal */ - /* 0x01 */ u32 give_reward:1; /* set to true when player cannot take the item, and will skip quest completion checks */ - /* 0x01 */ u32 unused:2; + /* 0x00 */ u32 quest_type : 2; /* type, 0 = delivery, 1 = errand, 2 = contest, 3 = none */ + /* 0x00 */ u32 quest_kind : 6; /* kind, differs by type */ + /* 0x01 */ u32 time_limit_enabled : 1; /* when set, the time limit will be utilized */ + /* 0x01 */ u32 progress : 4; /* progress towards quest goal */ + /* 0x01 */ u32 give_reward : 1; /* player cannot take the item, and will skip quest completion checks */ + /* 0x01 */ u32 unused : 2; - /* 0x02 */ lbRTC_time_c time_limit; + /* 0x02 */ lbRTC_time_c time_limit; } mQst_base_c; /* Contest Quest */ enum { - mQst_CONTEST_KIND_FRUIT, /* get fruit for villager */ - mQst_CONTEST_KIND_SOCCER, /* get ball for villager */ - mQst_CONTEST_KIND_SNOWMAN, /* build snowman for villager */ - mQst_CONTEST_KIND_FLOWER, /* plant flowers for villager */ - mQst_CONTEST_KIND_FISH, /* get fish for villager */ - mQst_CONTEST_KIND_INSECT, /* get insect for villager */ - mQst_CONTEST_KIND_LETTER, /* send letter to villager */ + mQst_CONTEST_KIND_FRUIT, /* get fruit for villager */ + mQst_CONTEST_KIND_SOCCER, /* get ball for villager */ + mQst_CONTEST_KIND_SNOWMAN, /* build snowman for villager */ + mQst_CONTEST_KIND_FLOWER, /* plant flowers for villager */ + mQst_CONTEST_KIND_FISH, /* get fish for villager */ + mQst_CONTEST_KIND_INSECT, /* get insect for villager */ + mQst_CONTEST_KIND_LETTER, /* send letter to villager */ - mQst_CONTEST_KIND_NUM + mQst_CONTEST_KIND_NUM +}; + +enum { + mQst_CONTEST_DATA_NONE, + mQst_CONTEST_DATA_FLOWER, + mQst_CONTEST_DATA_LETTER, + + mQst_CONTEST_DATA_NUM }; /* sizeof(mQst_contest_info_u) == 4 */ typedef union quest_contest_info_s { - struct { - /* 0x00 */ u8 flowers_requested; /* number of flowers village requests be planted in acre */ - } flower_data; + struct { + /* 0x00 */ u8 flowers_requested; /* number of flowers village requests be planted in acre */ + } flower_data; - struct { - /* 0x00 */ u8 score; /* score rank of letter */ - /* 0x02 */ mActor_name_t present; /* present sent with letter */ - } letter_data; + struct { + /* 0x00 */ u8 score; /* score rank of letter */ + /* 0x02 */ mActor_name_t present; /* present sent with letter */ + } letter_data; } mQst_contest_info_u; /* sizeof(mQst_contest_c) == 0x28 */ typedef struct quest_contest_s { - /* 0x00 */ mQst_base_c base; /* quest base struct */ - /* 0x0C */ mActor_name_t requested_item; /* item (if any) requested by the villager */ - /* 0x0E */ PersonalID_c player_id; /* personal id of the player */ - /* 0x22 */ s8 type; /* type of quest, seems to be repeat of data in quest base */ - /* 0x24 */ mQst_contest_info_u info; /* contest info for flower & letter quests */ + /* 0x00 */ mQst_base_c base; /* quest base struct */ + /* 0x0C */ mActor_name_t requested_item; /* item (if any) requested by the villager */ + /* 0x0E */ PersonalID_c player_id; /* personal id of the player */ + /* 0x22 */ s8 type; /* type of quest, seems to be repeat of data in quest base */ + /* 0x24 */ mQst_contest_info_u info; /* contest info for flower & letter quests */ } mQst_contest_c; /* Delivery Quest */ +enum { + mQst_DELIVERY_KIND_NORMAL, // standard delivery + mQst_DELIVERY_KIND_FOREIGN, // delivered to a foreign animal + mQst_DELIVERY_KIND_REMOVE, // delivered to the animal who last left for another town + mQst_DELIVERY_KIND_LOST, // assumed, probably for when a delivery is 'undeliverable' + + mQst_DELIVERY_KIND_NUM +}; + /* sizeof(mQst_delivery_c) == 0x28 */ typedef struct quest_delivery_s { - /* 0x00 */ mQst_base_c base; /* quest base info */ - /* 0x0C */ AnmPersonalID_c recipient; /* villager who will receive it */ - /* 0x1A */ AnmPersonalID_c sender; /* villager who sent it */ + /* 0x00 */ mQst_base_c base; /* quest base info */ + /* 0x0C */ AnmPersonalID_c recipient; /* villager who will receive it */ + /* 0x1A */ AnmPersonalID_c sender; /* villager who sent it */ } mQst_delivery_c; /* Errand Quest */ @@ -109,68 +124,69 @@ typedef struct quest_delivery_s { #define mQst_ERRAND_CHAIN_ANIMAL_NUM 3 enum { - mQst_ERRAND_REQUEST, - mQst_ERRAND_REQUEST_CONTINUE, - mQst_ERRAND_REQUEST_FINAL, - - mQst_ERRAND_FIRSTJOB_CHANGE_CLOTH, - mQst_ERRAND_FIRSTJOB_PLANT_FLOWER, - mQst_ERRAND_FIRSTJOB_DELIVER_FTR, - mQst_ERRAND_FIRSTJOB_SEND_LETTER, - mQst_ERRAND_FIRSTJOB_DELIVER_CARPET, - mQst_ERRAND_FIRSTJOB_DELIVER_AXE, - mQst_ERRAND_FIRSTJOB_POST_NOTICE, - mQst_ERRAND_FIRSTJOB_SEND_LETTER2, - mQst_ERRAND_FIRSTJOB_DELIVER_AXE2, - mQst_ERRAND_FIRSTJOB_INTRODUCTIONS, - mQst_ERRAND_FIRSTJOB_OPEN, - mQst_ERRAND_FIRSTJOB_START, + mQst_ERRAND_REQUEST, + mQst_ERRAND_REQUEST_CONTINUE, + mQst_ERRAND_REQUEST_FINAL, - mQst_ERRAND_NUM + mQst_ERRAND_FIRSTJOB_CHANGE_CLOTH, + mQst_ERRAND_FIRSTJOB_PLANT_FLOWER, + mQst_ERRAND_FIRSTJOB_DELIVER_FTR, + mQst_ERRAND_FIRSTJOB_SEND_LETTER, + mQst_ERRAND_FIRSTJOB_DELIVER_CARPET, + mQst_ERRAND_FIRSTJOB_DELIVER_AXE, + mQst_ERRAND_FIRSTJOB_POST_NOTICE, + mQst_ERRAND_FIRSTJOB_SEND_LETTER2, + mQst_ERRAND_FIRSTJOB_DELIVER_AXE2, + mQst_ERRAND_FIRSTJOB_INTRODUCTIONS, + mQst_ERRAND_FIRSTJOB_OPEN, + mQst_ERRAND_FIRSTJOB_START, + + mQst_ERRAND_NUM }; enum { - mQst_ERRAND_TYPE_NONE, - mQst_ERRAND_TYPE_CHAIN, - mQst_ERRAND_TYPE_FIRST_JOB, + mQst_ERRAND_TYPE_NONE, + mQst_ERRAND_TYPE_CHAIN, + mQst_ERRAND_TYPE_FIRST_JOB, - mQst_ERRAND_TYPE_NUM + mQst_ERRAND_TYPE_NUM }; /* sizeof(mQst_first_job_c) == 0x20 */ typedef struct quest_first_job_s { - /* 0x00 */ AnmPersonalID_c used_ids[mQst_ERRAND_FIRST_JOB_ANIMAL_NUM]; /* villagers already used for first job quest (furniture, then letter) */ - /* 0x1C */ u8 used_num:7; /* used count for 'used_ids' */ - /* 0x1C */ u8 wrong_cloth:1; /* set to TRUE if player changes out of work uniform during chores */ + /* 0x00 */ AnmPersonalID_c used_ids[mQst_ERRAND_FIRST_JOB_ANIMAL_NUM]; /* villagers already used for first job quest + (furniture, then letter) */ + /* 0x1C */ u8 used_num : 7; /* used count for 'used_ids' */ + /* 0x1C */ u8 wrong_cloth : 1; /* set to TRUE if player changes out of work uniform during chores */ } mQst_firstjob_c; /* sizeof(mQst_errand_chain_c) == 0x2C */ typedef struct quest_errand_chain_s { - /* 0x00 */ AnmPersonalID_c used_ids[mQst_ERRAND_CHAIN_ANIMAL_NUM]; - /* 0x2A */ u8 used_num; + /* 0x00 */ AnmPersonalID_c used_ids[mQst_ERRAND_CHAIN_ANIMAL_NUM]; + /* 0x2A */ u8 used_num; } mQst_errand_chain_c; /* sizeof(mQst_errand_info_u) == 0x2C */ typedef union { - mQst_errand_chain_c chain; - mQst_firstjob_c first_job; + mQst_errand_chain_c chain; + mQst_firstjob_c first_job; } mQst_errand_info_u; /* sizeof(mQst_errand_c) == 0x58 */ typedef struct quest_errand_s { - /* 0x00 */ mQst_base_c base; /* quest base info */ - /* 0x0C */ AnmPersonalID_c recipient; /* villager who will receive it */ - /* 0x1A */ AnmPersonalID_c sender; /* villager who sent it */ - /* 0x28 */ mActor_name_t item; /* errand item */ - /* 0x2A */ s8 pockets_idx:5; /* index in player pockets where the errand item is */ - /* 0x2A */ s8 errand_type:3; /* errand type */ - /* 0x2C */ mQst_errand_info_u info; /* errand type-specific data */ + /* 0x00 */ mQst_base_c base; /* quest base info */ + /* 0x0C */ AnmPersonalID_c recipient; /* villager who will receive it */ + /* 0x1A */ AnmPersonalID_c sender; /* villager who sent it */ + /* 0x28 */ mActor_name_t item; /* errand item */ + /* 0x2A */ s8 pockets_idx : 5; /* index in player pockets where the errand item is */ + /* 0x2A */ s8 errand_type : 3; /* errand type */ + /* 0x2C */ mQst_errand_info_u info; /* errand type-specific data */ } mQst_errand_c; /* 'Not Saved' Quest */ typedef struct not_saved_quest_s { - int work; - u8 h; + int work; + u8 h; } mQst_not_saved_c; extern void mQst_ClearQuestInfo(mQst_base_c* quest); @@ -216,7 +232,8 @@ extern void mQst_SetFirstJobAxe(mQst_errand_c* errand, AnmPersonalID_c* pid, mAc extern void mQst_SetFirstJobAxe2(mQst_errand_c* errand, AnmPersonalID_c* pid, mActor_name_t item, u8 slot); extern void mQst_SetFirstJobNotice(mQst_errand_c* errand); extern int mQst_GetRandom(int max); -extern void mQst_GetGoods_common(mActor_name_t* item, AnmPersonalID_c* pid, int category, mActor_name_t* exist_table, int exist_num, int list); +extern void mQst_GetGoods_common(mActor_name_t* item, AnmPersonalID_c* pid, int category, mActor_name_t* exist_table, + int exist_num, int list); extern int mQst_CheckSoccerTarget(ACTOR* actor); extern void mQst_NextSoccer(ACTOR* actor); extern void mQst_NextSnowman(xyz_t snowman_pos); diff --git a/include/m_submenu.h b/include/m_submenu.h index 39906db5..caa3fbe6 100644 --- a/include/m_submenu.h +++ b/include/m_submenu.h @@ -19,120 +19,128 @@ typedef struct submenu_s Submenu; #define mSM_INV_BUTTON_1 BUTTON_Y enum { - mSM_PROCESS_WAIT, - mSM_PROCESS_PREWAIT, - mSM_PROCESS_LINKWAIT, - mSM_PROCESS_PLAY, - mSM_PROCESS_END, + mSM_PROCESS_WAIT, + mSM_PROCESS_PREWAIT, + mSM_PROCESS_LINKWAIT, + mSM_PROCESS_PLAY, + mSM_PROCESS_END, - mSM_PROCESS_NUM + mSM_PROCESS_NUM }; enum { - mSM_DLF_SUBMENU_OVL, - mSM_DLF_PLAYER_ACTOR, + mSM_DLF_SUBMENU_OVL, + mSM_DLF_PLAYER_ACTOR, - mSM_DLF_NUM + mSM_DLF_NUM }; enum { - mSM_MOVE_OUT_RIGHT, - mSM_MOVE_IN_RIGHT, - - mSM_MOVE_OUT_LEFT, - mSM_MOVE_IN_LEFT, - - mSM_MOVE_OUT_TOP, - mSM_MOVE_IN_TOP, - - mSM_MOVE_OUT_BOTTOM, - mSM_MOVE_IN_BOTTOM, + mSM_MOVE_OUT_RIGHT, + mSM_MOVE_IN_RIGHT, - mSM_MOVE_NUM + mSM_MOVE_OUT_LEFT, + mSM_MOVE_IN_LEFT, + + mSM_MOVE_OUT_TOP, + mSM_MOVE_IN_TOP, + + mSM_MOVE_OUT_BOTTOM, + mSM_MOVE_IN_BOTTOM, + + mSM_MOVE_NUM }; enum submenu_overlay { - mSM_OVL_NONE, - - mSM_OVL_INVENTORY, - mSM_OVL_HBOARD, - mSM_OVL_TIMEIN, - mSM_OVL_LEDIT, - mSM_OVL_MAP, - mSM_OVL_NOTICE, - mSM_OVL_REPAY, - mSM_OVL_MSCORE, - mSM_OVL_BIRTHDAY, - mSM_OVL_EDITOR, - mSM_OVL_MAILBOX, - mSM_OVL_BOARD, - mSM_OVL_ADDRESS, - mSM_OVL_HANIWA, - mSM_OVL_EDITENDCHK, - mSM_OVL_WARNING, - mSM_OVL_CPMAIL, - mSM_OVL_CPWARNING, - mSM_OVL_CPEDIT, - mSM_OVL_CATALOG, - mSM_OVL_MUSIC, - mSM_OVL_BANK, - mSM_OVL_NEEDLEWORK, - mSM_OVL_CPORIGINAL, - mSM_OVL_DESIGN, - mSM_OVL_GBA, - mSM_OVL_DIARY, - mSM_OVL_CALENDAR, - mSM_OVL_PASSWORDMAKE, - mSM_OVL_PASSWORDCHK, + mSM_OVL_NONE, - mSM_OVL_NUM + mSM_OVL_INVENTORY, + mSM_OVL_HBOARD, + mSM_OVL_TIMEIN, + mSM_OVL_LEDIT, + mSM_OVL_MAP, + mSM_OVL_NOTICE, + mSM_OVL_REPAY, + mSM_OVL_MSCORE, + mSM_OVL_BIRTHDAY, + mSM_OVL_EDITOR, + mSM_OVL_MAILBOX, + mSM_OVL_BOARD, + mSM_OVL_ADDRESS, + mSM_OVL_HANIWA, + mSM_OVL_EDITENDCHK, + mSM_OVL_WARNING, + mSM_OVL_CPMAIL, + mSM_OVL_CPWARNING, + mSM_OVL_CPEDIT, + mSM_OVL_CATALOG, + mSM_OVL_MUSIC, + mSM_OVL_BANK, + mSM_OVL_NEEDLEWORK, + mSM_OVL_CPORIGINAL, + mSM_OVL_DESIGN, + mSM_OVL_GBA, + mSM_OVL_DIARY, + mSM_OVL_CALENDAR, + mSM_OVL_PASSWORDMAKE, + mSM_OVL_PASSWORDCHK, + + mSM_OVL_NUM }; enum { - mSM_IV_OPEN_NORMAL, - mSM_IV_OPEN_MAILBOX, - mSM_IV_OPEN_HANIWA_ENTRUST, - mSM_IV_OPEN_HANIWA_TAKE, - mSM_IV_OPEN_QUEST, - mSM_IV_OPEN_SELL, - mSM_IV_OPEN_GIVE, - mSM_IV_OPEN_SEND_MAIL, - mSM_IV_OPEN_TAKE, - mSM_IV_OPEN_PUTIN_FTR, - mSM_IV_OPEN_MINIDISK, - mSM_IV_OPEN_SHRINE, - mSM_IV_OPEN_12, - mSM_IV_OPEN_EXCHANGE, - mSM_IV_OPEN_14, - mSM_IV_OPEN_CURATOR, - mSM_IV_OPEN_16, + mSM_IV_OPEN_NORMAL, + mSM_IV_OPEN_MAILBOX, + mSM_IV_OPEN_HANIWA_ENTRUST, + mSM_IV_OPEN_HANIWA_TAKE, + mSM_IV_OPEN_QUEST, + mSM_IV_OPEN_SELL, + mSM_IV_OPEN_GIVE, + mSM_IV_OPEN_SEND_MAIL, + mSM_IV_OPEN_TAKE, + mSM_IV_OPEN_PUTIN_FTR, + mSM_IV_OPEN_MINIDISK, + mSM_IV_OPEN_SHRINE, + mSM_IV_OPEN_12, + mSM_IV_OPEN_EXCHANGE, + mSM_IV_OPEN_14, + mSM_IV_OPEN_CURATOR, + mSM_IV_OPEN_16, - mSM_IV_OPEN_NUM + mSM_IV_OPEN_NUM }; enum { - mSM_BD_OPEN_WRITE, - mSM_BD_OPEN_READ, - mSM_BD_OPEN_REWRITE, - mSM_BD_OPEN_WRITE_ISLAND, - mSM_BD_OPEN_READ_ISLAND, + mSM_IV_ITEM_NORMAL, + mSM_IV_ITEM_PUT_AWAY, + mSM_IV_ITEM_WAIT, - mSM_BD_OPEN_NUM + mSM_IV_ITEM_NUM +}; + +enum { + mSM_BD_OPEN_WRITE, + mSM_BD_OPEN_READ, + mSM_BD_OPEN_REWRITE, + mSM_BD_OPEN_WRITE_ISLAND, + mSM_BD_OPEN_READ_ISLAND, + + mSM_BD_OPEN_NUM }; typedef struct submenu_item_s { - mActor_name_t item; - u8 slot_no; + mActor_name_t item; + u8 slot_no; } Submenu_Item_c; typedef struct submenu_dlftbl { - void* _00; - int _04; - int _08; - int _0C; - int _10; - int _14; - const char* name; + void* _00; + int _04; + int _08; + int _0C; + int _10; + int _14; + const char* name; } mSM_dlftbl_c; typedef void (*SUBMENU_PROC)(Submenu*); @@ -140,36 +148,38 @@ typedef void (*SUBMENU_GAME_PROC)(Submenu*, GAME*); /* sizeof (struct submenu_s) == 0x1B8 */ struct submenu_s { - /* 0x000 */ int mode; - /* 0x004 */ int menu_type; - /* 0x008 */ int current_menu_type; + /* 0x000 */ int mode; + /* 0x004 */ int menu_type; + /* 0x008 */ int current_menu_type; - /* 0x00C */ int process_status; + /* 0x00C */ int process_status; - /* 0x010 */ int param0; - /* 0x014 */ int param1; - /* 0x018 */ void* param2; - /* 0x01C */ int param3; + /* 0x010 */ int param0; + /* 0x014 */ int param1; + /* 0x018 */ void* param2; + /* 0x01C */ int param3; - /* 0x020 */ int wait_timer; + /* 0x020 */ int wait_timer; - /* 0x024 */ char* overlay_address; - /* 0x028 */ char* next_overlay_address; - /* 0x02C */ Submenu_Overlay_c* overlay; - /* 0x030 */ SUBMENU_PROC move_proc; - /* 0x034 */ SUBMENU_GAME_PROC draw_proc; + /* 0x024 */ char* overlay_address; + /* 0x028 */ char* next_overlay_address; + /* 0x02C */ Submenu_Overlay_c* overlay; + /* 0x030 */ SUBMENU_PROC move_proc; + /* 0x034 */ SUBMENU_GAME_PROC draw_proc; - /* 0x038 */ Mail_c mail; /* selected mail */ - /* 0x162 */ u8 open_flag; // only set to 0 or 1, checked at least once in aQMgr_actor_move_talk_sub_hand_item_wait - /* 0x163 */ u8 after_mode; /* relates to code which runs after the submenu process */ - /* 0x164 */ u8 unk_164; // only set to 0 in mSM_move_LINKWait in AC - /* 0x165 */ u8 disable_start_btn_flag; /* when set to TRUE, the START button input will be ignored */ - /* 0x166 */ u8 disable_start_btn_timer; /* timer for when to disable the start button ignore flag */ - /* 0x168 */ xyz_t water_pos; /* calculated to the nearest water position to the player for releasing fish */ - /* 0x174 */ Submenu_Item_c* item_p; /* pointer to a 'Submenu_Item_c' array, seemingly only points to Submenu::items */ - /* 0x178 */ s16 item_num; /* number of items in the item array */ - /* 0x17A */ s16 selected_item_num; /* number of selected items in the item array */ - /* 0x17C */ Submenu_Item_c items[mPr_POCKETS_SLOT_COUNT]; /* item buffer, entries are only set when an item is selected by the player */ + /* 0x038 */ Mail_c mail; /* selected mail */ + /* 0x162 */ u8 open_flag; // only set to 0 or 1, checked at least once in aQMgr_actor_move_talk_sub_hand_item_wait + /* 0x163 */ u8 after_mode; /* relates to code which runs after the submenu process */ + /* 0x164 */ u8 unk_164; // only set to 0 in mSM_move_LINKWait in AC + /* 0x165 */ u8 disable_start_btn_flag; /* when set to TRUE, the START button input will be ignored */ + /* 0x166 */ u8 disable_start_btn_timer; /* timer for when to disable the start button ignore flag */ + /* 0x168 */ xyz_t water_pos; /* calculated to the nearest water position to the player for releasing fish */ + /* 0x174 */ Submenu_Item_c* + item_p; /* pointer to a 'Submenu_Item_c' array, seemingly only points to Submenu::items */ + /* 0x178 */ s16 item_num; /* number of items in the item array */ + /* 0x17A */ s16 selected_item_num; /* number of selected items in the item array */ + /* 0x17C */ Submenu_Item_c + items[mPr_POCKETS_SLOT_COUNT]; /* item buffer, entries are only set when an item is selected by the player */ }; extern int mSM_COLLECT_INSECT_GET(int idx); diff --git a/src/ac_quest_talk_init.c b/src/ac_quest_talk_init.c new file mode 100644 index 00000000..33e7e7fe --- /dev/null +++ b/src/ac_quest_talk_init.c @@ -0,0 +1,2238 @@ +#include "ac_quest_talk_init.h" + +#include "m_common_data.h" +#include "m_item_name.h" +#include "m_font.h" +#include "m_msg.h" +#include "m_string.h" +#include "libultra/libultra.h" + +enum { + aQMgr_CHECK_TO, + aQMgr_CHECK_FROM, + + aQMgr_CHECK_OWN_NUM +}; + +enum { + aQMgr_QUEST_TYPE_FJ, + aQMgr_QUEST_TYPE_QUEST, + + aQMgr_QUEST_TYPE_NUM +}; + +enum { + aQMgr_TALK_STEP_SELECT_TALK, + aQMgr_TALK_STEP_RECONF_OR_NORMAL, + aQMgr_TALK_STEP_ROOT_RECONF_OR_NORMAL, + aQMgr_TALK_STEP_NO_OR_NORMAL, + aQMgr_TALK_STEP_FULL_ITEM_OR_NORMAL, + aQMgr_TALK_STEP_RENEW_ERRAND_OR_NORMAL, + aQMgr_TALK_STEP_NEW_QUEST_OR_NORMAL, + aQMgr_TALK_STEP_NORMAL, + aQMgr_TALK_STEP_OCCUR_QUEST, + aQMgr_TALK_STEP_GIVEUP, + aQMgr_TALK_STEP_GIVEUP_WAIT_BUTTON, + aQMgr_TALK_STEP_GIVEUP_OPEN_MENU, + aQMgr_TALK_STEP_GIVEUP_ITEM, + aQMgr_TALK_STEP_GIVEUP_NPC_ITEM, + aQMgr_TALK_STEP_FIN_QUEST_START, + aQMgr_TALK_STEP_TALK_FIN_QUEST_START_NOT_HAND, + aQMgr_TALK_STEP_FIN_QUEST_REWARD, + aQMgr_TALK_STEP_FIN_QUEST_THANKS, + aQMgr_TALK_STEP_AFTER_REWARD, + aQMgr_TALK_STEP_AFTER_REWARD_THANKS, + aQMgr_TALK_STEP_WAIT_TALK, + aQMgr_TALK_STEP_OPEN_MENU, + aQMgr_TALK_STEP_GET_ITEM, + aQMgr_TALK_STEP_NPC_GET_ITEM_WAIT, + aQMgr_TALK_STEP_CHANGE_WAIT, + aQMgr_TALK_STEP_RENEW_ERRAND_IRAI_END, + aQMgr_TALK_STEP_RENEW_ERRAND_IRAI_END_GIVE_ITEM, + aQMgr_TALK_STEP_CONTEST_HOKA_OR_NORMAL, + aQMgr_TALK_STEP_FINISH_LETTER, + aQMgr_TALK_STEP_WAIT, + aQMgr_TALK_STEP_NO_OR_ISLAND, + aQMgr_TALK_STEP_FINISH +}; + +static mActor_name_t l_quest_item_list[] = { ITM_QST_VIDEOTAPE, ITM_QST_ORGANIZER, ITM_QST_POKEMON_PIKACHU, + ITM_QST_COMIC_BOOK, ITM_QST_PICTURE_BOOK, ITM_QST_GAME_BOY, + ITM_QST_CAMREA, ITM_QST_WATCH, ITM_QST_HANDKERCHIEF, + ITM_QST_GLASSES_CASE }; + +static int l_reward_msg[] = { 0x011B, 0x00D3, 0x00E5, 0x00F7, 0x0109, 0x013F, 0x012D, 0x081D }; + +static int l_fruit_reward_msg[] = { 0x011B, 0x00D3, 0x00E5, 0x1146, 0x1158, 0x116A, 0x00E5, 0x081D }; + +static int l_soccer_reward_msg[] = { 0x0DA3, 0x00D3, 0x00E5, 0x0DB5, 0x0DC7, 0x013F, 0x00E5, 0x081D }; + +static int l_snowman_reward_msg[] = { 0x0E57, 0x00D3, 0x00E5, 0x0E69, 0x0E7B, 0x013F, 0x00E5, 0x081D }; + +static int l_flower_reward_msg[] = { 0x0FD9, 0x00D3, 0x00E5, 0x0FEB, 0x0FFD, 0x013F, 0x00E5, 0x081D }; + +static int l_fish_reward_msg[] = { 0x157A, 0x00D3, 0x00E5, 0x1556, 0x1568, 0x013F, 0x00E5, 0x081D }; + +static int l_insect_reward_msg[] = { 0x15F8, 0x00D3, 0x00E5, 0x15D4, 0x15E6, 0x013F, 0x00E5, 0x081D }; + +static int l_after_reward_msg[] = { 0x0304, 0x0000, 0x0000, 0x0316, 0x0328, 0x0000, 0x0000, 0x0000 }; + +typedef struct quest_manager_quest_info_s { + int* type_table; + int type_count; + + int* kind_table[mQst_QUEST_TYPE_NUM]; + int kind_count[mQst_QUEST_TYPE_NUM]; +} aQMgr_qst_info_c; + +static int l_quest_type_table_fj[] = { mQst_QUEST_TYPE_DELIVERY, mQst_QUEST_TYPE_ERRAND }; +static int l_quest_type_table_qst[] = { mQst_QUEST_TYPE_DELIVERY, mQst_QUEST_TYPE_ERRAND, mQst_QUEST_TYPE_CONTEST }; + +static int l_quest_kind_table_fj_delivery[] = { mQst_DELIVERY_KIND_NORMAL, mQst_DELIVERY_KIND_LOST }; +static int l_quest_kind_table_fj_errand[] = { mQst_ERRAND_REQUEST }; +static int l_quest_kind_table_qst_delivery[] = { mQst_DELIVERY_KIND_NORMAL, mQst_DELIVERY_KIND_FOREIGN, + mQst_DELIVERY_KIND_REMOVE, mQst_DELIVERY_KIND_LOST }; +static int l_quest_kind_table_qst_errand[] = { mQst_ERRAND_REQUEST }; +static int l_quest_kind_table_qst_contest[] = { mQst_CONTEST_KIND_FRUIT, mQst_CONTEST_KIND_SOCCER, + mQst_CONTEST_KIND_SNOWMAN, mQst_CONTEST_KIND_FLOWER, + mQst_CONTEST_KIND_FISH, mQst_CONTEST_KIND_INSECT, + mQst_CONTEST_KIND_LETTER }; + +static aQMgr_qst_info_c l_new_fj_quest_info = { l_quest_type_table_fj, + ARRAY_COUNT(l_quest_type_table_fj), + + l_quest_kind_table_fj_delivery, + l_quest_kind_table_fj_errand, + NULL, + + ARRAY_COUNT(l_quest_kind_table_fj_delivery), + ARRAY_COUNT(l_quest_kind_table_fj_errand), + 0 }; + +static aQMgr_qst_info_c l_new_quest_quest_info = { l_quest_type_table_qst, + ARRAY_COUNT(l_quest_type_table_qst), + + l_quest_kind_table_qst_delivery, + l_quest_kind_table_qst_errand, + l_quest_kind_table_qst_contest, + + ARRAY_COUNT(l_quest_kind_table_qst_delivery), + ARRAY_COUNT(l_quest_kind_table_qst_errand), + ARRAY_COUNT(l_quest_kind_table_qst_contest) }; + +static int aQMgr_actor_check_own_quest(QUEST_MANAGER_ACTOR* manager, int mode) { + NPC_ACTOR* client = (NPC_ACTOR*)*manager->client; + Animal_c* animal = client->npc_info.animal; + aQMgr_regist_c* regist = manager->regist; + int res = -1; + + if (animal != NULL) { + AnmPersonalID_c* pid; + int i; + + for (i = 0; i < aQMgr_REGIST_NUM; i++, regist++) { + if (regist->quest_info != NULL) { + if (mode == aQMgr_CHECK_TO) { + pid = ®ist->to_id; + } else { + pid = ®ist->from_id; + } + + if (mNpc_CheckCmpAnimalPersonalID(&animal->id, pid) == TRUE) { + res = i; + break; + } + } + } + } + + return res; +} + +static int aQMgr_actor_check_still_reward(QUEST_MANAGER_ACTOR* manager) { + Animal_c* animal = ((NPC_ACTOR*)*manager->client)->npc_info.animal; + aQMgr_regist_c* regist = manager->regist; + int idx = -1; + AnmPersonalID_c* anm_id = &animal->id; + int i; + PersonalID_c* pid = &Common_Get(now_private)->player_ID; + + if (anm_id != NULL) { + + for (i = 0; i < aQMgr_REGIST_NUM; i++, regist++) { + if (regist->quest_info != NULL && regist->quest_info->give_reward == TRUE && + mNpc_CheckCmpAnimalPersonalID(anm_id, ®ist->to_id) == TRUE && + mPr_CheckCmpPersonalID(pid, regist->pid) == TRUE) { + idx = i; + break; + } + } + } + + return idx; +} + +static int aQMgr_actor_check_fin_step(mQst_base_c* quest_info) { + int res = FALSE; + + if (quest_info->progress == 0) { + res = TRUE; + } + + return res; +} + +static int aQMgr_actor_check_finish(aQMgr_regist_c* regist, Animal_c* animal) { + aQMgr_CHECK_FINISH_PROC check_finish_proc = regist->check_finish_proc; + mQst_base_c* quest_info = regist->quest_info; + int res = FALSE; + + if (quest_info != NULL) { + if (check_finish_proc != NULL) { + res = (*check_finish_proc)(quest_info, animal); + } else { + res = aQMgr_actor_check_fin_step(quest_info); + } + } + + return res; +} + +static int aQMgr_actor_check_limit(aQMgr_regist_c* regist) { + mQst_base_c* quest_info = regist->quest_info; + int res = FALSE; + + if (quest_info != NULL) { + res = mQst_CheckLimitOver(quest_info); + } + + return res; +} + +static int aQMgr_actor_check_errand_from(QUEST_MANAGER_ACTOR* manager) { + NPC_ACTOR* client = (NPC_ACTOR*)*manager->client; + int idx = -1; + Animal_c* animal = client->npc_info.animal; + aQMgr_regist_c* regist = manager->regist; + aQMgr_quest_c* quest; + int count = 0; + + if (animal != NULL) { + int i; + + for (i = 0; i < aQMgr_REGIST_NUM; i++, regist++) { + if (count >= manager->regist_use_no) { + break; + } + + quest = (aQMgr_quest_c*)regist->quest_info; + if (quest != NULL) { + if (quest->base.quest_type == mQst_QUEST_TYPE_ERRAND && + (quest->errand.errand_type == mQst_ERRAND_REQUEST_CONTINUE && + mNpc_CheckCmpAnimalPersonalID(&animal->id, &quest->errand.info.chain.used_ids[0]) == TRUE)) { + idx = i; + break; + } + + count++; + } + } + } + + return idx; +} + +static int aQMgr_actor_check_client_quest_info(QUEST_MANAGER_ACTOR* manager) { + int res = FALSE; + + if (aQMgr_GET_CLIENT(manager)->npc_info.list->quest_info.quest_type != mQst_QUEST_TYPE_NONE) { + res = TRUE; + } + + return res; +} + +static int aQMgr_actor_get_errand_next_idx(aQMgr_regist_c* regist) { + mQst_errand_c* errand; + int idx = -1; + + if (regist != NULL && regist->quest_info != NULL && regist->animal_idx >= 0 && regist->animal_idx < 5) { + errand = (mQst_errand_c*)regist->quest_info; + + if (errand->base.quest_type == mQst_QUEST_TYPE_ERRAND) { + idx = regist->animal_idx; + } + } + + return idx; +} + +static int aQMgr_actor_set_errand_next(u8* next, aQMgr_regist_c* regist, u8 kind) { + int idx = aQMgr_actor_get_errand_next_idx(regist); + + if (idx >= 0 && idx < mPr_ERRAND_QUEST_NUM) { + next[idx] = kind; + } +} + +static u8 aQMgr_actor_get_errand_next(aQMgr_regist_c* regist, u8* next) { + u8 kind = mQst_ERRAND_REQUEST; + int idx = aQMgr_actor_get_errand_next_idx(regist); + + if (idx >= 0 && idx < mPr_ERRAND_QUEST_NUM) { + kind = next[idx]; + } + + return kind; +} + +static int aQMgr_actor_check_free_quest(mQst_base_c* quest_info) { + int res = FALSE; + + if (quest_info != NULL && quest_info->quest_type == mQst_QUEST_TYPE_NONE) { + res = TRUE; + } + + return res; +} + +static void aQMgr_actor_get_free_quest_p(QUEST_MANAGER_ACTOR* manager, int type) { + AnmPersonalID_c* client_id = &aQMgr_GET_CLIENT_ANIMAL(manager)->id; + mQst_contest_c* client_contest = &aQMgr_GET_CLIENT_ANIMAL(manager)->contest_quest; + mQst_base_c** free_data_p = &manager->target.free_data_p; + Private_c* priv = Common_Get(now_private); + mActor_name_t item; + mActor_name_t* pockets = priv->inventory.pockets; + Animal_c* animal = Save_Get(animals); + int idx = -1; + int i; + + *free_data_p = NULL; + switch (type) { + case mQst_QUEST_TYPE_DELIVERY: { + for (i = 0; i < mPr_POCKETS_SLOT_COUNT; i++) { + if (aQMgr_actor_check_free_quest(&priv->deliveries[i].base) == TRUE && pockets[i] == EMPTY_NO) { + manager->target.quest_inv_item_idx = i; + *free_data_p = &priv->deliveries[i].base; + idx = i; + break; + } + } + break; + } + + case mQst_QUEST_TYPE_ERRAND: { + for (i = 0; i < mPr_ERRAND_QUEST_NUM; i++) { + if (aQMgr_actor_check_free_quest(&priv->errands[i].base) == TRUE) { + *free_data_p = &priv->errands[i].base; + idx = i; + break; + } + } + break; + } + + case mQst_QUEST_TYPE_CONTEST: { + if (aQMgr_actor_check_free_quest(&client_contest->base) == TRUE) { + for (i = 0; i < ANIMAL_NUM_MAX; i++, animal++) { + if (mNpc_CheckCmpAnimalPersonalID(&animal->id, client_id) == TRUE) { + *free_data_p = &animal->contest_quest.base; + idx = i; + break; + } + } + } + break; + } + } + + manager->target.free_data_idx = idx; +} + +static void aQMgr_actor_set_client_quest_info(QUEST_MANAGER_ACTOR* manager) { + mQst_CopyQuestInfo(&((NPC_ACTOR*)*manager->client)->npc_info.list->quest_info, &manager->target.quest_info); +} + +static void aQMgr_actor_client_quest_set_new(QUEST_MANAGER_ACTOR* manager) { + mQst_CopyQuestInfo(&manager->target.quest_info, &((NPC_ACTOR*)*manager->client)->npc_info.list->quest_info); +} + +static void aQMgr_actor_decide_quest_type_kind(int* type, int* kind) { + static aQMgr_qst_info_c* type_kind_decide_table[aQMgr_QUEST_TYPE_NUM] = { &l_new_fj_quest_info, + &l_new_quest_quest_info }; + aQMgr_qst_info_c* tbl_p; + int* kind_tbl_p; + u32 fj_event = mEv_SAVED_FIRSTJOB_PLR0 + Common_Get(player_no); + int choose_type = aQMgr_QUEST_TYPE_QUEST; + + if (mLd_PlayerManKindCheck() == FALSE && mEv_CheckEvent(fj_event) == TRUE) { + choose_type = aQMgr_QUEST_TYPE_FJ; + } + + tbl_p = type_kind_decide_table[choose_type]; + *type = tbl_p->type_table[mQst_GetRandom(tbl_p->type_count)]; + + kind_tbl_p = tbl_p->kind_table[*type]; + *kind = kind_tbl_p[mQst_GetRandom(tbl_p->kind_count[*type])]; +} + +static int aQMgr_get_before_quest_idx(int type, int kind) { + mNpc_NpcList_c* npclist = Common_Get(npclist); + int i; + int res = -1; + + for (i = 0; i < ANIMAL_NUM_MAX; i++, npclist++) { + if (mQst_CheckFreeQuest(&npclist->quest_info) == FALSE && npclist->quest_info.quest_type == type && + npclist->quest_info.quest_kind == kind) { + res = i; + break; + } + } + + return res; +} + +static int aQMgr_actor_check_occur(u32 type, u32 kind, Animal_c* animal, int home_bx, int home_bz) { + lbRTC_time_c* rtc_time = Common_GetPointer(time.rtc_time); + int occur = FALSE; + int animal_idx = -1; + + if (type == mQst_QUEST_TYPE_CONTEST) { + // Contest kind can't already be active + if (mQst_GetOccuredContestIdx(kind) == -1) { + switch (kind) { + case mQst_CONTEST_KIND_FRUIT: + occur = TRUE; + break; + case mQst_CONTEST_KIND_SOCCER: + occur = TRUE; + break; + case mQst_CONTEST_KIND_SNOWMAN: + if (((rtc_time->month == lbRTC_JANUARY) || + (rtc_time->month == lbRTC_FEBRUARY && rtc_time->day <= 17) || + (rtc_time->month == lbRTC_DECEMBER && rtc_time->day >= 25)) && + (rtc_time->hour >= 8 && rtc_time->hour <= 16)) { + occur = TRUE; + } + break; + case mQst_CONTEST_KIND_FLOWER: + if (((rtc_time->month == lbRTC_FEBRUARY && rtc_time->day >= 25) || + (rtc_time->month >= lbRTC_MARCH && rtc_time->month <= lbRTC_AUGUST)) && + (mQst_GetNullNoNum(home_bx, home_bz) >= 4) && (mQst_GetFlowerNum(home_bx, home_bz) <= 20)) { + occur = TRUE; + } + break; + case mQst_CONTEST_KIND_FISH: + occur = TRUE; + break; + case mQst_CONTEST_KIND_INSECT: + if (((rtc_time->month >= lbRTC_MARCH) && (rtc_time->month <= lbRTC_OCTOBER)) || + (rtc_time->month == lbRTC_NOVEMBER && rtc_time->day <= 28)) { + occur = TRUE; + } + break; + case mQst_CONTEST_KIND_LETTER: + if (mLd_PlayerManKindCheck() == FALSE) { + occur = TRUE; + } + break; + } + } + } else if (type == mQst_QUEST_TYPE_DELIVERY) { + if (animal != NULL) { + animal_idx = mNpc_SearchAnimalinfo(Save_Get(animals), animal->id.npc_id, ANIMAL_NUM_MAX); + } + + switch (kind) { + case mQst_DELIVERY_KIND_FOREIGN: { + int before_idx = aQMgr_get_before_quest_idx(mQst_QUEST_TYPE_DELIVERY, mQst_DELIVERY_KIND_FOREIGN); + int occured_idx = mQst_GetOccuredDeliveryIdx(mQst_DELIVERY_KIND_FOREIGN); + + if (occured_idx == -1 && (before_idx == -1 || before_idx == animal_idx) && + mNpc_CheckFreeAnimalPersonalID(&Common_Get(now_private)->stored_anm_id) == FALSE) { + occur = TRUE; + } + + break; + } + + case mQst_DELIVERY_KIND_REMOVE: { + int before_idx = aQMgr_get_before_quest_idx(mQst_QUEST_TYPE_DELIVERY, mQst_DELIVERY_KIND_REMOVE); + int occured_idx = mQst_GetOccuredDeliveryIdx(mQst_DELIVERY_KIND_REMOVE); + + if (occured_idx == -1 && (before_idx == -1 || before_idx == animal_idx) && + mNpc_CheckFreeAnimalPersonalID(Save_GetPointer(last_removed_animal_id)) == FALSE) { + occur = TRUE; + } + + break; + } + + default: + occur = TRUE; + break; + } + } else if (type == mQst_QUEST_TYPE_ERRAND) { + occur = TRUE; + } + + return occur; +} + +static int aQMgr_actor_decide_quest(QUEST_MANAGER_ACTOR* manager) { + Animal_c* client_animal = ((NPC_ACTOR*)*manager->client)->npc_info.animal; + aQMgr_target_c* target = &manager->target; + int res = FALSE; + + if (aQMgr_actor_check_client_quest_info(manager) == TRUE) { + aQMgr_actor_client_quest_set_new(manager); + aQMgr_actor_get_free_quest_p(manager, target->quest_info.quest_type); + + if (target->free_data_p != NULL) { + res = TRUE; + } else if (target->quest_info.quest_type == mQst_QUEST_TYPE_DELIVERY) { + aQMgr_actor_set_client_quest_info(manager); + } + } else if (mQst_GetRandom(4) != 0) { + int occur; + int type; + int kind; + + aQMgr_actor_decide_quest_type_kind(&type, &kind); + occur = aQMgr_actor_check_occur(type, kind, client_animal, client_animal->home_info.block_x, + client_animal->home_info.block_z); + + if (occur == TRUE) { + target->quest_info.quest_type = type; + target->quest_info.quest_kind = kind; + aQMgr_actor_get_free_quest_p(manager, target->quest_info.quest_type); + + if (target->free_data_p != NULL) { + res = TRUE; + } else if (target->quest_info.quest_type == mQst_QUEST_TYPE_DELIVERY) { + aQMgr_actor_set_client_quest_info(manager); + } + } + } + + return res; +} + +static void aQMgr_actor_decide_item(mActor_name_t* item) { + *item = l_quest_item_list[RANDOM(ARRAY_COUNT(l_quest_item_list))]; +} + +static void aQMgr_actor_decide_cloth(mActor_name_t* item, mActor_name_t exclude_item) { + mSP_SelectRandomItem_New(NULL, item, 1, &exclude_item, 1, mSP_KIND_CLOTH, mSP_LISTTYPE_ABC, FALSE); +} + +static void aQMgr_actor_set_contest_work_data(int kind, aQMgr_work_data_c* work, Animal_c* animal) { + switch (kind) { + case mQst_CONTEST_KIND_FLOWER: { + work->flower.exist_num = mQst_GetFlowerSeedNum(animal->home_info.block_x, animal->home_info.block_z); + work->flower.goal_num = work->flower.exist_num + aQMgr_FLOWER_GOAL_NUM; + work->flower.remain_num = aQMgr_FLOWER_GOAL_NUM; + + break; + } + } +} + +static void aQMgr_actor_set_work_data(QUEST_MANAGER_ACTOR* manager) { + aQMgr_target_c* target = &manager->target; + mQst_base_c* quest_info = &target->quest_info; + + switch (quest_info->quest_type) { + case mQst_QUEST_TYPE_CONTEST: + aQMgr_actor_set_contest_work_data(quest_info->quest_kind, &target->work, + ((NPC_ACTOR*)*manager->client)->npc_info.animal); + break; + case mQst_QUEST_TYPE_DELIVERY: + case mQst_QUEST_TYPE_ERRAND: + break; + } +} + +static int aQMgr_actor_set_quest_data(QUEST_MANAGER_ACTOR* manager, aQMgr_quest_c* quest) { + Animal_c* animal = aQMgr_GET_CLIENT_ANIMAL(manager); + AnmPersonalID_c* from_id = &aQMgr_GET_CLIENT_ANIMAL(manager)->id; + AnmPersonalID_c* to_id; + AnmPersonalID_c exclude_ids[mQst_ERRAND_CHAIN_ANIMAL_NUM + 1]; + aQMgr_target_c* target = &manager->target; + aQMgr_set_data_c* set_data_p = target->set_data_p; + Private_c* priv = Common_Get(now_private); + int i; + + if (set_data_p == NULL) { + return aQMgr_NEW_QUEST_ERROR; + } + + target->from_id = &animal->id; + + // Set the recipient + switch (set_data_p->to_type) { + case aQMgr_QUEST_TARGET_RANDOM: { + target->to_id = mNpc_GetOtherAnimalPersonalIDOtherBlock(from_id, 1, animal->home_info.block_x, + animal->home_info.block_z, TRUE); + + if (target->to_id == NULL) { + return aQMgr_NEW_QUEST_ERROR; + } + break; + } + + case aQMgr_QUEST_TARGET_RANDOM_EXCLUDED: { + for (i = 0; i < ARRAY_COUNT(exclude_ids); i++) { + mNpc_ClearAnimalPersonalID(&exclude_ids[i]); + } + + // if the quest exists, assume it's an errand and copy up to the 3 other 'chain' villagers + if (quest != NULL) { + for (i = 0; i < mQst_ERRAND_CHAIN_ANIMAL_NUM; i++) { + mNpc_CopyAnimalPersonalID(&exclude_ids[i], &quest->errand.info.chain.used_ids[i]); + } + } + + // copy the quest giver into the exclusion table + mNpc_CopyAnimalPersonalID(&exclude_ids[mQst_ERRAND_CHAIN_ANIMAL_NUM], &animal->id); + target->to_id = mNpc_GetOtherAnimalPersonalIDOtherBlock( + exclude_ids, ARRAY_COUNT(exclude_ids), animal->home_info.block_x, animal->home_info.block_z, TRUE); + + if (target->to_id == NULL) { + return aQMgr_NEW_QUEST_ERROR; + } + + target->errand_type = mQst_ERRAND_TYPE_CHAIN; + break; + } + + case aQMgr_QUEST_TARGET_ORIGINAL_TARGET: { + if (quest != NULL) { + target->to_id = &quest->errand.info.chain.used_ids[0]; + } else { + target->to_id = from_id; + } + break; + } + + case aQMgr_QUEST_TARGET_FOREIGN: { + to_id = &Common_Get(now_private)->stored_anm_id; + + if (mNpc_CheckFreeAnimalPersonalID(to_id) == FALSE) { + target->to_id = to_id; + } else { + return aQMgr_NEW_QUEST_NO_FOREIGN_ID; + } + break; + } + + case aQMgr_QUEST_TARGET_LAST_REMOVE: { + to_id = &Save_Get(last_removed_animal_id); + + if (mNpc_CheckFreeAnimalPersonalID(to_id) == FALSE) { + target->to_id = to_id; + } else { + return aQMgr_NEW_QUEST_NO_REMOVE_ANIMAL_ID; + } + break; + } + + case aQMgr_QUEST_TARGET_CLIENT: { + target->to_id = &aQMgr_GET_CLIENT_ANIMAL(manager)->id; + break; + } + } + + // Set the item + switch (set_data_p->src_item_type) { + case aQMgr_QUEST_ITEM_RANDOM: { + aQMgr_actor_decide_item(&target->quest_item); + break; + } + + case aQMgr_QUEST_ITEM_FRUIT: { + target->quest_item = mFI_GetOtherFruit(); + break; + } + + case aQMgr_QUEST_ITEM_CLOTH: { + aQMgr_actor_decide_cloth(&target->quest_item, animal->cloth); + break; + } + + case aQMgr_QUEST_ITEM_FROM_DATA: { + target->quest_item = set_data_p->item; + break; + } + + case aQMgr_QUEST_ITEM_CURRENT_ITEM: { + if (quest != NULL) { + target->quest_item = quest->errand.item; + } else { + target->quest_item = ITM_CLOTH001; + } + break; + } + + case aQMgr_QUEST_ITEM_NONE: { + target->quest_item = EMPTY_NO; + break; + } + + default: { + return aQMgr_NEW_QUEST_ERROR; + } + } + + // Set whether an item is being entrusted to the player + if (set_data_p->handover_item == TRUE) { + int item_idx = mPr_GetPossessionItemIdx(priv, EMPTY_NO); + + if (item_idx != -1) { + target->quest_inv_item_idx = item_idx; + } else { + target->quest_inv_item_idx = -1; + return aQMgr_NEW_QUEST_NO_SPACE; + } + } else { + target->quest_inv_item_idx = -1; + } + + // Set time limit + if (set_data_p->day_limit != 0) { + lbRTC_TimeCopy(&target->limit, Common_GetPointer(time.rtc_time)); + lbRTC_Add_DD(&target->limit, set_data_p->day_limit); + target->quest_info.time_limit_enabled = TRUE; + } else { + target->quest_info.time_limit_enabled = FALSE; + } + + target->quest_info.progress = set_data_p->last_step; + aQMgr_actor_set_work_data(manager); + return aQMgr_NEW_QUEST_SUCCESS; +} + +static void aQMgr_actor_new_quest(QUEST_MANAGER_ACTOR* manager, int animal_idx, int looks, int* sel_regist_idx, + int regist_idx) { + aQMgr_quest_c* quest = NULL; + aQMgr_regist_c* regist; + u32 stage = 0; + int quest_exist; + + if (regist_idx != -1) { + int next_type; + u8 next; + + regist = &manager->regist[regist_idx]; + quest = (aQMgr_quest_c*)regist->quest_info; // TODO: maybe quest_info should be aQMgr_quest_c* here? + manager->target.quest_info.quest_type = quest->base.quest_type; + next_type = 0; + next = aQMgr_actor_get_errand_next(regist, manager->errand_next); + + if (next == 0) { + next_type = RANDOM(2); + } else if (next <= 2) { + next_type = next - 1; + } + + aQMgr_actor_set_errand_next(manager->errand_next, regist, next_type + 1); + + if (next_type == 0) { + stage = 0; + } else { + stage = quest->base.progress - 1; + } + + if (stage == 0) { + manager->target.quest_info.quest_kind = mQst_ERRAND_REQUEST_FINAL; + } else { + manager->target.quest_info.quest_kind = mQst_ERRAND_REQUEST_CONTINUE; + } + + manager->target.free_data_p = (mQst_base_c*)quest; // TODO: Again, should this be aQMgr_quest_c*? + manager->target.free_data_idx = regist->animal_idx; + *sel_regist_idx = regist_idx; + quest_exist = TRUE; + } else { + quest_exist = aQMgr_actor_decide_quest(manager); + } + + if (quest_exist == TRUE) { + (*manager->talk_common_proc)(manager, aQMgr_TALK_COMMON_GET_SET_DATA); + quest_exist = aQMgr_actor_set_quest_data(manager, quest); + + if (quest_exist == aQMgr_NEW_QUEST_SUCCESS) { + if (regist_idx != -1) { + aQMgr_regist_c* regist = manager->regist + regist_idx; + + manager->target.from_id = &aQMgr_GET_CLIENT_ANIMAL(manager)->id; + + if (stage != 0) { + manager->target.quest_info.progress = stage; + } + + aQMgr_actor_set_errand_next(manager->errand_next, regist, 0); + } + } else if (quest_exist == aQMgr_NEW_QUEST_NO_SPACE) { + if (manager->target.quest_info.quest_type == mQst_QUEST_TYPE_DELIVERY) { + aQMgr_actor_set_client_quest_info(manager); + } + + manager->talk_step = aQMgr_TALK_STEP_FULL_ITEM_OR_NORMAL; + } else { + quest_exist = FALSE; + } + } + + if (quest_exist == FALSE) { + if (aQMgr_actor_check_client_quest_info(manager) == TRUE) { + manager->talk_step = aQMgr_TALK_STEP_FULL_ITEM_OR_NORMAL; + } else if (manager->target.quest_info.quest_type == mQst_QUEST_TYPE_DELIVERY && + manager->target.set_data_p == NULL) { + manager->talk_step = aQMgr_TALK_STEP_FULL_ITEM_OR_NORMAL; + (*manager->talk_common_proc)(manager, aQMgr_TALK_COMMON_GET_SET_DATA); + } else { + manager->talk_step = aQMgr_TALK_STEP_NO_OR_NORMAL; + mNpc_SetQuestRequestOFF(animal_idx, looks); + } + + mQst_ClearQuestInfo(&manager->target.quest_info); + manager->target.free_data_p = NULL; + manager->target.free_data_idx = -1; + } +} + +static void aQMgr_actor_set_delivery(aQMgr_target_c* target, AnmPersonalID_c* from_id) { + mQst_delivery_c* delivery = (mQst_delivery_c*)target->free_data_p; + + mQst_CopyQuestInfo(&delivery->base, &target->quest_info); + mNpc_CopyAnimalPersonalID(&delivery->sender, from_id); + mNpc_CopyAnimalPersonalID(&delivery->recipient, target->to_id); + delivery->base.time_limit = target->limit; +} + +static void aQMgr_actor_set_errand(aQMgr_target_c* target, AnmPersonalID_c* from_id) { + mQst_errand_c* errand = (mQst_errand_c*)target->free_data_p; + AnmPersonalID_c* pids = errand->info.chain.used_ids; + int i; + + mQst_CopyQuestInfo(&errand->base, &target->quest_info); + mNpc_CopyAnimalPersonalID(&errand->sender, from_id); + mNpc_CopyAnimalPersonalID(&errand->recipient, target->to_id); + errand->base.time_limit = target->limit; + errand->item = target->quest_item; + errand->pockets_idx = target->quest_inv_item_idx; + errand->errand_type = target->errand_type; + + switch (target->errand_type) { + case mQst_ERRAND_TYPE_CHAIN: { + // Clear intermediate chain animals on initial request + if (target->quest_info.quest_kind == mQst_ERRAND_REQUEST) { + for (i = 0; i < mQst_ERRAND_CHAIN_ANIMAL_NUM; i++) { + mNpc_ClearAnimalPersonalID(&pids[i]); + errand->info.chain.used_num = 0; // Why is this in the loop? + } + } + + // Copy this villager as a 'chain step' animal + for (i = 0; i < mQst_ERRAND_CHAIN_ANIMAL_NUM; i++, pids++) { + if (mNpc_CheckFreeAnimalPersonalID(pids) == TRUE) { + mNpc_CopyAnimalPersonalID(pids, from_id); + break; + } + } + + // Update that an entry in the chain has been used + errand->info.chain.used_num++; + break; + } + } +} + +static void aQMgr_actor_set_contest(aQMgr_target_c* target) { + mQst_contest_c* contest = (mQst_contest_c*)target->free_data_p; + + mQst_CopyQuestInfo(&contest->base, &target->quest_info); + contest->base.time_limit = target->limit; + contest->requested_item = target->quest_item; + + switch (target->quest_info.quest_kind) { + case mQst_CONTEST_KIND_FRUIT: + break; + case mQst_CONTEST_KIND_SOCCER: + break; + case mQst_CONTEST_KIND_SNOWMAN: + break; + + case mQst_CONTEST_KIND_FLOWER: { + contest->type = mQst_CONTEST_DATA_FLOWER; + contest->info.flower_data.flowers_requested = target->work.flower.goal_num; + break; + } + + case mQst_CONTEST_KIND_FISH: + break; + case mQst_CONTEST_KIND_INSECT: + break; + + case mQst_CONTEST_KIND_LETTER: { + contest->type = mQst_CONTEST_DATA_LETTER; + contest->info.letter_data.score = 0; + contest->info.letter_data.present = EMPTY_NO; + break; + } + } +} + +static void aQMgr_actor_set_quest_info(QUEST_MANAGER_ACTOR* manager) { + Private_c* priv = Common_Get(now_private); + AnmPersonalID_c* from_id = &aQMgr_GET_CLIENT_ANIMAL(manager)->id; + aQMgr_target_c* target = &manager->target; + int type = target->quest_info.quest_type; + + switch (type) { + case mQst_QUEST_TYPE_DELIVERY: + aQMgr_actor_set_delivery(target, from_id); + break; + case mQst_QUEST_TYPE_ERRAND: + aQMgr_actor_set_errand(target, from_id); + break; + case mQst_QUEST_TYPE_CONTEST: + aQMgr_actor_set_contest(target); + break; + } + + if (target->quest_inv_item_idx != -1) { + mPr_SetPossessionItem(priv, target->quest_inv_item_idx, target->quest_item, mPr_ITEM_COND_QUEST); + } +} + +static aQMgr_actor_clear_client_quest_info(QUEST_MANAGER_ACTOR* manager) { + mQst_ClearQuestInfo(&aQMgr_GET_CLIENT(manager)->npc_info.list->quest_info); +} + +static void aQMgr_actor_set_free_str(QUEST_MANAGER_ACTOR* manager, int regist_idx) { + u8 str1[ANIMAL_NAME_LEN]; + u8 str0[ANIMAL_NAME_LEN]; + u8 str2[mIN_ITEM_NAME_LEN]; + + aQMgr_target_c* target = &manager->target; + + mNpc_GetNpcWorldNameAnm(str0, target->from_id); + mMsg_Set_free_str(mMsg_Get_base_window_p(), mMsg_FREE_STR0, str0, sizeof(str0)); + + if (target->to_id != NULL) { + mNpc_GetNpcWorldNameAnm(str1, target->to_id); + mMsg_Set_free_str_cl(mMsg_Get_base_window_p(), mMsg_FREE_STR1, str1, sizeof(str1), 1); + mLd_SetFreeStrLandMuraName(target->to_id->land_name, mMsg_FREE_STR3); + } + + if (target->quest_item != EMPTY_NO) { + mIN_copy_name_str(str2, target->quest_item); + mMsg_Set_free_str_cl_art(mMsg_Get_base_window_p(), mMsg_FREE_STR2, str2, sizeof(str2), 2, + mIN_get_item_article(target->quest_item)); + } + + mLd_SetFreeStrLandMuraName(target->from_id->land_name, mMsg_FREE_STR4); + if (regist_idx != -1) { + aQMgr_regist_c* regist = manager->regist + regist_idx; + + if (regist != NULL) { + mQst_errand_c* errand = (mQst_errand_c*)regist->quest_info; + + if (errand != NULL && errand->base.quest_type == mQst_QUEST_TYPE_ERRAND) { + AnmPersonalID_c* anm_id = &errand->info.chain.used_ids[0]; + + if (mNpc_CheckFreeAnimalPersonalID(anm_id) == FALSE) { + mNpc_GetNpcWorldNameAnm(str1, anm_id); + mMsg_Set_free_str_cl(mMsg_Get_base_window_p(), mMsg_FREE_STR5, str1, sizeof(str1), 1); + } + } + } + } +} + +static void aQMgr_actor_set_free_str_reward(aQMgr_target_c* target) { + u8 str[mIN_ITEM_NAME_LEN]; + + if (target->reward_kind == aQMgr_QUEST_REWARD_MONEY) { + mFont_UnintToString(str, sizeof(str), target->pay, 10, TRUE, FALSE, TRUE); + mMsg_Set_free_str(mMsg_Get_base_window_p(), mMsg_FREE_STR9, str, sizeof(str)); + } else { + mQst_SetItemNameStr(target->reward_item, mMsg_ITEM_STR0); + } +} + +static u32 aQMgr_actor_get_rate(int money_power) { + // spread, base + static f32 rate_table[][2] = { + { 0.3000f, 0.0f }, // [ 0, 29] + { 0.7000f, -40.0f }, // [ 30, 99] + { 2.7000f, -440.0f }, // [100, 367] + { 1.3000f, -20.0f }, // [370, 498] + { 1.0000f, 100.0f }, // [500, 599] + { 0.6000f, 300.0f }, // [600, 659] + { 0.0012f, 660.0f } // [660, 660] + }; + + u32 rate = 0; + + if (money_power > 0) { + f32 base; + f32 scale; + int idx = money_power / 100; + + if (idx >= ARRAY_COUNT(rate_table)) { + idx = ARRAY_COUNT(rate_table) - 1; + } + + base = rate_table[idx][1]; + scale = rate_table[idx][0]; + rate = base + scale * (f32)money_power; + } + + return rate; +} + +static u32 aQMgr_actor_get_pay(u32 base_pay) { + f32 scale = 100.0f; + static f32 plus_minus[2] = { 1.0f, -1.0f }; + int dir_idx = RANDOM(2); + f32 percent = fqrand(); + f32 dir = plus_minus[dir_idx]; + u32 pay; + f32 pay_f; + f32 final_pay; + + scale += dir * 10.0f * percent; + + pay = aQMgr_actor_get_rate(mPr_GetMoneyPower()); + + if (pay > 700) { + pay = 700; + } + + // min: (90.9 * 100) / 10000 = ~0.91x (max percent = ~1.1x) + // max: (109.9 * 760) / 10000 = ~8.36x (min percent = ~6.916x) + pay_f = 100.0f; + pay_f += pay; + final_pay = (scale * pay_f) / 10000.0f; + final_pay = base_pay * final_pay; + return final_pay; +} + +static int aQMgr_actor_hand_reward(aQMgr_target_c* target) { + Private_c* priv = Common_Get(now_private); + int reward_kind = target->reward_kind; + int inv_idx = target->quest_inv_item_idx; + int res = FALSE; + + if (reward_kind == aQMgr_QUEST_REWARD_MONEY) { + u32 money = priv->inventory.wallet; + + money += target->pay; + if (money > mPr_WALLET_MAX) { + if (money <= (mPr_WALLET_MAX + mPr_GetPossessionItemSum(priv, EMPTY_NO) * 30000)) { + if (inv_idx != -1 && priv->inventory.pockets[inv_idx] == EMPTY_NO) { + mPr_SetPossessionItem(priv, inv_idx, ITM_MONEY_30000, mPr_ITEM_COND_NORMAL); + money -= 30000; + } + + while (money > mPr_WALLET_MAX) { + inv_idx = mPr_GetPossessionItemIdx(priv, EMPTY_NO); + + if (inv_idx != -1) { + mPr_SetPossessionItem(priv, inv_idx, ITM_MONEY_30000, mPr_ITEM_COND_NORMAL); + money -= 30000; + } else { + money = mPr_WALLET_MAX; // ran out of space + break; + } + } + + priv->inventory.wallet = money; // remaining money goes in the wallet + res = TRUE; + } + } else { + priv->inventory.wallet = money; + res = TRUE; + } + } else if (reward_kind != -1) { + if (inv_idx != -1 && priv->inventory.pockets[inv_idx] == EMPTY_NO) { + mPr_SetPossessionItem(priv, inv_idx, target->reward_item, mPr_ITEM_COND_NORMAL); + res = TRUE; + } else { + inv_idx = mPr_GetPossessionItemIdx(priv, EMPTY_NO); + + if (inv_idx != -1) { + mPr_SetPossessionItem(priv, inv_idx, target->reward_item, mPr_ITEM_COND_NORMAL); + res = TRUE; + } + } + } + + return res; +} + +static void aQMgr_actor_get_errand_reward(u8* reward_percents, u32* payment, u8 npc_num) { + static u8 errand_reward[4][aQMgr_QUEST_REWARD_NUM] = { + { 0, 75, 25, 0, 0, 0, 0, 0 }, // 75% stationery, 25% clothing + { 25, 25, 25, 0, 0, 25, 0, 0 }, // 25% ftr, 25% stationery, 25% clothing, 25% money + { 50, 0, 25, 0, 0, 25, 0, 0 }, // 50% ftr, 25% clothing, 25% money + { 65, 0, 0, 5, 5, 25, 0, 0 }, // 65% ftr, 5% carpet, 5% wallpaper, 25% money + }; + u32 reward_pay[4] = { 0, 500, 750, 1000 }; // someone forgot a `static` qualifier here + u8* reward_p; + int i; + + npc_num--; + if (npc_num >= ARRAY_COUNT(reward_pay)) { + npc_num = ARRAY_COUNT(reward_pay) - 1; + } + + reward_p = errand_reward[npc_num]; + for (i = 0; i < aQMgr_QUEST_REWARD_NUM; i++) { + *reward_percents++ = *reward_p++; + } + + *payment = reward_pay[npc_num]; +} + +static mActor_name_t aQMgr_actor_get_other_pl_cloth() { + Private_c* priv = Common_Get(now_private); + mActor_name_t other_pl_cloth = ITM_CLOTH001; + + if (priv != NULL) { + aQMgr_actor_decide_cloth(&other_pl_cloth, priv->cloth.item); + } + + return other_pl_cloth; +} + +static void aQMgr_actor_set_reward(QUEST_MANAGER_ACTOR* manager) { + Animal_c* animal = aQMgr_GET_CLIENT_ANIMAL(manager); + aQMgr_target_c* target = &manager->target; + aQMgr_set_data_c* set_data_p = target->set_data_p; + u32 pay = 0; + u8 reward_percentages[aQMgr_QUEST_REWARD_NUM]; + u8* reward_percent_p; + int prob_tbl[100]; + int prob_idx; + int j; + int i; + + if (target->quest_info.quest_type == mQst_QUEST_TYPE_ERRAND) { + aQMgr_actor_get_errand_reward( + reward_percentages, &pay, + ((mQst_errand_c*)manager->regist[manager->regist_idx].quest_info)->info.chain.used_num); + reward_percent_p = reward_percentages; + } else { + pay = set_data_p->max_pay; + reward_percent_p = set_data_p->reward_percentages; + } + + // 100 slots (1% each), values ranging from 0-7 (aQMgr_QUEST_REWARD_*) + prob_idx = 0; + bzero(prob_tbl, sizeof(prob_tbl)); + for (i = 0; i < aQMgr_QUEST_REWARD_NUM; i++) { + j = reward_percent_p[i]; + + while (j != 0) { + if (prob_idx >= 100) { + break; + } + + prob_tbl[prob_idx] = i; + prob_idx++; + j--; + } + } + + target->reward_kind = prob_tbl[RANDOM(100)]; + if (target->reward_kind == aQMgr_QUEST_REWARD_MONEY) { + pay = aQMgr_actor_get_pay(pay); + target->pay = pay; + target->reward_item = ITM_MONEY_1000; + } else if (target->reward_kind == aQMgr_QUEST_REWARD_WORN_CLOTH) { + if (animal != NULL) { + if (manager->cloth == RSV_CLOTH) { + target->reward_item = aQMgr_actor_get_other_pl_cloth(); + target->reward_kind = aQMgr_QUEST_REWARD_CLOTH; + } else { + target->reward_item = manager->cloth; + } + } else { + target->reward_item = ITM_CLOTH001; + } + } else { + mQst_GetGoods_common(&target->reward_item, &animal->id, target->reward_kind, NULL, 0, mSP_LISTTYPE_ABC); + } +} + +static void aQMgr_talk_quest_clear_quest(QUEST_MANAGER_ACTOR* manager) { + int regist_idx = manager->regist_idx; + + if (regist_idx != -1) { + aQMgr_regist_c* regist = manager->regist + regist_idx; + aQMgr_quest_c* quest = (aQMgr_quest_c*)regist->quest_info; + + switch (quest->base.quest_type) { + case mQst_QUEST_TYPE_DELIVERY: + mQst_ClearDelivery(&quest->delivery, 1); + break; + case mQst_QUEST_TYPE_ERRAND: + mQst_ClearErrand(&quest->errand, 1); + break; + case mQst_QUEST_TYPE_CONTEST: + mQst_ClearContest(&quest->contest); + break; + } + } +} + +static void aQMgr_actor_talk_finish(QUEST_MANAGER_ACTOR* manager) { + aQMgr_target_c* target = &manager->target; + aQMgr_quest_c* free_quest = (aQMgr_quest_c*)target->free_data_p; + int regist_idx = manager->regist_idx; + + if (regist_idx != -1) { + aQMgr_talk_quest_clear_quest(manager); + (*manager->clear_regist_proc)(manager->regist, aQMgr_REGIST_NUM); + } + + if (free_quest != NULL) { + int idx = 0; + (*manager->regist_quest_proc)(manager, &idx, free_quest, target->free_data_idx); + } +} + +static void aQMgr_talk_quest_start_choice_random(int* choice_no, int start, int num) { + *choice_no = start + mQst_GetRandom(num); +} + +static void aQMgr_talk_quest_select_get_choice(QUEST_MANAGER_ACTOR* manager) { + aQMgr_choice_c* choice = &manager->choice; + int talk_step = manager->talk_step; + aQMgr_target_c* target = &manager->target; + int type = target->quest_info.quest_type; + int kind = target->quest_info.quest_kind; + + switch (talk_step) { + case aQMgr_TALK_STEP_RENEW_ERRAND_OR_NORMAL: { + choice->choice_ids[0] = 0x97; // "I'm picking up!" + choice->choice_ids[1] = 0x89; // "Let's talk!" + break; + } + + case aQMgr_TALK_STEP_FIN_QUEST_START: { + choice->choice_ids[0] = 0x94; // "Delivery!" + + if (type == mQst_QUEST_TYPE_DELIVERY) { + if (kind == mQst_DELIVERY_KIND_NORMAL) { + choice->choice_ids[0] = 0x94; // "Delivery!" + } else if (kind == mQst_DELIVERY_KIND_FOREIGN) { + choice->choice_ids[0] = 0x95; // "You forgot this!" + } else if (kind == mQst_DELIVERY_KIND_REMOVE) { + choice->choice_ids[0] = 0x95; // "You forgot this!" + } + } else if (type == mQst_QUEST_TYPE_ERRAND) { + switch (kind) { + case mQst_ERRAND_REQUEST_FINAL: + choice->choice_ids[0] = 0x94; // "Delivery!" + break; + default: + choice->choice_ids[0] = 0x97; // "I'm picking up!" + break; + } + } else if (type == mQst_QUEST_TYPE_CONTEST) { + switch (kind) { + case mQst_CONTEST_KIND_FRUIT: + choice->choice_ids[0] = 0x96; // "It's fruit time!" + break; + case mQst_CONTEST_KIND_FISH: + choice->choice_ids[0] = 0xEA; // "I brought fish." + break; + case mQst_CONTEST_KIND_INSECT: + choice->choice_ids[0] = 0xEB; // "I caught a bug!" + break; + default: + choice->choice_ids[0] = 0x94; // "Delivery!" + break; + } + } + + aQMgr_talk_quest_start_choice_random(&choice->choice_ids[1], 0x89, 10); + break; + } + + case aQMgr_TALK_STEP_TALK_FIN_QUEST_START_NOT_HAND: { + if (type == mQst_QUEST_TYPE_CONTEST) { + if (kind == mQst_CONTEST_KIND_SOCCER) { + choice->choice_ids[0] = 0x98; // "Here's the ball." + } else if (kind == mQst_CONTEST_KIND_SNOWMAN) { + choice->choice_ids[0] = 0x99; // "Look! Snowman!" + } else if (kind == mQst_CONTEST_KIND_FLOWER) { + choice->choice_ids[0] = 0x9A; // "The flowers..." + } + + choice->choice_ids[1] = 0x9B; // "Yeah, um..." + } + + break; + } + + case aQMgr_TALK_STEP_FULL_ITEM_OR_NORMAL: { + if (type == mQst_QUEST_TYPE_ERRAND) { + if (kind == mQst_ERRAND_REQUEST) { + choice->choice_ids[0] = 0x97; // "I'm picking up!" + } else if (kind == mQst_ERRAND_REQUEST_CONTINUE) { + choice->choice_ids[0] = 0x97; // "I'm picking up!" + } else if (kind == mQst_ERRAND_REQUEST_FINAL) { + choice->choice_ids[0] = 0x97; // "I'm picking up!" + } + } else { + aQMgr_talk_quest_start_choice_random(&choice->choice_ids[0], 0x7F, 10); + } + + aQMgr_talk_quest_start_choice_random(&choice->choice_ids[1], 0x89, 10); + break; + } + + default: { + aQMgr_talk_quest_start_choice_random(&choice->choice_ids[0], 0x7F, 10); + aQMgr_talk_quest_start_choice_random(&choice->choice_ids[1], 0x89, 10); + break; + } + } + + aQMgr_talk_quest_start_choice_random(&choice->choice_ids[2], 0x16A, 5); + choice->talk_action = -1; + choice->choice_num = 3; +} + +static void aQMgr_talk_quest_select_get_choice_island(QUEST_MANAGER_ACTOR* manager) { + aQMgr_choice_c* choice = &manager->choice; + + aQMgr_talk_quest_start_choice_random(&choice->choice_ids[0], 0x89, 10); + aQMgr_talk_quest_start_choice_random(&choice->choice_ids[1], 0x16A, 5); + choice->talk_action = -1; + choice->choice_num = 2; +} + +static void aQMgr_talk_quest_start_choice(QUEST_MANAGER_ACTOR* manager) { + aQMgr_choice_c* choice = &manager->choice; + + aQMgr_talk_quest_start_choice_random(&choice->choice_ids[0], 0x43, 10); + aQMgr_talk_quest_start_choice_random(&choice->choice_ids[1], 0x4D, 10); + choice->choice_num = 2; + choice->talk_action = -1; +} + +static void aQMgr_talk_quest_finish_firstjob_open_quest() { + mQst_errand_c* errand = mQst_GetFirstJobData(); + u32 event_id = mEv_SAVED_FIRSTJOB_PLR0 + Common_Get(player_no); + + if (mLd_PlayerManKindCheck() == FALSE && mEv_CheckEvent(event_id) == TRUE && errand != NULL && + errand->base.quest_type == mQst_QUEST_TYPE_ERRAND && errand->base.quest_kind == mQst_ERRAND_FIRSTJOB_OPEN && + errand->base.progress == 2 && errand->errand_type == mQst_ERRAND_TYPE_FIRST_JOB) { + errand->base.progress = 0; + } +} + +static void aQMgr_talk_quest_set_cancel_msg_com(QUEST_MANAGER_ACTOR* manager, int base_cancel_msg) { + manager->msg_category = aQMgr_MSG_KIND_NONE; + manager->category_msg_no_start = base_cancel_msg; + manager->choice.talk_action = -1; + (*manager->talk_common_proc)(manager, aQMgr_TALK_COMMON_SET_MSG_NO); + mMsg_Set_continue_msg_num(mMsg_Get_base_window_p(), manager->msg_no); + manager->sub_talk_state = aQMgr_TALK_SUB_STATE_WAIT; +} + +static void aQMgr_talk_quest_change_normal_or_hint(QUEST_MANAGER_ACTOR* manager) { + if (manager->choice.talk_action == 2) { + mMsg_Set_ForceNext(mMsg_Get_base_window_p()); + aQMgr_talk_quest_set_cancel_msg_com(manager, 0x254A); + } else { + if (*manager->memory != NULL) { + mNpc_AddFriendship(*manager->memory, 1); + } + + (*manager->talk_common_proc)(manager, aQMgr_TALK_COMMON_CHANGE_TALK_NORMAL); + } +} + +static int l_contest_hoka_msg_no[mQst_CONTEST_KIND_NUM] = { 0x1134, 0x0E21, 0x0ED5, 0x1057, 0x1544, 0x15C2, 0x1AF3 }; + +static int aQMgr_talk_quest_get_contest_hoka_msg_no(mQst_contest_c* contest, Animal_c* animal) { + int kind = contest->base.quest_kind; + int hoka_msg_no = 0; + + if (kind == mQst_CONTEST_KIND_FLOWER && + contest->info.flower_data.flowers_requested > + mQst_GetFlowerSeedNum(animal->home_info.block_x, animal->home_info.block_z)) { + hoka_msg_no = 0x1069; // flower quest complete but less flowers than originally requested (some were destroyed) + } + + if (hoka_msg_no == 0) { + hoka_msg_no = l_contest_hoka_msg_no[kind]; + } + + return hoka_msg_no; +} + +static void aQMgr_talk_quest_set_work(aQMgr_work_data_c* work, int type, int kind) { + // stubbed +} + +static void aQMgr_actor_talk_select_talk(QUEST_MANAGER_ACTOR* manager) { + Animal_c* animal = aQMgr_GET_CLIENT_ANIMAL(manager); + int animal_idx = mNpc_SearchAnimalPersonalID(&animal->id); + aQMgr_quest_c* quest; + aQMgr_regist_c* regist; + int sel_regist_idx = -1; + int regist_idx; + int target_flag = TRUE; + + regist_idx = aQMgr_actor_check_still_reward(manager); + if (regist_idx != -1) { + manager->msg_category = aQMgr_MSG_KIND_AFTER_REWARD; + manager->talk_step = aQMgr_TALK_STEP_AFTER_REWARD; + } else { + regist_idx = aQMgr_actor_check_own_quest(manager, aQMgr_CHECK_TO); + + if (regist_idx != -1) { + regist = manager->regist + regist_idx; + quest = (aQMgr_quest_c*)regist->quest_info; + + if (quest->base.quest_type == mQst_QUEST_TYPE_ERRAND && + quest->errand.errand_type == mQst_ERRAND_TYPE_FIRST_JOB) { + manager->talk_state = aQMgr_TALK_STATE_INIT; + manager->talk_change_type = aQMgr_TALK_KIND_FIRST_JOB; + manager->talk_step = aQMgr_TALK_STEP_SELECT_TALK; + target_flag = FALSE; + mMsg_Set_LockContinue(mMsg_Get_base_window_p()); + } else if (aQMgr_actor_check_finish(regist, animal) == TRUE) { + manager->category_msg_no_start = 0x2A6; + + if (quest->base.quest_type == mQst_QUEST_TYPE_CONTEST && + quest->base.quest_kind == mQst_CONTEST_KIND_LETTER) { + if (mQst_SendRemail(&quest->contest, &animal->id) == TRUE) { + manager->talk_step = aQMgr_TALK_STEP_FINISH_LETTER; + } else { + manager->talk_step = aQMgr_TALK_STEP_CONTEST_HOKA_OR_NORMAL; + manager->category_msg_no_start = 0x2A6; + } + } else if (quest->base.quest_type == mQst_QUEST_TYPE_CONTEST && + (quest->base.quest_kind == mQst_CONTEST_KIND_SOCCER || + quest->base.quest_kind == mQst_CONTEST_KIND_SNOWMAN || + quest->base.quest_kind == mQst_CONTEST_KIND_FLOWER)) { + mMsg_Set_free_str(mMsg_Get_base_window_p(), mMsg_FREE_STR12, quest->contest.player_id.player_name, + PLAYER_NAME_LEN); + manager->talk_step = aQMgr_TALK_STEP_TALK_FIN_QUEST_START_NOT_HAND; + } else { + manager->talk_step = aQMgr_TALK_STEP_FIN_QUEST_START; + } + } else { + if (quest->base.quest_type == mQst_QUEST_TYPE_ERRAND) { + manager->talk_step = aQMgr_TALK_STEP_RENEW_ERRAND_OR_NORMAL; + sel_regist_idx = regist_idx; + regist_idx = -1; + } else if (quest->base.quest_type == mQst_QUEST_TYPE_CONTEST) { + regist = manager->regist + regist_idx; + + if (aQMgr_actor_check_limit(regist) == FALSE) { + if (quest->base.progress == 0) { + if (mPr_CheckCmpPersonalID(&quest->contest.player_id, + &Common_Get(now_private)->player_ID) == TRUE) { + manager->talk_step = aQMgr_TALK_STEP_NO_OR_NORMAL; + mQst_ClearQuestInfo(&manager->target.quest_info); + manager->target.free_data_p = NULL; + manager->target.free_data_idx = -1; + target_flag = FALSE; + } else if (mPr_NullCheckPersonalID(&quest->contest.player_id) == FALSE) { + manager->talk_step = aQMgr_TALK_STEP_CONTEST_HOKA_OR_NORMAL; + } else { + manager->talk_step = aQMgr_TALK_STEP_RECONF_OR_NORMAL; + } + } else if (quest->base.quest_kind == mQst_CONTEST_KIND_LETTER) { + if (mLd_PlayerManKindCheck() == FALSE) { + manager->talk_step = aQMgr_TALK_STEP_RECONF_OR_NORMAL; + } else { + manager->talk_step = aQMgr_TALK_STEP_NO_OR_NORMAL; + mQst_ClearQuestInfo(&manager->target.quest_info); + manager->target.free_data_p = NULL; + manager->target.free_data_idx = -1; + target_flag = FALSE; + } + } else { + manager->talk_step = aQMgr_TALK_STEP_RECONF_OR_NORMAL; + } + } else { + manager->talk_step = aQMgr_TALK_STEP_NO_OR_NORMAL; + mQst_ClearQuestInfo(&manager->target.quest_info); + manager->target.free_data_p = NULL; + manager->target.free_data_idx = -1; + target_flag = FALSE; + manager->regist_idx = regist_idx; + aQMgr_actor_talk_finish(manager); + } + } + + manager->category_msg_no_start = 0x2A6; + } + } else { + regist_idx = aQMgr_actor_check_own_quest(manager, aQMgr_CHECK_FROM); + + if (regist_idx != -1) { + regist = manager->regist + regist_idx; + + if (aQMgr_actor_check_limit(regist) == FALSE) { + manager->talk_step = aQMgr_TALK_STEP_RECONF_OR_NORMAL; + manager->category_msg_no_start = 0x2A6; + } else { + regist = manager->regist + regist_idx; + quest = (aQMgr_quest_c*)regist->quest_info; + + if (quest->base.quest_type == mQst_QUEST_TYPE_ERRAND && + (quest->base.quest_kind == mQst_ERRAND_REQUEST || + quest->base.quest_kind == mQst_ERRAND_REQUEST_CONTINUE)) { + manager->regist_idx = regist_idx; + + (*manager->talk_common_proc)(manager, aQMgr_TALK_COMMON_SET_TARGET); + + manager->target.quest_inv_item_idx = + (*manager->talk_common_proc)(manager, aQMgr_TALK_COMMON_GET_ITEM_IDX); + + aQMgr_talk_quest_set_work(&manager->target.work, manager->target.quest_info.quest_type, + manager->target.quest_info.quest_kind); + aQMgr_actor_set_free_str(manager, regist_idx); + manager->target.free_data_p = NULL; + manager->target.free_data_idx = -1; + aQMgr_actor_talk_finish(manager); + target_flag = FALSE; + } + + manager->talk_step = aQMgr_TALK_STEP_GIVEUP; + manager->msg_category = aQMgr_MSG_KIND_FAILURE_INIT; + } + } else { + regist_idx = aQMgr_actor_check_errand_from(manager); + + if (regist_idx != -1) { + regist = manager->regist + regist_idx; + quest = (aQMgr_quest_c*)regist->quest_info; + + if (aQMgr_actor_check_limit(regist) == FALSE) { + manager->talk_step = aQMgr_TALK_STEP_ROOT_RECONF_OR_NORMAL; + manager->category_msg_no_start = 0x2A6; + } else { + manager->talk_step = aQMgr_TALK_STEP_GIVEUP; + manager->msg_category = aQMgr_MSG_KIND_FAILURE_INIT; + + if (quest->base.quest_kind == mQst_ERRAND_REQUEST || + quest->base.quest_kind == mQst_ERRAND_REQUEST_CONTINUE) { + manager->regist_idx = regist_idx; + + (*manager->talk_common_proc)(manager, aQMgr_TALK_COMMON_SET_TARGET); + + manager->target.quest_inv_item_idx = + (*manager->talk_common_proc)(manager, aQMgr_TALK_COMMON_GET_ITEM_IDX); + + aQMgr_talk_quest_set_work(&manager->target.work, manager->target.quest_info.quest_type, + manager->target.quest_info.quest_kind); + aQMgr_actor_set_free_str(manager, regist_idx); + manager->target.free_data_p = NULL; + manager->target.free_data_idx = -1; + aQMgr_actor_talk_finish(manager); + + if (quest->base.quest_kind == mQst_ERRAND_REQUEST) { + manager->msg_category = aQMgr_MSG_KIND_NONE; + manager->category_msg_no_start = 0x2B73; + } + + target_flag = FALSE; + } + } + } else if (mNpc_CheckQuestRequest(animal_idx) == TRUE) { + manager->talk_step = aQMgr_TALK_STEP_NEW_QUEST_OR_NORMAL; + manager->category_msg_no_start = 0x2A6; + } else { + manager->talk_step = aQMgr_TALK_STEP_NO_OR_NORMAL; + manager->category_msg_no_start = 0x2A6; + mQst_ClearQuestInfo(&manager->target.quest_info); + manager->target.free_data_p = NULL; + manager->target.free_data_idx = -1; + target_flag = FALSE; + } + } + } + } + + if (manager->category_msg_no_start == 0x2A6) { + mChoice_no_b_set(mChoice_Get_base_window_p()); + } + + if (target_flag == TRUE) { + if (regist_idx != -1) { + manager->regist_idx = regist_idx; + (*manager->talk_common_proc)(manager, aQMgr_TALK_COMMON_SET_TARGET); + + if (manager->talk_step != aQMgr_TALK_STEP_AFTER_REWARD) { + manager->target.quest_inv_item_idx = + (*manager->talk_common_proc)(manager, aQMgr_TALK_COMMON_GET_ITEM_IDX); + } + } else { + aQMgr_actor_new_quest(manager, animal_idx, animal->id.looks, ®ist_idx, sel_regist_idx); + } + + if (manager->target.quest_info.quest_type != mQst_QUEST_TYPE_NONE) { + aQMgr_talk_quest_set_work(&manager->target.work, manager->target.quest_info.quest_type, + manager->target.quest_info.quest_kind); + aQMgr_actor_set_free_str(manager, regist_idx); + } + + manager->regist_idx = regist_idx; + } + + aQMgr_talk_quest_select_get_choice(manager); + (*manager->talk_common_proc)(manager, aQMgr_TALK_COMMON_SET_MSG_NO); + mMsg_Set_continue_msg_num(mMsg_Get_base_window_p(), manager->msg_no); + manager->sub_talk_state = aQMgr_TALK_SUB_STATE_WAIT; +} + +static void aQMgr_actor_talk_select_talk_island(QUEST_MANAGER_ACTOR* manager) { + manager->category_msg_no_start = 0x3567; + mChoice_no_b_set(mChoice_Get_base_window_p()); + aQMgr_talk_quest_select_get_choice_island(manager); + manager->msg_category = aQMgr_MSG_KIND_NONE; + (*manager->talk_common_proc)(manager, aQMgr_TALK_COMMON_SET_MSG_NO); + mMsg_Set_continue_msg_num(mMsg_Get_base_window_p(), manager->msg_no); + manager->sub_talk_state = aQMgr_TALK_SUB_STATE_WAIT; + manager->talk_step = aQMgr_TALK_STEP_NO_OR_ISLAND; +} + +static void aQMgr_actor_talk_select_talk_2(QUEST_MANAGER_ACTOR* manager) { + Animal_c* animal = aQMgr_GET_CLIENT_ANIMAL(manager); + + manager->mail_memory = NULL; + if (mNpc_CheckIslandAnimal(animal) == TRUE) { + aQMgr_actor_talk_select_talk_island(manager); + } else { + aQMgr_actor_talk_select_talk(manager); + } +} + +static void aQMgr_actor_talk_reconf_or_normal(QUEST_MANAGER_ACTOR* manager) { + manager->sub_talk_state = aQMgr_TALK_SUB_STATE_WAIT; + + if (manager->choice.talk_action == 0) { + manager->msg_category = aQMgr_MSG_KIND_REQUEST_RECONF; + manager->choice.talk_action = -1; + mMsg_Set_ForceNext(mMsg_Get_base_window_p()); + (*manager->talk_common_proc)(manager, aQMgr_TALK_COMMON_SET_MSG_NO); + mMsg_Set_continue_msg_num(mMsg_Get_base_window_p(), manager->msg_no); + } else { + aQMgr_talk_quest_change_normal_or_hint(manager); + } + + manager->sub_talk_state = aQMgr_TALK_SUB_STATE_WAIT; +} + +static void aQMgr_actor_talk_root_reconf_or_normal(QUEST_MANAGER_ACTOR* manager) { + if (manager->choice.talk_action == 0) { + manager->category_msg_no_start = 0x03D4; + manager->choice.talk_action = -1; + mMsg_Set_ForceNext(mMsg_Get_base_window_p()); + (*manager->talk_common_proc)(manager, aQMgr_TALK_COMMON_SET_MSG_NO); + mMsg_Set_continue_msg_num(mMsg_Get_base_window_p(), manager->msg_no); + } else { + aQMgr_talk_quest_change_normal_or_hint(manager); + } + + manager->sub_talk_state = aQMgr_TALK_SUB_STATE_WAIT; +} + +static void aQMgr_actor_talk_no_or_normal(QUEST_MANAGER_ACTOR* manager) { + if (manager->choice.talk_action == 0) { + aQMgr_talk_quest_finish_firstjob_open_quest(); + manager->target.free_data_p = NULL; + manager->category_msg_no_start = 0x0282; + manager->choice.talk_action = -1; + mMsg_Set_ForceNext(mMsg_Get_base_window_p()); + (*manager->talk_common_proc)(manager, aQMgr_TALK_COMMON_SET_MSG_NO); + mMsg_Set_continue_msg_num(mMsg_Get_base_window_p(), manager->msg_no); + } else { + aQMgr_talk_quest_change_normal_or_hint(manager); + } + + manager->sub_talk_state = aQMgr_TALK_SUB_STATE_WAIT; +} + +static void aQMgr_actor_talk_no_or_island(QUEST_MANAGER_ACTOR* manager) { + if (manager->choice.talk_action == 0) { + if (*manager->memory != NULL) { + mNpc_AddFriendship(*manager->memory, 1); + } + + (*manager->talk_common_proc)(manager, aQMgr_TALK_COMMON_CHANGE_TALK_ISLAND); + } else { + mMsg_Set_ForceNext(mMsg_Get_base_window_p()); + aQMgr_talk_quest_set_cancel_msg_com(manager, 0x359D); + } + + manager->sub_talk_state = aQMgr_TALK_SUB_STATE_WAIT; +} + +static void aQMgr_actor_talk_full_item_or_normal(QUEST_MANAGER_ACTOR* manager) { + if (manager->choice.talk_action == 0) { + if (manager->target.set_data_p == NULL) { + manager->category_msg_no_start = 0x0440; + } else { + manager->msg_category = aQMgr_MSG_KIND_FULL_ITEM; + } + + manager->choice.talk_action = -1; + mMsg_Set_ForceNext(mMsg_Get_base_window_p()); + (*manager->talk_common_proc)(manager, aQMgr_TALK_COMMON_SET_MSG_NO); + mMsg_Set_continue_msg_num(mMsg_Get_base_window_p(), manager->msg_no); + } else { + aQMgr_talk_quest_change_normal_or_hint(manager); + } + + manager->sub_talk_state = aQMgr_TALK_SUB_STATE_WAIT; +} + +static void aQMgr_actor_talk_renew_errand_or_normal(QUEST_MANAGER_ACTOR* manager) { + if (manager->choice.talk_action == 0) { + manager->msg_category = aQMgr_MSG_KIND_REQUEST_INIT; + aQMgr_actor_set_quest_info(manager); + aQMgr_actor_clear_client_quest_info(manager); + (*manager->clear_regist_proc)(manager->regist, aQMgr_REGIST_NUM); + manager->regist_idx = -1; + aQMgr_talk_quest_start_choice(manager); + mChoice_no_b_set(mChoice_Get_base_window_p()); + mMsg_Set_ForceNext(mMsg_Get_base_window_p()); + + if (manager->target.free_data_p->quest_type == mQst_QUEST_TYPE_ERRAND && + manager->target.free_data_p->progress == 0) { + manager->talk_step = aQMgr_TALK_STEP_RENEW_ERRAND_IRAI_END_GIVE_ITEM; + } else { + manager->talk_step = aQMgr_TALK_STEP_RENEW_ERRAND_IRAI_END; + } + + (*manager->talk_common_proc)(manager, aQMgr_TALK_COMMON_SET_MSG_NO); + mMsg_Set_continue_msg_num(mMsg_Get_base_window_p(), manager->msg_no); + } else { + aQMgr_talk_quest_change_normal_or_hint(manager); + } + + manager->sub_talk_state = aQMgr_TALK_SUB_STATE_WAIT; +} + +static void aQMgr_actor_talk_renew_errand_irai_end_give_item(QUEST_MANAGER_ACTOR* manager) { + (*manager->talk_common_proc)(manager, aQMgr_TALK_COMMON_SET_NPC_TAKEOUT_ITEM); + manager->talk_step = aQMgr_TALK_STEP_CHANGE_WAIT; + manager->sub_talk_state = aQMgr_TALK_SUB_STATE_WAIT; + manager->msg_category = aQMgr_MSG_KIND_REQUEST_END; + aQMgr_actor_talk_finish(manager); + (*manager->talk_common_proc)(manager, aQMgr_TALK_COMMON_SET_MSG_NO); + mMsg_Set_continue_msg_num(mMsg_Get_base_window_p(), manager->msg_no); +} + +static void aQMgr_actor_talk_renew_errand_irai_end(QUEST_MANAGER_ACTOR* manager) { + manager->sub_talk_state = aQMgr_TALK_SUB_STATE_WAIT; + manager->msg_category = aQMgr_MSG_KIND_REQUEST_END; + aQMgr_actor_talk_finish(manager); + (*manager->talk_common_proc)(manager, aQMgr_TALK_COMMON_SET_MSG_NO); + mMsg_Set_continue_msg_num(mMsg_Get_base_window_p(), manager->msg_no); +} + +static void aQMgr_actor_talk_new_quest_or_normal(QUEST_MANAGER_ACTOR* manager) { + if (manager->choice.talk_action == 0) { + aQMgr_talk_quest_finish_firstjob_open_quest(); + manager->talk_step = aQMgr_TALK_STEP_OCCUR_QUEST; + manager->msg_category = aQMgr_MSG_KIND_REQUEST_INIT; + + if (manager->target.quest_info.quest_type == mQst_QUEST_TYPE_CONTEST) { + aQMgr_actor_set_quest_info(manager); + aQMgr_actor_clear_client_quest_info(manager); + } + + aQMgr_talk_quest_start_choice(manager); + mChoice_no_b_set(mChoice_Get_base_window_p()); + mMsg_Set_ForceNext(mMsg_Get_base_window_p()); + (*manager->talk_common_proc)(manager, aQMgr_TALK_COMMON_SET_MSG_NO); + mMsg_Set_continue_msg_num(mMsg_Get_base_window_p(), manager->msg_no); + } else { + aQMgr_talk_quest_change_normal_or_hint(manager); + } + + manager->sub_talk_state = aQMgr_TALK_SUB_STATE_WAIT; +} + +static void aQMgr_actor_talk_occur_quest(QUEST_MANAGER_ACTOR* manager) { + if (manager->choice.talk_action == 0) { + mQst_base_c* quest_info; + + manager->msg_category = aQMgr_MSG_KIND_REQUEST_END; + aQMgr_actor_set_quest_info(manager); + aQMgr_actor_clear_client_quest_info(manager); + + quest_info = manager->target.free_data_p; + if (quest_info->quest_type != mQst_QUEST_TYPE_ERRAND || + (quest_info->quest_type == mQst_QUEST_TYPE_ERRAND && quest_info->progress == 0)) { + manager->talk_step = aQMgr_TALK_STEP_WAIT_TALK; + manager->sub_talk_state = aQMgr_TALK_SUB_STATE_NO_WAIT; + + if (quest_info->quest_type != mQst_QUEST_TYPE_ERRAND) { + sAdo_SysTrgStart(0x12E); + } + } else { + manager->talk_step = aQMgr_TALK_STEP_FINISH; + manager->sub_talk_state = aQMgr_TALK_SUB_STATE_WAIT; + + if (quest_info->quest_type == mQst_QUEST_TYPE_ERRAND && quest_info->quest_kind == mQst_ERRAND_REQUEST) { + sAdo_SysTrgStart(0x12E); + } + } + + (*manager->talk_common_proc)(manager, aQMgr_TALK_COMMON_SET_MSG_NO); + mMsg_Set_continue_msg_num(mMsg_Get_base_window_p(), manager->msg_no); + } else if (manager->choice.talk_action == 1) { + aQMgr_actor_set_client_quest_info(manager); + manager->msg_category = aQMgr_MSG_KIND_REQUEST_REJECT; + manager->sub_talk_state = aQMgr_TALK_SUB_STATE_WAIT; + (*manager->talk_common_proc)(manager, aQMgr_TALK_COMMON_SET_MSG_NO); + mMsg_Set_continue_msg_num(mMsg_Get_base_window_p(), manager->msg_no); + + /* If the player rejects a quest then apply a friendship penalty */ + if (*manager->memory != NULL) { + mNpc_AddFriendship(*manager->memory, -3); + } + } else if (manager->choice.talk_action == 2) { + aQMgr_talk_quest_set_cancel_msg_com(manager, 0x254A); + } else { + manager->msg_category = aQMgr_MSG_KIND_REQUEST_END; + aQMgr_actor_set_quest_info(manager); + aQMgr_actor_clear_client_quest_info(manager); + manager->sub_talk_state = aQMgr_TALK_SUB_STATE_WAIT; + (*manager->talk_common_proc)(manager, aQMgr_TALK_COMMON_SET_MSG_NO); + mMsg_Set_continue_msg_num(mMsg_Get_base_window_p(), manager->msg_no); + } + + mMsg_Set_ForceNext(mMsg_Get_base_window_p()); +} + +static void aQMgr_talk_quest_wait_talk(QUEST_MANAGER_ACTOR* manager) { + (*manager->talk_common_proc)(manager, aQMgr_TALK_COMMON_SET_NPC_TAKEOUT_ITEM); + manager->sub_talk_state = aQMgr_TALK_SUB_STATE_ITEM_PLAYER_WAIT; + mMsg_Set_LockContinue(mMsg_Get_base_window_p()); + manager->msg_category = aQMgr_MSG_KIND_REQUEST_END; + aQMgr_actor_talk_finish(manager); + manager->talk_step = aQMgr_TALK_STEP_CHANGE_WAIT; + (*manager->talk_common_proc)(manager, aQMgr_TALK_COMMON_SET_MSG_NO); + mMsg_Set_continue_msg_num(mMsg_Get_base_window_p(), manager->msg_no); +} + +static void aQMgr_actor_talk_giveup(QUEST_MANAGER_ACTOR* manager) { + if (manager->target.quest_inv_item_idx != -1) { + manager->sub_talk_state = aQMgr_TALK_SUB_STATE_CHECK_BUTTON; + manager->talk_step = aQMgr_TALK_STEP_GIVEUP_WAIT_BUTTON; + } + + (*manager->talk_common_proc)(manager, aQMgr_TALK_COMMON_SET_MSG_NO); + mMsg_Set_continue_msg_num(mMsg_Get_base_window_p(), manager->msg_no); +} + +static void aQMgr_talk_quest_giveup_wait_button(QUEST_MANAGER_ACTOR* manager) { + manager->talk_step = aQMgr_TALK_STEP_GIVEUP_OPEN_MENU; + mMsg_request_main_disappear_wait_type2(mMsg_Get_base_window_p()); + manager->sub_talk_state = aQMgr_TALK_SUB_STATE_MSG_DISAPPEAR_WAIT; + mMsg_Set_LockContinue(mMsg_Get_base_window_p()); + (*manager->talk_common_proc)(manager, aQMgr_TALK_COMMON_SET_MSG_NO); + mMsg_Set_continue_msg_num(mMsg_Get_base_window_p(), manager->msg_no); + mMsg_Set_ForceNext(mMsg_Get_base_window_p()); +} + +static void aQMgr_talk_quest_giveup_open_menu(QUEST_MANAGER_ACTOR* manager) { + mSM_open_submenu_new2(manager->submenu, mSM_OVL_INVENTORY, mSM_IV_OPEN_QUEST, manager->target.quest_inv_item_idx, + NULL, mSM_IV_ITEM_PUT_AWAY); + manager->sub_talk_state = aQMgr_TALK_SUB_STATE_HAND_ITEM_WAIT; + manager->talk_step = aQMgr_TALK_STEP_GIVEUP_ITEM; + (*manager->talk_common_proc)(manager, aQMgr_TALK_COMMON_SET_MSG_NO); + mMsg_Set_continue_msg_num(mMsg_Get_base_window_p(), manager->msg_no); +} + +static void aQMgr_talk_quest_giveup_item(QUEST_MANAGER_ACTOR* manager) { + aQMgr_set_data_c* set_data = (aQMgr_set_data_c*)manager->target.set_data_p; + int base_msg; + int friendship = 0; + + if (manager->handover_item) { + manager->msg_category = aQMgr_MSG_KIND_FAILURE_END; + manager->talk_step = aQMgr_TALK_STEP_GIVEUP_NPC_ITEM; + manager->sub_talk_state = aQMgr_TALK_SUB_STATE_MSG_APPEAR_WAIT; + + if (set_data != NULL && *manager->memory != NULL) { + base_msg = set_data->msg_start[aQMgr_MSG_KIND_FAILURE_END]; + + switch (base_msg) { + case 0x2B8: + friendship = -5; + break; + case 0x452: + friendship = -2; + break; + case 0x2CA: + friendship = -1; + break; + } + + mNpc_AddFriendship(*manager->memory, friendship); + } + } else { + manager->msg_category = aQMgr_MSG_KIND_NONE; + manager->category_msg_no_start = 0x499; + manager->talk_step = aQMgr_TALK_STEP_GIVEUP; + manager->sub_talk_state = aQMgr_TALK_SUB_STATE_WAIT; + } + + (*manager->talk_common_proc)(manager, aQMgr_TALK_COMMON_SET_MSG_NO); + mMsg_ChangeMsgData(mMsg_Get_base_window_p(), manager->msg_no); + mMsg_request_main_appear_wait_type1(mMsg_Get_base_window_p()); + mMsg_Unset_LockContinue(mMsg_Get_base_window_p()); +} + +static void aQMgr_talk_quest_giveup_npc_item(QUEST_MANAGER_ACTOR* manager) { + manager->sub_talk_state = aQMgr_TALK_SUB_STATE_NPC_HAND_WAIT_MSG_WAIT; + aQMgr_actor_talk_finish(manager); + manager->talk_step = aQMgr_TALK_STEP_CHANGE_WAIT; +} + +static void aQMgr_actor_talk_fin_quest_start(QUEST_MANAGER_ACTOR* manager) { + if (manager->choice.talk_action == 0) { + mMsg_Set_LockContinue(mMsg_Get_base_window_p()); + mMsg_request_main_disappear_wait_type2(mMsg_Get_base_window_p()); + + manager->sub_talk_state = aQMgr_TALK_SUB_STATE_MSG_DISAPPEAR_WAIT; + manager->talk_step = aQMgr_TALK_STEP_OPEN_MENU; + manager->choice.talk_action = -1; + manager->msg_category = aQMgr_MSG_KIND_COMPLETE_INIT; + + (*manager->talk_common_proc)(manager, aQMgr_TALK_COMMON_SET_MSG_NO); + mMsg_Set_continue_msg_num(mMsg_Get_base_window_p(), manager->msg_no); + mMsg_Set_ForceNext(mMsg_Get_base_window_p()); + } else { + aQMgr_talk_quest_change_normal_or_hint(manager); + manager->sub_talk_state = aQMgr_TALK_SUB_STATE_WAIT; + } +} + +static void aQMgr_talk_quest_talk_fin_quest_start_not_hand(QUEST_MANAGER_ACTOR* manager) { + if (manager->choice.talk_action == 2) { + aQMgr_talk_quest_set_cancel_msg_com(manager, 0x254A); + } else { + manager->talk_step = aQMgr_TALK_STEP_FIN_QUEST_REWARD; + manager->choice.talk_action = -1; + manager->msg_category = aQMgr_MSG_KIND_COMPLETE_INIT; + + (*manager->talk_common_proc)(manager, aQMgr_TALK_COMMON_SET_MSG_NO); + mMsg_Set_continue_msg_num(mMsg_Get_base_window_p(), manager->msg_no); + } + + mMsg_Set_ForceNext(mMsg_Get_base_window_p()); + manager->sub_talk_state = aQMgr_TALK_SUB_STATE_WAIT; +} + +static void aQMgr_talk_quest_open_menu(QUEST_MANAGER_ACTOR* manager) { + aQMgr_target_c* target = &manager->target; + Submenu* submenu = manager->submenu; + int item_idx = target->quest_inv_item_idx; + + if (target->quest_info.quest_type == mQst_QUEST_TYPE_CONTEST) { + switch (target->quest_info.quest_kind) { + case mQst_CONTEST_KIND_FISH: + mSM_open_submenu(submenu, mSM_OVL_INVENTORY, mSM_IV_OPEN_TAKE, 1); + break; + case mQst_CONTEST_KIND_INSECT: + mSM_open_submenu(submenu, mSM_OVL_INVENTORY, mSM_IV_OPEN_TAKE, 2); + break; + default: + mSM_open_submenu_new2(submenu, mSM_OVL_INVENTORY, mSM_IV_OPEN_QUEST, item_idx, NULL, + mSM_IV_ITEM_PUT_AWAY); + break; + } + } else { + int mode; + + if (ITEM_NAME_GET_TYPE(target->quest_item) == NAME_TYPE_ITEM1 && + ITEM_NAME_GET_CAT(target->quest_item) == ITEM1_CAT_CLOTH) { + mode = mSM_IV_ITEM_NORMAL; + } else { + mode = mSM_IV_ITEM_PUT_AWAY; + } + + mSM_open_submenu_new2(submenu, mSM_OVL_INVENTORY, mSM_IV_OPEN_QUEST, item_idx, NULL, mode); + } + + manager->talk_step = aQMgr_TALK_STEP_GET_ITEM; + manager->sub_talk_state = aQMgr_TALK_SUB_STATE_HAND_ITEM_WAIT; + (*manager->talk_common_proc)(manager, aQMgr_TALK_COMMON_SET_MSG_NO); + mMsg_Set_continue_msg_num(mMsg_Get_base_window_p(), manager->msg_no); +} + +static void aQMgr_talk_quest_get_item(QUEST_MANAGER_ACTOR* manager) { + aQMgr_target_c* target = &manager->target; + + if (manager->handover_item) { + manager->msg_category = aQMgr_MSG_KIND_COMPLETE_INIT; + manager->talk_step = aQMgr_TALK_STEP_NPC_GET_ITEM_WAIT; + + mQst_SetItemNameFreeStr(manager->handover_item, mMsg_FREE_STR2); + if (ITEM_NAME_GET_TYPE(target->quest_item) == NAME_TYPE_ITEM1 && + ITEM_NAME_GET_CAT(target->quest_item) == ITEM1_CAT_CLOTH) { + Common_Set(npc_chg_cloth, target->quest_item); + } + } else { + manager->msg_category = aQMgr_MSG_KIND_NONE; + manager->category_msg_no_start = 0x4AB; + manager->talk_step = aQMgr_TALK_STEP_CHANGE_WAIT; + + if (*manager->memory != NULL) { + mNpc_AddFriendship(*manager->memory, -1); + } + } + + (*manager->talk_common_proc)(manager, aQMgr_TALK_COMMON_SET_MSG_NO); + mMsg_ChangeMsgData(mMsg_Get_base_window_p(), manager->msg_no); + mMsg_request_main_appear_wait_type1(mMsg_Get_base_window_p()); + mMsg_Unset_LockContinue(mMsg_Get_base_window_p()); + manager->sub_talk_state = aQMgr_TALK_SUB_STATE_MSG_APPEAR_WAIT; +} + +static void aQMgr_talk_quest_npc_get_item_wait(QUEST_MANAGER_ACTOR* manager) { + manager->talk_step = aQMgr_TALK_STEP_FIN_QUEST_REWARD; + manager->sub_talk_state = aQMgr_TALK_SUB_STATE_NPC_HAND_WAIT_MSG_WAIT; +} + +static void aQMgr_actor_talk_fin_quest_reward(QUEST_MANAGER_ACTOR* manager) { + aQMgr_target_c* target = &manager->target; + aQMgr_regist_c* regist = &manager->regist[manager->regist_idx]; + + aQMgr_actor_set_reward(manager); + + if (aQMgr_actor_hand_reward(target) == TRUE) { + aQMgr_actor_set_free_str_reward(target); + manager->msg_category = aQMgr_MSG_KIND_NONE; + + if (regist->quest_info != NULL && regist->quest_info->quest_type == mQst_QUEST_TYPE_CONTEST) { + // missing static qualifier + int* reward_msg_table[mQst_CONTEST_KIND_NUM] = { l_fruit_reward_msg, l_soccer_reward_msg, + l_snowman_reward_msg, l_flower_reward_msg, + l_fish_reward_msg, l_insect_reward_msg, + l_reward_msg }; + + if (regist->quest_info->quest_kind >= mQst_CONTEST_KIND_NUM) { + regist->quest_info->quest_kind = mQst_CONTEST_KIND_LETTER; + } + + manager->category_msg_no_start = reward_msg_table[regist->quest_info->quest_kind][target->reward_kind]; + } else { + manager->category_msg_no_start = l_reward_msg[target->reward_kind]; + } + + manager->talk_step = aQMgr_TALK_STEP_FIN_QUEST_THANKS; + sAdo_SysTrgStart(0x12F); + if (*manager->memory != NULL) { + mNpc_AddFriendship(*manager->memory, 3); + } + } else { + manager->msg_category = aQMgr_MSG_KIND_REWARD_FULL_ITEM; + regist->quest_info->give_reward = TRUE; + manager->regist_idx = -1; + } + + if (regist->quest_info->quest_type == mQst_QUEST_TYPE_CONTEST) { + if (regist->quest_info->progress != 0) { + regist->quest_info->progress--; + lbRTC_Add_DD(®ist->quest_info->time_limit, 3); // add 3 extra days to finish + mPr_CopyPersonalID(&((mQst_contest_c*)regist->quest_info)->player_id, &Common_Get(now_private)->player_ID); + } + + manager->regist_idx = -1; + } + + manager->sub_talk_state = aQMgr_TALK_SUB_STATE_WAIT; + aQMgr_actor_talk_finish(manager); + (*manager->talk_common_proc)(manager, aQMgr_TALK_COMMON_SET_MSG_NO); + mMsg_Set_continue_msg_num(mMsg_Get_base_window_p(), manager->msg_no); +} + +static void aQMgr_actor_talk_fin_quest_thanks(QUEST_MANAGER_ACTOR* manager) { + manager->msg_category = aQMgr_MSG_KIND_COMPLETE_END; + (*manager->talk_common_proc)(manager, aQMgr_TALK_COMMON_SET_NPC_TAKEOUT_REWARD); + manager->sub_talk_state = aQMgr_TALK_SUB_STATE_WAIT; + (*manager->talk_common_proc)(manager, aQMgr_TALK_COMMON_SET_MSG_NO); + mMsg_Set_continue_msg_num(mMsg_Get_base_window_p(), manager->msg_no); +} + +static void aQMgr_actor_talk_after_reward(QUEST_MANAGER_ACTOR* manager) { + aQMgr_regist_c* regist; + int regist_idx = manager->regist_idx; + + aQMgr_actor_set_reward(manager); + + if (aQMgr_actor_hand_reward(&manager->target) == TRUE) { + aQMgr_actor_set_free_str_reward(&manager->target); + regist = &manager->regist[regist_idx]; + manager->msg_category = aQMgr_MSG_KIND_NONE; + + if (regist->quest_info != NULL && regist->quest_info->quest_type == mQst_QUEST_TYPE_CONTEST) { + // missing static qualifier + int* reward_msg_table[mQst_CONTEST_KIND_NUM] = { l_after_reward_msg, l_soccer_reward_msg, + l_snowman_reward_msg, l_flower_reward_msg, + l_after_reward_msg, l_after_reward_msg, + l_after_reward_msg }; + + if (regist->quest_info->quest_kind >= mQst_CONTEST_KIND_NUM) { + regist->quest_info->quest_kind = mQst_CONTEST_KIND_LETTER; + } + + manager->category_msg_no_start = + reward_msg_table[regist->quest_info->quest_kind][manager->target.reward_kind]; + } else { + manager->category_msg_no_start = l_after_reward_msg[manager->target.reward_kind]; + } + + manager->talk_step = aQMgr_TALK_STEP_AFTER_REWARD_THANKS; + sAdo_SysTrgStart(0x12F); + } else { + manager->msg_category = aQMgr_MSG_KIND_REWARD_FULL_ITEM2; + } + + (*manager->talk_common_proc)(manager, aQMgr_TALK_COMMON_SET_MSG_NO); + mMsg_Set_continue_msg_num(mMsg_Get_base_window_p(), manager->msg_no); + manager->sub_talk_state = aQMgr_TALK_SUB_STATE_WAIT; +} + +static void aQMgr_actor_talk_after_reward_thanks(QUEST_MANAGER_ACTOR* manager) { + manager->msg_category = aQMgr_MSG_KIND_AFTER_REWARD_THANKS; + (*manager->talk_common_proc)(manager, aQMgr_TALK_COMMON_SET_NPC_TAKEOUT_REWARD); + manager->sub_talk_state = aQMgr_TALK_SUB_STATE_WAIT; + aQMgr_actor_talk_finish(manager); + (*manager->talk_common_proc)(manager, aQMgr_TALK_COMMON_SET_MSG_NO); + mMsg_Set_continue_msg_num(mMsg_Get_base_window_p(), manager->msg_no); +} + +static void aQMgr_talk_quest_contest_hoka_or_normal(QUEST_MANAGER_ACTOR* manager) { + aQMgr_regist_c* regist = &manager->regist[manager->regist_idx]; + + if (manager->choice.talk_action == 0) { + aQMgr_talk_quest_finish_firstjob_open_quest(); + manager->target.free_data_p = NULL; + mMsg_Set_free_str(mMsg_Get_base_window_p(), mMsg_FREE_STR12, + ((mQst_contest_c*)regist->quest_info)->player_id.player_name, PLAYER_NAME_LEN); + if (regist->quest_info->quest_type == mQst_QUEST_TYPE_CONTEST && + regist->quest_info->quest_kind == mQst_CONTEST_KIND_LETTER) { + if (mPr_CheckCmpPersonalID(&((mQst_contest_c*)regist->quest_info)->player_id, + &Common_Get(now_private)->player_ID) == FALSE) { + manager->category_msg_no_start = aQMgr_talk_quest_get_contest_hoka_msg_no( + (mQst_contest_c*)regist->quest_info, aQMgr_GET_CLIENT_ANIMAL(manager)); + } else { + manager->category_msg_no_start = 0x1B05; + } + } else { + manager->category_msg_no_start = aQMgr_talk_quest_get_contest_hoka_msg_no( + (mQst_contest_c*)regist->quest_info, aQMgr_GET_CLIENT_ANIMAL(manager)); + manager->target.free_data_p = NULL; + aQMgr_actor_talk_finish(manager); + } + + manager->choice.talk_action = -1; + mMsg_Set_ForceNext(mMsg_Get_base_window_p()); + (*manager->talk_common_proc)(manager, aQMgr_TALK_COMMON_SET_MSG_NO); + mMsg_Set_continue_msg_num(mMsg_Get_base_window_p(), manager->msg_no); + } else { + aQMgr_talk_quest_change_normal_or_hint(manager); + } + + manager->sub_talk_state = aQMgr_TALK_SUB_STATE_WAIT; +} + +static void aQMgr_talk_quest_change_wait(QUEST_MANAGER_ACTOR* manager) { + manager->sub_talk_state = aQMgr_TALK_SUB_STATE_WAIT; + (*manager->talk_common_proc)(manager, aQMgr_TALK_COMMON_SET_MSG_NO); + mMsg_Set_continue_msg_num(mMsg_Get_base_window_p(), manager->msg_no); +} + +static void aQMgr_actor_talk_finish_letter(QUEST_MANAGER_ACTOR* manager) { + aQMgr_regist_c* regist = &manager->regist[manager->regist_idx]; + mQst_contest_c* contest = (mQst_contest_c*)regist->quest_info; + + mMsg_Set_free_str(mMsg_Get_base_window_p(), mMsg_FREE_STR12, contest->player_id.player_name, PLAYER_NAME_LEN); + + if (mPr_CheckCmpPersonalID(&contest->player_id, &Common_Get(now_private)->player_ID) == TRUE) { + manager->category_msg_no_start = 0x1B17; + } else { + manager->category_msg_no_start = 0x1B29; + } + + (*manager->talk_common_proc)(manager, aQMgr_TALK_COMMON_SET_MSG_NO); + mMsg_Set_continue_msg_num(mMsg_Get_base_window_p(), manager->msg_no); + manager->talk_step = aQMgr_TALK_STEP_CHANGE_WAIT; + manager->sub_talk_state = aQMgr_TALK_SUB_STATE_WAIT; + manager->target.free_data_p = NULL; + aQMgr_actor_talk_finish(manager); + mMsg_Set_ForceNext(mMsg_Get_base_window_p()); +} + +typedef void (*aQMgr_QUEST_TALK_PROC)(QUEST_MANAGER_ACTOR*); + +extern void aQMgr_actor_move_talk_init(QUEST_MANAGER_ACTOR* manager) { + static aQMgr_QUEST_TALK_PROC talk_proc[] = { + &aQMgr_actor_talk_select_talk_2, + &aQMgr_actor_talk_reconf_or_normal, + &aQMgr_actor_talk_root_reconf_or_normal, + &aQMgr_actor_talk_no_or_normal, + &aQMgr_actor_talk_full_item_or_normal, + &aQMgr_actor_talk_renew_errand_or_normal, + &aQMgr_actor_talk_new_quest_or_normal, + &aQMgr_actor_talk_finish, + &aQMgr_actor_talk_occur_quest, + &aQMgr_actor_talk_giveup, + &aQMgr_talk_quest_giveup_wait_button, + &aQMgr_talk_quest_giveup_open_menu, + &aQMgr_talk_quest_giveup_item, + &aQMgr_talk_quest_giveup_npc_item, + &aQMgr_actor_talk_fin_quest_start, + &aQMgr_talk_quest_talk_fin_quest_start_not_hand, + &aQMgr_actor_talk_fin_quest_reward, + &aQMgr_actor_talk_fin_quest_thanks, + &aQMgr_actor_talk_after_reward, + &aQMgr_actor_talk_after_reward_thanks, + &aQMgr_talk_quest_wait_talk, + &aQMgr_talk_quest_open_menu, + &aQMgr_talk_quest_get_item, + &aQMgr_talk_quest_npc_get_item_wait, + &aQMgr_talk_quest_change_wait, + &aQMgr_actor_talk_renew_errand_irai_end, + &aQMgr_actor_talk_renew_errand_irai_end_give_item, + &aQMgr_talk_quest_contest_hoka_or_normal, + &aQMgr_actor_talk_finish_letter, + (aQMgr_QUEST_TALK_PROC)&none_proc1, + &aQMgr_actor_talk_no_or_island, + &aQMgr_actor_talk_finish, + }; + + int step = manager->talk_step; + int choice = mChoice_Get_ChoseNum(mChoice_Get_base_window_p()); + + mChoice_Clear_ChoseNum(mChoice_Get_base_window_p()); + manager->choice.talk_action = choice; + (*talk_proc[step])(manager); + (*manager->talk_common_proc)(manager, aQMgr_TALK_COMMON_SET_CHOICE_STR); + + if (manager->talk_change_type >= aQMgr_TALK_KIND_NUM) { + manager->talk_state = aQMgr_TALK_STATE_SUB; + } +} diff --git a/src/m_npc.c b/src/m_npc.c index 66989f3c..359bbefc 100644 --- a/src/m_npc.c +++ b/src/m_npc.c @@ -5141,12 +5141,12 @@ extern int mNpc_CheckQuestRequest(int animal_idx) { return res; } -extern void mNpc_SetQuestRequestOFF(int animal_idx, int feel) { +extern void mNpc_SetQuestRequestOFF(int animal_idx, int looks) { mNpc_Talk_Info_c* talk_info = &l_npc_talk_info[animal_idx]; if (animal_idx >= 0 && animal_idx < ARRAY_COUNT(l_npc_talk_info)) { if (talk_info->quest_request == TRUE) { - mNpc_SetUnlockTimer(&talk_info->unlock_timer, &talk_info->reset_timer, feel); + mNpc_SetUnlockTimer(&talk_info->unlock_timer, &talk_info->reset_timer, looks); } talk_info->quest_request = FALSE;