From 9512806c9f3cbeefc626cf6f62882ecc20371980 Mon Sep 17 00:00:00 2001 From: Cuyler36 Date: Mon, 23 Oct 2023 12:28:26 -0400 Subject: [PATCH] Implement & link m_soncho.c --- config/rel_slices.yml | 4 + include/ac_handOverItem.h | 45 ++ include/ac_npc.h | 11 +- include/ac_taisou_npc0.h | 19 + include/m_clip.h | 3 +- include/m_common_data.h | 2 +- include/m_msg.h | 3 + include/m_name_table.h | 94 ++- include/m_player_lib.h | 2 + include/m_shop.h | 2 +- include/m_soncho.h | 124 +++- include/m_string.h | 13 +- include/m_string_data.h | 27 + rel/m_field_info.c | 14 +- rel/m_shop.c | 2 +- rel/m_soncho.c | 1179 +++++++++++++++++++++++++++++++++++++ 16 files changed, 1509 insertions(+), 35 deletions(-) create mode 100644 include/m_string_data.h create mode 100644 rel/m_soncho.c diff --git a/config/rel_slices.yml b/config/rel_slices.yml index 17ec6fea..be2d2f79 100644 --- a/config/rel_slices.yml +++ b/config/rel_slices.yml @@ -221,6 +221,10 @@ m_shop.c: .rodata: [0x80643270, 0x806432D0] .data: [0x8065D690, 0x8065DBF8] .bss: [0x8129F308, 0x8129F320] +m_soncho.c: + .text: [0x803EC240, 0x803EDEC0] + .rodata: [0x806432D0, 0x806432E0] + .data: [0x8065DBF8, 0x8065DD70] m_start_data_init.c: .text: [0x803EDEC0, 0x803EED30] .rodata: [0x806432E0, 0x806432F0] diff --git a/include/ac_handOverItem.h b/include/ac_handOverItem.h index a14579d9..2a47d972 100644 --- a/include/ac_handOverItem.h +++ b/include/ac_handOverItem.h @@ -3,11 +3,56 @@ #include "types.h" #include "m_actor.h" +#include "m_scene.h" #ifdef __cplusplus extern "C" { #endif +enum { + aHOI_REQUEST_NO_REQUEST, + aHOI_REQUEST_TRANSFER, + aHOI_REQUEST_TRANS_WAIT, + aHOI_REQUEST_GET, + aHOI_REQUEST_GET_PULL, + aHOI_REQUEST_EAT, + aHOI_REQUEST_CHANGE, + aHOI_REQUEST_PUTAWAY, + aHOI_REQUEST_GET_PULL_WAIT, + aHOI_REQUEST_RETURN, + aHOI_REQUEST_RETURN_WAIT, + aHOI_REQUEST_ESTIMATE, + + aHOI_REQUEST_NUM +}; + +typedef struct hand_over_item_actor_s HANDOVERITEM_ACTOR; + +typedef ACTOR* (*aHOI_BIRTH_PROC)(mActor_name_t, int, int); +typedef ACTOR* (*aHOI_CHG_MASTER_PROC)(ACTOR*); +typedef int (*aHOI_CHG_REQUEST_MODE_PROC)(ACTOR*, int); +typedef void (*aHOI_REBUILD_DMA_PROC)(Object_Exchange_c*, ACTOR*); /* yoinked from DnM, unused in AC */ + +typedef struct hand_over_item_clip_s { + aHOI_BIRTH_PROC birth_proc; + aHOI_CHG_MASTER_PROC chg_master_proc; + aHOI_CHG_REQUEST_MODE_PROC chg_request_mode_proc; + u8 request_mode; + u8 player_after_mode; + mActor_name_t item; + ACTOR* master_actor; + ACTOR* target_actor; + u8 present_flag; + u8 master_changed_flag; + HANDOVERITEM_ACTOR* handOverItem_p; + aHOI_REBUILD_DMA_PROC rebuild_dma_proc; +} aHOI_Clip_c; + +struct hand_over_item_actor_s { + ACTOR actor_class; + u8 _174[0x1F4 - 0x174]; /* TODO */ +}; + extern ACTOR_PROFILE HandOverItem_Profile; #ifdef __cplusplus diff --git a/include/ac_npc.h b/include/ac_npc.h index f14f1465..841569d0 100644 --- a/include/ac_npc.h +++ b/include/ac_npc.h @@ -71,11 +71,18 @@ struct npc_actor_s { NpcActorInfo_c npc_info; u8 _194[0x718 - 0x194]; int texture_bank_idx; // TEMP: this is part of draw struct - u8 _71C[0x978 - 0x71C]; + u8 _71C[0x974 - 0x71C]; + s16 talk_base_anim_id; + s16 _976; s16 melody_inst; - u8 _97A[0x9D8 - 0x97A]; + u8 _97A[0x994 - 0x97A]; /* TODO: 0x994 may be too big. Verify size. Seen in ac_normal_npc, ac_npc_engineer */ }; +typedef struct animal_npc_actor_s { + NPC_ACTOR npc_actor_class; + u8 _994[0x9D8 - 0x994]; +} ANIMAL_NPC_ACTOR; + extern ACTOR_PROFILE Npc_Profile; #ifdef __cplusplus diff --git a/include/ac_taisou_npc0.h b/include/ac_taisou_npc0.h index 37dc1d5a..ae0e07b9 100644 --- a/include/ac_taisou_npc0.h +++ b/include/ac_taisou_npc0.h @@ -3,11 +3,30 @@ #include "types.h" #include "m_actor.h" +#include "ac_npc.h" #ifdef __cplusplus extern "C" { #endif +typedef struct taisou_npc0_actor_s { + NPC_ACTOR npc_actor_class; + s8 ratio_idx; + u8 anim_initialized; + u8 gymnastic_state; + u8 delay_cnt; + s8 radio_counter; + f32 end_ratio; + int _9A0; + int anime_dir; + f32 current_ratio; + int frame; + mActor_name_t held_item; + u8 talk_proc; + u8 talk_state; + u8 soncho_event; +} TAISOU_NPC0_ACTOR; + extern ACTOR_PROFILE Taisou_Npc0_Profile; #ifdef __cplusplus diff --git a/include/m_clip.h b/include/m_clip.h index 9b5bd1b5..516f2e63 100644 --- a/include/m_clip.h +++ b/include/m_clip.h @@ -20,6 +20,7 @@ #include "ac_my_indoor.h" #include "ac_arrange_room.h" #include "ac_shop_umbrella.h" +#include "ac_handOverItem.h" #ifdef __cplusplus extern "C" { @@ -44,7 +45,7 @@ typedef struct clip_s { /* 0x07C */ aINS_Clip_c* insect_clip; /* 0x080 */ aMR_Clip_c* my_room_clip; /* 0x084 */ void* _084; - /* 0x088 */ void* _088; + /* 0x088 */ aHOI_Clip_c* handOverItem_clip; /* 0x08C */ aSTR_Clip_c* structure_clip; /* 0x090 */ eEC_EffectControl_Clip_c* effect_clip; /* 0x094 */ aTOL_Clip_c* tools_clip; diff --git a/include/m_common_data.h b/include/m_common_data.h index 993f6299..b02f334f 100644 --- a/include/m_common_data.h +++ b/include/m_common_data.h @@ -71,7 +71,7 @@ typedef struct bridge_s { typedef struct lighthouse_s { lbRTC_ymd_c renew_time; - u8 players_switch_on; + u8 days_switched_on; u8 players_quest_started; u8 players_completed; } LightHouse_c; diff --git a/include/m_msg.h b/include/m_msg.h index 3193a9ac..1df650d6 100644 --- a/include/m_msg.h +++ b/include/m_msg.h @@ -240,6 +240,9 @@ extern int mMsg_Check_MainDisappear(mMsg_Window_c* msg_win); extern void mMsg_request_main_disappear_wait_type1(mMsg_Window_c* msg_win); extern void mMsg_request_main_appear_wait_type1(mMsg_Window_c* msg_win); extern void mMsg_Get_BodyParam(u32 table_rom_start, u32 data_rom_start, int entry_no, u32* data_addr, u32* data_size); +extern void mMsg_Set_LockContinue(mMsg_Window_c* msg_win); +extern void mMsg_Unset_LockContinue(mMsg_Window_c* msg_win); +extern int mMsg_Get_msg_num(mMsg_Window_c* msg_win); #ifdef __cplusplus } diff --git a/include/m_name_table.h b/include/m_name_table.h index 039d8f52..a519bb10 100644 --- a/include/m_name_table.h +++ b/include/m_name_table.h @@ -553,14 +553,32 @@ extern mActor_name_t bg_item_fg_sub_dig2take_conv(mActor_name_t item); #define FTR_DINO_DISP_STEGO 0x1F94 #define FTR_DINO_DISP_STEGO2 0x1F98 #define FTR_FOSSIL 0x1F9C - +#define FTR_SHOGI_PIECE 0x1FA0 +#define FTR_CHOCOLATES 0x1FA4 +#define FTR_POST_BOX 0x1FA8 #define FTR_PIGGY_BANK 0x1FAC - #define FTR_TISSUE 0x1FB0 - +#define FTR_TRIBAL_MASK 0x1FB4 +#define FTR_MATRYOSHKA 0x1FB8 +#define FTR_FAMICOM_LEGEND_OF_ZELDA_DISK 0x1FBC +#define FTR_BOTTLED_SHIP 0x1FC0 +#define FTR_TIGER_BOBBLEHEAD 0x1FC4 +#define FTR_MOAI_STATUE 0x1FC8 +#define FTR_AEROBICS_RADIO 0x1FCC +#define FTR_PAGODA 0x1FD0 +#define FTR_FISHING_BEAR 0x1FD4 +#define FTR_MOUTH_OF_TRUTH 0x1FD8 +#define FTR_CHINESE_LIONESS 0x1FDC +#define FTR_TOWER_OF_PISA 0x1FE0 +#define FTR_MERLION 0x1FE4 +#define FTR_MANEKIN_PIS 0x1FE8 +#define FTR_TOKYO_TOWER 0x1FEC +#define FTR_RED_BALLOON 0x1FF0 +#define FTR_YELLOW_BALLOON 0x1FF4 +#define FTR_BLUE_BALLOON 0x1FF8 +#define FTR_GREE_BALLOON 0x1FFC #define FTR0_END 0x1FFF - #define ITM_PAPER_START 0x2000 #define ITM_PAPER00 (ITM_PAPER_START + 0) #define ITM_PAPER01 (ITM_PAPER_START + 1) @@ -1182,9 +1200,54 @@ extern mActor_name_t bg_item_fg_sub_dig2take_conv(mActor_name_t item); #define FTR_MANOR_MODEL 0x3028 #define FTR_POLICE_MODEL 0x302C #define FTR_MUSEUM_MODEL 0x3030 - +#define FTR_PLATE_ARMOR 0x3034 +#define FTR_TSUKIMI_DANGO 0x3038 +#define FTR_BEAN_THROWING_SET 0x303C +#define FTR_OSECHI 0x3040 +#define FTR_LOVELY_PHONE 0x3044 +#define FTR_MARKET_MODEL 0x3048 +#define FTR_FORTUNE_TENT_MODEL 0x304C +#define FTR_CHINESE_LION 0x3050 +#define FTR_TANABATA_PALM 0x3054 +#define FTR_SPRING_PENNANT 0x3058 +#define FTR_AUTUMN_PENNANT 0x305C +#define FTR_SHOP_MDOEL 0x3060 +#define FTR_COMPASS 0x3064 +#define FTR_LONG_LIFE_NOODLES 0x3068 +#define FTR_BASS_BOAT 0x306C +#define FTR_LIGHTHOUSE_MODEL 0x3070 +#define FTR_LIFE_RING 0x3074 +#define FTR_TREE_MODEL 0x3078 +#define FTR_PINK_TREE_MODEL 0x307C +#define FTR_WEED_MODEL 0x3080 +#define FTR_NEEDLEWORK_MODEL 0x3084 +#define FTR_DUMP_MODEL 0x3088 +#define FTR_MORTAR_BALL 0x308C +#define FTR_SNOWMAN 0x3090 +#define FTR_MINI_CAR 0x3094 +#define FTR_BIG_CATCH_FLAG 0x3098 +#define FTR_MOON 0x309C #define FTR_LOCOMOTIVE_MODEL 0x30A0 - +#define FTR_DOLLY 0x30A4 +#define FTR_STATION_MODEL0 0x30A8 +#define FTR_STATION_MODEL1 0x30AC +#define FTR_STATION_MODEL2 0x30B0 +#define FTR_STATION_MODEL3 0x30B4 +#define FTR_STATION_MODEL4 0x30B8 +#define FTR_STATION_MODEL5 0x30BC +#define FTR_STATION_MODEL6 0x30C0 +#define FTR_STATION_MODEL7 0x30C4 +#define FTR_STATION_MODEL8 0x30C8 +#define FTR_STATION_MODEL9 0x30CC +#define FTR_STATION_MODEL10 0x30D0 +#define FTR_STATION_MODEL11 0x30D4 +#define FTR_STATION_MODEL12 0x30D8 +#define FTR_STATION_MODEL13 0x30DC +#define FTR_STATION_MODEL14 0x30E0 +#define FTR_WELL_MODEL 0x30E4 +#define FTR_GRASS_MODEL 0x30E8 +#define FTR_TRACK_MODEL 0x30EC +#define FTR_DIRT_MODEL 0x30F0 #define FTR_TRAIN_CAR_MODEL 0x30F4 #define FTR_ORANGEBOX 0x30F8 @@ -1192,12 +1255,29 @@ extern mActor_name_t bg_item_fg_sub_dig2take_conv(mActor_name_t item); #define FTR_CALLIGRAPHY_PAD_WEST 0x313B +#define FTR_BOTTLE_ROCKET 0x31F0 + +#define FTR_FISHING_TROPHY 0x3210 + +#define FTR_TELESCOPE 0x3238 + #define FTR_FESTIVE_FLAG 0x327C +#define FTR_SUPER_TORTIMER 0x3280 #define FTR_MAILBOX 0x3294 #define FTR_FESTIVE_CANDLE 0x3298 -#define FTR1_END 0x3000 +#define FTR_SPRING_MEDAL 0x32A8 +#define FTR_AUTUMN_MEDAL 0x32AC + +#define FTR_ANGLER_TROPHY 0x3374 + +#define FTR_CORNUCOPIA 0x33B4 +#define FTR_JUDGES_BELL 0x33B8 +#define FTR_NOISEMAKER 0x33BC +#define FTR_CHOWER 0x33C0 +#define FTR_DUMMY 0x33C4 +#define FTR1_END 0x33C8 #define DOOR_START 0x4000 #define DOOR0 DOOR_START /* 0x4000 */ diff --git a/include/m_player_lib.h b/include/m_player_lib.h index cb26a2f1..99ffc66c 100644 --- a/include/m_player_lib.h +++ b/include/m_player_lib.h @@ -27,11 +27,13 @@ extern void mPlib_change_player_cloth_info_lv2(Private_c* priv, mActor_name_t cl extern int mPlib_Get_address_able_display(); extern int mPlib_get_player_actor_main_index(GAME_PLAY* play); extern int mPlib_check_player_actor_main_index_AllWade(GAME_PLAY* play); +extern int mPlib_request_main_demo_wait_type1(GAME_PLAY* play, int param_2, void* param_3); extern void mPlib_Object_Exchange_keep_new_PlayerMdl(GAME_PLAY* play); extern void mPlib_Object_Exchange_keep_new_PlayerTex(GAME_PLAY* play, int bank_id, int base_idx); extern void mPlib_Object_Exchange_keep_new_PlayerFaceTex(GAME_PLAY* play); extern void mPlib_Object_Exchange_keep_new_PlayerFacePallet(GAME_PLAY* play, int bank_id, int base_idx); +extern void mPlib_request_main_give_type1(GAME_PLAY* play, mActor_name_t item, int mode, int present, int on_surface); #define GET_PLAYER_ACTOR(play) get_player_actor_withoutCheck(play) #define GET_PLAYER_ACTOR_NOW() get_player_actor_withoutCheck((GAME_PLAY*)gamePT) diff --git a/include/m_shop.h b/include/m_shop.h index 4e14a115..c34591af 100644 --- a/include/m_shop.h +++ b/include/m_shop.h @@ -18,7 +18,7 @@ extern "C" { #define mSP_LOTTERY_ITEM_COUNT 3 #define mSP_SIGNBOARD_PRICE 500 -#define mSP_FORIEGN_FRUIT_PRICE 2000 +#define mSP_FOREIGN_FRUIT_PRICE 2000 #define mSP_NET_SALES_SUM 3000 // minimum sales sum before net appears (Nook's Cranny only) #define mSP_ROD_SALES_SUM 8000 // minimum sales sum before rod appears (Nook's Cranny only) diff --git a/include/m_soncho.h b/include/m_soncho.h index 92e039d9..4fd02585 100644 --- a/include/m_soncho.h +++ b/include/m_soncho.h @@ -2,13 +2,135 @@ #define M_SONCHO_H #include "types.h" +#include "m_play_h.h" +#include "ac_taisou_npc0.h" #ifdef __cplusplus extern "C" { #endif -extern u32 mSC_check_ArbeitPlayer(); +#define mSC_TROPHY_MAX 32 +#define mSC_RADIO_DAYS 13 +#define mSC_LIGHTHOUSE_DAYS 17 + +enum { + mSC_EVENT_NEW_YEARS_DAY, + mSC_EVENT_FOUNDERS_DAY, + mSC_EVENT_GRADUATION_DAY, + mSC_EVENT_APRILFOOLS_DAY, + mSC_EVENT_TOWN_DAY, + mSC_EVENT_MOTHERS_DAY, + mSC_EVENT_SALE_DAY, + mSC_EVENT_CHERRY_BLOSSOM_FESTIVAL, + mSC_EVENT_SPRING_SPORTS_FAIR, + mSC_EVENT_NATURE_DAY, + mSC_EVENT_SPRING_CLEANING, + mSC_EVENT_FATHERS_DAY, + mSC_EVENT_FISHING_TOURNEY_1, + mSC_EVENT_GROUNDHOG_DAY, + mSC_EVENT_EXPLORERS_DAY, + mSC_EVENT_FIREWORKS_SHOW, + mSC_EVENT_METEOR_SHOWER, + mSC_EVENT_HARVEST_MOON_FESTIVAL, + mSC_EVENT_MAYORS_DAY, + mSC_EVENT_OFFICERS_DAY, + mSC_EVENT_FALL_SPORTS_FAIR, + mSC_EVENT_HALLOWEEN, + mSC_EVENT_FISHING_TOURNEY_2, + mSC_EVENT_SNOW_DAY, + mSC_EVENT_LABOR_DAY, + mSC_EVENT_TOY_DAY, + mSC_EVENT_NEW_YEARS_EVE_COUNTDOWN, + mSC_EVENT_HARVEST_FESTIVAL, + mSC_EVENT_PLAYER_BIRTHDAY, + + mSC_EVENT_NUM = mSC_EVENT_PLAYER_BIRTHDAY, + + mSC_SPECIAL_EVENT_JAN_VACATION = 101, + mSC_SPECIAL_EVENT_FEB_VACATION = 102, + mSC_SPECIAL_EVENT_MORNING_AEROBICS = 103 +}; + +enum { + mSC_FIELD_EVENT_FOOT_RACE, + mSC_FIELD_EVENT_BALL_TOSS, + mSC_FIELD_EVENT_TUG_O_WAR, + mSC_FIELD_EVENT_AEROBICS, + + mSC_FIELD_EVENT_NUM +}; + +enum { + mSC_RADIO_TIME_LESS, + mSC_RADIO_TIME_SAME_DAY, + mSC_RADIO_TIME_OVER, + + mSC_RADIO_TIME_NUM +}; + +enum { + mSCR_TALK_PICKUP_ALL, + mSCR_TALK_INSPECTION, + mSCR_TALK_NEXT_INSPECTION, + mSCR_TALK_NEWCARD, + mSCR_TALK_BEFORE_GIVE, + mSCR_TALK_GIVE, + mSCR_TALK_NEXT, + mSCR_TALK_7, + mSCR_TALK_8, + mSCR_TALK_9, + + mSCR_TALK_NUM +}; + +enum { + mSCR_ACTION_TOO_LATE, // too late into aerobics to complete + mSCR_ACTION_DELETE_OLD_CARD, + mSCR_ACTION_NEW_CARD, + mSCR_ACTION_LOST_CARD, + mSCR_ACTION_STAMP_CARD, + mSCR_ACTION_FINISH_CARD, + mSCR_ACTION_LOST_CARD_AND_FINISH, // "lost" radio card but finished today + + mSCR_ACTION_NUM +}; + +enum { + mSC_LIGHTHOUSE_PERIOD_0, + mSC_LIGHTHOUSE_PERIOD_1, + mSC_LIGHTHOUSE_PERIOD_2, + mSC_LIGHTHOUSE_PERIOD_NONE, + + mSC_LIGHTHOUSE_PERIOD_NUM +}; + +extern u8 mSC_get_soncho_event(); +extern int mSC_get_soncho_field_event(); +extern void mSC_delete_soncho(ACTOR* actor, GAME_PLAY* play); +extern int mSC_trophy_get(u8 num); +extern void mSC_trophy_set(u8 num); +extern mActor_name_t mSC_trophy_item(u8 soncho_event); +extern void mSC_item_string_set(mActor_name_t item, int str_no); +extern void mSC_get_event_name_str(u8* buf, int buf_len, int soncho_event); +extern void mSC_event_name_set(u8 soncho_event); +extern void mSC_set_free_str_number(int free_str_no, u32 num); +extern int mSC_Radio_Set_Talk_Proc(TAISOU_NPC0_ACTOR* taisou_actor); +extern mSC_Radio_Talk_Proc(TAISOU_NPC0_ACTOR* taisou_actor, GAME_PLAY* play); +extern int mSC_LightHouse_get_period(lbRTC_time_c* time); +extern int mSC_LightHouse_day(const lbRTC_time_c* time); +extern int mSC_LightHouse_Event_Check(int player_no); +extern void mSC_LightHouse_Event_Clear(int player_no); +extern mActor_name_t mSC_LightHouse_Event_Present_Item(); +extern int mSC_LightHouse_Event_Start(); +extern int mSC_LightHouse_Talk_After_Check(); +extern void mSC_LightHouse_Quest_Start(); +extern int mSC_LightHouse_Switch_Check(); +extern int mSC_LightHouse_In_Check(); +extern void mSC_LightHouse_Switch_On(); +extern void mSC_LightHouse_Delete_Player(int player_no); extern int mSC_LightHouse_travel_check(); +extern void mSC_change_player_freeze(GAME_PLAY* play); +extern u32 mSC_check_ArbeitPlayer(); #ifdef __cplusplus } diff --git a/include/m_string.h b/include/m_string.h index 5362e6de..2ede566f 100644 --- a/include/m_string.h +++ b/include/m_string.h @@ -3,6 +3,7 @@ #include "types.h" #include "lb_rtc.h" +#include "m_string_data.h" #ifdef __cplusplus extern "C" { @@ -10,18 +11,6 @@ extern "C" { #define mString_MAX_STR 0x7FF -#define mString_AM 0x001 -#define mString_PM 0x002 -#define mString_WEEKDAY_START 0x009 -#define mString_DAY_START 0x64E -#define mString_MONTH_START 0x66D -#define mString_ARTICLE_START 0x737 -#define mString_HANIWA_MSG0 0x76A -#define mString_HANIWA_MSG1 0x76B -#define mString_HANIWA_MSG2 0x76C -#define mString_HANIWA_MSG3 0x76D - - extern void mString_aram_init(); extern void mString_Load_StringFromRom(u8* dst, int dst_len, int str_no); extern int mString_Load_YearStringFromRom(u8* dst, lbRTC_year_t year); diff --git a/include/m_string_data.h b/include/m_string_data.h new file mode 100644 index 00000000..6714edb0 --- /dev/null +++ b/include/m_string_data.h @@ -0,0 +1,27 @@ +#ifndef M_STRING_DATA_H +#define M_STRING_DATA_H + +#include "types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define mString_AM 0x001 +#define mString_PM 0x002 +#define mString_WEEKDAY_START 0x009 +#define mString_DAY_START 0x64E +#define mString_MONTH_START 0x66D +#define mString_SONCHO_EVENT_NAME_START 0x6F8 +#define mString_ARTICLE_START 0x737 +#define mString_HANIWA_MSG0 0x76A +#define mString_HANIWA_MSG1 0x76B +#define mString_HANIWA_MSG2 0x76C +#define mString_HANIWA_MSG3 0x76D + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/rel/m_field_info.c b/rel/m_field_info.c index 6cbf1c5b..769aac77 100644 --- a/rel/m_field_info.c +++ b/rel/m_field_info.c @@ -2915,18 +2915,14 @@ extern mActor_name_t mFI_GetOtherFruit() { #else /* This implementation gives an equal 25% chance for all non-native fruit to be rolled */ extern mActor_name_t mFI_GetOtherFruit() { - mActor_name_t other_fruit_tbl[ITM_FOOD_ORANGE - ITM_FOOD_APPLE]; - int idx = 0; - mActor_name_t native_fruit = Save_Get(fruit); - mActor_name_t i; + mActor_name_t other_fruit = ITM_FOOD_START | RANDOM(4); - for (i = ITM_FOOD_APPLE; i < ITM_FOOD_ORANGE + 1; i++) { - if (i != native_fruit) { - other_fruit_tbl[idx++] = i; - } + /* simple fix is to add one if the random fruit is also greater than the town fruit */ + if (other_fruit >= Save_Get(fruit)) { + other_fruit++; } - return other_fruit_tbl[RANDOM(4)]; + return other_fruit; } #endif diff --git a/rel/m_shop.c b/rel/m_shop.c index 536b5017..2a7b1c46 100644 --- a/rel/m_shop.c +++ b/rel/m_shop.c @@ -785,7 +785,7 @@ extern u32 mSP_ItemNo2ItemPrice(mActor_name_t item_no) { case ITM_FOOD_ORANGE: { if (Save_Get(fruit) != item_no) { - return mSP_FORIEGN_FRUIT_PRICE; + return mSP_FOREIGN_FRUIT_PRICE; } break; diff --git a/rel/m_soncho.c b/rel/m_soncho.c new file mode 100644 index 00000000..b7de7f3e --- /dev/null +++ b/rel/m_soncho.c @@ -0,0 +1,1179 @@ +#include "m_soncho.h" + +#include "m_common_data.h" +#include "m_name_table.h" +#include "m_event.h" +#include "m_play.h" +#include "m_room_type.h" +#include "m_msg.h" +#include "m_item_name.h" +#include "m_string.h" +#include "m_font.h" +#include "ac_taisou_npc0.h" +#include "m_player_lib.h" + +static u8 event_table[mSC_EVENT_NUM] = { + mEv_EVENT_SONCHO_NEW_YEARS_DAY, + mEv_EVENT_SONCHO_FOUNDERS_DAY, + mEv_EVENT_SONCHO_GRADUATION_DAY, + mEv_EVENT_SONCHO_APRILFOOLS_DAY, + mEv_EVENT_SONCHO_TOWN_DAY, + mEv_EVENT_SONCHO_MOTHERS_DAY, + mEv_EVENT_SONCHO_SALE_DAY, + mEv_EVENT_SONCHO_CHERRY_BLOSSOM_FESTIVAL, + mEv_EVENT_SONCHO_SPRING_SPORTS_FAIR, + mEv_EVENT_SONCHO_NATURE_DAY, + mEv_EVENT_SONCHO_SPRING_CLEANING, + mEv_EVENT_SONCHO_FATHERS_DAY, + mEv_EVENT_SONCHO_FISHING_TOURNEY_1, + mEv_EVENT_SONCHO_GROUNDHOG_DAY, + mEv_EVENT_SONCHO_EXPLORERS_DAY, + mEv_EVENT_SONCHO_FIREWORKS_SHOW, + mEv_EVENT_METEOR_SHOWER, + mEv_EVENT_HARVEST_MOON_FESTIVAL, + mEv_EVENT_SONCHO_MAYORS_DAY, + mEv_EVENT_SONCHO_OFFICERS_DAY, + mEv_EVENT_SONCHO_FALL_SPORTS_FAIR, + mEv_EVENT_SONCHO_HALLOWEEN, + mEv_EVENT_SONCHO_FISHING_TOURNEY_2, + mEv_EVENT_SONCHO_SNOW_DAY, + mEv_EVENT_SONCHO_LABOR_DAY, + mEv_EVENT_SONCHO_TOY_DAY, + mEv_EVENT_NEW_YEARS_EVE_COUNTDOWN, + mEv_EVENT_SONCHO_HARVEST_FESTIVAL +}; + +extern u8 mSC_get_soncho_event() { + u8* event_table_p = event_table; + int i = 0; + + for (i = 0; i < mSC_EVENT_NUM; i++) { + if (i != mSC_EVENT_FISHING_TOURNEY_2 && mEv_check_status(event_table[i], mEv_STATUS_RUN) != FALSE) { + return i; + } + } + + if (mEv_check_status(mEv_EVENT_SONCHO_FISHING_TOURNEY_2, mEv_STATUS_RUN)) { + return mSC_EVENT_FISHING_TOURNEY_2; + } + + if (mEv_check_status(mEv_EVENT_SONCHO_VACATION_JANUARY, mEv_STATUS_RUN)) { + return mSC_SPECIAL_EVENT_JAN_VACATION; + } + + if (mEv_check_status(mEv_EVENT_SONCHO_VACATION_FEBRUARY, mEv_STATUS_RUN)) { + return mSC_SPECIAL_EVENT_FEB_VACATION; + } + + if (mEv_check_status(mEv_EVENT_MORNING_AEROBICS, mEv_STATUS_RUN)) { + return mSC_SPECIAL_EVENT_MORNING_AEROBICS; + } + + return 0xFF; +} + +extern int mSC_get_soncho_field_event() { + if (mEv_check_status(mEv_EVENT_SPORTS_FAIR_FOOT_RACE, mEv_STATUS_RUN)) { + return mSC_FIELD_EVENT_FOOT_RACE; + } + + if (mEv_check_status(mEv_EVENT_SPORTS_FAIR_BALL_TOSS, mEv_STATUS_RUN)) { + return mSC_FIELD_EVENT_BALL_TOSS; + } + + if (mEv_check_status(mEv_EVENT_SPORTS_FAIR_TUG_OF_WAR, mEv_STATUS_RUN)) { + return mSC_FIELD_EVENT_TUG_O_WAR; + } + + return mSC_FIELD_EVENT_AEROBICS; // mEv_EVENT_SPORTS_FAIR_AEROBICS +} + +extern void mSC_delete_soncho(ACTOR* actor, GAME_PLAY* play) { + u8 event = mSC_get_soncho_event(); + + switch (event) { + case mSC_EVENT_NEW_YEARS_DAY: + { + ACTOR* ev_miko = Actor_info_name_search(&play->actor_info, mAc_PROFILE_EV_MIKO, ACTOR_PART_NPC); + + if (ev_miko != NULL) { + Actor_delete(ev_miko); + } + + break; + } + + case mSC_EVENT_FOUNDERS_DAY: + case mSC_EVENT_GRADUATION_DAY: + case mSC_EVENT_APRILFOOLS_DAY: + case mSC_EVENT_TOWN_DAY: + case mSC_EVENT_MOTHERS_DAY: + case mSC_EVENT_SALE_DAY: + case mSC_EVENT_CHERRY_BLOSSOM_FESTIVAL: + case mSC_EVENT_NATURE_DAY: + case mSC_EVENT_SPRING_CLEANING: + case mSC_EVENT_FATHERS_DAY: + case mSC_EVENT_FISHING_TOURNEY_1: + case mSC_EVENT_GROUNDHOG_DAY: + case mSC_EVENT_EXPLORERS_DAY: + case mSC_EVENT_FIREWORKS_SHOW: + case mSC_EVENT_METEOR_SHOWER: + case mSC_EVENT_HARVEST_MOON_FESTIVAL: + case mSC_EVENT_MAYORS_DAY: + case mSC_EVENT_OFFICERS_DAY: + case mSC_EVENT_HALLOWEEN: + case mSC_EVENT_FISHING_TOURNEY_2: + case mSC_EVENT_SNOW_DAY: + case mSC_EVENT_LABOR_DAY: + case mSC_EVENT_TOY_DAY: + case mSC_EVENT_NEW_YEARS_EVE_COUNTDOWN: + case mSC_EVENT_HARVEST_FESTIVAL: + { + mEv_actor_dying_message(event_table[event], actor); + break; + } + + case mSC_EVENT_SPRING_SPORTS_FAIR: + case mSC_EVENT_FALL_SPORTS_FAIR: + { + if (mEv_check_status(mEv_EVENT_SPORTS_FAIR_BALL_TOSS, mEv_STATUS_SHOW)) { + mEv_actor_dying_message(mEv_EVENT_SPORTS_FAIR_BALL_TOSS, actor); + } + else if (mEv_check_status(mEv_EVENT_SPORTS_FAIR_FOOT_RACE, mEv_STATUS_SHOW)) { + mEv_actor_dying_message(mEv_EVENT_SPORTS_FAIR_FOOT_RACE, actor); + } + else if (mEv_check_status(mEv_EVENT_SPORTS_FAIR_TUG_OF_WAR, mEv_STATUS_SHOW)) { + mEv_actor_dying_message(mEv_EVENT_SPORTS_FAIR_TUG_OF_WAR, actor); + } + + break; + } + + case mSC_SPECIAL_EVENT_JAN_VACATION: + { + mEv_actor_dying_message(mEv_EVENT_SONCHO_VACATION_JANUARY, actor); + break; + } + + case mSC_SPECIAL_EVENT_FEB_VACATION: + { + mEv_actor_dying_message(mEv_EVENT_SONCHO_VACATION_FEBRUARY, actor); + break; + } + + case 0xFF: + { + break; + } + } +} + +extern int mSC_trophy_get(u8 num) { + int res = FALSE; + + if (num <= mSC_TROPHY_MAX) { + if (num >= mSC_EVENT_NUM) { + if ((Common_Get(now_private)->soncho_trophy_field1 & (1 << (u8)(num - mSC_EVENT_NUM))) != 0) { + res = TRUE; + } + } + else if ((Common_Get(now_private)->soncho_trophy_field0 & (1 << num)) != 0) { + res = TRUE; + } + } + + return res; +} + +extern void mSC_trophy_set(u8 num) { + if (num > mSC_TROPHY_MAX) { + return; + } + + if (num >= mSC_EVENT_NUM) { + Common_Get(now_private)->soncho_trophy_field1 |= (1 << (u8)(num - mSC_EVENT_NUM)); + } + else { + Common_Get(now_private)->soncho_trophy_field0 |= (1 << num); + } +} + +extern mActor_name_t mSC_trophy_item(u8 soncho_event) { + static mActor_name_t soncho_item_table[mSC_EVENT_NUM] = { + ITM_FOOD_APPLE, // mSC_EVENT_NEW_YEARS_DAY + FTR_WEED_MODEL, // mSC_EVENT_FOUNDERS_DAY + FTR_NEEDLEWORK_MODEL, // mSC_EVENT_GRADUATION_DAY + FTR_SUPER_TORTIMER, // mSC_EVENT_APRILFOOLS_DAY + ITM_FOOD_APPLE, // mSC_EVENT_TOWN_DAY + FTR_LOVELY_PHONE, // mSC_EVENT_MOTHERS_DAY + FTR_MARKET_MODEL, // mSC_EVENT_SALE_DAY + FTR_PINK_TREE_MODEL, // mSC_EVENT_CHERRY_BLOSSOM_FESTIVAL + FTR_SPRING_MEDAL, // mSC_EVENT_SPRING_SPORTS_FAIR + FTR_TREE_MODEL, // mSC_EVENT_NATURE_DAY + FTR_DUMP_MODEL, // mSC_EVENT_SPRING_CLEANING + FTR_LOCOMOTIVE_MODEL, // mSC_EVENT_FATHERS_DAY + FTR_ANGLER_TROPHY, // mSC_EVENT_FISHING_TOURNEY_1 + ITM_FOOD_PEAR, // mSC_EVENT_GROUNDHOG_DAY + FTR_BOTTLED_SHIP, // mSC_EVENT_EXPLORERS_DAY + FTR_BOTTLE_ROCKET, // mSC_EVENT_FIREWORKS_SHOW + FTR_TELESCOPE, // mSC_EVENT_METEOR_SHOWER + FTR_MOON, // mSC_EVENT_HARVEST_MOON_FESTIVAL + FTR_WELL_MODEL, // mSC_EVENT_MAYORS_DAY + FTR_POLICE_MODEL, // mSC_EVENT_OFFICERS_DAY + FTR_AUTUMN_MEDAL, // mSC_EVENT_FALL_SPORTS_FAIR + FTR_FORTUNE_TENT_MODEL, // mSC_EVENT_HALLOWEEN + FTR_FISHING_TROPHY, // mSC_EVENT_FISHING_TOURNEY_2 + FTR_SNOWMAN, // mSC_EVENT_SNOW_DAY + FTR_SHOP_MDOEL, // mSC_EVENT_LABOR_DAY + ITM_FOOD_APPLE, // mSC_EVENT_TOY_DAY + FTR_NOISEMAKER, // mSC_EVENT_NEW_YEARS_EVE_COUNTDOWN + FTR_CORNUCOPIA // mSC_EVENT_HARVEST_FESTIVAL + }; + + mActor_name_t item = ITM_FOOD_APPLE; + + if (soncho_event < mSC_EVENT_NUM) { + switch (soncho_event) { + case mSC_EVENT_NEW_YEARS_DAY: + { + /* @BUG - devs have another off-by-one error here, as there are 16 diaries but this can only generate the first 15 */ + #ifndef BUGFIXES + item = (RANDOM(DIARY_NUM-1) & 15) + ITM_DIARY_START; + #else + item = RANDOM(DIARY_NUM) + ITM_DIARY_START; + #endif + break; + } + + case mSC_EVENT_TOY_DAY: + { + if (Common_Get(now_private)->gender == mPr_SEX_MALE) { + item = FTR_MINI_CAR; + } + else { + item = FTR_DOLLY; + } + break; + } + + case mSC_EVENT_TOWN_DAY: + { + item = mSP_GetRandomStationToyItemNo(); + break; + } + + case mSC_EVENT_GROUNDHOG_DAY: + { + item = mRmTp_FtrIdx2FtrItemNo(0x4DE + RANDOM(9), mRmTp_DIRECT_SOUTH); // random flower model + break; + } + + case mSC_EVENT_FOUNDERS_DAY: + case mSC_EVENT_GRADUATION_DAY: + case mSC_EVENT_APRILFOOLS_DAY: + case mSC_EVENT_MOTHERS_DAY: + case mSC_EVENT_SALE_DAY: + case mSC_EVENT_CHERRY_BLOSSOM_FESTIVAL: + case mSC_EVENT_SPRING_SPORTS_FAIR: + case mSC_EVENT_NATURE_DAY: + case mSC_EVENT_SPRING_CLEANING: + case mSC_EVENT_FATHERS_DAY: + case mSC_EVENT_FISHING_TOURNEY_1: + case mSC_EVENT_EXPLORERS_DAY: + case mSC_EVENT_FIREWORKS_SHOW: + case mSC_EVENT_METEOR_SHOWER: + case mSC_EVENT_HARVEST_MOON_FESTIVAL: + case mSC_EVENT_MAYORS_DAY: + case mSC_EVENT_OFFICERS_DAY: + case mSC_EVENT_FALL_SPORTS_FAIR: + case mSC_EVENT_HALLOWEEN: + case mSC_EVENT_FISHING_TOURNEY_2: + case mSC_EVENT_SNOW_DAY: + case mSC_EVENT_LABOR_DAY: + default: + { + item = soncho_item_table[soncho_event]; + break; + } + } + } + + return item; +} + +extern void mSC_item_string_set(mActor_name_t item, int str_no) { + u8 item_name[mIN_ITEM_NAME_LEN]; + mMsg_Window_c* window = mMsg_Get_base_window_p(); + + mIN_copy_name_str(item_name, item); + mMsg_Set_item_str_art(window, str_no, item_name, mIN_ITEM_NAME_LEN, mIN_get_item_article(item)); +} + +extern void mSC_get_event_name_str(u8* buf, int buf_len, int soncho_event) { + static int chg_string_idx[mSC_EVENT_NUM + 1] = { + 0, // New Year's Day + 14, // Founder's Day + 8, // Graduation Day + 3, // April Fools' Day + 11, // "Town" Day + 7, // Mother's Day + 24, // Sale Day + 4, // Cherry Festival + 2, // Sports Fair + 5, // Nature Day + 6, // Spring Cleaning + 9, // Father's Day + 10, // Fishing Tourney + 1, // Groundhog Day + 18, // Explorer's Day + 12, // Fireworks Show + 13, // Meteor Shower + 17, // Harvest Moon + 20, // Mayor's Day + 21, // Officer's Day + 16, // Sports Fair + 19, // Halloween + 22, // Fishing Tourney + 25, // Snow Day + 15, // Labor Day + 26, // Toy Day + 27, // New Year's Eve + 23, // Harvest Festival + 28 // birthday + }; + + mString_Load_StringFromRom(buf, buf_len, mString_SONCHO_EVENT_NAME_START + chg_string_idx[soncho_event & 0x7F]); +} + +extern void mSC_event_name_set(u8 soncho_event) { + u8 event_name_buf[mIN_ITEM_NAME_LEN]; + int ofs = 0; // for town day name + + if (soncho_event < mSC_EVENT_NUM) { + if (soncho_event == mSC_EVENT_TOWN_DAY) { + mLd_CopyLandName(event_name_buf, Save_Get(land_info).name); + ofs = mMl_strlen(event_name_buf, LAND_NAME_SIZE, CHAR_SPACE); + } + + mSC_get_event_name_str(event_name_buf + ofs, mIN_ITEM_NAME_LEN - ofs, soncho_event); + mMsg_Set_item_str(mMsg_Get_base_window_p(), mMsg_ITEM_STR1, event_name_buf, mIN_ITEM_NAME_LEN); + } +} + +extern void mSC_set_free_str_number(int free_str_no, u32 num) { + u8 number[mIN_ITEM_NAME_LEN]; + int fig; + + if (num >= 100) { + fig = 3; + } + else if (num >= 10) { + fig = 2; + } + else { + fig = 1; + } + + mFont_UnintToString(number, 3, num, fig, TRUE, FALSE, TRUE); + mMsg_Set_free_str(mMsg_Get_base_window_p(), free_str_no, number, fig); +} + +static int mSC_Radio_many_taisou_card() { + int i; + int cards; + Private_c* priv = Common_Get(now_private); + + for (i = 0, cards = 0; i < 13; i++) { + cards += mPr_GetPossessionItemSumWithCond(priv, ITM_EXCERCISE_CARD00 + i, mPr_ITEM_COND_NORMAL); + } + + return cards; +} + +static mActor_name_t mSC_Radio_have_taisou_card() { + int i; + Private_c* priv = Common_Get(now_private); + + for (i = 0; i < 13; i++) { + if (mPr_GetPossessionItemSumWithCond(priv, ITM_EXCERCISE_CARD00 + i, mPr_ITEM_COND_NORMAL) > 0) { + return ITM_EXCERCISE_CARD00 + i; + } + } + + return ITM_EXCERCISE_CARD00; +} + +static int mSC_Radio_time_check() { + Private_c* priv = Common_Get(now_private); + int equal_date; + + if (Common_Get(time.rtc_time).year != priv->radiocard.last_date.year) { + return 0; + } + + equal_date = lbRTC_IsEqualDate( + Common_Get(time.rtc_time).year, Common_Get(time.rtc_time).month, Common_Get(time.rtc_time).day, + priv->radiocard.last_date.year, priv->radiocard.last_date.month, priv->radiocard.last_date.day + ); + + switch (equal_date) { + case lbRTC_LESS: + return mSC_RADIO_TIME_LESS; + case lbRTC_EQUAL: + return mSC_RADIO_TIME_SAME_DAY; + case lbRTC_OVER: + return mSC_RADIO_TIME_OVER; + default: + return mSC_RADIO_TIME_LESS; + } +} + +static int mSC_Radio_limit_check() { + if (Common_Get(time.rtc_time).month >= lbRTC_AUGUST && Common_Get(time.rtc_time).day >= 19) { + return FALSE; + } + + return TRUE; +} + +static void mSC_Radio_delete_taisou_card() { + int i; + Private_c* priv = Common_Get(now_private); + + for (i = 0; i < 13; i++) { + int idx = mPr_GetPossessionItemIdxWithCond(priv, ITM_EXCERCISE_CARD00 + i, mPr_ITEM_COND_NORMAL); + + while (idx != -1) { + mPr_SetPossessionItem(Common_Get(now_private), idx, EMPTY_NO, mPr_ITEM_COND_NORMAL); // probably a macro + idx = mPr_GetPossessionItemIdxWithCond(priv, ITM_EXCERCISE_CARD00 + i, mPr_ITEM_COND_NORMAL); + } + } +} + +static void mSC_Radio_change_taisou_card(mActor_name_t old_card, mActor_name_t new_card) { + Private_c* priv = Common_Get(now_private); + int idx = mPr_GetPossessionItemIdxWithCond(priv, old_card, mPr_ITEM_COND_NORMAL); + + if (idx != -1) { + mPr_SetPossessionItem(Common_Get(now_private), idx, new_card, mPr_ITEM_COND_NORMAL); // again, probably a macro + } +} + +static void mSC_Radio_stamp_card(lbRTC_day_t days) { + const lbRTC_time_c* rtc_time = Common_GetPointer(time.rtc_time); + mPr_day_day_c* radiocard = &Common_Get(now_private)->radiocard; + + radiocard->last_date.year = rtc_time->year; + radiocard->last_date.month = rtc_time->month; + radiocard->last_date.day = rtc_time->day; + radiocard->days = days; +} + +static int mSC_Radio_msg(TAISOU_NPC0_ACTOR* taisou_actor, int idx) { + return 0x3280 + taisou_actor->soncho_event * 10 + idx; +} + +extern int mSC_Radio_Set_Talk_Proc(TAISOU_NPC0_ACTOR* taisou_actor) { + u8 item_name[mIN_ITEM_NAME_LEN]; + mPr_day_day_c* radiocard = &Common_Get(now_private)->radiocard; + int msg_no; + + taisou_actor->talk_proc = mSCR_TALK_9; + if (taisou_actor->soncho_event == mSC_SPECIAL_EVENT_MORNING_AEROBICS) { + int time_check = mSC_Radio_time_check(); + int num_cards = mSC_Radio_many_taisou_card(); + mActor_name_t card; + int article; + + if (Common_Get(player_no) == mPr_FOREIGNER) { + msg_no = 0x343B; + } + else if (time_check == mSC_RADIO_TIME_SAME_DAY) { + msg_no = 0x3433; + taisou_actor->talk_state = 18 + RANDOM(3); + taisou_actor->talk_proc = mSCR_TALK_NEXT; + } + else { + int action = mSCR_ACTION_TOO_LATE; + + if (num_cards <= 0) { + int limit_check = mSC_Radio_limit_check(); + + if (limit_check == FALSE && (radiocard->days == mSC_RADIO_DAYS || time_check == mSC_RADIO_TIME_LESS)) { + action = mSCR_ACTION_TOO_LATE; + } + else { + switch (time_check) { + case mSC_RADIO_TIME_LESS: + action = mSCR_ACTION_NEW_CARD; + break; + + case mSC_RADIO_TIME_OVER: + { + if (radiocard->days == (mSC_RADIO_DAYS - 1)) { + action = mSCR_ACTION_LOST_CARD_AND_FINISH; + } + else if (radiocard->days < mSC_RADIO_DAYS) { + action = mSCR_ACTION_LOST_CARD; + } + else { + action = mSCR_ACTION_NEW_CARD; + } + break; + } + } + } + } + else if (num_cards > 1) { + action = mSCR_ACTION_DELETE_OLD_CARD; + } + else { + card = mSC_Radio_have_taisou_card(); + + switch (time_check) { + case mSC_RADIO_TIME_LESS: + action = mSCR_ACTION_DELETE_OLD_CARD; + break; + + case mSC_RADIO_TIME_SAME_DAY: + break; + + case mSC_RADIO_TIME_OVER: + { + radiocard->days = card - ITM_EXCERCISE_CARD00; + radiocard->days++; + + if (radiocard->days >= mSC_RADIO_DAYS) { + action = mSCR_ACTION_FINISH_CARD; + } + else { + action = mSCR_ACTION_STAMP_CARD; + } + + break; + } + } + } + + switch (action) { + case mSCR_ACTION_TOO_LATE: + { + msg_no = 0x3437; + taisou_actor->talk_state = 22 + RANDOM(3); + taisou_actor->talk_proc = mSCR_TALK_NEXT; + break; + } + + case mSCR_ACTION_DELETE_OLD_CARD: + { + taisou_actor->talk_proc = mSCR_TALK_PICKUP_ALL; + msg_no = 0x343C; + mSC_Radio_delete_taisou_card(); + break; + } + + case mSCR_ACTION_NEW_CARD: + { + taisou_actor->talk_state = mSCR_TALK_NEXT_INSPECTION; + msg_no = 0x3422; + + if ( + mCD_calendar_event_check( + Common_Get(time.rtc_time).year, Common_Get(time.rtc_time).month, Common_Get(time.rtc_time).day, + -1, taisou_actor->soncho_event + ) + ) { + msg_no = 0x3423; + } + + if ((u32)mPr_GetPossessionItemSumWithCond(Common_Get(now_private), EMPTY_NO, mPr_ITEM_COND_NORMAL) == 0) { + taisou_actor->talk_proc = mSCR_TALK_NEXT; + } + else { + taisou_actor->talk_proc = mSCR_TALK_NEXT_INSPECTION; + taisou_actor->held_item = ITM_EXCERCISE_CARD00; + mPr_SetFreePossessionItem(Common_Get(now_private), ITM_EXCERCISE_CARD00, mPr_ITEM_COND_NORMAL); + mSC_Radio_stamp_card(0); + taisou_actor->talk_state++; + } + + break; + } + + case mSCR_ACTION_LOST_CARD: + { + taisou_actor->talk_state = 14; + msg_no = 0x342E; + mSC_set_free_str_number(mMsg_FREE_STR0, radiocard->days + 2); + + if ( + mCD_calendar_event_check( + Common_Get(time.rtc_time).year, Common_Get(time.rtc_time).month, Common_Get(time.rtc_time).day, + -1, taisou_actor->soncho_event + ) + ) { + msg_no = 0x342F; + } + + if ((u32)mPr_GetPossessionItemSumWithCond(Common_Get(now_private), EMPTY_NO, mPr_ITEM_COND_NORMAL) == 0) { + taisou_actor->talk_proc = mSCR_TALK_NEXT; + } + else { + taisou_actor->talk_proc = mSCR_TALK_NEXT_INSPECTION; + radiocard->days++; + taisou_actor->held_item = ITM_EXCERCISE_CARD00 + radiocard->days; + mPr_SetFreePossessionItem(Common_Get(now_private), taisou_actor->held_item, mPr_ITEM_COND_NORMAL); + mSC_Radio_stamp_card(radiocard->days); + taisou_actor->talk_state++; + } + + break; + } + + case mSCR_ACTION_STAMP_CARD: + { + taisou_actor->talk_proc = mSCR_TALK_INSPECTION; + card = mSC_Radio_have_taisou_card(); + mSC_Radio_stamp_card(radiocard->days); + mSC_Radio_change_taisou_card(card, ITM_EXCERCISE_CARD00 + radiocard->days); + mSC_set_free_str_number(mMsg_FREE_STR0, radiocard->days + 1); + taisou_actor->talk_state = mSCR_TALK_NEXT; + msg_no = 0x3427; + + break; + } + + case mSCR_ACTION_FINISH_CARD: + { + taisou_actor->talk_proc = mSCR_TALK_INSPECTION; + card = mSC_Radio_have_taisou_card(); + mSC_Radio_stamp_card(radiocard->days); + taisou_actor->held_item = FTR_AEROBICS_RADIO; + mSC_Radio_change_taisou_card(card, taisou_actor->held_item); + mIN_copy_name_str(item_name, taisou_actor->held_item); + article = mIN_get_item_article(taisou_actor->held_item); + mMsg_Set_free_str_art(mMsg_Get_base_window_p(), mMsg_FREE_STR1, item_name, mIN_ITEM_NAME_LEN, article); + taisou_actor->talk_state = 9; + msg_no = 0x342A; + + break; + } + + case mSCR_ACTION_LOST_CARD_AND_FINISH: + { + taisou_actor->talk_state = 28; + msg_no = 0x342E; + mSC_set_free_str_number(mMsg_FREE_STR0, radiocard->days + 2); + + if ( + mCD_calendar_event_check( + Common_Get(time.rtc_time).year, Common_Get(time.rtc_time).month, Common_Get(time.rtc_time).day, + -1, taisou_actor->soncho_event + ) + ) { + msg_no = 0x342F; + } + + if ((u32)mPr_GetPossessionItemSumWithCond(Common_Get(now_private), EMPTY_NO, mPr_ITEM_COND_NORMAL) == 0) { + taisou_actor->talk_proc = mSCR_TALK_NEXT; + } + else { + taisou_actor->talk_proc = mSCR_TALK_NEXT_INSPECTION; + radiocard->days++; + taisou_actor->held_item = FTR_AEROBICS_RADIO; + mPr_SetFreePossessionItem(Common_Get(now_private), taisou_actor->held_item, mPr_ITEM_COND_NORMAL); + mIN_copy_name_str(item_name, taisou_actor->held_item); + article = mIN_get_item_article(taisou_actor->held_item); + mMsg_Set_free_str_art(mMsg_Get_base_window_p(), mMsg_FREE_STR1, item_name, mIN_ITEM_NAME_LEN, article); + mSC_Radio_stamp_card(radiocard->days); + taisou_actor->talk_state--; + } + + break; + } + + default: + { + msg_no = 0x3437; + taisou_actor->talk_state = 22 + RANDOM(3); + taisou_actor->talk_proc = mSCR_TALK_NEXT; + break; + } + } + } + } + else if (Common_Get(player_no) == mPr_FOREIGNER) { + msg_no = mSC_Radio_msg(taisou_actor, 9); + taisou_actor->talk_proc = mSCR_TALK_8; + } + else if (mSC_trophy_get(taisou_actor->soncho_event) != FALSE) { + if ( + mCD_calendar_event_check( + Common_Get(time.rtc_time).year, Common_Get(time.rtc_time).month, Common_Get(time.rtc_time).day, + -1, taisou_actor->soncho_event + ) + ) { + msg_no = mSC_Radio_msg(taisou_actor, 6 + RANDOM(3)); + } + else { + msg_no = mSC_Radio_msg(taisou_actor, 5); + } + + taisou_actor->talk_proc = mSCR_TALK_7; + } + else { + taisou_actor->talk_proc = mSCR_TALK_BEFORE_GIVE; + + if ( + mCD_calendar_event_check( + Common_Get(time.rtc_time).year, Common_Get(time.rtc_time).month, Common_Get(time.rtc_time).day, + -1, taisou_actor->soncho_event + ) + ) { + msg_no = mSC_Radio_msg(taisou_actor, 1); + } + else { + msg_no = mSC_Radio_msg(taisou_actor, 0); + } + } + + return msg_no; +} + +static void mSCR_talk_pickup_all(TAISOU_NPC0_ACTOR* taisou_actor, GAME_PLAY* play) { + switch (mDemo_Get_OrderValue(mDemo_ORDER_NPC0, 9)) { + case 1: + { + mPlib_request_main_give_type1(play, ITM_EXCERCISE_CARD00, 7, FALSE, FALSE); + mDemo_Set_OrderValue(mDemo_ORDER_NPC0, 9, 2); + mMsg_Set_LockContinue(mMsg_Get_base_window_p()); + mDemo_Set_OrderValue(mDemo_ORDER_NPC0, 1, 3); + break; + } + + case 2: + { + if (Common_Get(clip).handOverItem_clip->master_actor == NULL) { + mMsg_Unset_LockContinue(mMsg_Get_base_window_p()); + mDemo_Set_OrderValue(mDemo_ORDER_NPC0, 9, 0); + taisou_actor->talk_proc = mSCR_TALK_9; + } + + break; + } + } +} + +static void mSCR_talk_inspection(TAISOU_NPC0_ACTOR* taisou_actor, GAME_PLAY* play) { + int order = mDemo_Get_OrderValue(mDemo_ORDER_NPC0, 9); + mMsg_Window_c* msg_win = mMsg_Get_base_window_p(); + mPr_day_day_c* radiocard = &Common_Get(now_private)->radiocard; + + switch (order) { + case 1: + { + mPlib_request_main_give_type1(play, ITM_EXCERCISE_CARD00, 8, FALSE, FALSE); + mDemo_Set_OrderValue(mDemo_ORDER_NPC0, 9, 2); + mDemo_Set_OrderValue(mDemo_ORDER_NPC0, 1, 3); + mMsg_Set_continue_msg_num(msg_win, 0x3422 + taisou_actor->talk_state); + taisou_actor->talk_state++; + break; + } + + case 2: + { + if (Common_Get(clip).handOverItem_clip->request_mode == aHOI_REQUEST_TRANS_WAIT) { + mDemo_Set_OrderValue(mDemo_ORDER_NPC0, 1, 3); + Common_Get(clip).handOverItem_clip->player_after_mode = 8; + mDemo_Set_OrderValue(mDemo_ORDER_NPC0, 9, 3); + mMsg_Unset_LockContinue(msg_win); + taisou_actor->npc_actor_class.talk_base_anim_id = 30; + } + break; + } + + case 3: + { + if ((mMsg_Get_msg_num(msg_win) == 0x342B || mMsg_Get_msg_num(msg_win) == 0x3428) && mMsg_Check_MainNormalContinue(msg_win)) { + mDemo_Set_OrderValue(mDemo_ORDER_NPC0, 9, 4); + mMsg_Set_LockContinue(mMsg_Get_base_window_p()); + } + + break; + } + + case 4: + { + if (Common_Get(clip).handOverItem_clip->master_actor == NULL) { + taisou_actor->npc_actor_class.talk_base_anim_id = -1; + mDemo_Set_OrderValue(mDemo_ORDER_NPC0, 9, 0); + + if (radiocard->days >= mSC_RADIO_DAYS) { + taisou_actor->talk_proc = mSCR_TALK_NEWCARD; + } + else { + taisou_actor->talk_proc = mSCR_TALK_9; + } + + mMsg_Unset_LockContinue(msg_win); + mMsg_Set_continue_msg_num(msg_win, 0x3422 + taisou_actor->talk_state); + taisou_actor->talk_state++; + } + + break; + } + } +} + +static void mSCR_talk_newcard(TAISOU_NPC0_ACTOR* taisou_actor, GAME_PLAY* play) { + int order = mDemo_Get_OrderValue(mDemo_ORDER_NPC0, 1); + mMsg_Window_c* msg_win = mMsg_Get_base_window_p(); + + if (order == 2) { + mDemo_Set_OrderValue(mDemo_ORDER_NPC1, 0, taisou_actor->held_item); + mDemo_Set_OrderValue(mDemo_ORDER_NPC1, 1, 7); + mDemo_Set_OrderValue(mDemo_ORDER_NPC1, 2, 0); + + if (taisou_actor->talk_state == 28) { + mMsg_Set_continue_msg_num(msg_win, 0x342D); /* dialog after giving aerobics radio */ + } + else { + mMsg_Set_continue_msg_num(msg_win, 0x3422 + taisou_actor->talk_state); + taisou_actor->talk_state++; + } + + taisou_actor->talk_proc = mSCR_TALK_9; + } +} + +static void mSCR_talk_before_give(TAISOU_NPC0_ACTOR* taisou_actor, GAME_PLAY* play) { + mMsg_Window_c* msg_win = mMsg_Get_base_window_p(); + + if (mMsg_Check_MainNormalContinue(msg_win)) { + if ((u32)mPr_GetPossessionItemSumWithCond(Common_Get(now_private), EMPTY_NO, mPr_ITEM_COND_NORMAL) == 0) { + mMsg_Set_continue_msg_num(msg_win, mSC_Radio_msg(taisou_actor, 2)); + taisou_actor->talk_proc = mSCR_TALK_9; + } + else { + mMsg_Set_continue_msg_num(msg_win, mSC_Radio_msg(taisou_actor, 3)); + taisou_actor->talk_proc = mSCR_TALK_GIVE; + } + } +} + +static void mSCR_talk_give(TAISOU_NPC0_ACTOR* taisou_actor, GAME_PLAY* play) { + int order = mDemo_Get_OrderValue(mDemo_ORDER_NPC0, 1); + + if (order == 2) { + mActor_name_t trophy_item = mSC_trophy_item(taisou_actor->soncho_event); + + mSC_item_string_set(trophy_item, mMsg_ITEM_STR0); + mDemo_Set_OrderValue(mDemo_ORDER_NPC1, 0, trophy_item); + mDemo_Set_OrderValue(mDemo_ORDER_NPC1, 1, 7); + mDemo_Set_OrderValue(mDemo_ORDER_NPC1, 2, 0); + mPr_SetFreePossessionItem(Common_Get(now_private), trophy_item, mPr_ITEM_COND_NORMAL); + mSC_trophy_set(taisou_actor->soncho_event); + taisou_actor->talk_proc = mSCR_TALK_9; + } +} + +static void mSCR_talk_next(TAISOU_NPC0_ACTOR* taisou_actor, GAME_PLAY* play) { + mMsg_Window_c* msg_win = mMsg_Get_base_window_p(); + + if (mMsg_Check_MainNormalContinue(msg_win)) { + mMsg_Set_continue_msg_num(msg_win, 0x3422 + taisou_actor->talk_state); + taisou_actor->talk_proc++; + taisou_actor->talk_state++; + } +} + +typedef void (*mSCR_TALK_PROC)(TAISOU_NPC0_ACTOR*, GAME_PLAY*); + +extern mSC_Radio_Talk_Proc(TAISOU_NPC0_ACTOR* taisou_actor, GAME_PLAY* play) { + static mSCR_TALK_PROC proc[mSCR_TALK_NUM] = { + &mSCR_talk_pickup_all, + &mSCR_talk_inspection, + &mSCR_talk_next, + &mSCR_talk_newcard, + &mSCR_talk_before_give, + &mSCR_talk_give, + &mSCR_talk_next, + (mSCR_TALK_PROC)&none_proc1, + (mSCR_TALK_PROC)&none_proc1, + (mSCR_TALK_PROC)&none_proc1 + }; + + (*proc[taisou_actor->talk_proc])(taisou_actor, play); +} + +extern int mSC_LightHouse_get_period(lbRTC_time_c* time) { + lbRTC_time_c lh_start_time; + lbRTC_time_c lh_end_time; + lbRTC_time_c lh_max_time; + lbRTC_ymd_c* renew_time = &Save_Get(LightHouse).renew_time; + int equal; + + if (Save_Get(LightHouse).renew_time.day == 0) { + return mSC_LIGHTHOUSE_PERIOD_NONE; + } + + mTM_ymd_2_time(&lh_start_time, renew_time); + lbRTC_TimeCopy(&lh_end_time, &lh_start_time); + lbRTC_Add_DD(&lh_end_time, lbRTC_WEEK); + lbRTC_TimeCopy(&lh_max_time, &lh_start_time); + lbRTC_Add_DD(&lh_max_time, mSC_LIGHTHOUSE_DAYS); + + equal = lbRTC_IsEqualDate( + lh_start_time.year, lh_start_time.month, lh_start_time.day, + time->year, time->month, time->day + ); + + if (equal == lbRTC_OVER) { + return mSC_LIGHTHOUSE_PERIOD_NONE; // start date is after the current date (time travelled backwards) + } + + if (equal == lbRTC_EQUAL) { + return mSC_LIGHTHOUSE_PERIOD_0; // start date is current date + } + + if ( + lbRTC_IsEqualDate( + lh_end_time.year, lh_end_time.month, lh_end_time.day, + time->year, time->month, time->day + ) != lbRTC_LESS + ) { + return mSC_LIGHTHOUSE_PERIOD_1; + } + else if (lbRTC_IsEqualDate( + lh_max_time.year, lh_max_time.month, lh_max_time.day, + time->year, time->month, time->day + ) != lbRTC_LESS + ) { + return mSC_LIGHTHOUSE_PERIOD_2; + } + + return mSC_LIGHTHOUSE_PERIOD_NONE; +} + +extern int mSC_LightHouse_day(const lbRTC_time_c* time) { + lbRTC_time_c lh_start_time; + int days; + lbRTC_ymd_c* renew_time = &Save_Get(LightHouse).renew_time; + + if (Save_Get(LightHouse).renew_time.day == 0) { + return 0; + } + + mTM_ymd_2_time(&lh_start_time, renew_time); + + if (lbRTC_IsOverTime(&lh_start_time, time) == lbRTC_LESS) { + return 0; + } + + days = lbRTC_GetIntervalDays(&lh_start_time, time) - 1; + + if (days < 0) { + return 0; + } + + return days <= (lbRTC_WEEK - 1) ? days : (lbRTC_WEEK - 1); +} + +extern int mSC_LightHouse_Event_Check(int player_no) { + LightHouse_c* lh = Save_GetPointer(LightHouse); + + if (player_no == -1) { + player_no = Common_Get(player_no); + } + + if (player_no >= mPr_FOREIGNER) { + return 0; + } + + if (mSC_LightHouse_get_period(Common_GetPointer(time.rtc_time)) != mSC_LIGHTHOUSE_PERIOD_2) { + return 0; + } + + if ((lh->players_completed & (1 << player_no)) != 0) { + return 0; + } + + if ((lh->days_switched_on & 0x7F) == 0x7F) { + if ((lh->players_quest_started & (u8)(1 << (player_no + 4))) != 0) { + if (lh->renew_time.month == lbRTC_JANUARY) { + return 1; + } + else { + return 3; + } + } + } + else if ((lh->players_quest_started & (u8)(1 << Common_Get(player_no))) != 0) { + if (lh->renew_time.month == lbRTC_JANUARY) { + return 2; + } + else { + return 4; + } + } + + return 0; +} + +extern void mSC_LightHouse_Event_Clear(int player_no) { + LightHouse_c* lh = Save_GetPointer(LightHouse); + + if (player_no == -1) { + player_no = Common_Get(player_no); + } + + if (player_no < mPr_FOREIGNER) { + int check; + + lh->players_completed |= (1 << player_no); + check = mSC_LightHouse_Event_Check(player_no); + + if (check == 2 || check == 4) { + lh->players_completed |= 0b1111; + } + } +} + +extern mActor_name_t mSC_LightHouse_Event_Present_Item() { + if (Save_Get(LightHouse).renew_time.month == lbRTC_JANUARY) { + return FTR_LIGHTHOUSE_MODEL; + } + + return FTR_CHOCOLATES; +} + +static void mSC_LightHouse_clear_data() { + mem_clear((u8*)Save_GetPointer(LightHouse), sizeof(LightHouse_c), 0); +} + +extern int mSC_LightHouse_Event_Start() { + LightHouse_c* lh = Save_GetPointer(LightHouse); + lbRTC_time_c* rtc_time = Common_GetPointer(time.rtc_time); + + if (lh->renew_time.day == 0) { + return TRUE; + } + + if (mSC_LightHouse_get_period(rtc_time) != mSC_LIGHTHOUSE_PERIOD_NONE) { + return FALSE; + } + + mSC_LightHouse_clear_data(); + return TRUE; +} + +extern int mSC_LightHouse_Talk_After_Check() { + LightHouse_c* lh = Save_GetPointer(LightHouse); + lbRTC_time_c* rtc_time = Common_GetPointer(time.rtc_time); + + if (mSC_LightHouse_get_period(rtc_time) == mSC_LIGHTHOUSE_PERIOD_NONE) { + return FALSE; + } + + return (lh->players_quest_started & 0b1111) != 0; +} + +extern void mSC_LightHouse_Quest_Start() { + LightHouse_c* lh = Save_GetPointer(LightHouse); + lbRTC_time_c* rtc_time = Common_GetPointer(time.rtc_time); + + mSC_LightHouse_clear_data(); + mTM_set_renew_time(&lh->renew_time, rtc_time); + lh->players_quest_started |= (u8)(1 << Common_Get(player_no)); +} + +extern int mSC_LightHouse_Switch_Check() { + lbRTC_time_c adjusted_rtc_time; + LightHouse_c* lh = Save_GetPointer(LightHouse); + lbRTC_time_c* rtc_time = Common_GetPointer(time.rtc_time); + int day; + + lbRTC_TimeCopy(&adjusted_rtc_time, rtc_time); + lbRTC_Sub_hh(&adjusted_rtc_time, 6); + + if (lh->renew_time.day == 0) { + return TRUE; + } + + if (mSC_LightHouse_get_period(&adjusted_rtc_time) != mSC_LIGHTHOUSE_PERIOD_1) { + return TRUE; + } + + day = mSC_LightHouse_day(&adjusted_rtc_time); + return (lh->days_switched_on & (1 << day)) != 0; +} + +extern int mSC_LightHouse_In_Check() { + lbRTC_time_c time; + LightHouse_c* lh = Save_GetPointer(LightHouse); + lbRTC_time_c* rtc_time = Common_GetPointer(time.rtc_time); + int day; + + if (Common_Get(player_no) >= mPr_FOREIGNER) { + return FALSE; + } + + if (mEv_CheckFirstJob() != FALSE) { + return FALSE; + } + + lbRTC_TimeCopy(&time, rtc_time); + + if (lh->renew_time.day == 0) { + return FALSE; + } + + if (mSC_LightHouse_get_period(&time) != mSC_LIGHTHOUSE_PERIOD_1) { + return FALSE; + } + + if (time.hour < 18 || time.hour >= 22) { + return FALSE; + } + + day = mSC_LightHouse_day(&time); + return (lh->days_switched_on & (1 << day)) == 0; +} + +extern void mSC_LightHouse_Switch_On() { + LightHouse_c* lh = Save_GetPointer(LightHouse); + lbRTC_time_c* rtc_time = Common_GetPointer(time.rtc_time); + int day; + int player_no; + + day = mSC_LightHouse_day(rtc_time); + lh->days_switched_on |= (1 << day); + player_no = Common_Get(player_no); + + if (player_no < mPr_FOREIGNER) { + lh->players_quest_started |= (u8)(1 << (player_no + 4)); + } +} + +extern void mSC_LightHouse_Delete_Player(int player_no) { + Save_Get(LightHouse).players_quest_started &= ~(u8)(1 << (player_no + 4)); +} + +extern int mSC_LightHouse_travel_check() { + switch (mSC_LightHouse_get_period(Common_GetPointer(time.rtc_time))) { + case mSC_LIGHTHOUSE_PERIOD_1: + return TRUE; + default: + return FALSE; + } +} + +extern void mSC_change_player_freeze(GAME_PLAY* play) { + if (mPlib_get_player_actor_main_index(play) != 74) { + mPlib_request_main_demo_wait_type1(play, 0, NULL); + } +} + +extern u32 mSC_check_ArbeitPlayer() { + return mSC_trophy_get(32); +}