diff --git a/.gitignore b/.gitignore index 2caee755..fb77e13a 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,4 @@ tools/cli.ini tools/cli.py src/data/bin1 src/data/bin2 +objdiff.json diff --git a/config/assets.yml b/config/assets.yml index e4843890..22b3210f 100644 --- a/config/assets.yml +++ b/config/assets.yml @@ -142,6 +142,16 @@ config/dol.yml: addrs: [0x800ab260, 0x800af3c0] config/rel.yml: + con_waku_swaku3_tex: # m_choice + addrs: [0x8064F880, 0x80650880] + con_sentaku2_v: + addrs: [0x80650880, 0x806508C0] + type: vtx + # ac_boat_demo + aBTD_island_prg: + addrs: [0x8065FD4C, 0x80674F90] + aBTD_island_ldr: + addrs: [0x80674F90, 0x806817CC] wipe1_v: addrs: [0x80652AD0, 0x80652C60] type: vtx diff --git a/config/rel_slices.yml b/config/rel_slices.yml index 9d408db2..11afc101 100644 --- a/config/rel_slices.yml +++ b/config/rel_slices.yml @@ -51,6 +51,11 @@ m_camera2.c: .text: [0x8037DA54, 0x8038344C] .rodata: [0x80641438, 0x80641828] .data: [0x8064F818, 0x8064F860] +m_choice.c: + .text: [0x8038344C, 0x80385404] + .rodata: [0x80641828, 0x80641A90] + .data: [0x8064F860, 0x80650960] + .bss: [0x812633A0, 0x81263410] m_cockroach.c: .text: [0x80385430, 0x80385A80] m_collision_obj.c: @@ -378,8 +383,13 @@ ac_animal_logo.c: .data: [0x8065FB68, 0x8065FBA8] ac_animal_logo_misc.c: .text: [0x804117D4, 0x80411A60] +ac_boat_demo.c: + .text: [0x80414EC4, 0x80415BD8] + .rodata: [0x80643B98, 0x80643BA0] + .data: [0x8065FD28, 0x806818A0] + .bss: [0x812F96E8, 0x812F96F0] ac_boxManager.c: - .text: [0x80415BD8,0x80415BE8] + .text: [0x80415BD8, 0x80415BE8] .data: [0x806818A0, 0x806818C8] ac_boxMove.c: .text: [0x80415BE8, 0x80415BF8] @@ -544,6 +554,10 @@ ac_aprilfool_control.c: ac_groundhog_control.c: .text: [0x805155C8, 0x80515C48] .data: [0x8069FD88, 0x8069FDD0] +ac_ev_castaway.c: + .text: [0x8051CAC4, 0x8051CDCC] + .rodata: [0x806491B0, 0x806491B8] + .data: [0x806A03A0, 0x806A03F8] ac_ev_dokutu.c: .text: [0x8051DFF4, 0x8051E228] .data: [0x806A05C8, 0x806A0608] @@ -551,6 +565,10 @@ ac_ev_gypsy.c: .text: [0x80520D78, 0x80521414] .rodata: [0x80649228, 0x80649238] .data: [0x806A0938, 0x806A09F8] +ac_ev_santa.c: + .text: [0x80523498, 0x8052400C] + .rodata: [0x80649268, 0x80649270] + .data: [0x806A0BE0, 0x806A0D38] ac_ev_soncho.c: .text: [0x8052400C, 0x8052475C] .rodata: [0x80649270, 0x80649278] diff --git a/configure.py b/configure.py index c4f3f8ea..3f9f6677 100644 --- a/configure.py +++ b/configure.py @@ -723,6 +723,30 @@ def make_asm_list(path: str, asm_includes: List[AsmInclude]): forcefiles = [] +def remove_prefix(text, prefix): + if text.startswith(prefix): + return text[len(prefix):] + return text + +def make_objdiff_json(sources: List[Source]): + data = { + 'min_version' : "0.4.3", + 'custom_make' : "ninja", + 'target_dir' : f"{c.EXPECTED}/build", + 'base_dir' : f"{c.BUILDDIR}", + 'build_target' : False, + 'objects' : [ + { + 'path' : remove_prefix(src.o_path, "$builddir/"), + 'name' : src.src_path, + } + for src in sources + if src.decompiled + ] + } + with open("objdiff.json", 'w') as f: + json.dump(data, f, indent=4) + dol_sources = load_sources(c.DOL_CTX) dol_gen_includes = find_gen_includes(dol_sources) make_asm_list(c.DOL_ASM_LIST, dol_gen_includes[AsmInclude]) @@ -731,6 +755,8 @@ rel_sources = load_sources(c.REL_CTX) rel_gen_includes = find_gen_includes(rel_sources) make_asm_list(c.REL_ASM_LIST, rel_gen_includes[AsmInclude]) +make_objdiff_json(dol_sources + rel_sources) + ########## # Builds # ########## diff --git a/diff.py b/diff.py index a8b26a01..5000d1d4 100644 --- a/diff.py +++ b/diff.py @@ -1118,7 +1118,7 @@ def search_map_file( find = re.findall( re.compile( # ram elf rom alignment - r" \S+ \S+ (\S+) (\S+) +\S+ " + r" \S+ (\S+) (\S+) +\S+ " + re.escape(fn_name) + r"(?: \(entry of " + re.escape(config.diff_section) diff --git a/diff_settings.py b/diff_settings.py index ca0cdd6d..9078478d 100644 --- a/diff_settings.py +++ b/diff_settings.py @@ -21,4 +21,4 @@ def apply(config, args: Namespace): config["show_line_numbers_default"] = True def add_custom_arguments(parser: ArgumentParser): - parser.add_argument("-r", "--rel", action="store_true", help="(SPM) Diff a function in relF.rel") \ No newline at end of file + parser.add_argument("-r", "--rel", action="store_true", help="(AC) Diff a function in foresta.rel") \ No newline at end of file diff --git a/include/ac_boat.h b/include/ac_boat.h index 9912d121..485f638a 100644 --- a/include/ac_boat.h +++ b/include/ac_boat.h @@ -8,6 +8,13 @@ extern "C" { #endif +typedef struct boat_s BOAT_ACTOR; + +struct boat_s { + ACTOR actor_class; + // TODO +}; + extern ACTOR_PROFILE Boat_Profile; #ifdef __cplusplus diff --git a/include/ac_boat_demo.h b/include/ac_boat_demo.h index 55700d5f..f7bee4e5 100644 --- a/include/ac_boat_demo.h +++ b/include/ac_boat_demo.h @@ -3,11 +3,78 @@ #include "types.h" #include "m_actor.h" +#include "m_demo.h" +#include "ac_boat.h" +#include "ac_npc_sendo.h" +#include "ac_ev_castaway.h" +#include "m_common_data.h" #ifdef __cplusplus extern "C" { #endif +enum { + aBTD_ACTION_SENDO_BIRTH_WAIT, + aBTD_ACTION_PL_RIDE_ON_START_WAIT, + aBTD_ACTION_PL_RIDE_ON_END_WAIT, + aBTD_ACTION_START_CALL_END_WAIT, + aBTD_ACTION_SONG_BGM_START_WAIT, + aBTD_ACTION_SING_SENDO_START_WAIT, + aBTD_ACTION_SING_SENDO_MSG_SET_WAIT, + aBTD_ACTION_SENDO_DIALOGUE_START_WAIT, + aBTD_ACTION_SING_SENDO_START_WAIT2, + aBTD_ACTION_MOVE_BOAT_END_WAIT, + aBTD_ACTION_TOUCH_WHARF_END_WAIT, + aBTD_ACTION_PL_RIDE_OFF_START_WAIT, + aBTD_ACTION_PL_RIDE_OFF_END_WAIT, + aBTD_ACTION_ANCHOR_WAIT, + + aBTD_ACTION_NUM +}; + +enum { + aBTD_DEMO_PL_RIDE_ON_START, + aBTD_DEMO_PL_RIDE_ON_END, + aBTD_DEMO_START_CALL_END, + aBTD_DEMO_MOVE_BOAT_END, + aBTD_DEMO_TOUCH_WHARF_END, + aBTD_DEMO_PL_RIDE_OFF_START, + aBTD_DEMO_PL_RIDE_OFF_END, + aBTD_DEMO_ANCHOR, + + aBTD_DEMO_NUM +}; + +typedef struct boat_demo_s BOAT_DEMO_ACTOR; + +#define aBTD_GET_DEMO_ACTOR() (BOAT_DEMO_ACTOR*)(Common_Get(clip).demo_clip2->class) + +typedef void (*aBTD_PROC)(BOAT_DEMO_ACTOR*, GAME_PLAY*); + +struct boat_demo_s { + ACTOR actor_class; + int action; + aBTD_PROC action_proc; + int demo_act; + int song_bgm_timer; + BOAT_ACTOR* boat_actor; + NPC_SENDO_ACTOR* npc_sendo_actor; + EV_CASTAWAY_ACTOR* castaway_actor; + int at_island; + xyz_t passenger_ofs; + f32 boat_speed; + int island_npc_info_registered; + u8* island_gba_loader_p; + u8* island_gba_program_p; + u8 player_pattern; + u8 sing_dialog_ofs; + u8 sing_2nd_part; + u8 sing_2nd_part_bgm_no; + int sing_msg_no; + u16 touch_wharf_timer; + u8 touching_wharf; +}; + extern ACTOR_PROFILE Boat_Demo_Profile; #ifdef __cplusplus diff --git a/include/ac_ev_castaway.h b/include/ac_ev_castaway.h index be48b6bc..08c49480 100644 --- a/include/ac_ev_castaway.h +++ b/include/ac_ev_castaway.h @@ -3,11 +3,19 @@ #include "types.h" #include "m_actor.h" +#include "ac_npc.h" #ifdef __cplusplus extern "C" { #endif +typedef struct ev_castaway_s EV_CASTAWAY_ACTOR; + +struct ev_castaway_s { + NPC_ACTOR npc_class; + s16 bobbing_cycle; +}; + extern ACTOR_PROFILE Ev_Castaway_Profile; #ifdef __cplusplus diff --git a/include/ac_ev_santa.h b/include/ac_ev_santa.h index ff553268..f75c6622 100644 --- a/include/ac_ev_santa.h +++ b/include/ac_ev_santa.h @@ -3,11 +3,34 @@ #include "types.h" #include "m_actor.h" +#include "ac_npc.h" +#include "m_event.h" #ifdef __cplusplus extern "C" { #endif +typedef struct event_santa_s EVENT_SANTA_ACTOR; + +typedef struct santa_talk_data_s { + int msg_no; + int talk_act; +} aESNT_talk_data_c; + +typedef void(*aESNT_TALK_PROC)(EVENT_SANTA_ACTOR*, GAME_PLAY*); +typedef void (*aESNT_SETUP_TALK_PROC)(EVENT_SANTA_ACTOR*, GAME_PLAY*, int); + +struct event_santa_s { + /* 0x000 */ NPC_ACTOR npc_class; + /* 0x994 */ int talk_act; + /* 0x998 */ aESNT_TALK_PROC talk_proc; + /* 0x99C */ aESNT_SETUP_TALK_PROC setup_talk_proc; + /* 0x9A0 */ mActor_name_t present; + /* 0x9A4 */ aESNT_talk_data_c* talk_data_p; + /* 0x9A8 */ mEv_santa_event_c* event_p; + /* 0x9AC */ mEv_santa_event_common_c* event_common_p; +}; + extern ACTOR_PROFILE Ev_Santa_Profile; #ifdef __cplusplus diff --git a/include/ac_npc.h b/include/ac_npc.h index 8cfce413..a4d70dd8 100644 --- a/include/ac_npc.h +++ b/include/ac_npc.h @@ -14,6 +14,9 @@ extern "C" { #endif #define aNPC_SPNPC_BIT_CURATOR 0 +#define aNPC_SPNPC_BIT_GOHOME_NPC 1 +#define aNPC_SPNPC_BIT_MASK_CAT 2 +#define aNPC_SPNPC_BIT_DOZAEMON 4 #define aNPC_SPNPC_BIT_EV_SONCHO 5 #define aNPC_SPNPC_BIT_GET(field, bit) (((field) >> (bit)) & 1) @@ -141,7 +144,7 @@ typedef struct npc_draw_info_s { /* 0x008 */ u8 _000[0x20 - 8]; /* 0x020 */ f32 _20; /* 0x024 */ f32 _24; - /* 0x024 */ u8 _028[0x534 - 0x028]; + /* 0x028 */ u8 _028[0x534 - 0x028]; /* 0x538 */ u8 _534; /* 0x538 */ u8 _535; /* 0x538 */ u8 _536; @@ -149,13 +152,13 @@ typedef struct npc_draw_info_s { /* 0x538 */ u8 _538; /* 0x538 */ u8 _539; /* 0x540 */ u8 _53A[0x580 - 0x53A]; - /* 0x580 */ int _580; + /* 0x580 */ int animation_id; /* 0x584 */ int texture_bank_idx; /* 0x588 */ u8 _588[0x5BD - 0x588]; /* 0x5BD */ u8 _5BD; /* 0x5BE */ u8 _5BE; /* 0x5BE */ u8 _5BF[0x630 - 0x5BF]; -} aNPC_draw_info_c; +} aNPC_draw_info_c; typedef void (*aNPC_THINK_PROC)(NPC_ACTOR*, GAME_PLAY*, int); diff --git a/include/ac_npc_sendo.h b/include/ac_npc_sendo.h index 01bd45b0..e6aa4ce4 100644 --- a/include/ac_npc_sendo.h +++ b/include/ac_npc_sendo.h @@ -3,11 +3,19 @@ #include "types.h" #include "m_actor.h" +#include "ac_npc.h" #ifdef __cplusplus extern "C" { #endif +typedef struct npc_sendo_s NPC_SENDO_ACTOR; + +struct npc_sendo_s { + NPC_ACTOR npc_class; + // TODO +}; + extern ACTOR_PROFILE Npc_Sendo_Profile; #ifdef __cplusplus diff --git a/include/ac_weather.h b/include/ac_weather.h index 5f11a135..7774e372 100644 --- a/include/ac_weather.h +++ b/include/ac_weather.h @@ -9,6 +9,8 @@ extern "C" { #endif extern int aWeather_ChangingWeather(); +extern void aWeather_RequestChangeWeatherToIsland(); +extern void aWeather_RequestChangeWeatherFromIsland(); extern ACTOR_PROFILE Weather_Profile; diff --git a/include/m_choice.h b/include/m_choice.h index a70f0ab0..3d29970c 100644 --- a/include/m_choice.h +++ b/include/m_choice.h @@ -9,6 +9,7 @@ extern "C" { #endif #define mChoice_CHOICE_STRING_LEN 16 +#define mChoice_SELECT_STR_NUM 607 typedef struct choice_s mChoice_c; typedef struct choice_data_s mChoice_Data_c; @@ -54,58 +55,71 @@ struct choice_data_s { struct choice_s { /* Current XY position (centered) */ - f32 center_x; - f32 center_y; + /* 0x00 */ f32 center_x; + /* 0x04 */ f32 center_y; /* Initial XY position */ - f32 center_x_begin; - f32 center_y_begin; + /* 0x08 */ f32 center_x_begin; + /* 0x0C */ f32 center_y_begin; /* Target XY position */ - f32 center_x_target; - f32 center_y_target; + /* 0x10 */ f32 center_x_target; + /* 0x14 */ f32 center_y_target; /* Text settings */ - rgba_t text_color; - f32 text_scale_x; - f32 text_scale_y; - f32 text_x; - f32 text_y; + /* 0x18 */ rgba_t text_color; + /* 0x1C */ f32 text_scale_x; + /* 0x20 */ f32 text_scale_y; + /* 0x24 */ f32 text_x; + /* 0x28 */ f32 text_y; /* Window scaling XY */ - f32 scale_x; - f32 scale_y; + /* 0x2C */ f32 scale_x; + /* 0x30 */ f32 scale_y; /* Text related data */ - mChoice_Data_c data; + /* 0x34 */ mChoice_Data_c data; - int selected_choice_idx; - rgba_t selected_choice_text_color; + /* 0xC8 */ int selected_choice_idx; + /* 0xCC */ rgba_t selected_choice_text_color; - rgba_t background_color; + /* 0xD0 */ rgba_t background_color; - f32 _D4; - f32 _D8; + /* 0xD4 */ f32 _D4; + /* 0xD8 */ f32 _D8; - f32 scale; // total choice window scaling percentage + /* 0xDC */ f32 scale; // total choice window scaling percentage - int main_index; - int requested_main_index; + /* 0xE0 */ int main_index; + /* 0xE4 */ int requested_main_index; - int window_visible_flag; - int font_visible_flag; + /* 0xE8 */ int window_visible_flag; + /* 0xEC */ int font_visible_flag; - int choice_automove_type; - f32 choice_automove_timer; + /* 0xF0 */ int choice_automove_type; + /* 0xF4 */ f32 choice_automove_timer; - f32 timer; + /* 0xF8 */ f32 timer; - u8 no_b_flag; // can't press B to select last option - u8 no_close_flag; // pressing B won't auto-cancel the choice selection? + /* 0xFC */ u8 no_b_flag; // can't press B to select last option + /* 0xFD */ u8 no_close_flag; // pressing B won't auto-cancel the choice selection? }; +extern void mChoice_Main(mChoice_c* choice, GAME* game); +extern void mChoice_Draw(mChoice_c* choice, GAME* game, int mode); +extern void mChoice_aram_init(); +extern void mChoice_ct(mChoice_c* choice, GAME* game); +extern void mChoice_dt(mChoice_c* choice, GAME* game); extern mChoice_c* mChoice_Get_base_window_p(); +extern void mChoice_Change_request_main_index(mChoice_c* choice, int request_main_index); +extern int mChoice_check_main_index(mChoice_c* choice); +extern int mChoice_check_main_normal(mChoice_c* choice); +extern void mChoice_Set_choice_data( mChoice_c* choice, u8* str0, int str0_len, u8* str1, int str1_len, u8* str2, int str2_len, u8* str3, int str3_len, u8* str4, int str4_len, u8* str5, int str5_len); extern int mChoice_Get_ChoseNum(mChoice_c* choice); +extern void mChoice_Clear_ChoseNum(mChoice_c* choice); +extern void mChoice_Load_ChoseStringFromRom(mChoice_c* choice, u8* str, int str_no, ACTOR* actor); +extern void mChoice_no_b_set(mChoice_c* choice); +extern void mChoice_no_b_close_set(mChoice_c* choice); #ifdef __cplusplus } diff --git a/include/m_clip.h b/include/m_clip.h index 71f86e99..128300fe 100644 --- a/include/m_clip.h +++ b/include/m_clip.h @@ -53,7 +53,7 @@ typedef struct clip_s { /* 0x098 */ void* _098; /* 0x09C */ aMI_Clip_c* my_indoor_clip; /* 0x0A0 */ mDemo_Clip_c* demo_clip; /* can be multiple clip classes */ - /* 0x0A4 */ void* demo_clip2; /* can be multiple clip classes */ + /* 0x0A4 */ mDemo_Clip_c* demo_clip2; /* can be multiple clip classes */ /* 0x0A8 */ void* _0A8; /* 0x0AC */ aGYO_Clip_c* gyo_clip; /* 0x0B0 */ void* _0B0; diff --git a/include/m_common_data.h b/include/m_common_data.h index 753c3505..f81028fc 100644 --- a/include/m_common_data.h +++ b/include/m_common_data.h @@ -131,8 +131,9 @@ typedef struct Save_s { /* 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 */ lbRTC_ymd_c event_year_ymd; /* might not exist and just be lbRTC_year_t */ - /* 0x02139A */ u8 unused_2139A[6]; + /* 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 */ @@ -229,8 +230,10 @@ typedef struct common_data_s { /* 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[mDemo_CLIP_TYPE_NUM - 1]; - /* 0x028596 */ u8 _28596[0x285BE - 0x28596]; + /* 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; diff --git a/include/m_demo.h b/include/m_demo.h index d4775428..2747d3df 100644 --- a/include/m_demo.h +++ b/include/m_demo.h @@ -94,6 +94,9 @@ enum demo_clip_type { mDemo_CLIP_TYPE_NONE, mDemo_CLIP_TYPE_INTRO_DEMO, mDemo_CLIP_TYPE_RIDE_OFF_DEMO, + mDemo_CLIP_TYPE_PRESENT_DEMO, + mDemo_CLIP_TYPE_BOAT_DEMO, + mDemo_CLIP_TYPE_RESET_DEMO, mDemo_CLIP_TYPE_NUM }; diff --git a/include/m_event.h b/include/m_event.h index 93677d88..8e7c8bfb 100644 --- a/include/m_event.h +++ b/include/m_event.h @@ -15,18 +15,45 @@ extern "C" { #define mEv_TODAY_EVENT_NUM 16 #define mEv_SCHEDULE_LAST_WEEKDAY_OF_MONTH 6 /* day of last weekday of the month */ -#define mEv_SCHEDULE_WEEKLY 7 /* scheduled for the desired day this week (e.g. this saturday) */ +#define mEv_SCHEDULE_EVERY_WEEK 7 /* scheduled for the desired day this week (e.g. this saturday) */ -#define mEv_SCHEDULE_MULTIDAY 0x40 /* event scheduled over more than a single day */ +/* Month flags */ +#define mEv_SCHEDULE_HARVEST_MOON_DATE 0x40 /* Use this year's lunisolar harvest moon date */ +#define mEv_SCHEDULE_NOW_MONTH 0x20 +#define mEv_SCHEDULE_USE_SAVE_MONTH 0x10 + +#define mEv_SCHEDULE_SAVE_MONTH(m) (mEv_SCHEDULE_USE_SAVE_MONTH | ((m) & 0xF)) +#define mEv_SCHEDULE_LUNAR(m) (mEv_SCHEDULE_HARVEST_MOON_DATE | ((m) & 0xF)) + +/* Day flags */ +#define mEv_SCHEDULE_WEEKLY 0x80 /* Event happens on a given weekday and week of the month */ +#define mEv_SCHEDULE_TOWN_DAY 0x40 /* Use save data 'town day' day */ +#define mEv_SCHEDULE_DAY_AFTER 0x40 /* When used in conjunction with the 'weekly' flag, it schedules on the day after the Nth weekday */ +#define mEv_SCHEDULE_LAST_DAY_OF_MONTH 0x20 + +#define mEv_SCHEDULE_MAKE_WEEKLY_DATA(week, weekday) (mEv_SCHEDULE_WEEKLY | ((((week) & 0b111) << 3) | ((weekday) & 0b111))) +#define mEv_SCHEDULE_1ST_WEEKDAY(weekday) mEv_SCHEDULE_MAKE_WEEKLY_DATA(1, weekday) +#define mEv_SCHEDULE_2ND_WEEKDAY(weekday) mEv_SCHEDULE_MAKE_WEEKLY_DATA(2, weekday) +#define mEv_SCHEDULE_3RD_WEEKDAY(weekday) mEv_SCHEDULE_MAKE_WEEKLY_DATA(3, weekday) +#define mEv_SCHEDULE_4TH_WEEKDAY(weekday) mEv_SCHEDULE_MAKE_WEEKLY_DATA(4, weekday) +#define mEv_SCHEDULE_5TH_WEEKDAY(weekday) mEv_SCHEDULE_MAKE_WEEKLY_DATA(5, weekday) +#define mEv_SCHEDULE_LAST_WEEKDAY(weekday) mEv_SCHEDULE_MAKE_WEEKLY_DATA(mEv_SCHEDULE_LAST_WEEKDAY_OF_MONTH, weekday) +#define mEv_SCHEDULE_EVERY_WEEKDAY(weekday) mEv_SCHEDULE_MAKE_WEEKLY_DATA(mEv_SCHEDULE_EVERY_WEEK, weekday) + +/* Hour flags */ #define mEv_SCHEDULE_TODAY 0x80 /* event will be active on the day loaded */ +#define mEv_SCHEDULE_MULTIDAY 0x40 /* event scheduled over more than a single day */ +#define mEv_SCHEDULE_USE_SAVE_SLOT_VALUE 0x20 + +#define mEv_SCHEDULE_HOUR_SLOT(h) (mEv_SCHEDULE_USE_SAVE_SLOT_VALUE | (h & 0xF)) #define mEv_TO_DAY(month_day) ((lbRTC_day_t)(month_day)) #define mEv_TO_MONTH(month_day) ((lbRTC_month_t)((month_day) >> 8)) typedef union event_monthday_s { struct { - s8 month; - s8 day; + u8 month; + u8 day; }; u16 raw; } mEv_MonthDay_u; @@ -36,16 +63,20 @@ typedef struct event_today_s { u32 active_hours; /* bitfield (24 bits) */ mEv_MonthDay_u begin_date; mEv_MonthDay_u end_date; - u16 status; + s16 status; u16 pad; } mEv_event_today_c; typedef struct event_date_s { - struct { - mEv_MonthDay_u month_day; - u8 _2; - u8 hour; - }; + u8 month; + u8 day; + u8 _2; + u8 hour; +} mEv_schedule_date_c; + +typedef union { + mEv_schedule_date_c d; + u16 md, _h; u32 raw; } mEv_schedule_date_u; @@ -55,6 +86,10 @@ typedef struct event_schedule_s { s16 type; /* event type */ } mEv_schedule_c; +#define mEv_EVENT_HOUR_START_EVENT (1 << 28) +#define mEv_EVENT_HOUR_CLEAR_EVENT (1 << 29) +#define mEv_EVENT_HOUR_TOO_SHORT_EVENT (1 << 30) + /** * Event type definition * xxxyyyyy yyyyyyyy yyyyyyyy yyyyyyyy @@ -94,6 +129,7 @@ enum events { mEv_SPNPC_ARTIST, mEv_SPNPC_ARABIAN, mEv_SPNPC_GYPSY, + mEv_SPNPC_END, mEv_SAVED_RENEWSHOP = (int)mEv_SET(mEv_SAVED_EVENT, 0), /* renew shop */ mEv_SAVED_UNK1, /* unused */ @@ -197,7 +233,7 @@ enum event_table { mEv_EVENT_LABOR_DAY, mEv_EVENT_RUMOR_FALL_SPORTS_FAIR, mEv_EVENT_AUTUMN_EQUINOX, - mEv_EVENT_HARVEST_MOON_DAY, + mEv_EVENT_RUMOR_HARVEST_MOON_DAY, mEv_EVENT_HARVEST_MOON_FESTIVAL, mEv_EVENT_EXPLORERS_DAY, mEv_EVENT_RUMOR_MUSHROOM_SEASON, @@ -279,7 +315,7 @@ enum event_table { mEv_EVENT_SONCHO_BRIDGE_MAKE, mEv_EVENT_GHOST, - mEv_EVENT_MASK_CAT, + mEv_EVENT_MASK_NPC, // "Go Home Npc" & "Blanca" events mEv_EVENT_74, // unused? @@ -290,6 +326,28 @@ enum event_table { mEv_EVENT_NUM }; +enum { + mEv_SAVE_DATE_TODAY, + mEv_SAVE_DATE_LAST_PLAY_DATE, + mEv_SAVE_DATE_BIRTHDAY, + mEv_SAVE_DATE_SPECIAL0, /* Initialized to rtc month-day in init_special_event */ + mEv_SAVE_DATE_SPECIAL1, /* Initialized to beginning month-day of special event in init_special_event */ + mEv_SAVE_DATE_SPECIAL2, /* Initialized to ending month-day of special event in init_special_event */ + mEv_SAVE_DATE_WEEKLY, + mEv_SAVE_DATE_SPECIAL3, /* Initialized to opening hours for shop sale in init_special_event */ + + mEv_SAVE_DATE_NUM +}; + +enum { + mEv_SPECIAL_STATE_UNSCHEDULED, + mEv_SPECIAL_STATE_SCHEDULED_LATER, + mEv_SPECIAL_STATE_SCHEDULED_TODAY, + mEv_SPECIAL_STATE_ACTIVE, + + mEv_SPECIAL_STATE_NUM +}; + #define mEv_STATUS_ACTIVE (1 << 0) /* event is active */ #define mEv_STATUS_STOP (1 << 1) /* event is stopped */ #define mEv_STATUS_SHOW (1 << 2) /* event is shown */ @@ -319,7 +377,7 @@ typedef struct kabu_peddler_event_s { } mEv_kabu_peddler_c; typedef struct dozaemon_event_s { - u32 flags; + u16 flags; } mEv_dozaemon_c; typedef union { @@ -401,6 +459,14 @@ typedef struct santa_event_common_s { mActor_name_t last_talk_cloth; } mEv_santa_event_common_c; +#define mEv_SANTA_CLOTH_NUM_MAX 10 /* How many different shirts can the player trick Jingle with */ + +typedef struct santa_event_s { + PersonalID_c pid; + u8 present_count; + mActor_name_t cloth[mEv_SANTA_CLOTH_NUM_MAX]; +} mEv_santa_event_c; + typedef union { mEv_broker_common_c broker; mEv_santa_event_common_c santa; @@ -420,8 +486,8 @@ typedef struct event_s { } Event_c; typedef struct event_info_s { - s8 type; - s8 id; + u8 type; + u8 id; u16 year; mEv_MonthDay_u start_date; mEv_MonthDay_u end_date; @@ -444,42 +510,49 @@ typedef struct event_area_s { int data[11]; } mEv_area_c; +#define mEv_AREA_NUM 5 +#define mEv_PLACE_NUM 10 + typedef struct event_common_s { s16 _00; s16 area_use_bitfield; - mEv_area_c area[5]; + mEv_area_c area[mEv_AREA_NUM]; s16 too_short; s16 place_use_bitfield; - mEv_place_c place[10]; + mEv_place_c place[mEv_PLACE_NUM]; s16 fieldday_event_id; s16 fieldday_event_over_status; u32 unused[2]; } mEv_common_data_c; typedef struct event_save_event_info_s { - s8 type; - s8 flags; + u8 type; + u8 flags; } mEv_event_save_info_c; typedef struct event_common_save_data { mEv_event_save_info_c special_event; mEv_event_save_info_c weekly_event; - u16 dates[8]; + u16 dates[mEv_SAVE_DATE_NUM]; int area_use_bitfield; - mEv_area_c area[5]; + mEv_area_c area[mEv_AREA_NUM]; int last_date; - int _120; + int delete_event_id; u32 valentines_day_date; u32 white_day_date; /* unused in AC */ u16 ghost_day; u16 bridge_day; // last date suspension bridge event was active - struct { - u8 used_all_locations:1; // set to true when tortimer has cycled through all possible bridge locations? - u8 locations_used:7; // index of river acre w/ possible bridge location currently at + union { + struct { + u8 used_all_locations:1; // set to true when tortimer has cycled through all possible bridge locations? + u8 locations_used:7; // index of river acre w/ possible bridge location currently at + }; + + u8 raw; } bridge_flags; u8 ghost_event_type; // 0x72 will spawn wisp, 0x77 won't? u8 soncho_event_type; // checked not equal to 0xFF for summer & fall fishing tournies - u8 current_event_state; // used to signal when you've received an item from gracie or woken gulliver up + u8 dozaemon_completed; // used to signal when you've received an item from gulliver } mEv_save_common_data_c; extern int mEv_CheckFirstJob(); @@ -488,10 +561,10 @@ extern int mEv_CheckArbeit(); extern int mEv_CheckTitleDemo(); extern int mEv_check_status(int event, s16 status); extern int mEv_check_status_edge(s16 status); -extern s8* mEv_get_common_area(int type, s8 id); -extern s8* mEv_reserve_common_area(int type, s8 id); -extern s8* mEv_get_save_area(int type, s8 id); -extern s8* mEv_reserve_save_area(int type, s8 id); +extern u8* mEv_get_common_area(int type, u8 id); +extern u8* mEv_reserve_common_area(int type, u8 id); +extern u8* mEv_get_save_area(int type, u8 id); +extern u8* mEv_reserve_save_area(int type, u8 id); extern void mEv_actor_dying_message(int type, ACTOR* actor); extern int mEv_ArbeitPlayer(u32 player_no); extern u16 mEv_get_special_event_type(); @@ -499,14 +572,14 @@ extern void mEv_ClearEventSaveInfo(mEv_event_save_c* event_save_data); extern void mEv_EventON(u32 event_kind); extern int mEv_CheckGateway(); extern int mEv_check_schedule(int event); -extern mEv_place_data_c* mEv_get_common_place(int type, s8 id); +extern mEv_place_data_c* mEv_get_common_place(int type, u8 id); extern void mEv_set_status(int event, s16 status); extern void mEv_GetEventWeather(s16* weather, s16* intensity); extern int mEv_CheckRealArbeit(); extern int mEv_CheckEvent(u32 event); extern u16 mEv_get_bargain_day(); -extern int mEv_weekday2day(lbRTC_month_t month, int week_type, lbRTC_weekday_t weekday); +extern int mEv_weekday2day(lbRTC_month_t month, int week_type, int weekday); extern void mEv_ClearEventInfo(); extern void mEv_init(Event_c* event); @@ -518,6 +591,9 @@ extern void mEv_finish(Event_c* event); extern int mEv_CheckTitleDemo(); extern void mEv_SetTitleDemo(int titledemo_no); +extern int mGH_check_birth2(); +extern int mMC_check_birth(); + extern void mEv_debug_print4f(gfxprint_t* gfxprint); extern void mEv_sp_debug_print4f(gfxprint_t* gfxprint); diff --git a/include/m_island.h b/include/m_island.h index 3eddea0a..15e81e7f 100644 --- a/include/m_island.h +++ b/include/m_island.h @@ -44,8 +44,8 @@ typedef struct island_s { /* 0x18CA */ lbRTC_time_c renew_time; /* last time island was visited? */ /* 0x18D2 */ u8 unused_18D2[14]; /* unused */ /* 0x18E0 */ u8 grass_tex_type; /* grass type */ - /* 0x18E1 */ u8 last_song_male; /* last song kapp'n sang for a male character */ - /* 0x18E2 */ u8 last_song_female; /* last song kapp'n sang for a female character */ + /* 0x18E1 */ u8 last_song_to_island; /* last song kapp'n sang to the island */ + /* 0x18E2 */ u8 last_song_from_island; /* last song kapp'n sang leaving the island */ /* 0x18E3 */ u8 unused_18E3[29]; /* unused */ } Island_c; @@ -180,8 +180,8 @@ typedef struct island_agb_s { /* 0x3948 */ u16 npc_pal[16]; /* 0x3968 */ u8 _3968[20]; /* 0x397C */ u8 _397C; - /* 0x397D */ u8 last_song_male; /* last song kapp'n sang for a male character */ - /* 0x397E */ u8 last_song_female; /* last song kapp'n sang for a female character */ + /* 0x397D */ u8 last_song_to_island; /* last song kapp'n sang for a male character */ + /* 0x397E */ u8 last_song_from_island; /* last song kapp'n sang for a female character */ /* 0x397F */ u8 checksum; } Island_agb_c; diff --git a/include/m_mask_cat.h b/include/m_mask_cat.h index 2361380a..2ca770ea 100644 --- a/include/m_mask_cat.h +++ b/include/m_mask_cat.h @@ -11,8 +11,13 @@ extern "C" { #define mMC_TALK_IDX_MAX 10 +typedef struct mask_cat_data_s { + /* 0x000 */ PersonalID_c creator_pid; + /* 0x020 */ u8 design[mNW_DESIGN_TEX_SIZE] ATTRIBUTE_ALIGN(32); /* this is aligned to 32 bytes for ARAM transfer */ +} mMC_design_c; + typedef struct mask_cat_s { - mNW_original_design_c design; + mMC_design_c design; u8 palette_no; u8 cloth_no; u8 talk_idx; diff --git a/include/m_msg.h b/include/m_msg.h index 31948de9..53484f3b 100644 --- a/include/m_msg.h +++ b/include/m_msg.h @@ -4,6 +4,8 @@ #include "types.h" #include "libu64/gfxprint.h" #include "m_choice.h" +#include "m_item_name.h" +#include "m_msg_data.h" #ifdef __cplusplus extern "C" { @@ -67,6 +69,9 @@ enum { mMsg_MAIL_STR_NUM }; +#define mMsg_STATUS_FLAG_ZOOMDOWN_LONG (1 << 11) /* When set, mMsg_sound_ZOOMDOWN_SHORT() sfx will not play */ +#define mMsg_STATUS_FLAG_USE_AM (1 << 17) /* 'AM' when set, 'PM' when not set */ + typedef struct message_window_s mMsg_Window_c; typedef struct message_data_s mMsg_Data_c; @@ -144,88 +149,89 @@ struct message_data_s { }; struct message_window_s { - int data_loaded; - int msg_no; - int _008; - mMsg_Data_c* msg_data; - f32 center_x; - f32 center_y; - f32 width; - f32 height; + /* 0x000 */ int data_loaded; + /* 0x004 */ int msg_no; + /* 0x008 */ int _008; + /* 0x00C */ mMsg_Data_c* msg_data; + /* 0x010 */ f32 center_x; + /* 0x014 */ f32 center_y; + /* 0x018 */ f32 width; + /* 0x01C */ f32 height; - ACTOR* talk_actor; - int show_actor_name; - int actor_name_len; - int nameplate_x; - int nameplay_y; + /* 0x020 */ ACTOR* talk_actor; + /* 0x024 */ int show_actor_name; + /* 0x028 */ int actor_name_len; + /* 0x02C */ int nameplate_x; + /* 0x030 */ int nameplay_y; - int show_continue_button; + /* 0x034 */ int show_continue_button; - u8 free_str[mMsg_FREE_STR_NUM][mMsg_FREE_STRING_LEN]; - int free_str_article[mMsg_FREE_STR_NUM]; + /* 0x038 */ u8 free_str[mMsg_FREE_STR_NUM][mMsg_FREE_STRING_LEN]; + /* 0x178 */ int free_str_article[mMsg_FREE_STR_NUM]; - u8 item_str[mMsg_ITEM_STR_NUM][mMsg_FREE_STRING_LEN]; - int item_str_article[mMsg_ITEM_STR_NUM]; + /* 0x1C8 */ u8 item_str[mMsg_ITEM_STR_NUM][mMsg_FREE_STRING_LEN]; + /* 0x218 */ int item_str_article[mMsg_ITEM_STR_NUM]; - u8 mail_str[mMsg_MAIL_STR_NUM][mMsg_MAIL_STRING_LEN]; + /* 0x22C */ u8 mail_str[mMsg_MAIL_STR_NUM][mMsg_MAIL_STRING_LEN]; - rgba_t name_text_color; - rgba_t name_background_color; + /* 0x2B0 */ rgba_t name_text_color; + /* 0x2B4 */ rgba_t name_background_color; - rgba_t window_background_color; - rgba_t font_color[4]; + /* 0x2B8 */ rgba_t window_background_color; + /* 0x2BC */ rgba_t font_color[4]; - rgba_t continue_button_color; + /* 0x2CC */ rgba_t continue_button_color; - f32 font_scale_x; - f32 font_scale_y; + /* 0x2D0 */ f32 font_scale_x; + /* 0x2D4 */ f32 font_scale_y; - int _2D8; - int _2DC; + /* 0x2D8 */ int _2D8; + /* 0x2DC */ int _2DC; - int text_lines; - int current_line; + /* 0x2E0 */ int text_lines; + /* 0x2E4 */ int current_line; - mChoice_c choice_window; + /* 0x2E8 */ mChoice_c choice_window; - int _3E8; + /* 0x3E8 */ int _3E8; - u16 end_timer; - s16 animal_voice_idx; - int voice_sfx_idx; - u8 voice_idx; - u8 voice2_idx; - u8 voice3_idx; - s8 hide_choice_window_timer; - int spec; - u8 free_str_color_idx[4]; - u8 _404[8]; // unused? - u32 status_flags; + /* 0x3EC */ u16 end_timer; + /* 0x3EE */ s16 animal_voice_idx; + /* 0x3F0 */ int voice_sfx_idx; + /* 0x3F4 */ u8 voice_idx; + /* 0x3F5 */ u8 voice2_idx; + /* 0x3F6 */ u8 voice3_idx; + /* 0x3F7 */ s8 hide_choice_window_timer; + /* 0x3F8 */ u8 force_voice_enable_flag; + /* 0x3FC */ int spec; + /* 0x400 */ u8 free_str_color_idx[4]; + /* 0x408 */ u8 _404[8]; // unused? + /* 0x40C */ u32 status_flags; - f32 timer; - f32 cursor_timer; - f32 continue_button_timer; + /* 0x410 */ f32 timer; + /* 0x414 */ f32 cursor_timer; + /* 0x418 */ f32 continue_button_timer; - int start_text_cursor_idx; - int end_text_cursor_idx; - f32 window_scale; - f32 text_scale; + /* 0x41C */ int start_text_cursor_idx; + /* 0x420 */ int end_text_cursor_idx; + /* 0x424 */ f32 window_scale; + /* 0x428 */ f32 text_scale; - int requested_main_index; - int requested_priority; + /* 0x42C */ int requested_main_index; + /* 0x430 */ int requested_priority; - int main_index; - int draw_flag; - int cancel_flag; - int cancelable_flag; - int continue_msg_no; - int continue_cancel_flag; - int force_next; - int lock_continue; - s8 now_utter; + /* 0x434 */ int main_index; + /* 0x438 */ int draw_flag; + /* 0x43C */ int cancel_flag; + /* 0x440 */ int cancelable_flag; + /* 0x444 */ int continue_msg_no; + /* 0x448 */ int continue_cancel_flag; + /* 0x44C */ int force_next; + /* 0x450 */ int lock_continue; + /* 0x454 */ s8 now_utter; - mMsg_Main_Data_c main_data; - mMsg_Request_Data_c request_data; + /* 0x458 */ mMsg_Main_Data_c main_data; + /* 0x460 */ mMsg_Request_Data_c request_data; }; extern int mMsg_Get_Length_String(u8* buf, size_t buf_size); @@ -262,6 +268,26 @@ extern int mMsg_Check_main_hide(mMsg_Window_c* msg_win); extern int mMsg_sound_voice_get_for_editor(int code); extern int mMsg_sound_spec_change_voice(mMsg_Window_c* msg_win); extern void mMsg_request_main_forceoff(); +extern int mMsg_CopyPlayerName(u8* data, int idx, int max_size, int capitalize); +extern int mMsg_CopyTalkName(ACTOR* actor, u8* data, int idx, int max_size, int capitalize); +extern int mMsg_CopyTail(ACTOR* actor, u8* data, int idx, int max_size, int capitalize); +extern int mMsg_CopyYear(u8* data, int idx, int max_size); +extern int mMsg_CopyMonth(u8* data, int idx, int max_size); +extern int mMsg_CopyWeek(u8* data, int idx, int max_size); +extern int mMsg_CopyDay(u8* data, int idx, int max_size); +extern int mMsg_CopyHour(u8* data, int idx, int max_size); +extern int mMsg_CopyMin(u8* data, int idx, int max_size); +extern int mMsg_CopySec(u8* data, int idx, int max_size); +extern int mMsg_CopyFree(mMsg_Window_c* msg_win, int free_idx, u8* data, int idx, int max_size, int article, int capitalize); +extern int mMsg_CopyDetermination(mMsg_Window_c* msg_win, u8* data, int idx, int max_size); +extern int mMsg_CopyCountryName(u8* data, int idx, int max_size, int capitalize); +extern int mMsg_CopyRamdomNumber2(u8* data, int idx, int max_size); +extern int mMsg_CopyItem(mMsg_Window_c* msg_win, int item_idx, u8* data, int idx, int max_size, int article, int capitalize); +extern int mMsg_CopyMail(mMsg_Window_c* msg_win, int mail_idx, u8* data, int idx, int max_size); +extern int mMsg_CopyIslandName(u8* data, int idx, int max_size, int capitalize); +extern int mMsg_CopyAmPm(mMsg_Window_c* msg_win, u8* data, int idx, int max_size); +extern void mMsg_sound_set_voice_silent(mMsg_Window_c* msg_win, int update_voice_mode); +extern void mMsg_sound_unset_voice_silent(mMsg_Window_c* msg_win, int update_voice_mode); #ifdef __cplusplus } diff --git a/include/m_msg_data.h b/include/m_msg_data.h new file mode 100644 index 00000000..ec22a936 --- /dev/null +++ b/include/m_msg_data.h @@ -0,0 +1,19 @@ +#ifndef M_MSG_DATA_H +#define M_MSG_DATA_H + +#include "types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define MSG_SANTA_WISH_FTR 0x2B54 +#define MSG_SANTA_WISH_WALL 0x2B55 +#define MSG_SANTA_WISH_CARPET 0x2B56 +#define MSG_SANTA_WISH_CLOTH 0x2B57 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/m_name_table.h b/include/m_name_table.h index 51bd9944..69db556a 100644 --- a/include/m_name_table.h +++ b/include/m_name_table.h @@ -1617,90 +1617,90 @@ extern int mNT_check_unknown(mActor_name_t item_no); #define NPC_HOUSE_END 0x50EE #define STRUCTURE_START 0x5800 -#define HOUSE0 (STRUCTURE_START) -#define HOUSE1 (HOUSE0 + 1) -#define HOUSE2 (HOUSE1 + 1) -#define HOUSE3 (HOUSE2 + 1) -#define SHOP0 (HOUSE3 + 1) -#define SHOP1 (SHOP0 + 1) -#define SHOP2 (SHOP1 + 1) -#define SHOP3 (SHOP2 + 1) -#define POST_OFFICE (SHOP3 + 1) -#define TRAIN_STATION (POST_OFFICE + 1) -#define TRAIN0 (TRAIN_STATION + 1) -#define TRAIN1 (TRAIN0 + 1) -#define POLICE_STATION (TRAIN1 + 1) -#define WATERFALL_SOUTH (POLICE_STATION + 1) -#define WATERFALL_EAST (WATERFALL_SOUTH + 1) -#define WATERFALL_WEST (WATERFALL_EAST + 1) +#define HOUSE0 (STRUCTURE_START + 0) +#define HOUSE1 (STRUCTURE_START + 1) +#define HOUSE2 (STRUCTURE_START + 2) +#define HOUSE3 (STRUCTURE_START + 3) +#define SHOP0 (STRUCTURE_START + 4) +#define SHOP1 (STRUCTURE_START + 5) +#define SHOP2 (STRUCTURE_START + 6) +#define SHOP3 (STRUCTURE_START + 7) +#define POST_OFFICE (STRUCTURE_START + 8) +#define TRAIN_STATION (STRUCTURE_START + 9) +#define TRAIN0 (STRUCTURE_START + 10) +#define TRAIN1 (STRUCTURE_START + 11) +#define POLICE_STATION (STRUCTURE_START + 12) +#define WATERFALL_SOUTH (STRUCTURE_START + 13) +#define WATERFALL_EAST (STRUCTURE_START + 14) +#define WATERFALL_WEST (STRUCTURE_START + 15) #define SIGN00 (STRUCTURE_START + 16) -#define SIGN01 (SIGN00 + 1) -#define SIGN02 (SIGN01 + 1) -#define SIGN03 (SIGN02 + 1) -#define SIGN04 (SIGN03 + 1) -#define SIGN05 (SIGN04 + 1) -#define SIGN06 (SIGN05 + 1) -#define SIGN07 (SIGN06 + 1) -#define SIGN08 (SIGN07 + 1) -#define SIGN09 (SIGN08 + 1) -#define SIGN10 (SIGN09 + 1) -#define SIGN11 (SIGN10 + 1) -#define SIGN12 (SIGN11 + 1) -#define SIGN13 (SIGN12 + 1) -#define SIGN14 (SIGN13 + 1) -#define SIGN15 (SIGN14 + 1) -#define SIGN16 (SIGN15 + 1) -#define SIGN17 (SIGN16 + 1) -#define SIGN18 (SIGN17 + 1) -#define SIGN19 (SIGN18 + 1) -#define SIGN20 (SIGN19 + 1) -#define WISHING_WELL (SIGN20 + 1) -#define BROKER_TENT (WISHING_WELL + 1) -#define FORTUNE_TENT (BROKER_TENT + 1) -#define DESIGNER_CAR (FORTUNE_TENT + 1) -#define KAMAKURA (DESIGNER_CAR + 1) -#define SAKURA_TABLE0 (KAMAKURA + 1) -#define SAKURA_TABLE1 (SAKURA_TABLE0 + 1) -#define AEROBICS_RADIO (SAKURA_TABLE1 + 1) -#define FIREWORKS_STALL0 (AEROBICS_RADIO + 1) -#define FIREWORKS_STALL1 (FIREWORKS_STALL0 + 1) -#define NEWYEAR_SHRINE0 (FIREWORKS_STALL1 + 1) -#define NEWYEAR_SHRINE1 (NEWYEAR_SHRINE0 + 1) -#define NEWYEAR_TABLE (NEWYEAR_SHRINE1 + 1) -#define NEWYEAR_COUNTDOWN0 (NEWYEAR_TABLE + 1) -#define NEWYEAR_COUNTDOWN1 (NEWYEAR_COUNTDOWN0 + 1) -#define SPORTSFAIR_BALLS_RED (NEWYEAR_COUNTDOWN1 + 1) -#define SPORTSFAIR_BALLS_WHITE (SPORTSFAIR_BALLS_RED + 1) -#define SPORTSFAIR_BASKET_RED (SPORTSFAIR_BALLS_WHITE + 1) -#define SPORTSFAIR_BASKET_WHITE (SPORTSFAIR_BASKET_RED + 1) -#define FISHCHECK_STAND0 (SPORTSFAIR_BASKET_WHITE + 1) -#define FISHCHECK_STAND1 (FISHCHECK_STAND0 + 1) -#define KOINOBORI_WINDSOCK (FISHCHECK_STAND1 + 1) -#define DUMP (KOINOBORI_WINDSOCK + 1) -#define WINDMILL0 (DUMP + 1) -#define WINDMILL1 (WINDMILL0 + 1) -#define WINDMILL2 (WINDMILL1 + 1) -#define WINDMILL3 (WINDMILL2 + 1) -#define WINDMILL4 (WINDMILL3 + 1) -#define LOTUS (WINDMILL4 + 1) -#define MIKANBOX (LOTUS + 1) -#define DOUZOU (MIKANBOX + 1) // train station statue -#define TOUDAI (DOUZOU + 1) // lighthouse -#define GHOG (TOUDAI + 1) -#define HTABLE0 (GHOG + 1) -#define HTABLE1 (HTABLE0 + 1) -#define HTABLE2 (HTABLE1 + 1) -#define TENT (HTABLE2 + 1) -#define MUSEUM (TENT + 1) -#define BRIDGE_A0 (MUSEUM + 1) -#define BRIDGE_A1 (BRIDGE_A0 + 1) -#define NEEDLEWORK_SHOP (BRIDGE_A1 + 1) -#define FLAG (NEEDLEWORK_SHOP + 1) -#define BOAT (FLAG + 1) -#define COTTAGE_MY (BOAT + 1) -#define COTTAGE_NPC (COTTAGE_MY + 1) -#define PORT_SIGN (COTTAGE_NPC + 1) -#define STRUCTURE_END (PORT_SIGN + 1) +#define SIGN01 (STRUCTURE_START + 17) +#define SIGN02 (STRUCTURE_START + 18) +#define SIGN03 (STRUCTURE_START + 19) +#define SIGN04 (STRUCTURE_START + 20) +#define SIGN05 (STRUCTURE_START + 21) +#define SIGN06 (STRUCTURE_START + 22) +#define SIGN07 (STRUCTURE_START + 23) +#define SIGN08 (STRUCTURE_START + 24) +#define SIGN09 (STRUCTURE_START + 25) +#define SIGN10 (STRUCTURE_START + 26) +#define SIGN11 (STRUCTURE_START + 27) +#define SIGN12 (STRUCTURE_START + 28) +#define SIGN13 (STRUCTURE_START + 29) +#define SIGN14 (STRUCTURE_START + 30) +#define SIGN15 (STRUCTURE_START + 31) +#define SIGN16 (STRUCTURE_START + 32) +#define SIGN17 (STRUCTURE_START + 33) +#define SIGN18 (STRUCTURE_START + 34) +#define SIGN19 (STRUCTURE_START + 35) +#define SIGN20 (STRUCTURE_START + 36) +#define WISHING_WELL (STRUCTURE_START + 37) +#define BROKER_TENT (STRUCTURE_START + 38) +#define FORTUNE_TENT (STRUCTURE_START + 39) +#define DESIGNER_CAR (STRUCTURE_START + 40) +#define KAMAKURA (STRUCTURE_START + 41) +#define SAKURA_TABLE0 (STRUCTURE_START + 42) +#define SAKURA_TABLE1 (STRUCTURE_START + 43) +#define AEROBICS_RADIO (STRUCTURE_START + 44) +#define FIREWORKS_STALL0 (STRUCTURE_START + 45) +#define FIREWORKS_STALL1 (STRUCTURE_START + 46) +#define NEWYEAR_SHRINE0 (STRUCTURE_START + 47) +#define NEWYEAR_SHRINE1 (STRUCTURE_START + 48) +#define NEWYEAR_TABLE (STRUCTURE_START + 49) +#define NEWYEAR_COUNTDOWN0 (STRUCTURE_START + 50) +#define NEWYEAR_COUNTDOWN1 (STRUCTURE_START + 51) +#define SPORTSFAIR_BALLS_RED (STRUCTURE_START + 52) +#define SPORTSFAIR_BALLS_WHITE (STRUCTURE_START + 53) +#define SPORTSFAIR_BASKET_RED (STRUCTURE_START + 54) +#define SPORTSFAIR_BASKET_WHITE (STRUCTURE_START + 55) +#define FISHCHECK_STAND0 (STRUCTURE_START + 56) +#define FISHCHECK_STAND1 (STRUCTURE_START + 57) +#define KOINOBORI_WINDSOCK (STRUCTURE_START + 58) +#define DUMP (STRUCTURE_START + 59) +#define WINDMILL0 (STRUCTURE_START + 60) +#define WINDMILL1 (STRUCTURE_START + 61) +#define WINDMILL2 (STRUCTURE_START + 62) +#define WINDMILL3 (STRUCTURE_START + 63) +#define WINDMILL4 (STRUCTURE_START + 64) +#define LOTUS (STRUCTURE_START + 65) +#define MIKANBOX (STRUCTURE_START + 66) +#define DOUZOU (STRUCTURE_START + 67) // train station statue +#define TOUDAI (STRUCTURE_START + 68) // lighthouse +#define GHOG (STRUCTURE_START + 69) +#define HTABLE0 (STRUCTURE_START + 70) +#define HTABLE1 (STRUCTURE_START + 71) +#define HTABLE2 (STRUCTURE_START + 72) +#define TENT (STRUCTURE_START + 73) +#define MUSEUM (STRUCTURE_START + 74) +#define BRIDGE_A0 (STRUCTURE_START + 75) +#define BRIDGE_A1 (STRUCTURE_START + 76) +#define NEEDLEWORK_SHOP (STRUCTURE_START + 77) +#define FLAG (STRUCTURE_START + 78) +#define BOAT (STRUCTURE_START + 79) +#define COTTAGE_MY (STRUCTURE_START + 80) +#define COTTAGE_NPC (STRUCTURE_START + 81) +#define PORT_SIGN (STRUCTURE_START + 82) +#define STRUCTURE_END (STRUCTURE_START + 83) #define ETC_START 0x8000 #define ETC_AIRPLANE ETC_START @@ -1858,7 +1858,7 @@ extern int mNT_check_unknown(mActor_name_t item_no); #define SP_NPC_SONCHO_D078 (SP_NPC_START + 120) // D078 #define SP_NPC_SONCHO_D079 (SP_NPC_START + 121) // D079 #define SP_NPC_SASHO (SP_NPC_START + 122) // D07A -// +#define SP_NPC_CASTAWAY (SP_NPC_START + 123) // D07B #define SP_NPC_MAJIN_D07C (SP_NPC_START + 124) // D07C #define SP_NPC_MAJIN_D07D (SP_NPC_START + 125) // D07D #define SP_NPC_MAJIN_BROTHER (SP_NPC_START + 126) // D07E diff --git a/include/m_player_lib.h b/include/m_player_lib.h index 21d24d17..afdebe32 100644 --- a/include/m_player_lib.h +++ b/include/m_player_lib.h @@ -49,6 +49,8 @@ extern void mPlib_request_main_give_from_submenu(mActor_name_t disp_item, int su extern int mPlib_Check_tree_shaken_big(const xyz_t* pos); extern int mPlib_Check_tree_shaken_little(const xyz_t* pos); extern int mPlib_request_main_recieve_wait_type1(GAME* game, mActor_name_t item, int counter_flag); +extern int mPlib_able_player_warp_forEvent(); +extern int mPlib_Get_unable_wade(); extern mPlayer_change_data_from_submenu_c* mPlib_Get_change_data_from_submenu_p(); diff --git a/src/ac_boat_demo.c b/src/ac_boat_demo.c new file mode 100644 index 00000000..d3675274 --- /dev/null +++ b/src/ac_boat_demo.c @@ -0,0 +1,70 @@ +#include "ac_boat_demo.h" + +#include "libultra/libultra.h" +#include "ac_weather.h" +#include "m_bg_item.h" +#include "m_bgm.h" +#include "m_msg.h" + +/* For whatever reason, this file seems to have -pool off */ +#pragma push +#pragma pool_data off + +static void aBTD_actor_ct(ACTOR* actorx, GAME* game); +static void aBTD_actor_dt(ACTOR* actorx, GAME* game); +static void aBTD_actor_move(ACTOR* actorx, GAME* game); + +ACTOR_PROFILE Boat_Demo_Profile = { + mAc_PROFILE_BOAT_DEMO, + ACTOR_PART_CONTROL, + ACTOR_STATE_CAN_MOVE_IN_DEMO_SCENES | ACTOR_STATE_NO_MOVE_WHILE_CULLED, + EMPTY_NO, + ACTOR_OBJ_BANK_KEEP, + sizeof(BOAT_DEMO_ACTOR), + &aBTD_actor_ct, + &aBTD_actor_dt, + &aBTD_actor_move, + mActor_NONE_PROC1, + NULL +}; + +static mDemo_Clip_c aBTD_clip; + +static u8 aBTD_island_prg[] = { +#include "assets/aBTD_island_prg.inc" +}; + +static u8 aBTD_island_ldr[] = { +#include "assets/aBTD_island_ldr.inc" +}; + +static void aBTD_setupAction(BOAT_DEMO_ACTOR* boat_demo, GAME_PLAY* play, int action); + +static void aBTD_actor_ct(ACTOR* actorx, GAME* game) { + BOAT_DEMO_ACTOR* boat_demo = (BOAT_DEMO_ACTOR*)actorx; + GAME_PLAY* play = (GAME_PLAY*)game; + + Common_Get(clip).demo_clip2 = &aBTD_clip; + bzero(&aBTD_clip, sizeof(aBTD_clip)); + Common_Get(clip).demo_clip2->class = boat_demo; + Common_Get(clip).demo_clip2->type = mDemo_CLIP_TYPE_BOAT_DEMO; + boat_demo->island_gba_loader_p = aBTD_island_ldr; + boat_demo->island_gba_program_p = aBTD_island_prg; + + if (mFI_CheckBlockKind(play->block_table.block_x, play->block_table.block_z, mRF_BLOCKKIND_ISLAND) == TRUE) { + boat_demo->at_island = TRUE; + boat_demo->island_npc_info_registered = TRUE; + } + + aBTD_setupAction(boat_demo, play, aBTD_ACTION_SENDO_BIRTH_WAIT); +} + +static void aBTD_actor_dt(ACTOR* actorx, GAME* game) { + if (Common_Get(clip).demo_clip2 != NULL) { + Common_Get(clip).demo_clip2 = NULL; + } +} + +#include "../src/ac_boat_demo_move.c_inc" + +#pragma pop diff --git a/src/ac_boat_demo_move.c_inc b/src/ac_boat_demo_move.c_inc new file mode 100644 index 00000000..715c505a --- /dev/null +++ b/src/ac_boat_demo_move.c_inc @@ -0,0 +1,433 @@ +static int aBTD_check_sendo_and_boat(BOAT_DEMO_ACTOR* boat_demo) { + int res = TRUE; + + if (boat_demo->npc_sendo_actor == NULL) { + if (boat_demo->boat_actor != NULL) { + Actor_delete((ACTOR*)boat_demo->boat_actor); + } + + res = FALSE; + } + + if (boat_demo->boat_actor == NULL) { + if (boat_demo->npc_sendo_actor != NULL) { + Actor_delete((ACTOR*)boat_demo->npc_sendo_actor); + } + + res = FALSE; + } + + return res; +} + +static int aBTD_regist_island_npc_info() { + Island_c* island = Save_GetPointer(island); + Animal_c* animal = &island->animal; + mNpc_NpcList_c* npclist = Common_Get(island_npclist); + int res; + + mNpc_SetNpcList(npclist, animal, mISL_ISLANDER_NUM, TRUE); + + res = mFI_RegistMoveActorList( + npclist->name, + animal->home_info.block_x, animal->home_info.block_z, + animal->home_info.ut_x, animal->home_info.ut_z, + -ANIMAL_NUM_MAX, + 0 + ); + + if (res == TRUE) { + mNPS_set_island_schedule_area(&animal->id); + } + + return res; +} + +static int aBTD_unregist_island_npc_info() { + mNpc_NpcList_c* npclist = Common_Get(island_npclist); + Island_c* island = Save_GetPointer(island); + Animal_c* animal = &island->animal; + int res = mFI_UnregistMoveActorList( + npclist->name, + animal->home_info.block_x, + animal->home_info.block_z + ); + + if (res == TRUE) { + mNPS_reset_schedule_area(&Save_Get(island).animal.id); + mNpc_InitNpcList(npclist, mISL_ISLANDER_NUM); + } + + return res; +} + +static void aBTD_chg_regist_island_npc_info(BOAT_DEMO_ACTOR* boat_demo) { + if (boat_demo->at_island == FALSE) { + if (boat_demo->island_npc_info_registered == FALSE && aBTD_regist_island_npc_info() == TRUE) { + boat_demo->island_npc_info_registered = TRUE; + } + } + else { + if (boat_demo->island_npc_info_registered == TRUE && aBTD_unregist_island_npc_info() == TRUE) { + boat_demo->island_npc_info_registered = FALSE; + } + } +} + +static void aBTD_setup_castaway(BOAT_DEMO_ACTOR* boat_demo, GAME_PLAY* play) { + if (boat_demo->action > aBTD_ACTION_PL_RIDE_ON_START_WAIT && boat_demo->action != aBTD_ACTION_ANCHOR_WAIT) { + if (mEv_check_status(mEv_EVENT_DOZAEMON, mEv_STATUS_RUN) && (Common_Get(spnpc_first_talk_flags) & (1 << aNPC_SPNPC_BIT_DOZAEMON)) == 0) { + mEv_dozaemon_c* dozaemon_ev = (mEv_dozaemon_c*)mEv_reserve_save_area(mEv_EVENT_DOZAEMON, 13); // Shouldn't this be mEv_get_save_area? + + if ( + (dozaemon_ev == NULL || (dozaemon_ev->flags & 1) == 0) && + Save_Get(event_save_common).dozaemon_completed != TRUE && + boat_demo->castaway_actor == NULL + ) { + int setupActor = (*Common_Get(clip).npc_clip->setupActor_proc)(play, SP_NPC_CASTAWAY, -1, -1, -1, -1 , -1, 0, 0); + + if (setupActor == TRUE) { + EV_CASTAWAY_ACTOR* castaway = (EV_CASTAWAY_ACTOR*)Actor_info_fgName_search(&play->actor_info, SP_NPC_CASTAWAY, ACTOR_PART_NPC); + + if (castaway != NULL) { + boat_demo->castaway_actor = castaway; + } + } + } + } + } +} + +static void aBTD_change_season(BOAT_DEMO_ACTOR* boat_demo, GAME_PLAY* play) { + if (boat_demo->at_island == TRUE) { + mFI_SetClimate(mFI_CLIMATE_0); + mFM_returnSeason(); + aWeather_RequestChangeWeatherFromIsland(); + mNpc_ClearIslandPresentFtrInfo(); + mNpc_SetIslandGetLetter(FALSE); + mNpc_SetIslandCheckFtrMsg(FALSE); + } + else { + mFI_SetClimate(mFI_CLIMATE_ISLAND); + mFM_toSummer(); + aWeather_RequestChangeWeatherToIsland(); + mISL_ChangeBG(); + mRmTp_DecideCottageDefaultLightSwitch(); + mSP_SelectRandomItemToAGB(); + mISL_ClearNowPlayerAction(); + mNpc_SetIslandPresentFtr(); + mNpc_SetIslandRoomFtr(&Save_Get(island).animal); + mNpc_SetIslandGetLetter(FALSE); + mNpc_SetIslandCheckFtrMsg(FALSE); + } + + mBI_change_bg_item(play); +} + +static void aBTD_sendo_birth_wait(BOAT_DEMO_ACTOR* boat_demo, GAME_PLAY* play) { + if (Common_Get(clip).npc_clip != NULL && Common_Get(clip).npc_clip->setupActor_proc != NULL) { + int sendo_birth = (*Common_Get(clip).npc_clip->setupActor_proc)(play, SP_NPC_SENDO, -1, -1, -1, -1, -1, 0, 0); + + if (sendo_birth == TRUE) { + NPC_SENDO_ACTOR* sendo_actor = (NPC_SENDO_ACTOR*)Actor_info_fgName_search(&play->actor_info, SP_NPC_SENDO, ACTOR_PART_NPC); + + if (sendo_actor != NULL) { + BOAT_ACTOR* boat_actor = (BOAT_ACTOR*)Actor_info_fgName_search(&play->actor_info, BOAT, ACTOR_PART_ITEM); + + boat_demo->npc_sendo_actor = sendo_actor; + boat_demo->boat_actor = boat_actor; + + sendo_actor->npc_class.actor_class.parent_actor = (ACTOR*)boat_demo; + boat_actor->actor_class.parent_actor = (ACTOR*)boat_demo; + + aBTD_setupAction(boat_demo, play, aBTD_ACTION_PL_RIDE_ON_START_WAIT); + } + } + } +} + +static void aBTD_pl_ride_on_start_wait(BOAT_DEMO_ACTOR* boat_demo, GAME_PLAY* play) { + if (aBTD_check_sendo_and_boat(boat_demo) == FALSE) { + Actor_delete((ACTOR*)boat_demo); + } + else if (boat_demo->demo_act == aBTD_DEMO_PL_RIDE_ON_END) { + aBTD_setupAction(boat_demo, play, aBTD_ACTION_PL_RIDE_ON_END_WAIT); + } +} + +static void aBTD_pl_ride_on_end_wait(BOAT_DEMO_ACTOR* boat_demo, GAME_PLAY* play) { + if (boat_demo->demo_act == aBTD_DEMO_START_CALL_END) { + aBTD_setupAction(boat_demo, play, aBTD_ACTION_START_CALL_END_WAIT); + } +} + +static void aBTD_start_call_end_wait(BOAT_DEMO_ACTOR* boat_demo, GAME_PLAY* play) { + if (boat_demo->demo_act == aBTD_DEMO_MOVE_BOAT_END) { + aBTD_setupAction(boat_demo, play, aBTD_ACTION_SONG_BGM_START_WAIT); + } +} + +static void aBTD_song_bgm_start_wait(BOAT_DEMO_ACTOR* boat_demo, GAME_PLAY* play) { + boat_demo->song_bgm_timer--; + + if (boat_demo->song_bgm_timer <= 0) { + aBTD_setupAction(boat_demo, play, aBTD_ACTION_SING_SENDO_START_WAIT); + } +} + +static void aBTD_sing_sendo_start_wait(BOAT_DEMO_ACTOR* boat_demo, GAME_PLAY* play) { + boat_demo->song_bgm_timer--; + + if (boat_demo->song_bgm_timer <= 0) { + aBTD_setupAction(boat_demo, play, aBTD_ACTION_SING_SENDO_MSG_SET_WAIT); + } +} + +static void aBTD_sing_sendo_msg_set_wait(BOAT_DEMO_ACTOR* boat_demo, GAME_PLAY* play) { + int msg_no = mMsg_Get_msg_num(mMsg_Get_base_window_p()); + + if (msg_no == boat_demo->sing_msg_no) { + aBTD_setupAction(boat_demo, play, aBTD_ACTION_SENDO_DIALOGUE_START_WAIT); + } +} + +static void aBTD_sendo_dialogue_start_wait(BOAT_DEMO_ACTOR* boat_demo, GAME_PLAY* play) { + int msg_no = mMsg_Get_msg_num(mMsg_Get_base_window_p()); + + if (msg_no == boat_demo->sing_msg_no) { + aBTD_setupAction(boat_demo, play, aBTD_ACTION_SING_SENDO_START_WAIT2); + } +} + +static void aBTD_sing_sendo_start_wait2(BOAT_DEMO_ACTOR* boat_demo, GAME_PLAY* play) { + int msg_no = mMsg_Get_msg_num(mMsg_Get_base_window_p()); + + if (msg_no == boat_demo->sing_msg_no) { + aBTD_setupAction(boat_demo, play, aBTD_ACTION_MOVE_BOAT_END_WAIT); + } + + aBTD_chg_regist_island_npc_info(boat_demo); +} + +static void aBTD_move_boat_end_wait(BOAT_DEMO_ACTOR* boat_demo, GAME_PLAY* play) { + if (boat_demo->demo_act == aBTD_DEMO_TOUCH_WHARF_END) { + aBTD_setupAction(boat_demo, play, aBTD_ACTION_TOUCH_WHARF_END_WAIT); + } +} + +static void aBTD_touch_wharf_end_wait(BOAT_DEMO_ACTOR* boat_demo, GAME_PLAY* play) { + if (boat_demo->touching_wharf == FALSE) { + boat_demo->touch_wharf_timer--; + + if (boat_demo->touch_wharf_timer <= 0) { + sAdo_OngenTrgStart(0x165, &boat_demo->boat_actor->actor_class.world.position); + boat_demo->touching_wharf = TRUE; + } + } + + if (boat_demo->demo_act == aBTD_DEMO_PL_RIDE_OFF_START) { + aBTD_setupAction(boat_demo, play, aBTD_ACTION_PL_RIDE_OFF_START_WAIT); + } +} + +static void aBTD_pl_ride_off_start_wait(BOAT_DEMO_ACTOR* boat_demo, GAME_PLAY* play) { + if (boat_demo->demo_act == aBTD_DEMO_PL_RIDE_OFF_END) { + aBTD_setupAction(boat_demo, play, aBTD_ACTION_PL_RIDE_OFF_END_WAIT); + } +} + +static void aBTD_pl_ride_off_end_wait(BOAT_DEMO_ACTOR* boat_demo, GAME_PLAY* play) { + if (boat_demo->demo_act == aBTD_DEMO_ANCHOR) { + aBTD_setupAction(boat_demo, play, aBTD_ACTION_ANCHOR_WAIT); + } +} + +static void aBTD_anchor(BOAT_DEMO_ACTOR* boat_demo, GAME_PLAY* play) { + if (aBTD_check_sendo_and_boat(boat_demo) == FALSE) { + Actor_delete((ACTOR*)boat_demo); + } +} + +typedef void (*aBTD_INIT_PROC)(BOAT_DEMO_ACTOR*, GAME_PLAY*); + +static void aBTD_start_call_end_wait_init(BOAT_DEMO_ACTOR* boat_demo, GAME_PLAY* play) { + mBGMPsComp_make_ps_quietField(0x168); +} + +static void aBTD_song_bgm_start_wait_init(BOAT_DEMO_ACTOR* boat_demo, GAME_PLAY* play) { + boat_demo->song_bgm_timer = 0; +} + +static void aBTD_sing_sendo_start_wait_init(BOAT_DEMO_ACTOR* boat_demo, GAME_PLAY* play) { + static int player_pattern_table[2][2] = { + { 0, 1 }, + { 2, 3 } + }; + + static u8 sing_1st_part_bgm_no[4][5] = { + { 0x5C, 0x5D, 0x5E, 0x5F, 0x60 }, + { 0x66, 0x67, 0x68, 0x69, 0x6A }, + { 0x61, 0x62, 0x63, 0x64, 0x65 }, + { 0x6B, 0x6C, 0x6D, 0x6E, 0x6F } + }; + + static int sing_1st_part_msg_base_no[4] = { + 0x3091, + 0x3163, + 0x3096, + 0x3168 + }; + + int at_island = boat_demo->at_island; + int gender = Common_Get(now_private)->gender; + int kappn_song; + int player_pattern; + + do { + kappn_song = RANDOM(5); + if (!at_island) { + if (kappn_song != Save_Get(island).last_song_to_island) { + Save_Get(island).last_song_to_island = kappn_song; + break; + } + } + else { + if (kappn_song != Save_Get(island).last_song_from_island) { + Save_Get(island).last_song_from_island = kappn_song; + break; + } + } + } while (TRUE); + + player_pattern = player_pattern_table[at_island][gender]; + boat_demo->player_pattern = player_pattern; + mBGMPsComp_make_ps_lost_fanfare(sing_1st_part_bgm_no[player_pattern][kappn_song], 0x168); + boat_demo->sing_msg_no = sing_1st_part_msg_base_no[player_pattern] + kappn_song; + boat_demo->sing_dialog_ofs = RANDOM(10); + boat_demo->sing_2nd_part = RANDOM(10); + boat_demo->song_bgm_timer = 930; +} + +static void aBTD_sendo_dialogue_start_wait_init(BOAT_DEMO_ACTOR* boat_demo, GAME_PLAY* play) { + static int sing_dialogue_msg_base_no[4] = { + 0x309B, + 0x316D, + 0x30A5, + 0x3177 + }; + + int msg_no = sing_dialogue_msg_base_no[boat_demo->player_pattern] + boat_demo->sing_dialog_ofs; + + mMsg_Set_continue_msg_num(mMsg_Get_base_window_p(), msg_no); + boat_demo->sing_msg_no = msg_no; + mMsg_sound_set_voice_silent(mMsg_Get_base_window_p(), TRUE); + aBTD_change_season(boat_demo, play); +} + +static void aBTD_sing_sendo_start_wait2_init(BOAT_DEMO_ACTOR* boat_demo, GAME_PLAY* play) { + static u8 sing_2nd_part_bgm_no[10] = { + 0x70, 0x71, 0x72, 0x73, 0x74, + 0x75, 0x76, 0x77, 0x78, 0x79 + }; + + static int sing_2nd_part_msg_base_no[4] = { + 0x30AF, + 0x3181, + 0x30AF, + 0x3181 + }; + + int song_no; + int msg_no; + + + mMsg_sound_unset_voice_silent(mMsg_Get_base_window_p(), TRUE); + + song_no = sing_2nd_part_bgm_no[boat_demo->sing_2nd_part]; + mBGMPsComp_make_ps_demo(song_no, 0x168); + boat_demo->sing_2nd_part_bgm_no = song_no; + + msg_no = sing_2nd_part_msg_base_no[boat_demo->player_pattern] + boat_demo->sing_2nd_part; + mMsg_Set_continue_msg_num(mMsg_Get_base_window_p(), msg_no); + boat_demo->sing_msg_no = msg_no; +} + +static void aBTD_move_boat_end_wait_init(BOAT_DEMO_ACTOR* boat_demo, GAME_PLAY* play) { + mMsg_sound_set_voice_silent(mMsg_Get_base_window_p(), TRUE); +} + +static void aBTD_touch_wharf_end_wait_init(BOAT_DEMO_ACTOR* boat_demo, GAME_PLAY* play) { + boat_demo->touching_wharf = FALSE; + boat_demo->touch_wharf_timer = 190; +} + +static void aBTD_pl_ride_off_start_wait_init(BOAT_DEMO_ACTOR* boat_demo, GAME_PLAY* play) { + mBGMPsComp_delete_ps_demo(boat_demo->sing_2nd_part_bgm_no, 0x168); +} + +static void aBTD_anchor_init(BOAT_DEMO_ACTOR* boat_demo, GAME_PLAY* play) { + mBGMPsComp_delete_ps_quietField(); + + if (boat_demo->castaway_actor != NULL) { + Actor_delete((ACTOR*)boat_demo->castaway_actor); + } +} + +static void aBTD_init_proc(BOAT_DEMO_ACTOR* boat_demo, GAME_PLAY* play, int action) { + static aBTD_INIT_PROC init_proc[aBTD_ACTION_NUM] = { + (aBTD_INIT_PROC)&none_proc1, + (aBTD_INIT_PROC)&none_proc1, + (aBTD_INIT_PROC)&none_proc1, + &aBTD_start_call_end_wait_init, + &aBTD_song_bgm_start_wait_init, + &aBTD_sing_sendo_start_wait_init, + (aBTD_INIT_PROC)&none_proc1, + &aBTD_sendo_dialogue_start_wait_init, + &aBTD_sing_sendo_start_wait2_init, + &aBTD_move_boat_end_wait_init, + &aBTD_touch_wharf_end_wait_init, + &aBTD_pl_ride_off_start_wait_init, + (aBTD_INIT_PROC)&none_proc1, + &aBTD_anchor_init + }; + + (*init_proc[action])(boat_demo, play); +} + +static void aBTD_setupAction(BOAT_DEMO_ACTOR* boat_demo, GAME_PLAY* play, int action) { + static aBTD_PROC process[aBTD_ACTION_NUM] = { + &aBTD_sendo_birth_wait, + &aBTD_pl_ride_on_start_wait, + &aBTD_pl_ride_on_end_wait, + &aBTD_start_call_end_wait, + &aBTD_song_bgm_start_wait, + &aBTD_sing_sendo_start_wait, + &aBTD_sing_sendo_msg_set_wait, + &aBTD_sendo_dialogue_start_wait, + &aBTD_sing_sendo_start_wait2, + &aBTD_move_boat_end_wait, + &aBTD_touch_wharf_end_wait, + &aBTD_pl_ride_off_start_wait, + &aBTD_pl_ride_off_end_wait, + &aBTD_anchor + }; + + boat_demo->action_proc = process[action]; + boat_demo->action = action; + aBTD_init_proc(boat_demo, play, action); +} + +static void aBTD_actor_move(ACTOR* actorx, GAME* game) { + BOAT_DEMO_ACTOR* boat_demo = (BOAT_DEMO_ACTOR*)actorx; + GAME_PLAY* play = (GAME_PLAY*)game; + BOAT_ACTOR* boat_actor = boat_demo->boat_actor; + + if (boat_actor != NULL) { + actorx->shape_info.rotation.x = boat_actor->actor_class.shape_info.rotation.x; + actorx->shape_info.rotation.y = boat_actor->actor_class.shape_info.rotation.y; + boat_demo->boat_speed = boat_actor->actor_class.speed; + } + + aBTD_setup_castaway(boat_demo, play); + (*boat_demo->action_proc)(boat_demo, play); +} diff --git a/src/ac_ev_castaway.c b/src/ac_ev_castaway.c new file mode 100644 index 00000000..28c0b9d6 --- /dev/null +++ b/src/ac_ev_castaway.c @@ -0,0 +1,100 @@ +#include "ac_ev_castaway.h" + +#include "m_common_data.h" + +static void aECST_actor_ct(ACTOR* actorx, GAME* game); +static void aECST_actor_dt(ACTOR* actorx, GAME* game); +static void aECST_actor_init(ACTOR* actorx, GAME* game); +static void aECST_actor_move(ACTOR* actorx, GAME* game); +static void aECST_actor_draw(ACTOR* actorx, GAME* game); +static void aECST_actor_save(ACTOR* actorx, GAME* game); + +ACTOR_PROFILE Ev_Castaway_Profile = { + mAc_PROFILE_EV_CASTAWAY, + ACTOR_PART_NPC, + ACTOR_STATE_CAN_MOVE_IN_DEMO_SCENES | ACTOR_STATE_NO_MOVE_WHILE_CULLED, + EMPTY_NO, + ACTOR_OBJ_BANK_KEEP, + sizeof(EV_CASTAWAY_ACTOR), + &aECST_actor_ct, + &aECST_actor_dt, + &aECST_actor_init, + mActor_NONE_PROC1, + &aECST_actor_save +}; + +static void aECST_schedule_proc(NPC_ACTOR* actorx, GAME_PLAY* play, int type); + +static void aECST_actor_ct(ACTOR* actorx, GAME* game) { + static aNPC_ct_data_c ct_data = { + &aECST_actor_move, + &aECST_actor_draw, + 5, + NULL, + NULL, + NULL, + 0 + }; + + static xyz_t def_pos = { 3580.0f, 0.0f, 4670.0f }; // 'G-5' @ 9-4 + + EV_CASTAWAY_ACTOR* castaway = (EV_CASTAWAY_ACTOR*)actorx; + + if ((*Common_Get(clip).npc_clip->birth_check_proc)(actorx, game) == TRUE) { + castaway->npc_class.schedule.schedule_proc = &aECST_schedule_proc; + (*Common_Get(clip).npc_clip->ct_proc)(actorx, game, &ct_data); + castaway->npc_class.condition_info.demo_flg = ~aNPC_COND_DEMO_SKIP_MOVE_Y; // is this a mistake? + castaway->npc_class.condition_info.hide_request = FALSE; + castaway->npc_class.palActorIgnoreTimer = -1; + aNPC_SPNPC_BIT_SET(Common_Get(spnpc_first_talk_flags), aNPC_SPNPC_BIT_DOZAEMON); + actorx->status_data.weight = 254; + actorx->gravity = 0.0f; + actorx->max_velocity_y = 0.0f; + actorx->shape_info.rotation.y = DEG2SHORT_ANGLE(68.027344f); // 0x3060 + actorx->world.angle.y = DEG2SHORT_ANGLE(68.027344f); // 0x3060 + castaway->npc_class.movement.mv_angl = DEG2SHORT_ANGLE(68.027344f); // 0x3060 + actorx->world.position = def_pos; + actorx->home.position = def_pos; + } +} + +static void aECST_actor_save(ACTOR* actorx, GAME* game) { + (*Common_Get(clip).npc_clip->save_proc)(actorx, game); +} + +static void aECST_actor_dt(ACTOR* actorx, GAME* game) { + (*Common_Get(clip).npc_clip->dt_proc)(actorx, game); +} + +static void aECST_actor_init(ACTOR* actorx, GAME* game) { + (*Common_Get(clip).npc_clip->init_proc)(actorx, game); +} + +static void aECST_schedule_main_proc(NPC_ACTOR* actorx, GAME_PLAY* play) { + if (actorx->draw.animation_id != 116) { + (*Common_Get(clip).npc_clip->animation_init_proc)((ACTOR*)actorx, 116, 0); + } +} + +static void aECST_schedule_proc(NPC_ACTOR* actorx, GAME_PLAY* play, int type) { + static aNPC_SUB_PROC sched_proc[2] = { + (aNPC_SUB_PROC)&none_proc1, + aECST_schedule_main_proc + }; + + (*sched_proc[type])(actorx, play); +} + +static void aECST_actor_move(ACTOR* actorx, GAME* game) { + EV_CASTAWAY_ACTOR* castaway = (EV_CASTAWAY_ACTOR*)actorx; + s16 cycle = castaway->bobbing_cycle; + + cycle += 512; + actorx->position_speed.y = (actorx->home.position.y + 4.0f + sin_s(cycle) * 4.0f) - actorx->world.position.y; + castaway->bobbing_cycle = cycle; + (*Common_Get(clip).npc_clip->move_proc)(actorx, game); +} + +static void aECST_actor_draw(ACTOR* actorx, GAME* game) { + (*Common_Get(clip).npc_clip->draw_proc)(actorx, game); +} diff --git a/src/ac_ev_santa.c b/src/ac_ev_santa.c new file mode 100644 index 00000000..a88a16f9 --- /dev/null +++ b/src/ac_ev_santa.c @@ -0,0 +1,140 @@ +#include "ac_ev_santa.h" + +#include "libultra/libultra.h" +#include "m_common_data.h" +#include "m_msg.h" +#include "m_play.h" + +enum { + aESNT_ACTION_TALK_END_WAIT, + aESNT_ACTION_CHK_WISH_1ST, + aESNT_ACTION_CHK_WISH_2ND, + aESNT_ACTION_CHK_WISH_FINAL, + aESNT_ACTION_CHK_WISH_MORE, + aESNT_ACTION_MOTION_START_WAIT, + aESNT_ACTION_MOTION_END_WAIT, + + aESNT_ACTION_NUM +}; + +enum { + aESNT_WISH_FTR, + aESNT_WISH_CLOTH, + aESNT_WISH_WALL, + aESNT_WISH_CARPET, + + aESNT_WISH_NUM +}; + +#define aESNT_TALK_TALK_SAME_PLAYER_NUM 3 +#define aESNT_TALK_TALK_OTHER_PLAYER_NUM 3 +#define aESNT_TALK_FINAL_PRESENT_NUM 1 +#define aESNT_TALK_FINAL_NO_PRESENT_NUM 1 +#define aESNT_TALK_SAME_BLOCK_NUM 3 +#define aESNT_TALK_HELLO_NUM 1 +#define aESNT_TALK_CHK_1ST_NUM 1 +#define aESNT_TALK_CHK_2ND_NUM 1 +#define aESNT_TALK_CHK_FINAL_NUM aESNT_WISH_NUM +#define aESNT_TALK_ALMOST_RECOGNIZE_NUM 1 +#define aESNT_TALK_FINAL_PRESENT2_NUM 1 +#define aESNT_TALK_FINAL_NO_PRESENT2_NUM 1 +#define aESNT_TALK_NO_MORE_PRESENTS_NUM 3 + +enum { + aESNT_TALK_TALK_SAME_PLAYER, + aESNT_TALK_TALK_OTHER_PLAYER = aESNT_TALK_TALK_SAME_PLAYER + aESNT_TALK_TALK_SAME_PLAYER_NUM, + aESNT_TALK_FINAL_PRESENT = aESNT_TALK_TALK_OTHER_PLAYER + aESNT_TALK_TALK_OTHER_PLAYER_NUM, + aESNT_TALK_FINAL_NO_PRESENT = aESNT_TALK_FINAL_PRESENT + aESNT_TALK_FINAL_PRESENT_NUM, + aESNT_TALK_SAME_BLOCK = aESNT_TALK_FINAL_NO_PRESENT + aESNT_TALK_FINAL_NO_PRESENT_NUM, + aESNT_TALK_HELLO = aESNT_TALK_SAME_BLOCK + aESNT_TALK_SAME_BLOCK_NUM, + aESNT_TALK_CHK_1ST = aESNT_TALK_HELLO + aESNT_TALK_HELLO_NUM, + aESNT_TALK_CHK_2ND = aESNT_TALK_CHK_1ST + aESNT_TALK_CHK_1ST_NUM, + aESNT_TALK_CHK_FINAL = aESNT_TALK_CHK_2ND + aESNT_TALK_CHK_2ND_NUM, + aESNT_TALK_ALMOST_RECOGNIZE = aESNT_TALK_CHK_FINAL + aESNT_TALK_CHK_FINAL_NUM, + aESNT_TALK_FINAL_PRESENT2 = aESNT_TALK_ALMOST_RECOGNIZE + aESNT_TALK_ALMOST_RECOGNIZE_NUM, + aESNT_TALK_FINAL_NO_PRESENT2 = aESNT_TALK_FINAL_PRESENT2 + aESNT_TALK_FINAL_PRESENT2_NUM, + aESNT_TALK_NO_MORE_PRESENTS = aESNT_TALK_FINAL_NO_PRESENT2 + aESNT_TALK_FINAL_NO_PRESENT2_NUM, + + aESNT_TALK_NUM = aESNT_TALK_NO_MORE_PRESENTS + aESNT_TALK_NO_MORE_PRESENTS_NUM +}; + +static void aESNT_actor_ct(ACTOR*, GAME*); +static void aESNT_actor_dt(ACTOR*, GAME*); +static void aESNT_actor_init(ACTOR*, GAME*); +static void aESNT_actor_move(ACTOR*, GAME*); +static void aESNT_actor_draw(ACTOR*, GAME*); +static void aESNT_actor_save(ACTOR*, GAME*); +static void aESNT_talk_request(ACTOR*, GAME*); +static int aESNT_talk_init(ACTOR*, GAME*); +static int aESNT_talk_end_chk(ACTOR*, GAME*); +static void aESNT_setupAction(EVENT_SANTA_ACTOR*, GAME_PLAY*, int); + +ACTOR_PROFILE Ev_Santa_Profile = { + mAc_PROFILE_EV_SANTA, + ACTOR_PART_NPC, + ACTOR_STATE_NONE, + SP_NPC_SANTA, + ACTOR_OBJ_BANK_KEEP, + sizeof(EVENT_SANTA_ACTOR), + &aESNT_actor_ct, + &aESNT_actor_dt, + &aESNT_actor_init, + mActor_NONE_PROC1, + &aESNT_actor_save +}; + +static void aESNT_actor_ct(ACTOR* actorx, GAME* game) { + static aNPC_ct_data_c ct_data = { + &aESNT_actor_move, + &aESNT_actor_draw, + 3, + &aESNT_talk_request, + &aESNT_talk_init, + &aESNT_talk_end_chk, + 0 + }; + + EVENT_SANTA_ACTOR* santa = (EVENT_SANTA_ACTOR*)actorx; + + if ((*Common_Get(clip).npc_clip->birth_check_proc)(actorx, game) == TRUE) { + mEv_santa_event_c* event_p; + mEv_santa_event_common_c* event_common_p; + + (*Common_Get(clip).npc_clip->ct_proc)(actorx, game, &ct_data); + santa->setup_talk_proc = &aESNT_setupAction; + + event_p = (mEv_santa_event_c*)mEv_get_save_area(mEv_EVENT_TOY_DAY_JINGLE, 0); + if (event_p == NULL) { + /* Reserve event data */ + event_p = (mEv_santa_event_c*)mEv_reserve_save_area(mEv_EVENT_TOY_DAY_JINGLE, 0); + bzero(event_p, sizeof(mEv_santa_event_c)); + mPr_ClearPersonalID(&event_p->pid); + } + santa->event_p = event_p; + + event_common_p = (mEv_santa_event_common_c*)mEv_get_common_area(mEv_EVENT_TOY_DAY_JINGLE, 0); + if (event_common_p == NULL) { + event_common_p = (mEv_santa_event_common_c*)mEv_reserve_common_area(mEv_EVENT_TOY_DAY_JINGLE, 0); + } + santa->event_common_p = event_common_p; + } +} + +static void aESNT_actor_save(ACTOR* actorx, GAME* game) { + (*Common_Get(clip).npc_clip->save_proc)(actorx, game); +} + +static void aESNT_actor_dt(ACTOR* actorx, GAME* game) { + (*Common_Get(clip).npc_clip->dt_proc)(actorx, game); + mEv_actor_dying_message(mEv_EVENT_TOY_DAY_JINGLE, actorx); +} + +static void aESNT_actor_init(ACTOR* actorx, GAME* game) { + (*Common_Get(clip).npc_clip->init_proc)(actorx, game); +} + +static void aESNT_actor_draw(ACTOR* actorx, GAME* game) { + (*Common_Get(clip).npc_clip->draw_proc)(actorx, game); +} + +#include "../src/ac_ev_santa_move.c_inc" diff --git a/src/ac_ev_santa_move.c_inc b/src/ac_ev_santa_move.c_inc new file mode 100644 index 00000000..dd964a46 --- /dev/null +++ b/src/ac_ev_santa_move.c_inc @@ -0,0 +1,365 @@ +static void aESNT_chk_wish_1st(EVENT_SANTA_ACTOR* santa, GAME_PLAY* play) { + if (mMsg_Check_MainNormalContinue(mMsg_Get_base_window_p()) == TRUE) { + mEv_santa_event_common_c* event_common_p = santa->event_common_p; + int present_flag; + + switch (mChoice_Get_ChoseNum(mChoice_Get_base_window_p())) { + case mChoice_CHOICE0: + present_flag = 0; + break; + default: + present_flag = 1; + break; + } + + if (santa->talk_act != aESNT_ACTION_CHK_WISH_1ST) { + present_flag <<= 1; + } + + event_common_p->present |= present_flag; + (*santa->setup_talk_proc)(santa, play, aESNT_ACTION_TALK_END_WAIT); + } +} + +static void aESNT_chk_wish_final(EVENT_SANTA_ACTOR* santa, GAME_PLAY* play) { + if (mMsg_Check_MainNormalContinue(mMsg_Get_base_window_p()) == TRUE) { + mEv_santa_event_common_c* event_common_p = santa->event_common_p; + int present_flag = event_common_p->present; + + switch (mChoice_Get_ChoseNum(mChoice_Get_base_window_p())) { + case mChoice_CHOICE0: + present_flag &= 1; /* Furniture & Cloth */ + break; + default: + present_flag &= 2; /* Wallpaper & Carpet */ + + if ((present_flag & aESNT_WISH_WALL) == 0) { + present_flag = aESNT_WISH_CARPET; + } + break; + } + + event_common_p->present = present_flag; + (*santa->setup_talk_proc)(santa, play, aESNT_ACTION_TALK_END_WAIT); + } +} + +static void aESNT_chk_wish_more(EVENT_SANTA_ACTOR* santa, GAME_PLAY* play) { + int order = mDemo_Get_OrderValue(mDemo_ORDER_NPC0, 9); + + if (order != 0) { + mEv_santa_event_common_c* event_common_p = santa->event_common_p; + u8 present = aESNT_WISH_FTR; + + switch (mMsg_Get_msg_num(mMsg_Get_base_window_p())) { + case MSG_SANTA_WISH_FTR: + present = aESNT_WISH_FTR; + break; + case MSG_SANTA_WISH_WALL: + present = aESNT_WISH_WALL; + break; + case MSG_SANTA_WISH_CARPET: + present = aESNT_WISH_CARPET; + break; + case MSG_SANTA_WISH_CLOTH: + present = aESNT_WISH_CLOTH; + break; + } + + event_common_p->present = present; + mDemo_Set_OrderValue(mDemo_ORDER_NPC0, 9, 0); + (*santa->setup_talk_proc)(santa, play, aESNT_ACTION_TALK_END_WAIT); + } +} + + +static void aESNT_motion_start_wait(EVENT_SANTA_ACTOR* santa, GAME_PLAY* play) { + int order = mDemo_Get_OrderValue(mDemo_ORDER_NPC0, 1); + + if (order == 2) { + (*santa->setup_talk_proc)(santa, play, aESNT_ACTION_MOTION_END_WAIT); + } +} + +typedef void (*aESNT_INIT_PROC)(EVENT_SANTA_ACTOR*, GAME_PLAY*); + +static void aESNT_chk_wish_more_init(EVENT_SANTA_ACTOR* santa, GAME_PLAY* play) { + mDemo_Set_OrderValue(mDemo_ORDER_NPC0, 9, 0); +} + +static void aESNT_motion_end_wait_init(EVENT_SANTA_ACTOR* santa, GAME_PLAY* play) { + mDemo_Set_OrderValue(mDemo_ORDER_NPC1, 0, ITM_PRESENT); + mDemo_Set_OrderValue(mDemo_ORDER_NPC1, 1, 7); + mDemo_Set_OrderValue(mDemo_ORDER_NPC1, 2, 1); +} + +static void aESNT_init_proc(EVENT_SANTA_ACTOR* santa, GAME_PLAY* play, int act) { + static aESNT_INIT_PROC init_proc[aESNT_ACTION_NUM] = { + (aESNT_INIT_PROC)&none_proc1, + (aESNT_INIT_PROC)&none_proc1, + (aESNT_INIT_PROC)&none_proc1, + (aESNT_INIT_PROC)&none_proc1, + &aESNT_chk_wish_more_init, + (aESNT_INIT_PROC)&none_proc1, + &aESNT_motion_end_wait_init + }; + + (*init_proc[act])(santa, play); +} + +static void aESNT_setupAction(EVENT_SANTA_ACTOR* santa, GAME_PLAY* play, int act) { + static aESNT_TALK_PROC process[aESNT_ACTION_NUM] = { + (aESNT_TALK_PROC)&none_proc1, + &aESNT_chk_wish_1st, + &aESNT_chk_wish_1st, + &aESNT_chk_wish_final, + &aESNT_chk_wish_more, + &aESNT_motion_start_wait, + (aESNT_TALK_PROC)&none_proc1 + }; + + santa->talk_act = act; + santa->talk_proc = process[act]; + aESNT_init_proc(santa, play, act); +} + +static int aESNT_check_pl_cloth(mEv_santa_event_c* event_p) { + mActor_name_t* cloth_p = event_p->cloth; + mActor_name_t pl_cloth = Common_Get(now_private)->cloth.item; + int i; + int res = TRUE; + + for (i = 0; i != event_p->present_count; i++) { + if (*cloth_p == pl_cloth) { + res = FALSE; + break; + } + + cloth_p++; + } + + return res; +} + +static int aESNT_before_talk_present_decide_talk_data_idx(EVENT_SANTA_ACTOR* santa, mEv_santa_event_c* event_p, mEv_santa_event_common_c* event_common_p, int type) { + static int talk_data_idx[2][2] = { + { aESNT_TALK_FINAL_PRESENT, aESNT_TALK_FINAL_NO_PRESENT }, + { aESNT_TALK_FINAL_PRESENT2, aESNT_TALK_FINAL_NO_PRESENT2 } + }; + static int category[aESNT_WISH_NUM] = { mSP_KIND_FURNITURE, mSP_KIND_CLOTH, mSP_KIND_WALLPAPER, mSP_KIND_CARPET }; + int item_idx = mPr_GetPossessionItemIdx(Common_Get(now_private), EMPTY_NO); + int inv_full; + mActor_name_t present; + + if (item_idx != -1) { + if (event_common_p->present >= aESNT_WISH_NUM) { + event_common_p->present = aESNT_WISH_CARPET; + } + + mSP_SelectRandomItem_New(NULL, &present, 1, NULL, 0, category[event_common_p->present], mSP_LISTTYPE_CHRISTMAS, FALSE); + mPr_SetPossessionItem(Common_Get(now_private), item_idx, present, mPr_ITEM_COND_PRESENT); + mPr_CopyPersonalID(&event_p->pid, &Common_Get(now_private)->player_ID); + santa->present = present; + event_common_p->talk_counter = 0; + event_p->cloth[event_p->present_count] = Common_Get(now_private)->cloth.item; + event_p->present_count++; + inv_full = FALSE; + + } + else { + inv_full = TRUE; + } + + return talk_data_idx[type][inv_full]; +} + +static int aESNT_before_talk_more_check_decide_talk_data_idx(mEv_santa_event_common_c* event_common_p) { + int talk_data_idx = aESNT_TALK_HELLO; + + switch (event_common_p->talk_counter) { + case 0: + talk_data_idx = aESNT_TALK_HELLO; + break; + case 1: + talk_data_idx = aESNT_TALK_CHK_1ST; + break; + case 2: + talk_data_idx = aESNT_TALK_CHK_2ND; + break; + case 3: + talk_data_idx = aESNT_TALK_CHK_FINAL + event_common_p->present; /* select index based on desired present */ + break; + } + + event_common_p->talk_counter++; + return talk_data_idx; +} + +static int aESNT_before_talk_decide_talk_data_idx(EVENT_SANTA_ACTOR* santa, GAME_PLAY* play, mEv_santa_event_c* event_p, mEv_santa_event_common_c* event_common_p) { + int talk_data_idx; + + /* @BUG - because we compare the acre the player is in (GAME_PLAY block table) + * against the last acre we talked to Jingle, we can actually talk to him again + * without having to find him again. If you trap him at the border of an acre + * and then move into the adjacent acre and talk to him, GAME_PLAY's block state + * updates which passes the 'same block' check. Rinse and repeat between two acres + * to satisfy the talk requirements without having to do the search portion. + */ + #if !defined(BUGFIXES) || defined(ALLOW_EXPLOITS) + if (play->block_table.block_x == event_common_p->bx && play->block_table.block_z == event_common_p->bz) { + talk_data_idx = aESNT_TALK_SAME_BLOCK + RANDOM(aESNT_TALK_SAME_BLOCK_NUM); + } + #else + /* Use Jingle's actor block instead of GAME_PLAY's current block (player block) */ + if (santa->npc_class.actor_class.block_x == event_common_p->bx && santa->npc_class.actor_class.block_x == event_common_p->bz) { + talk_data_idx = aESNT_TALK_SAME_BLOCK + RANDOM(aESNT_TALK_SAME_BLOCK_NUM); + } + #endif + else if (event_common_p->talk_counter >= 4) { + talk_data_idx = aESNT_before_talk_present_decide_talk_data_idx(santa, event_p, event_common_p, 0); + } + else { + talk_data_idx = aESNT_before_talk_more_check_decide_talk_data_idx(event_common_p); + } + + if (talk_data_idx != aESNT_TALK_FINAL_NO_PRESENT) { + /* Update talked acre */ + #if !defined(BUGFIXES) || defined(ALLOW_EXPLOITS) + event_common_p->bx = play->block_table.block_x; + event_common_p->bz = play->block_table.block_z; + #else + event_common_p->bx = santa->npc_class.actor_class.block_x; + event_common_p->bz = santa->npc_class.actor_class.block_z; + #endif + } + + return talk_data_idx; +} + +static int aESNT_after_talk_restart_Q_decide_talk_data_idx(mEv_santa_event_common_c* event_common_p) { + event_common_p->last_talk_cloth = Common_Get(now_private)->cloth.item; + event_common_p->talk_counter++; + return aESNT_TALK_ALMOST_RECOGNIZE; +} + +static int aESNT_after_talk_same_pl_decide_talk_data_idx(EVENT_SANTA_ACTOR* santa, mEv_santa_event_c* event_p, mEv_santa_event_common_c* event_common_p) { + int talk_data_idx; + + if (aESNT_check_pl_cloth(event_p) == TRUE) { + if (event_p->present_count >= mEv_SANTA_CLOTH_NUM_MAX) { + talk_data_idx = aESNT_TALK_NO_MORE_PRESENTS + RANDOM(aESNT_TALK_NO_MORE_PRESENTS_NUM); + } + else if (event_common_p->talk_counter == 0) { + talk_data_idx = aESNT_after_talk_restart_Q_decide_talk_data_idx(event_common_p); + } + else if (event_common_p->last_talk_cloth == Common_Get(now_private)->cloth.item) { + talk_data_idx = aESNT_before_talk_present_decide_talk_data_idx(santa, event_p, event_common_p, 1); + } + else { + talk_data_idx = aESNT_after_talk_restart_Q_decide_talk_data_idx(event_common_p); + event_common_p->talk_counter = 1; + } + } + else { + event_common_p->talk_counter = 0; + talk_data_idx = aESNT_TALK_TALK_SAME_PLAYER + RANDOM(aESNT_TALK_TALK_SAME_PLAYER_NUM); + } + + return talk_data_idx; +} + +static int aESNT_after_talk_other_pl_decide_talk_data_idx(mEv_santa_event_c* event_p) { + mMsg_Set_free_str(mMsg_Get_base_window_p(), mMsg_FREE_STR0, event_p->pid.player_name, PLAYER_NAME_LEN); + return aESNT_TALK_TALK_OTHER_PLAYER + RANDOM(aESNT_TALK_TALK_OTHER_PLAYER_NUM); +} + +static int aESNT_after_talk_decide_talk_data_idx(EVENT_SANTA_ACTOR* santa, mEv_santa_event_c* event_p, mEv_santa_event_common_c* event_common_p) { + if (mPr_CheckCmpPersonalID(&event_p->pid, &Common_Get(now_private)->player_ID) == TRUE) { + return aESNT_after_talk_same_pl_decide_talk_data_idx(santa, event_p, event_common_p); + } + else { + return aESNT_after_talk_other_pl_decide_talk_data_idx(event_p); + } +} + +static void aESNT_getP_talk_data(ACTOR* actorx) { + static aESNT_talk_data_c talk_data[aESNT_TALK_NUM] = { + { 0x07BF, aESNT_ACTION_TALK_END_WAIT }, + { 0x07C0, aESNT_ACTION_TALK_END_WAIT }, + { 0x07C1, aESNT_ACTION_TALK_END_WAIT }, + { 0x07C2, aESNT_ACTION_TALK_END_WAIT }, + { 0x07C3, aESNT_ACTION_TALK_END_WAIT }, + { 0x07C4, aESNT_ACTION_TALK_END_WAIT }, + { 0x07BA, aESNT_ACTION_MOTION_START_WAIT }, + { 0x07B9, aESNT_ACTION_TALK_END_WAIT }, + { 0x07BC, aESNT_ACTION_TALK_END_WAIT }, + { 0x07BD, aESNT_ACTION_TALK_END_WAIT }, + { 0x07BE, aESNT_ACTION_TALK_END_WAIT }, + { 0x07AA, aESNT_ACTION_TALK_END_WAIT }, + { 0x07AB, aESNT_ACTION_CHK_WISH_1ST }, + { 0x07AE, aESNT_ACTION_CHK_WISH_2ND }, + { 0x07B2, aESNT_ACTION_CHK_WISH_FINAL }, + { 0x07B4, aESNT_ACTION_CHK_WISH_FINAL }, + { 0x07B1, aESNT_ACTION_CHK_WISH_FINAL }, + { 0x07B3, aESNT_ACTION_CHK_WISH_FINAL }, + { 0x2B4C, aESNT_ACTION_CHK_WISH_MORE }, + { 0x2B59, aESNT_ACTION_MOTION_START_WAIT }, + { 0x2B58, aESNT_ACTION_TALK_END_WAIT }, + { 0x2B5B, aESNT_ACTION_TALK_END_WAIT }, + { 0x2B5C, aESNT_ACTION_TALK_END_WAIT }, + { 0x2B5D, aESNT_ACTION_TALK_END_WAIT } + }; + + EVENT_SANTA_ACTOR* santa = (EVENT_SANTA_ACTOR*)actorx; + GAME_PLAY* play = (GAME_PLAY*)gamePT; + mEv_santa_event_c* event_p = santa->event_p; + mEv_santa_event_common_c* event_common_p = santa->event_common_p; + int talk_data_idx; + + if (mPr_NullCheckPersonalID(&event_p->pid) == FALSE) { + talk_data_idx = aESNT_after_talk_decide_talk_data_idx(santa, event_p, event_common_p); + } + else { + talk_data_idx = aESNT_before_talk_decide_talk_data_idx(santa, play, event_p, event_common_p); + } + + santa->talk_data_p = &talk_data[talk_data_idx]; +} + +static void aESNT_set_talk_info(ACTOR* actorx) { + EVENT_SANTA_ACTOR* santa = (EVENT_SANTA_ACTOR*)actorx; + + aESNT_getP_talk_data(actorx); + mEv_set_status(mEv_EVENT_TOY_DAY_JINGLE, mEv_STATUS_TALK); + mDemo_Set_msg_num(santa->talk_data_p->msg_no); +} + +static void aESNT_talk_request(ACTOR* actorx, GAME* game) { + mDemo_Request(mDemo_TYPE_TALK, actorx, &aESNT_set_talk_info); +} + +static int aESNT_talk_init(ACTOR* actorx, GAME* game) { + EVENT_SANTA_ACTOR* santa = (EVENT_SANTA_ACTOR*)actorx; + GAME_PLAY* play = (GAME_PLAY*)game; + + (*santa->setup_talk_proc)(santa, play, santa->talk_data_p->talk_act); + mDemo_Set_ListenAble(); + return TRUE; +} + +static int aESNT_talk_end_chk(ACTOR* actorx, GAME* game) { + EVENT_SANTA_ACTOR* santa = (EVENT_SANTA_ACTOR*)actorx; + GAME_PLAY* play = (GAME_PLAY*)game; + int res = FALSE; + + (*santa->talk_proc)(santa, play); + if (mDemo_Check(mDemo_TYPE_TALK, actorx) == FALSE) { + res = TRUE; + } + + return res; +} + +static void aESNT_actor_move(ACTOR* actorx, GAME* game) { + (*Common_Get(clip).npc_clip->move_proc)(actorx, game); +} diff --git a/src/ac_npc_rtc.c b/src/ac_npc_rtc.c index cd19d9ff..6eef7e3d 100644 --- a/src/ac_npc_rtc.c +++ b/src/ac_npc_rtc.c @@ -108,7 +108,7 @@ void aNRTC_actor_move(ACTOR* actor, GAME* game){ GAME_PLAY* play = (GAME_PLAY*)game; - if(rtc->npc_class.draw._580 == 0x76){ + if(rtc->npc_class.draw.animation_id == 0x76){ sAdos_GetStaffRollInfo(&info); if(info.unk0 != 4){ val = 0.0f; diff --git a/src/ac_npc_rtc_talk.c.inc b/src/ac_npc_rtc_talk.c.inc index f5a40a98..ccb8c4e9 100644 --- a/src/ac_npc_rtc_talk.c.inc +++ b/src/ac_npc_rtc_talk.c.inc @@ -326,10 +326,10 @@ int aNRTC_talk_end_chk(ACTOR* actor,GAME* game){ } if (mDemo_Get_OrderValue(4, 0) == 0) { if (unk9AC >= 0x258) { - if ( rtc->npc_class.draw._580 != 0x76) { + if ( rtc->npc_class.draw.animation_id != 0x76) { mDemo_Set_OrderValue(4, 0, 0xFF); } - } else if (rtc->npc_class.draw._580 == 0x76) { + } else if (rtc->npc_class.draw.animation_id == 0x76) { mDemo_Set_OrderValue(4, 0, 0xFD); } } diff --git a/src/ac_weather.c b/src/ac_weather.c index c4dc77cc..c3041cc6 100644 --- a/src/ac_weather.c +++ b/src/ac_weather.c @@ -102,11 +102,11 @@ static void aWeather_RequestChangeWeather(ACTOR* actor, s16 status, s16 level){ } } -void aWeather_RequestChangeWeatherToIsland(){ +extern void aWeather_RequestChangeWeatherToIsland(){ aWeather_RequestChangeWeather(&Common_Get(clip.weather_clip)->actor->actor_class,Common_Get(island_weather),Common_Get(island_weather_intensity)); } -void aWeather_RequestChangeWeatherFromIsland(){ +extern void aWeather_RequestChangeWeatherFromIsland(){ aWeather_RequestChangeWeather(&Common_Get(clip.weather_clip)->actor->actor_class, mEnv_SAVE_GET_WEATHER_TYPE(Save_Get(weather)) , mEnv_SAVE_GET_WEATHER_INTENSITY(Save_Get(weather))); } diff --git a/src/m_actor.c b/src/m_actor.c index 81ca1099..18b0bfc1 100644 --- a/src/m_actor.c +++ b/src/m_actor.c @@ -339,7 +339,7 @@ extern void Actor_info_ct(GAME* game, Actor_info* actor_info, Actor_data* player } /* Spawn any demo actors */ - for (i = 0; i < mDemo_CLIP_TYPE_NUM - 1; i++) { + for (i = 0; i < 2; i++) { s16 demo_profile = Common_Get(demo_profiles[i]); if (demo_profile != mAc_PROFILE_NUM) { diff --git a/src/m_camera2.c b/src/m_camera2.c index 8c351253..17ed1bc5 100644 --- a/src/m_camera2.c +++ b/src/m_camera2.c @@ -2671,7 +2671,7 @@ static void Camera2_main_Staff_Roll_SetPos(GAME_PLAY* play) { s_xyz angle; if (speaker != NULL || listener != NULL) { - s8* kk_save_area = mEv_get_save_area(mEv_EVENT_KK_SLIDER, 10); + u8* kk_save_area = mEv_get_save_area(mEv_EVENT_KK_SLIDER, 10); if (speaker == NULL || listener == NULL) { distance = 0.0f; diff --git a/src/m_choice.c b/src/m_choice.c new file mode 100644 index 00000000..ab0123b0 --- /dev/null +++ b/src/m_choice.c @@ -0,0 +1,121 @@ +#include "m_choice.h" + +#include "audio.h" +#include "jsyswrap.h" +#include "libultra/libultra.h" +#include "m_common_data.h" +#include "m_font.h" +#include "m_msg.h" +#include "sys_matrix.h" + +typedef void (*mChoice_MAIN_PROC)(mChoice_c*, GAME*); + +static void mChoice_MainSetup(mChoice_c* choice, GAME* game); + +static u32 Choice_table_rom_start = 0; +static u32 Choice_rom_start = 0; + +#ifdef MUST_MATCH +/* Force assetrip to detect these assets. They're used in a .c_inc file. */ +static u8 unused_con_waku_swaku3_tex[] = { + #ifndef __INTELLISENSE__ + #include "assets/con_waku_swaku3_tex.inc" + #endif +}; + +static Vtx unused_con_sentaku2_v[] = { + #ifndef __INTELLISENSE__ + #include "assets/con_sentaku2_v.inc" + #endif +}; +#endif + +static void mChoice_MainSetup_Hide(mChoice_c*, GAME*); +static void mChoice_MainSetup_Appear(mChoice_c*, GAME*); +static void mChoice_MainSetup_Normal(mChoice_c*, GAME*); +static void mChoice_MainSetup_Disappear(mChoice_c*, GAME*); + +static void mChoice_init(mChoice_c* choice, GAME* game); +static void mChoice_check_ct(mChoice_c* choice); +static void mChoice_SetMatrix(mChoice_c* choice, GAME* game, int type); +static void mChoice_SetMatrixDisplay(mChoice_c* choice, GAME* game, int type); +static void mChoice_UnSetMatrix(); +static void mChoice_UnSetMatrixDisplay(GAME* game, int type); +static void mChoice_DrawWindowBody(mChoice_c* choice, GAME* game, int type); +static void mChoice_DrawFont(mChoice_c* choice, GAME* game, int type); + +static void mChoice_Main_Hide(mChoice_c*, GAME*); +static void mChoice_Main_Appear(mChoice_c*, GAME*); +static void mChoice_Main_Normal(mChoice_c*, GAME*); +static void mChoice_Main_Disappear(mChoice_c*, GAME*); + +static void mChoice_MainSetup(mChoice_c* choice, GAME* game) { + static mChoice_MAIN_PROC proc[mChoice_MAIN_INDEX_NUM] = { + &mChoice_MainSetup_Hide, + &mChoice_MainSetup_Appear, + &mChoice_MainSetup_Normal, + &mChoice_MainSetup_Disappear + }; + + int index = choice->requested_main_index; + + /* This is necessary lol */ + if (index < 0) { + return; + } + else if (index < 0 || index >= mChoice_MAIN_INDEX_NUM || proc[index] == NULL) { + return; + } + + (*proc[index])(choice, game); +} + +extern void mChoice_Main(mChoice_c* choice, GAME* game) { + static mChoice_MAIN_PROC proc[mChoice_MAIN_INDEX_NUM] = { + &mChoice_Main_Hide, + &mChoice_Main_Appear, + &mChoice_Main_Normal, + &mChoice_Main_Disappear + }; + + int index = choice->main_index; + + if (index < 0 || index >= mChoice_MAIN_INDEX_NUM || proc[index] == NULL) { + return; + } + + (*proc[index])(choice, game); +} + +extern void mChoice_Draw(mChoice_c* choice, GAME* game, int mode) { + if (choice->window_visible_flag) { + mFont_SetMatrix(game->graph, mode); + mChoice_SetMatrix(choice, game, mode); + mChoice_SetMatrixDisplay(choice, game, mode); + mChoice_DrawWindowBody(choice, game, mode); + mChoice_UnSetMatrixDisplay(game, mode); + mChoice_DrawFont(choice, game, mode); + mChoice_UnSetMatrix(); + mFont_UnSetMatrix(game->graph, mode); + } +} + +extern void mChoice_aram_init() { + Choice_table_rom_start = JW_GetAramAddress(RESOURCE_SELECT_TABLE); + Choice_rom_start = JW_GetAramAddress(RESOURCE_SELECT); +} + +extern void mChoice_ct(mChoice_c* choice, GAME* game) { + mChoice_check_ct(choice); + mChoice_init(choice, game); +} + +extern void mChoice_dt(mChoice_c* choice, GAME* game) { } + +#include "../src/m_choice_main.c_inc" +#include "../src/m_choice_sound.c_inc" +#include "../src/m_choice_main_hide.c_inc" +#include "../src/m_choice_main_appear.c_inc" +#include "../src/m_choice_main_normal.c_inc" +#include "../src/m_choice_main_disappear.c_inc" +#include "../src/m_choice_draw.c_inc" diff --git a/src/m_choice_draw.c_inc b/src/m_choice_draw.c_inc new file mode 100644 index 00000000..b65b574c --- /dev/null +++ b/src/m_choice_draw.c_inc @@ -0,0 +1,168 @@ +static void mChoice_SetMatrix(mChoice_c* choice, GAME* game, int type) { + GRAPH* graph = game->graph; + f32 scale = choice->scale; + f32 x = ( choice->center_x - 160.0f) * 16.0f; + f32 y = (-choice->center_y + 120.0f) * 16.0f; + + Matrix_push(); + Matrix_translate(x, y, 0.0f, 1); + Matrix_scale(scale, scale, 1.0f, 1); + + OPEN_DISP(graph); + + if (type == mFont_MODE_FONT) { + gSPMatrix(NOW_FONT_DISP++, _Matrix_to_Mtx_new(graph), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + } + else { + gSPMatrix(NOW_POLY_OPA_DISP++, _Matrix_to_Mtx_new(graph), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + } + + CLOSE_DISP(graph); +} + +static void mChoice_SetMatrixDisplay(mChoice_c* choice, GAME* game, int type) { + GRAPH* graph = game->graph; + f32 scale_x = choice->scale_x; + f32 scale_y = choice->scale_y; + + Matrix_push(); + Matrix_scale(scale_x, scale_y, 1.0f, 1); + + OPEN_DISP(graph); + + if (type == mFont_MODE_FONT) { + gSPMatrix(NOW_FONT_DISP++, _Matrix_to_Mtx_new(graph), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + } + else { + gSPMatrix(NOW_POLY_OPA_DISP++, _Matrix_to_Mtx_new(graph), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + } + + CLOSE_DISP(graph); +} + +static void mChoice_UnSetMatrix() { + Matrix_pull(); +} + +static void mChoice_UnSetMatrixDisplay(GAME* game, int type) { + GRAPH* graph = game->graph; + + Matrix_pull(); + + OPEN_DISP(graph); + + if (type == mFont_MODE_FONT) { + gSPMatrix(NOW_FONT_DISP++, _Matrix_to_Mtx_new(graph), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + } + else { + gSPMatrix(NOW_POLY_OPA_DISP++, _Matrix_to_Mtx_new(graph), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + } + + CLOSE_DISP(graph); +} + +static u8 con_waku_swaku3_tex[] ATTRIBUTE_ALIGN(32) = { + #ifndef __INTELLISENSE__ + #include "assets/con_waku_swaku3_tex.inc" + #endif +}; + +static Vtx con_sentaku2_v[] = { + #ifndef __INTELLISENSE__ + #include "assets/con_sentaku2_v.inc" + #endif +}; + +static Gfx con_sentaku2_modelT[] = { + gsSPTexture(0, 0, 0, 0, G_ON), + gsDPSetPrimColor(0, 255, 255, 255, 155, 255), + gsDPLoadTextureBlock_4b_Dolphin(con_waku_swaku3_tex, G_IM_FMT_I, 128, 64, 15, GX_MIRROR, GX_MIRROR, 0, 0), + gsSPVertex(&con_sentaku2_v[0], 4, 0), + gsSPNTrianglesInit_5b( + 2, // tri count + 0, 1, 2, // tri0 + 0, 2, 3, // tri1 + 0, 0, 0 // tri2 + ), + gsSPEndDisplayList() +}; + +static Gfx mChoice_init_disp[] = { + gsDPPipeSync(), + gsSPClearGeometryMode(G_ZBUFFER | G_SHADE | G_CULL_BOTH | G_FOG | G_LIGHTING | G_TEXTURE_GEN | G_TEXTURE_GEN_LINEAR | G_LOD | G_SHADING_SMOOTH), + gsDPSetTextureLOD(G_TL_TILE), + gsDPSetTextureConvert(G_TC_FILT), + gsDPSetTextureFilter(G_TF_BILERP), + gsDPSetCycleType(G_CYC_1CYCLE), + gsDPSetTexturePersp(G_TP_PERSP), + gsDPSetAlphaDither(G_AD_DISABLE), + gsDPSetColorDither(G_CD_DISABLE), + gsDPSetCombineKey(G_CK_NONE), + gsDPSetCombineLERP(0, 0, 0, PRIMITIVE, 0, 0, 0, TEXEL0, 0, 0, 0, PRIMITIVE, 0, 0, 0, TEXEL0), + gsDPSetRenderMode(G_RM_XLU_SURF, G_RM_XLU_SURF2), + gsSPEndDisplayList() +}; + +static void mChoice_DrawWindowBody(mChoice_c* choice, GAME* game, int type) { + GRAPH* graph = game->graph; + + OPEN_DISP(graph); + + if (type == mFont_MODE_FONT) { + gSPDisplayList(NOW_FONT_DISP++, mChoice_init_disp); + gSPDisplayList(NOW_FONT_DISP++, con_sentaku2_modelT); + } + else { + gSPDisplayList(NOW_POLY_OPA_DISP++, mChoice_init_disp); + gSPDisplayList(NOW_POLY_OPA_DISP++, con_sentaku2_modelT); + } + + CLOSE_DISP(graph); +} + +static void mChoice_DrawFont(mChoice_c* choice, GAME* game, int type) { + int i; + int choice_num = choice->data.choice_num; + f32 x = choice->text_x; + f32 y = choice->text_y; + int selected_idx = choice->selected_choice_idx; + int r; + int g; + int b; + + for (i = 0; i < choice_num; i++) { + if (i == selected_idx) { + r = choice->selected_choice_text_color.r; + g = choice->selected_choice_text_color.g; + b = choice->selected_choice_text_color.b; + mFont_SetMarkChar( + game, + mFont_MARKTYPE_CHOICE, + x - 16.0f, y, + choice->background_color.r, choice->background_color.g, choice->background_color.b, 255, + FALSE, + 1.0f, 1.0f, + type + ); + } + else { + r = choice->text_color.r; + g = choice->text_color.g; + b = choice->text_color.b; + } + + mFont_SetLineStrings_AndSpace( + game, + choice->data.strings[i], choice->data.string_lens[i], + x, y, + r, g, b, 255, + FALSE, + TRUE, + 0, + 1.0f, 1.0f, + type + ); + + y += 16.0f; + } +} diff --git a/src/m_choice_main.c_inc b/src/m_choice_main.c_inc new file mode 100644 index 00000000..b47f0657 --- /dev/null +++ b/src/m_choice_main.c_inc @@ -0,0 +1,583 @@ +extern mChoice_c* mChoice_Get_base_window_p() { + return &mMsg_Get_base_window_p()->choice_window; +} + +static void mChoice_init(mChoice_c* choice, GAME* game) { + choice->center_x = 191.0f; + choice->center_y = 83.0f; + choice->text_color.r = 180; + choice->text_color.g = 150; + choice->text_color.b = 110; + choice->text_color.a = 255; + choice->text_scale_x = 1.0f; + choice->text_scale_y = 1.0f; + choice->text_x = 104.0f; + choice->text_y = 96.0f; + choice->scale_x = 1.0f; + choice->scale_y = 1.0f; + choice->data.choice_num = mChoice_CHOICE_NUM; + choice->selected_choice_idx = mChoice_CHOICE0; + choice->selected_choice_text_color.r = 120; + choice->selected_choice_text_color.g = 50; + choice->selected_choice_text_color.b = 50; + choice->selected_choice_text_color.a = 255; + choice->background_color.r = 0; + choice->background_color.g = 195; + choice->background_color.b = 185; + choice->background_color.a = 255; + choice->choice_automove_timer = 0.0f; + choice->_D4 = 232.0f; + choice->_D8 = 104.0f; + choice->scale = 0.0f; + choice->main_index = mChoice_MAIN_HIDE; + choice->requested_main_index = -1; + choice->window_visible_flag = FALSE; + choice->font_visible_flag = FALSE; + choice->choice_automove_type = mChoice_AUTOMOVE_STOPPED; + choice->choice_automove_timer = 0.0f; // duplicate set + choice->timer = 0.0f; + choice->no_b_flag = FALSE; + choice->no_close_flag = FALSE; +} + +extern void mChoice_Change_request_main_index(mChoice_c* choice, int request_main_index) { + choice->requested_main_index = request_main_index; +} + +extern int mChoice_check_main_index(mChoice_c* choice) { + return choice->main_index; +} + +extern int mChoice_check_main_normal(mChoice_c* choice) { + if (mChoice_check_main_index(choice) == mChoice_MAIN_NORMAL) { + return TRUE; + } + + return FALSE; +} + +static void mChoice_Init_choice_data(mChoice_c* choice) { + choice->data.choice_num = 0; +} + +static int mChoice_Add_choice_data(mChoice_c* choice, u8* str, int max_len) { + if (str != NULL && max_len > 0 && max_len <= mChoice_CHOICE_STRING_LEN) { + int num = choice->data.choice_num; + + if (num < mChoice_CHOICE_NUM) { + int len = mMsg_Get_Length_String(str, max_len); + u8* dst = choice->data.strings[num]; + int i; + + for (i = 0; i < len; i++) { + *dst++ = *str++; + } + + choice->data.string_lens[num] = len; + choice->data.choice_num++; + return num; + } + } + + return -1; +} + +extern void mChoice_Set_choice_data( + mChoice_c* choice, + u8* str0, int str0_len, + u8* str1, int str1_len, + u8* str2, int str2_len, + u8* str3, int str3_len, + u8* str4, int str4_len, + u8* str5, int str5_len +) { + mChoice_Init_choice_data(choice); + + if (str0 != NULL && str0_len > 0 && str0_len <= mChoice_CHOICE_STRING_LEN) { + mChoice_Add_choice_data(choice, str0, str0_len); + } + + if (str1 != NULL && str1_len > 0 && str1_len <= mChoice_CHOICE_STRING_LEN) { + mChoice_Add_choice_data(choice, str1, str1_len); + } + + if (str2 != NULL && str2_len > 0 && str2_len <= mChoice_CHOICE_STRING_LEN) { + mChoice_Add_choice_data(choice, str2, str2_len); + } + + if (str3 != NULL && str3_len > 0 && str3_len <= mChoice_CHOICE_STRING_LEN) { + mChoice_Add_choice_data(choice, str3, str3_len); + } + + if (str4 != NULL && str4_len > 0 && str4_len <= mChoice_CHOICE_STRING_LEN) { + mChoice_Add_choice_data(choice, str4, str4_len); + } + + if (str5 != NULL && str5_len > 0 && str5_len <= mChoice_CHOICE_STRING_LEN) { + mChoice_Add_choice_data(choice, str5, str5_len); + } +} + +static int mChoice_Get_MaxStringDotWidth(mChoice_c* choice) { + int i; + int choice_num = choice->data.choice_num; + int max_width = 0; + + for (i = 0; i < choice_num; i++) { + u8* str = choice->data.strings[i]; + int len = choice->data.string_lens[i]; + int width = mFont_GetStringWidth(str, len, TRUE); + + if (width > max_width) { + max_width = width; + } + } + + return max_width; +} + +static int mChoice_Get_MaxStringDotHeight(mChoice_c* choice) { + return choice->data.choice_num * 16; +} + +static void mChoice_Set_DisplayScaleAndDisplayPos(mChoice_c* choice) { + int dw = mChoice_Get_MaxStringDotWidth(choice); + f32 dotW = ((f32)dw - 24.0f) / 96.0f; + int dh = mChoice_Get_MaxStringDotHeight(choice); + f32 dotH = ((f32)dh - 32.0f) / 32.0f; + f32 scaleX = (dotW * 0.5833333730697632f) + (1.0f/2.4f); + f32 scaleY = (dotH * 0.3142857f) + (0.6857143f); + int choice_num = choice->data.choice_num; + f32 tempDotH; + + choice->scale_x = scaleX; + choice->scale_y = scaleY; + tempDotH = dotH * -20.057144f; + choice->text_x = (dotW * -48.0f) + 152.0f; + + if (choice_num > 4) { + choice->text_y = tempDotH + 105.0f + (f32)(choice_num - 3) * 2.0f; + } + else { + choice->text_y = tempDotH + 105.0f; + } + + tempDotH = dotH * 20.057144f; + choice->center_x = 242.0f; + choice->center_x_begin = 242.0f; + choice->center_x_target = 242.0f + (dotW * -35.0f); + + choice->center_y = 169.0f; + choice->center_y_begin = 169.0f; + + if (choice_num > 4) { + choice->center_y_target = (169.0f + tempDotH) - (f32)(choice_num - 4) * 16.0f; + } + else { + choice->center_y_target = 169.0f + tempDotH; + } +} + +extern int mChoice_Get_ChoseNum(mChoice_c* choice) { + return choice->data.selected_choice_idx; +} + +extern void mChoice_Clear_ChoseNum(mChoice_c* choice) { + choice->data.selected_choice_idx = -1; +} + +static void mChoice_check_ct(mChoice_c* choice) { } + +static void mChoice_Get_StringDataAddressAndSize(int idx, u32* addr, u32* size) { + mMsg_Get_BodyParam(Choice_table_rom_start, Choice_rom_start, idx, addr, size); +} + +static int mChoice_Put_String_PLAYER_NAME(u8* data, int idx, int max_size, ACTOR* actor) { + return mMsg_CopyPlayerName(data, idx, max_size, FALSE); +} + +static int mChoice_Put_String_TALK_NAME(u8* data, int idx, int max_size, ACTOR* actor) { + return mMsg_CopyTalkName(actor, data, idx, max_size, FALSE); +} + +static int mChoice_Put_String_TAIL(u8* data, int idx, int max_size, ACTOR* actor) { + return mMsg_CopyTail(actor, data, idx, max_size, FALSE); +} + +static int mChoice_Put_String_YEAR(u8* data, int idx, int max_size, ACTOR* actor) { + return mMsg_CopyYear(data, idx, max_size); +} + +static int mChoice_Put_String_MONTH(u8* data, int idx, int max_size, ACTOR* actor) { + return mMsg_CopyMonth(data, idx, max_size); +} + +static int mChoice_Put_String_WEEK(u8* data, int idx, int max_size, ACTOR* actor) { + return mMsg_CopyWeek(data, idx, max_size); +} + +static int mChoice_Put_String_DAY(u8* data, int idx, int max_size, ACTOR* actor) { + return mMsg_CopyDay(data, idx, max_size); +} + +static int mChoice_Put_String_HOUR(u8* data, int idx, int max_size, ACTOR* actor) { + mMsg_Window_c* msg_p = mMsg_Get_base_window_p(); + int hour = Common_Get(time.rtc_time.hour); + + if (hour < 12) { + msg_p->status_flags |= mMsg_STATUS_FLAG_USE_AM; + } + else { + msg_p->status_flags &= ~mMsg_STATUS_FLAG_USE_AM; + } + + return mMsg_CopyHour(data, idx, max_size); +} + +static int mChoice_Put_String_MIN(u8* data, int idx, int max_size, ACTOR* actor) { + return mMsg_CopyMin(data, idx, max_size); +} + +static int mChoice_Put_String_SEC(u8* data, int idx, int max_size, ACTOR* actor) { + return mMsg_CopySec(data, idx, max_size); +} + +static int mChoice_Put_String_FREE(u8* data, int idx, int max_size, ACTOR* actor, int free_idx) { + return mMsg_CopyFree(mMsg_Get_base_window_p(), free_idx, data, idx, max_size, mIN_ARTICLE_NUM, FALSE); +} + +static int mChoice_Put_String_FREE0(u8* data, int idx, int max_size, ACTOR* actor) { + return mChoice_Put_String_FREE(data, idx, max_size, actor, mMsg_FREE_STR0); +} + +static int mChoice_Put_String_FREE1(u8* data, int idx, int max_size, ACTOR* actor) { + return mChoice_Put_String_FREE(data, idx, max_size, actor, mMsg_FREE_STR1); +} + +static int mChoice_Put_String_FREE2(u8* data, int idx, int max_size, ACTOR* actor) { + return mChoice_Put_String_FREE(data, idx, max_size, actor, mMsg_FREE_STR2); +} + +static int mChoice_Put_String_FREE3(u8* data, int idx, int max_size, ACTOR* actor) { + return mChoice_Put_String_FREE(data, idx, max_size, actor, mMsg_FREE_STR3); +} + +static int mChoice_Put_String_FREE4(u8* data, int idx, int max_size, ACTOR* actor) { + return mChoice_Put_String_FREE(data, idx, max_size, actor, mMsg_FREE_STR4); +} + +static int mChoice_Put_String_FREE5(u8* data, int idx, int max_size, ACTOR* actor) { + return mChoice_Put_String_FREE(data, idx, max_size, actor, mMsg_FREE_STR5); +} + +static int mChoice_Put_String_FREE6(u8* data, int idx, int max_size, ACTOR* actor) { + return mChoice_Put_String_FREE(data, idx, max_size, actor, mMsg_FREE_STR6); +} + +static int mChoice_Put_String_FREE7(u8* data, int idx, int max_size, ACTOR* actor) { + return mChoice_Put_String_FREE(data, idx, max_size, actor, mMsg_FREE_STR7); +} + +static int mChoice_Put_String_FREE8(u8* data, int idx, int max_size, ACTOR* actor) { + return mChoice_Put_String_FREE(data, idx, max_size, actor, mMsg_FREE_STR8); +} + +static int mChoice_Put_String_FREE9(u8* data, int idx, int max_size, ACTOR* actor) { + return mChoice_Put_String_FREE(data, idx, max_size, actor, mMsg_FREE_STR9); +} + +static int mChoice_Put_String_FREE10(u8* data, int idx, int max_size, ACTOR* actor) { + return mChoice_Put_String_FREE(data, idx, max_size, actor, mMsg_FREE_STR10); +} + +static int mChoice_Put_String_FREE11(u8* data, int idx, int max_size, ACTOR* actor) { + return mChoice_Put_String_FREE(data, idx, max_size, actor, mMsg_FREE_STR11); +} + +static int mChoice_Put_String_FREE12(u8* data, int idx, int max_size, ACTOR* actor) { + return mChoice_Put_String_FREE(data, idx, max_size, actor, mMsg_FREE_STR12); +} + +static int mChoice_Put_String_FREE13(u8* data, int idx, int max_size, ACTOR* actor) { + return mChoice_Put_String_FREE(data, idx, max_size, actor, mMsg_FREE_STR13); +} + +static int mChoice_Put_String_FREE14(u8* data, int idx, int max_size, ACTOR* actor) { + return mChoice_Put_String_FREE(data, idx, max_size, actor, mMsg_FREE_STR14); +} + +static int mChoice_Put_String_FREE15(u8* data, int idx, int max_size, ACTOR* actor) { + return mChoice_Put_String_FREE(data, idx, max_size, actor, mMsg_FREE_STR15); +} + +static int mChoice_Put_String_FREE16(u8* data, int idx, int max_size, ACTOR* actor) { + return mChoice_Put_String_FREE(data, idx, max_size, actor, mMsg_FREE_STR16); +} + +static int mChoice_Put_String_FREE17(u8* data, int idx, int max_size, ACTOR* actor) { + return mChoice_Put_String_FREE(data, idx, max_size, actor, mMsg_FREE_STR17); +} + +static int mChoice_Put_String_FREE18(u8* data, int idx, int max_size, ACTOR* actor) { + return mChoice_Put_String_FREE(data, idx, max_size, actor, mMsg_FREE_STR18); +} + +static int mChoice_Put_String_FREE19(u8* data, int idx, int max_size, ACTOR* actor) { + return mChoice_Put_String_FREE(data, idx, max_size, actor, mMsg_FREE_STR19); +} + +static int mChoice_Put_String_DETERMINATION(u8* data, int idx, int max_size, ACTOR* actor) { + return mMsg_CopyDetermination(mMsg_Get_base_window_p(), data, idx, max_size); +} + +static int mChoice_Put_String_COUNTRY_NAME(u8* data, int idx, int max_size, ACTOR* actor) { + return mMsg_CopyCountryName(data, idx, max_size, FALSE); +} + +static int mChoice_Put_String_RAMDOM_NUMBER2(u8* data, int idx, int max_size, ACTOR* actor) { + return mMsg_CopyRamdomNumber2(data, idx, max_size); +} + +static int mChoice_Put_String_ITEM(u8* data, int idx, int max_size, ACTOR* actor, int item_idx) { + return mMsg_CopyItem(mMsg_Get_base_window_p(), item_idx, data, idx, max_size, mIN_ARTICLE_NUM, FALSE); +} + +static int mChoice_Put_String_ITEM0(u8* data, int idx, int max_size, ACTOR* actor) { + return mChoice_Put_String_ITEM(data, idx, max_size, actor, mMsg_ITEM_STR0); +} + +static int mChoice_Put_String_ITEM1(u8* data, int idx, int max_size, ACTOR* actor) { + return mChoice_Put_String_ITEM(data, idx, max_size, actor, mMsg_ITEM_STR1); +} + +static int mChoice_Put_String_ITEM2(u8* data, int idx, int max_size, ACTOR* actor) { + return mChoice_Put_String_ITEM(data, idx, max_size, actor, mMsg_ITEM_STR2); +} + +static int mChoice_Put_String_ITEM3(u8* data, int idx, int max_size, ACTOR* actor) { + return mChoice_Put_String_ITEM(data, idx, max_size, actor, mMsg_ITEM_STR3); +} + +static int mChoice_Put_String_ITEM4(u8* data, int idx, int max_size, ACTOR* actor) { + return mChoice_Put_String_ITEM(data, idx, max_size, actor, mMsg_ITEM_STR4); +} + +static int mChoice_Put_String_ISLAND_NAME(u8* data, int idx, int max_size, ACTOR* actor) { + return mMsg_CopyIslandName(data, idx, max_size, FALSE); +} + +static int mChoice_Put_String_AMPM(u8* data, int idx, int max_size, ACTOR* actor) { + return mMsg_CopyAmPm(mMsg_Get_base_window_p(), data, idx, max_size); +} + +typedef int (*mChoice_PUT_STRING_PROC)(u8*, int, int, ACTOR*); + +static int mChoice_Put_String(u8* data, int idx, int max_size, ACTOR* actor) { + static const mChoice_PUT_STRING_PROC proc[mFont_CONT_CODE_NUM] = { + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + &mChoice_Put_String_PLAYER_NAME, + &mChoice_Put_String_TALK_NAME, + &mChoice_Put_String_TAIL, + &mChoice_Put_String_YEAR, + &mChoice_Put_String_MONTH, + &mChoice_Put_String_WEEK, + &mChoice_Put_String_DAY, + &mChoice_Put_String_HOUR, + &mChoice_Put_String_MIN, + &mChoice_Put_String_SEC, + &mChoice_Put_String_FREE0, + &mChoice_Put_String_FREE1, + &mChoice_Put_String_FREE2, + &mChoice_Put_String_FREE3, + &mChoice_Put_String_FREE4, + &mChoice_Put_String_FREE5, + &mChoice_Put_String_FREE6, + &mChoice_Put_String_FREE7, + &mChoice_Put_String_FREE8, + &mChoice_Put_String_FREE9, + &mChoice_Put_String_DETERMINATION, + &mChoice_Put_String_COUNTRY_NAME, + &mChoice_Put_String_RAMDOM_NUMBER2, + &mChoice_Put_String_ITEM0, + &mChoice_Put_String_ITEM1, + &mChoice_Put_String_ITEM2, + &mChoice_Put_String_ITEM3, + &mChoice_Put_String_ITEM4, + &mChoice_Put_String_FREE10, + &mChoice_Put_String_FREE11, + &mChoice_Put_String_FREE12, + &mChoice_Put_String_FREE13, + &mChoice_Put_String_FREE14, + &mChoice_Put_String_FREE15, + &mChoice_Put_String_FREE16, + &mChoice_Put_String_FREE17, + &mChoice_Put_String_FREE18, + &mChoice_Put_String_FREE19, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + &mChoice_Put_String_ISLAND_NAME, + NULL, + NULL, + NULL, + NULL, + &mChoice_Put_String_AMPM, + NULL, + NULL, + NULL, + NULL + }; + + int type = data[idx + 1]; + + if (type >= 0 && type < mFont_CONT_CODE_NUM && proc[type] != NULL) { + return (*proc[type])(data, idx, max_size, actor); + } + + return max_size; +} + +static void mChoice_Change_ControlCode(u8* data, int max_size, ACTOR* actor) { + u8* src_p = data; + int new_max_size = max_size; + int idx = 0; + u8 code; + + while (idx < new_max_size) { + code = *src_p; + + if (code == CHAR_CONTROL_CODE) { + new_max_size = mChoice_Put_String(data, idx, new_max_size, actor); + } + else { + idx++; + src_p++; + } + } +} + +extern void mChoice_Load_ChoseStringFromRom(mChoice_c* choice, u8* str, int str_no, ACTOR* actor) { + if (str_no >= 0 && str_no < mChoice_SELECT_STR_NUM) { + u32 addr; + u32 size; + + mChoice_Get_StringDataAddressAndSize(str_no, &addr, &size); + + if (size == 0) { + mem_clear(str, mChoice_CHOICE_STRING_LEN, CHAR_SPACE); + } + else if (addr != 0) { + static u8 buff[80] ATTRIBUTE_ALIGN(32); + u32 align_addr = ALIGN_PREV(addr, 32); + u32 ofs = addr - align_addr; + u32 align_size = ALIGN_NEXT(ofs + size, 32); + int max; + int i; + u8* src_p; + u8* dst_p; + + _JW_GetResourceAram(align_addr, buff, align_size); + + max = mChoice_CHOICE_STRING_LEN; + if (size < mChoice_CHOICE_STRING_LEN) { + max = size; + } + + src_p = &buff[ofs]; + dst_p = str; + + /* Copy string from the temp aligned buffer to the destination */ + for (i = 0; i < max; i++) { + *dst_p++ = *src_p++; + } + + /* Fill remaining space with space characters */ + for (i; i < mChoice_CHOICE_STRING_LEN; i++) { + *dst_p++ = CHAR_SPACE; + } + + /* Process any control codes */ + mChoice_Change_ControlCode(str, mChoice_CHOICE_STRING_LEN, actor); + } + } +} + +extern void mChoice_no_b_set(mChoice_c* choice) { + choice->no_b_flag = TRUE; +} + +extern void mChoice_no_b_close_set(mChoice_c* choice) { + choice->no_b_flag = TRUE; + choice->no_close_flag = TRUE; +} diff --git a/src/m_choice_main_appear.c_inc b/src/m_choice_main_appear.c_inc new file mode 100644 index 00000000..7d18642f --- /dev/null +++ b/src/m_choice_main_appear.c_inc @@ -0,0 +1,48 @@ +static int mChoice_Main_Appear_SetScale(mChoice_c* choice, GAME* game) { + int res; + const f32 max = 10.2f; + + if (choice->timer < max) { + f32 scale; + + choice->timer += 1.0f; + scale = get_percent_forAccelBrake(choice->timer, 0.0f, max, 0.0f, 0.0f); + choice->scale = scale; + choice->center_x = choice->center_x_begin + scale * (choice->center_x_target - choice->center_x_begin); + choice->center_y = choice->center_y_begin + scale * (choice->center_y_target - choice->center_y_begin); + res = FALSE; + } + else { + choice->timer = 0.0f; + choice->scale = 1.0f; + choice->center_x = choice->center_x_target; + choice->center_y = choice->center_y_target; + res = TRUE; + } + + return res; +} + +static void mChoice_request_main_index_fromAppear(mChoice_c* choice, GAME* game, int open_flag) { + if (open_flag) { + mChoice_Change_request_main_index(choice, mChoice_MAIN_NORMAL); + } +} + +static void mChoice_Main_Appear(mChoice_c* choice, GAME* game) { + int open_flag = mChoice_Main_Appear_SetScale(choice, game); + + mChoice_request_main_index_fromAppear(choice, game, open_flag); + mChoice_MainSetup(choice, game); +} + +static void mChoice_MainSetup_Appear(mChoice_c* choice, GAME* game) { + choice->scale = 0.0f; + choice->main_index = mChoice_MAIN_APPEAR; + choice->requested_main_index = -1; + choice->window_visible_flag = TRUE; + choice->timer = 0.0f; + mChoice_Clear_ChoseNum(choice); + mChoice_sound_SENTAKU_OPEN(); + mChoice_Set_DisplayScaleAndDisplayPos(choice); +} diff --git a/src/m_choice_main_disappear.c_inc b/src/m_choice_main_disappear.c_inc new file mode 100644 index 00000000..4fcc7bee --- /dev/null +++ b/src/m_choice_main_disappear.c_inc @@ -0,0 +1,56 @@ +static int mChoice_Main_Disappear_SetScale(mChoice_c* choice, GAME* game) { + const f32 max = 10.2f; + + if (choice->timer < max) { + f32 scale; + + choice->timer += 1.0f; + scale = 1.0f - get_percent_forAccelBrake(choice->timer, 0.0f, max, 0.0f, 0.0f); + choice->scale = scale; + choice->center_x = choice->center_x_begin + scale * (choice->center_x_target - choice->center_x_begin); + choice->center_y = choice->center_y_begin + scale * (choice->center_y_target - choice->center_y_begin); + return FALSE; + } + else { + choice->timer = 0.0f; + choice->scale = 0.0f; + choice->center_x = choice->center_x_begin; + choice->center_y = choice->center_y_begin; + return TRUE; + } +} + +static void mChoice_request_main_index_fromDisappear(mChoice_c* choice, GAME* game, int closed_flag) { + if (closed_flag) { + mChoice_Change_request_main_index(choice, mChoice_MAIN_HIDE); + } +} + +static void mChoice_Main_Disappear(mChoice_c* choice, GAME* game) { + int closed_flag = mChoice_Main_Disappear_SetScale(choice, game); + + mChoice_request_main_index_fromDisappear(choice, game, closed_flag); + mChoice_MainSetup(choice, game); +} + +static void mChoice_MainSetup_Disappear(mChoice_c* choice, GAME* game) { + if (choice->no_b_flag && choice->selected_choice_idx == (choice->data.choice_num - 1)) { + if (choice->no_close_flag) { + mChoice_sound_ZOOMDOWN_LONG(); + mMsg_Get_base_window_p()->status_flags |= mMsg_STATUS_FLAG_ZOOMDOWN_LONG; + } + else { + mChoice_sound_ZOOMDOWN_SHORT(); + } + } + else { + mChoice_sound_SENTAKU_KETTEI(); + } + + choice->scale = 1.0f; + choice->main_index = mChoice_MAIN_DISAPPEAR; + choice->requested_main_index = -1; + choice->window_visible_flag = TRUE; + choice->timer = 0.0f; + choice->font_visible_flag = FALSE; +} diff --git a/src/m_choice_main_hide.c_inc b/src/m_choice_main_hide.c_inc new file mode 100644 index 00000000..94a1a79d --- /dev/null +++ b/src/m_choice_main_hide.c_inc @@ -0,0 +1,7 @@ +static void mChoice_Main_Hide(mChoice_c* choice, GAME* game) { + mChoice_MainSetup(choice, game); +} + +static void mChoice_MainSetup_Hide(mChoice_c* choice, GAME* game) { + mChoice_init(choice, game); +} diff --git a/src/m_choice_main_normal.c_inc b/src/m_choice_main_normal.c_inc new file mode 100644 index 00000000..4f2850dd --- /dev/null +++ b/src/m_choice_main_normal.c_inc @@ -0,0 +1,162 @@ +static void mChoice_determimation_set(mChoice_c* choice) { + mChoice_Data_c* choice_data = &choice->data; + int idx = choice->selected_choice_idx; + + bcopy(choice_data->strings[idx], choice_data->determination_string, mChoice_CHOICE_STRING_LEN); + choice_data->determination_len = choice_data->string_lens[idx]; + choice_data->selected_choice_idx = idx; +} + +static int mChoice_Main_Normal_SetChoice(mChoice_c* choice, GAME* game) { + int res = FALSE; + + if (chkTrigger(BUTTON_A)) { + mChoice_determimation_set(choice); + res = TRUE; + } + else if (choice->no_b_flag && chkTrigger(BUTTON_B)) { + choice->selected_choice_idx = choice->data.choice_num - 1; + mChoice_determimation_set(choice); + res = TRUE; + } + else { + f32 percent = gamePT->mcon.adjusted_pY; + int* choice_automove_p = &choice->choice_automove_type; + f32* choice_automove_timer_p = &choice->choice_automove_timer; + int* selected_idx_p = &choice->selected_choice_idx; + int cursor_sfx = FALSE; + + switch (*choice_automove_p) { + case mChoice_AUTOMOVE_INCREMENT_WAIT: + { + if (percent < 0.0f || chkButton(BUTTON_CDOWN)) { + (*choice_automove_timer_p) += 1.0f; + + if (*choice_automove_timer_p >= 18.0f) { + *choice_automove_timer_p = 0.0f; + *choice_automove_p = mChoice_AUTOMOVE_INCREMENT; + (*selected_idx_p)++; + cursor_sfx = TRUE; + } + } + else { + *choice_automove_p = mChoice_AUTOMOVE_STOPPED; + *choice_automove_timer_p = 0.0f; + } + + break; + } + + case mChoice_AUTOMOVE_INCREMENT: + { + if (percent < 0.0f || chkButton(BUTTON_CDOWN)) { + (*choice_automove_timer_p) += 1.0f; + + if (*choice_automove_timer_p >= 9.0f) { + *choice_automove_timer_p = 0.0f; + (*selected_idx_p)++; + cursor_sfx = TRUE; + } + } + else { + *choice_automove_p = mChoice_AUTOMOVE_STOPPED; + *choice_automove_timer_p = 0.0f; + } + + break; + } + + case mChoice_AUTOMOVE_DECREMENT_WAIT: + { + if (percent > 0.0f || chkButton(BUTTON_CUP)) { + (*choice_automove_timer_p) += 1.0f; + + if (*choice_automove_timer_p >= 18.0f) { + *choice_automove_timer_p = 0.0f; + *choice_automove_p = mChoice_AUTOMOVE_DECREMENT; + (*selected_idx_p)--; + cursor_sfx = TRUE; + } + } + else { + *choice_automove_p = mChoice_AUTOMOVE_STOPPED; + *choice_automove_timer_p = 0.0f; + } + + break; + } + + case mChoice_AUTOMOVE_DECREMENT: + { + if (percent > 0.0f || chkButton(BUTTON_CUP)) { + (*choice_automove_timer_p) += 1.0f; + + if (*choice_automove_timer_p >= 9.0f) { + *choice_automove_timer_p = 0.0f; + (*selected_idx_p)--; + cursor_sfx = TRUE; + } + } + else { + *choice_automove_p = mChoice_AUTOMOVE_STOPPED; + *choice_automove_timer_p = 0.0f; + } + + break; + } + + default: + { + if (percent > 0.0f || chkTrigger(BUTTON_CUP)) { + *choice_automove_p = mChoice_AUTOMOVE_DECREMENT_WAIT; + *choice_automove_timer_p = 0.0f; + (*selected_idx_p)--; + cursor_sfx = TRUE; + } + else if (percent < 0.0f || chkTrigger(BUTTON_CDOWN)) { + *choice_automove_p = mChoice_AUTOMOVE_INCREMENT_WAIT; + *choice_automove_timer_p = 0.0f; + (*selected_idx_p)++; + cursor_sfx = TRUE; + } + + break; + } + } + + if ((*selected_idx_p) < 0) { + *selected_idx_p = 0; + } + else if ((*selected_idx_p) >= choice->data.choice_num) { + *selected_idx_p = choice->data.choice_num - 1; + } + else { + if (cursor_sfx) { + mChoice_sound_CURSOL(); + } + } + } + + return res; +} + +static void mChoice_request_main_index_fromNormal(mChoice_c* choice, GAME* game, int close_flag) { + if (close_flag) { + mChoice_Change_request_main_index(choice, mChoice_MAIN_DISAPPEAR); + } +} + +static void mChoice_Main_Normal(mChoice_c* choice, GAME* game) { + int close_flag = mChoice_Main_Normal_SetChoice(choice, game); + + mChoice_request_main_index_fromNormal(choice, game, close_flag); + mChoice_MainSetup(choice, game); +} + +static void mChoice_MainSetup_Normal(mChoice_c* choice, GAME* game) { + choice->scale = 1.0f; + choice->timer = 0.0f; + choice->requested_main_index = -1; + choice->main_index = mChoice_MAIN_NORMAL; + choice->font_visible_flag = TRUE; +} diff --git a/src/m_choice_sound.c_inc b/src/m_choice_sound.c_inc new file mode 100644 index 00000000..978a0bf8 --- /dev/null +++ b/src/m_choice_sound.c_inc @@ -0,0 +1,19 @@ +static void mChoice_sound_SENTAKU_KETTEI() { + sAdo_SysTrgStart(0xD); +} + +static void mChoice_sound_SENTAKU_OPEN() { + sAdo_SysTrgStart(0xC); +} + +static void mChoice_sound_CURSOL() { + sAdo_SysTrgStart(0x1); +} + +static void mChoice_sound_ZOOMDOWN_SHORT() { + sAdo_SysTrgStart(0x8005); +} + +static void mChoice_sound_ZOOMDOWN_LONG() { + sAdo_SysTrgStart(0x8015); +} diff --git a/src/m_event.c b/src/m_event.c index ca5f3f00..7a4778cc 100644 --- a/src/m_event.c +++ b/src/m_event.c @@ -1,22 +1,44 @@ #include "m_event.h" #include "libultra/libultra.h" -#include "m_common_data.h" +#include "_mem.h" +#include "lb_reki.h" #include "ac_aprilfool_control_h.h" +#include "m_common_data.h" +#include "m_player_lib.h" #include "m_play.h" #include "m_scene_table.h" +#include "m_soncho.h" -static int n_today_events; -static int status_edge; -static int funeral; -static int dead; -static lbRTC_year_t weekday1st_year; +enum { + mEv_INIT_NO_RENEWAL, + mEv_INIT_RENEWAL, + mEv_INIT_FORCE_RENEWAL, + + mEv_INIT_NUM +}; + +static int n_today_events = 0; +static int status_edge = 0; +static int funeral = 0; +static int dead = 0; +static lbRTC_year_t weekday1st_year = 0; static lbRTC_weekday_t weekday1st[lbRTC_MONTHS_MAX]; +typedef union ymdh { + struct { + u8 year; + u8 month; + u8 day; + u8 hour; + }; + u32 raw; +} mEv_ymdh_u; + extern void mEv_ClearSpecialEvent(mEv_special_c* special_event) { special_event->type = -1; bzero(&special_event->event, sizeof(mEv_special_u)); - bzero(Common_GetPointer(event_common), sizeof(mEv_event_common_u)); + bzero(Common_GetPointer(special_event_common), sizeof(mEv_event_common_u)); } extern void mEv_ClearEventKabuPeddler(mEv_kabu_peddler_c* kabu_peddler) { @@ -32,6 +54,7 @@ extern void mEv_ClearEventSaveInfo(mEv_event_save_c* save_event) { } extern void mEv_ClearEventInfo() { + mEv_event_save_c* event_save = Save_GetPointer(event_save_data); u32* event_flag = Common_Get(event_flags); int i; @@ -40,55 +63,48 @@ extern void mEv_ClearEventInfo() { event_flag++; } - Common_Set(event_flags[1], Save_Get(event_save_data.flags)); + Common_Get(event_flags[1]) = event_save->flags; Common_Get(event_common).fieldday_event_id = -1; Common_Get(event_common).fieldday_event_over_status = -1; } extern void mEv_EventON(u32 event_kind) { - int type = mEv_GET_TYPE(event_kind); - u32 flag; + u32 type = mEv_GET_TYPE(event_kind); - if (type >= mEv_EVENT_TYPE_NUM) { - return; + if (type < mEv_EVENT_TYPE_NUM) { + u32* flag_p = Common_GetPointer(event_flags[type]); + *flag_p |= (1 << mEv_GET_SUBTYPE(event_kind)); + + if (type == mEv_SAVED_EVENT) { + Save_Get(event_save_data).flags = *flag_p; + } } - - flag = Common_Get(event_flags[type]); - flag |= (1 << mEv_GET_SUBTYPE(event_kind)); - Common_Set(event_flags[type], flag); - - if (type != mEv_SAVED_EVENT) { - return; - } - - Save_Get(event_save_data).flags = Common_Get(event_flags[flag]); } extern void mEv_EventOFF(u32 event_kind) { - int type = mEv_GET_TYPE(event_kind); - u32 flag; + u32 type = mEv_GET_TYPE(event_kind); - if (type >= mEv_EVENT_TYPE_NUM) { - return; + if (type < mEv_EVENT_TYPE_NUM) { + u32* flag_p = Common_GetPointer(event_flags[type]); + u32 mask = 1 << mEv_GET_SUBTYPE(event_kind); + + *flag_p &= ~mask; + if (type == mEv_SAVED_EVENT) { + Save_Get(event_save_data).flags = *flag_p; + } } - - flag = Common_Get(event_flags[type]); - flag &= ~(1 << mEv_GET_SUBTYPE(event_kind)); - Common_Set(event_flags[type], flag); - - if (type != mEv_SAVED_EVENT) { - return; - } - - Save_Get(event_save_data).flags = Common_Get(event_flags[flag]); } extern int mEv_CheckEvent(u32 event_kind) { - int type = mEv_GET_TYPE(event_kind); + u32 type = mEv_GET_TYPE(event_kind); int res = FALSE; - if (type < mEv_EVENT_TYPE_NUM && ((Common_Get(event_flags[type]) >> mEv_GET_SUBTYPE(event_kind)) & 1)) { - res = TRUE; + if (type < mEv_EVENT_TYPE_NUM) { + u32* flags_p = Common_GetPointer(event_flags[type]); + + if (((*flags_p) >> mEv_GET_SUBTYPE(event_kind)) & 1) { + res = TRUE; + } } return res; @@ -112,15 +128,16 @@ extern void mEv_ClearPersonalEventFlag(int player_no) { } extern void mEv_SetFirstJob() { - int player_no = Common_Get(player_no); + if (Common_Get(player_no) < PLAYER_NUM) { + u32 ev = mEv_SAVED_FIRSTJOB_PLR0; - if (player_no < PLAYER_NUM) { - mEv_EventON(mEv_SAVED_FIRSTJOB_PLR0 + player_no); + ev += Common_Get(player_no); + mEv_EventON(ev); } } extern int mEv_CheckRealArbeit() { - int player_no = Common_Get(player_no); + u32 player_no = Common_Get(player_no); int res = FALSE; if ( @@ -137,7 +154,7 @@ extern int mEv_CheckRealArbeit() { } extern int mEv_CheckArbeit() { - int player_no = Common_Get(player_no); + u32 player_no = Common_Get(player_no); int res = FALSE; if ( @@ -155,21 +172,23 @@ extern int mEv_CheckArbeit() { } extern int mFI_CheckFirstJob() { - int player_no = Common_Get(player_no); + u32 player_no = Common_Get(player_no); int res = FALSE; - if ( - player_no < PLAYER_NUM && - mEv_CheckEvent(mEv_SAVED_FIRSTJOB_PLR0 + player_no) == TRUE - ) { - res = TRUE; + if (player_no < PLAYER_NUM) { + u32 ev = mEv_SAVED_FIRSTJOB_PLR0; + ev += player_no; + + if (mEv_CheckEvent(ev) == TRUE) { + res = TRUE; + } } return res; } extern void mEv_UnSetFirstJob() { - int player_no = Common_Get(player_no); + u32 player_no = Common_Get(player_no); if (player_no < PLAYER_NUM) { mEv_EventOFF(mEv_SAVED_FIRSTJOB_PLR0 + player_no); @@ -178,62 +197,76 @@ extern void mEv_UnSetFirstJob() { } extern void mEv_SetFirstIntro() { - int player_no = Common_Get(player_no); + u32 player_no = Common_Get(player_no); if (player_no < PLAYER_NUM) { - mEv_EventON(mEv_SAVED_FIRSTINTRO_PLR0 + player_no); + u32 ev = mEv_SAVED_FIRSTINTRO_PLR0; + ev += player_no; + + mEv_EventON(ev); } } extern int mEv_CheckFirstIntro() { - int player_no = Common_Get(player_no); + u32 player_no = Common_Get(player_no); int res = FALSE; - if ( - player_no < PLAYER_NUM && - mEv_CheckEvent(mEv_SAVED_FIRSTINTRO_PLR0 + player_no) == TRUE - ) { - res = TRUE; + if (player_no < PLAYER_NUM) { + u32 ev = mEv_SAVED_FIRSTINTRO_PLR0; + ev += player_no; + + if (mEv_CheckEvent(ev) == TRUE) { + res = TRUE; + } } return res; } extern void mEv_UnSetFirstIntro() { - int player_no = Common_Get(player_no); + u32 player_no = Common_Get(player_no); if (player_no < PLAYER_NUM) { - mEv_EventOFF(mEv_SAVED_FIRSTINTRO_PLR0 + player_no); + u32 ev = mEv_SAVED_FIRSTINTRO_PLR0; + ev += player_no; + mEv_EventOFF(ev); } } extern void mEv_SetGateway() { - int player_no = Common_Get(player_no); + u32 player_no = Common_Get(player_no); if (player_no < TOTAL_PLAYER_NUM) { - mEv_EventON(mEv_SAVED_GATEWAY_PLR0 + player_no); + u32 ev = mEv_SAVED_GATEWAY_PLR0; + ev += player_no; + mEv_EventON(ev); } } extern int mEv_CheckGateway() { - int player_no = Common_Get(player_no); + u32 player_no = Common_Get(player_no); int res = FALSE; - if ( - player_no < TOTAL_PLAYER_NUM && - mEv_CheckEvent(mEv_SAVED_GATEWAY_PLR0 + player_no) == TRUE - ) { - res = TRUE; + if (player_no < TOTAL_PLAYER_NUM) { + u32 ev = mEv_SAVED_GATEWAY_PLR0; + ev += player_no; + + if (mEv_CheckEvent(ev) == TRUE) { + res = TRUE; + } } return res; } extern void mEv_UnSetGateway() { - int player_no = Common_Get(player_no); + u32 player_no = Common_Get(player_no); if (player_no < TOTAL_PLAYER_NUM) { - mEv_EventOFF(mEv_SAVED_GATEWAY_PLR0 + player_no); + u32 ev = mEv_SAVED_GATEWAY_PLR0; + ev += player_no; + + mEv_EventOFF(ev); } } @@ -250,11 +283,13 @@ extern void mEv_SetTitleDemo(int demo_number) { extern void mEv_RenewalDataEveryDay() { if (mTM_check_renew_time(mTM_RENEW_TIME_DAILY) == TRUE) { int i; - + for (i = 0; i < PLAYER_NUM; i++) { - if (mEv_CheckEvent(mEv_SAVED_HRAWAIT_PLR0 + i) == TRUE) { + + u32 check_event = mEv_SAVED_HRAWAIT_PLR0 + i; + if (mEv_CheckEvent(check_event) == TRUE) { /* After a new day starts, turn off all players' 'wait a day' HRA event and turn on talk to Tom Nook HRA event */ - mEv_EventOFF(mEv_SAVED_HRAWAIT_PLR0 + i); + mEv_EventOFF(check_event); mEv_EventON(mEv_SAVED_HRATALK_PLR0 + i); } } @@ -278,18 +313,61 @@ extern void mEv_GetEventWeather(s16* weather, s16* intensity) { } } -static lbRTC_day_t last_day_of_month(lbRTC_month_t month) { +#include "m_event_schedule.c_inc" + +static int event_rumor_table[] = { + mEv_EVENT_RUMOR_NEW_YEARS_DAY, + mEv_EVENT_RUMOR_KAMAKURA, + mEv_EVENT_RUMOR_VALENTINES_DAY, + mEv_EVENT_RUMOR_GROUNDHOG_DAY, + mEv_EVENT_RUMOR_APRILFOOLS_DAY, + mEv_EVENT_RUMOR_CHERRY_BLOSSOM_FESTIVAL, + mEv_EVENT_RUMOR_SPRING_SPORTS_FAIR, + mEv_EVENT_RUMOR_HARVEST_FESTIVAL, + mEv_EVENT_76, + mEv_EVENT_RUMOR_FISHING_TOURNEY_1, + mEv_EVENT_TALK_FISHING_TOURNEY_1, + mEv_EVENT_RUMOR_MORNING_AEROBICS, + mEv_EVENT_TALK_MORNING_AEROBICS, + mEv_EVENT_RUMOR_FIREWORKS_SHOW, + mEv_EVENT_76, + mEv_EVENT_RUMOR_METEOR_SHOWER, + mEv_EVENT_RUMOR_HARVEST_MOON_DAY, + mEv_EVENT_RUMOR_FALL_SPORTS_FAIR, + mEv_EVENT_RUMOR_MUSHROOM_SEASON, + mEv_EVENT_TALK_MUSHROOM_SEASON, + mEv_EVENT_RUMOR_HALLOWEEN, + mEv_EVENT_RUMOR_FISHING_TOURNEY_2, + mEv_EVENT_TALK_FISHING_TOURNEY_2, + mEv_EVENT_RUMOR_TOY_DAY, + mEv_EVENT_RUMOR_NEW_YEARS_EVE_COUNTDOWN +}; + +static int n_event_rumors = ARRAY_COUNT(event_rumor_table); + +static u16 special_event_types[] = { + mEv_EVENT_SHOP_SALE, + mEv_EVENT_DESIGNER, + mEv_EVENT_BROKER_SALE, + mEv_EVENT_ARTIST, + mEv_EVENT_CARPET_PEDDLER, + mEv_EVENT_GYPSY +}; + +static int n_special_event_type = ARRAY_COUNT(special_event_types); + +static int last_day_of_month(lbRTC_month_t month) { static lbRTC_day_t last_day[lbRTC_MONTHS_MAX] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; - lbRTC_time_c* rtc_time = Common_GetPointer(time.rtc_time); - lbRTC_year_t year = rtc_time->year; + lbRTC_year_t year = Common_Get(time.rtc_time.year); + lbRTC_day_t day = last_day[month - 1]; if (month != lbRTC_FEBRUARY) { - return last_day[month - 1]; + return day; } else if (lbRTC_IS_LEAPYEAR(year)) { return 29; @@ -301,10 +379,12 @@ static lbRTC_day_t last_day_of_month(lbRTC_month_t month) { static void init_weekday1st() { lbRTC_time_c* rtc_time = Common_GetPointer(time.rtc_time); - lbRTC_month_t month = rtc_time->month & 0xF; // ?? + lbRTC_month_t month; + lbRTC_month_t temp; lbRTC_month_t i; - lbRTC_weekday_t weekday; + int weekday; + month = rtc_time->month & 0xF; weekday1st_year = rtc_time->year; weekday = (rtc_time->weekday + (1 - rtc_time->day)) % lbRTC_WEEK; @@ -314,55 +394,69 @@ static void init_weekday1st() { weekday1st[month] = weekday; - for (i = month + 1; i <= lbRTC_MONTHS_MAX; i++) { - weekday1st[i] = (weekday1st[i - 1] + last_day_of_month(i)) % lbRTC_WEEK; + for (i = month, temp = month + 1; temp <= lbRTC_MONTHS_MAX; i++, temp++) { + int last = last_day_of_month(i); + int t = (weekday1st[i] + (u8)last) % lbRTC_WEEK; + + if (t < 0) { + t += lbRTC_WEEK; + } + + weekday1st[temp] = t; } - for (i = month - 1; i >= lbRTC_JANUARY; i--) { - weekday = (weekday1st[i + 1] - last_day_of_month(i)) % lbRTC_WEEK; + for (temp = month - 1, i = month; temp >= lbRTC_JANUARY; i--, temp--) { + lbRTC_day_t last_day = last_day_of_month(temp); + + weekday = (weekday1st[i] - last_day) % lbRTC_WEEK; if (weekday < 0) { weekday += lbRTC_WEEK; } - weekday1st[i] = weekday; + weekday1st[temp] = weekday; } } static int check_date_range(u16 date, u16 lower_bound, u16 upper_bound) { - if (upper_bound < lower_bound) { - if (date < lower_bound && date > upper_bound) { - return FALSE; + int res; + + if (lower_bound > upper_bound) { + res = FALSE; + if (lower_bound <= date || date <= upper_bound) { + res = TRUE; } - else { - return TRUE; - } - } - else if (date < lower_bound || date > upper_bound) { - return FALSE; } else { - return TRUE; + res = FALSE; + if (lower_bound <= date && date <= upper_bound) { + res = TRUE; + } } + + return res; } static int check_ymdh_range(u32 ymdh, u32 lower_bound, u32 upper_bound) { int res = FALSE; - if (ymdh >= lower_bound && ymdh <= upper_bound) { + if (lower_bound <= ymdh && ymdh <= upper_bound) { res = TRUE; } return res; } -static mEv_MonthDay_u after_n_day(mEv_MonthDay_u month_day, int n_day) { - mEv_MonthDay_u after = month_day; +static u16 after_n_day(u16 month_day, int n_day) { + mEv_MonthDay_u after; + u8 day; + + after.raw = month_day; if (n_day >= 0) { - lbRTC_day_t last_day = last_day_of_month(after.month); + day = last_day_of_month(after.month); after.day = after.day + n_day; - if (after.day > last_day) { + if (after.day > day) { if (after.month == lbRTC_DECEMBER) { after.month = lbRTC_JANUARY; } @@ -370,7 +464,7 @@ static mEv_MonthDay_u after_n_day(mEv_MonthDay_u month_day, int n_day) { after.month++; } - after.day -= last_day; + after.day -= day; } } else { @@ -383,27 +477,28 @@ static mEv_MonthDay_u after_n_day(mEv_MonthDay_u month_day, int n_day) { after.month--; } - after.day += last_day_of_month(after.month); + day = last_day_of_month(after.month); + after.day += day; } } - return after; + return after.raw; } extern lbRTC_day_t mEv_get_next_weekday(lbRTC_weekday_t weekday) { + lbRTC_time_c* rtc_time = Common_GetPointer(time.rtc_time); lbRTC_weekday_t next_weekday; lbRTC_day_t day; lbRTC_day_t last_day; - if (weekday >= Common_Get(time.rtc_time).weekday) { - next_weekday = weekday - Common_Get(time.rtc_time).weekday; + if (weekday >= rtc_time->weekday) { + day = rtc_time->day + (weekday - rtc_time->weekday); } else { - next_weekday = lbRTC_WEEK - (Common_Get(time.rtc_time).weekday - weekday); + day = rtc_time->day + (lbRTC_WEEK - (rtc_time->weekday - weekday)); } - day = Common_Get(time.rtc_time).day + next_weekday; - last_day = last_day_of_month(Common_Get(time.rtc_time).month); + last_day = last_day_of_month(rtc_time->month); if (day > last_day) { day -= last_day; @@ -416,22 +511,23 @@ extern lbRTC_day_t mEv_get_next_weekday(lbRTC_weekday_t weekday) { #define mEv_date_decode_week(day) (((day) & 0b00111000) >> 3) // 0-5 (which week of the month, 1st, 2nd, 3rd, ...) static lbRTC_day_t m_weekday2day(lbRTC_month_t month, u8 day_enc) { + lbRTC_time_c* rtc_time = Common_GetPointer(time.rtc_time); int week = mEv_date_decode_week(day_enc); // get the week of the month int weekday = mEv_date_decode_weekday(day_enc); // get the weekday lbRTC_day_t day = 0; - lbRTC_day_t last_day = last_day_of_month(month); + int last_day = last_day_of_month(month); - if (week == mEv_SCHEDULE_WEEKLY) { - if (month > Common_Get(time.rtc_time).month) { + if (week == mEv_SCHEDULE_EVERY_WEEK) { + if (month > rtc_time->month) { week = 1; /* 1st week of this month */ } - else if (month < Common_Get(time.rtc_time).month) { + else if (month < rtc_time->month) { week = mEv_SCHEDULE_LAST_WEEKDAY_OF_MONTH; /* last weekday of the month */ } else { - day = Common_Get(time.rtc_time).day - (Common_Get(time.rtc_time).weekday - weekday); + day = rtc_time->day - (rtc_time->weekday - weekday); - if (day > last_day) { + if (day > (u8)last_day) { week = mEv_SCHEDULE_LAST_WEEKDAY_OF_MONTH; } else { @@ -441,70 +537,68 @@ static lbRTC_day_t m_weekday2day(lbRTC_month_t month, u8 day_enc) { } if (week == mEv_SCHEDULE_LAST_WEEKDAY_OF_MONTH) { - int t_day = (last_day + weekday1st[month] - 1) % lbRTC_WEEK; /* get the weekday of the first day of next month */ + lbRTC_day_t d = last_day; + int t_day = (-1 + d + weekday1st[month]) % lbRTC_WEEK; /* get the weekday of the first day of next month */ - if (t_day < weekday) { - day = (last_day - (t_day - weekday)) - lbRTC_WEEK; + if (weekday <= t_day) { + day = d - (t_day - weekday); } else { - day = last_day - (t_day - weekday); + day = (d - (t_day - weekday)) - lbRTC_WEEK; } } else if (week != 0) { int t_day = weekday1st[month]; - if (weekday < t_day) { - day = week * lbRTC_WEEK + (weekday - t_day) + 1; + if (weekday >= t_day) { + day = 1 + (week - 1) * lbRTC_WEEK + (weekday - t_day); } else { - day = (week - 1) * lbRTC_WEEK + (weekday - t_day) + 1; + day = 1 + week * lbRTC_WEEK + (weekday - t_day); } } return day; } -extern lbRTC_day_t mEv_weeday2day(lbRTC_month_t month, int week, int weekday) { - lbRTC_day_t day = 0; - lbRTC_day_t last_day = last_day_of_month(month); +static lbRTC_weekday_t weekday1st[lbRTC_MONTHS_MAX]; - if (week == mEv_SCHEDULE_WEEKLY) { - if (month > Common_Get(time.rtc_time).month) { +extern int mEv_weekday2day(lbRTC_month_t month, int week, int weekday) { + lbRTC_time_c* rtc_time = Common_GetPointer(time.rtc_time); + lbRTC_day_t day = 0; + + if (week == mEv_SCHEDULE_EVERY_WEEK) { + if (month > rtc_time->month) { week = 1; /* 1st week of this month */ } - else if (month < Common_Get(time.rtc_time).month) { + else if (month < rtc_time->month) { week = mEv_SCHEDULE_LAST_WEEKDAY_OF_MONTH; /* last weekday of the month */ } else { - day = Common_Get(time.rtc_time).day - (Common_Get(time.rtc_time).weekday - weekday); - - if (day > last_day) { - week = mEv_SCHEDULE_LAST_WEEKDAY_OF_MONTH; - } - else { - week = 0; /* cleared */ - } + day = rtc_time->day - (rtc_time->weekday - weekday); + week = 0; /* cleared */ } } if (week == mEv_SCHEDULE_LAST_WEEKDAY_OF_MONTH) { - int t_day = (last_day + weekday1st[month] - 1) % lbRTC_WEEK; /* get the weekday of the first day of next month */ + lbRTC_day_t last_day = last_day_of_month(month); + int t_day = (-1 + last_day + weekday1st[month]) % lbRTC_WEEK; /* get the weekday of the first day of next month */ - if (t_day < weekday) { - day = (last_day - (t_day - weekday)) - lbRTC_WEEK; + if (weekday <= t_day) { + day = last_day - (t_day - weekday); } else { - day = last_day - (t_day - weekday); + day = (last_day - (t_day - weekday)) - lbRTC_WEEK; } } else if (week != 0) { int t_day = weekday1st[month]; - if (weekday < t_day) { - day = week * lbRTC_WEEK + (weekday - t_day) + 1; + if (weekday >= t_day) { + day = 1 + (week - 1) * lbRTC_WEEK + (weekday - t_day); } else { - day = (week - 1) * lbRTC_WEEK + (weekday - t_day) + 1; + day = 1 + week * lbRTC_WEEK + (weekday - t_day); } } @@ -515,13 +609,13 @@ static int get_end_time(u32 active_hours) { int hour; int i; - if (active_hours & ((1 << 24) - 1) == 0) { + if ((active_hours & ((1 << 24) - 1)) == 0) { return -1; /* no active hours */ } hour = 23; for (i = 0; i < 24; i++) { - if ((active_hours & (1 << 23)) & 1) { + if ((active_hours & (1 << 23)) != 0) { break; } @@ -537,12 +631,13 @@ static u8 index_today[mEv_EVENT_NUM]; extern int mEv_get_end_time(int event_type) { u8 idx = index_today[event_type]; + mEv_event_today_c* ev_today = &event_today[idx]; if (idx == 0xFF) { return -1; } else { - return get_end_time(event_today[idx].active_hours); + return get_end_time(ev_today->active_hours); } } @@ -558,69 +653,75 @@ static int search_empty_event_today() { return i; } -static int add_event_today(mEv_MonthDay_u month_day, mEv_schedule_c* schedule) { +static int add_event_today(u16 month_day, mEv_schedule_c* schedule) { + mEv_event_today_c* ev_today; u8 idx = index_today[schedule->type]; int res = FALSE; - if (idx == 0xFF) { - idx = search_empty_event_today(); + if (idx != 0xFF) { + ev_today = &event_today[idx]; + res = FALSE; + } + else { + int idx = search_empty_event_today(); if (idx >= mEv_TODAY_EVENT_NUM) { return FALSE; } - - n_today_events++; + index_today[schedule->type] = idx; + ev_today = &event_today[idx]; + n_today_events++; } { - u8 start_hour = schedule->date[0].hour; - u8 end_hour = schedule->date[1].hour; - u32 i; + u8 start_hour = schedule->date[0].d.hour; + u8 end_hour = schedule->date[1].d.hour; u32 n; + lbRTC_hour_t i; - if ((start_hour & mEv_SCHEDULE_TODAY) == 0) { - event_today[idx].begin_date = schedule->date[0].month_day; - event_today[idx].end_date = schedule->date[1].month_day; - } - else { - event_today[idx].begin_date = month_day; - event_today[idx].end_date = month_day; + if ((start_hour & mEv_SCHEDULE_TODAY) != 0) { + ev_today->begin_date.raw = month_day; + ev_today->end_date.raw = month_day; start_hour &= ~mEv_SCHEDULE_TODAY; end_hour &= ~mEv_SCHEDULE_TODAY; } + else { + ev_today->begin_date.raw = schedule->date[0].md; + ev_today->end_date.raw = schedule->date[1].md; + } if ((start_hour & mEv_SCHEDULE_MULTIDAY) != 0) { start_hour &= ~mEv_SCHEDULE_MULTIDAY; end_hour &= ~mEv_SCHEDULE_MULTIDAY; - if (month_day.raw != schedule->date[0].month_day.raw) { + if (month_day != schedule->date[0].md) { start_hour = 0; } - if (month_day.raw != schedule->date[1].month_day.raw) { + if (month_day != schedule->date[1].md) { end_hour = 23; } } n = 1; for (i = 0; i < 24; i++) { - if (i >= start_hour && i <= end_hour) { - event_today[idx].active_hours |= n; + if (start_hour <= i && i <= end_hour) { + ev_today->active_hours |= n; } n <<= 1; } - - event_today[idx].type = schedule->type; - event_today[idx].status |= mEv_STATUS_EXIST; } + ev_today->type = schedule->type; + ev_today->status |= mEv_STATUS_EXIST; + return res; } static int check_and_clear_event_today(Event_c* event, int type) { - u8 idx = index_today[idx]; + u8 idx = index_today[type]; if (idx != 0xFF) { mEv_event_today_c* today_event = &event_today[idx]; @@ -640,10 +741,10 @@ static int check_and_clear_event_today(Event_c* event, int type) { if (type == today_event->type && flags == 0) { today_event->type = -1; - n_today_events--; today_event->active_hours = 0; today_event->end_date.raw = 0; today_event->status = 0; + n_today_events--; index_today[type] = 0xFF; return TRUE; @@ -654,7 +755,7 @@ static int check_and_clear_event_today(Event_c* event, int type) { return FALSE; } -static int delete_too_short_event(Event_c* event, int type, mEv_schedule_date_u date) { +static int delete_too_short_event(Event_c* event, int type, u32 date) { u8 idx = index_today[type]; if (idx != 0xFF) { @@ -676,8 +777,8 @@ static int delete_too_short_event(Event_c* event, int type, mEv_schedule_date_u case mEv_EVENT_FISHING_TOURNEY_2: case mEv_EVENT_HARVEST_FESTIVAL: { - new_date = date; - new_date.hour = mEv_get_end_time(today_event->type); + new_date.raw = date; + new_date.d.hour = mEv_get_end_time(today_event->type); break; } @@ -687,8 +788,8 @@ static int delete_too_short_event(Event_c* event, int type, mEv_schedule_date_u case mEv_EVENT_NEW_YEARS_EVE_COUNTDOWN: { new_date.raw = 0; - new_date.month_day = today_event->end_date; - new_date.hour = mEv_get_end_time(today_event->type); + new_date.md = today_event->end_date.raw; + new_date.d.hour = mEv_get_end_time(today_event->type); break; } @@ -699,7 +800,7 @@ static int delete_too_short_event(Event_c* event, int type, mEv_schedule_date_u } } - if (new_date.raw != date.raw) { + if (new_date.raw != date) { return FALSE; } @@ -714,40 +815,32 @@ static int delete_too_short_event(Event_c* event, int type, mEv_schedule_date_u } static void init_today_event() { - mEv_event_today_c* today_event = event_today; int i; for (i = 0; i < mEv_TODAY_EVENT_NUM; i++) { - today_event->type = -1; - today_event->active_hours = 0; - today_event->end_date.raw = 0; - today_event->begin_date.raw = 0; - today_event->status = 0; - - today_event++; + mEv_event_today_c* ev_today = &event_today[i]; + + ev_today->type = -1; + ev_today->active_hours = 0; + ev_today->begin_date.raw = ev_today->end_date.raw = 0; + ev_today->status = 0; } n_today_events = 0; - - { - u8* index_today_p = index_today; - - for (i = 0; i < mEv_EVENT_NUM; i++) { - index_today_p[0] = 0xFF; - index_today_p++; - } + for (i = 0; i < mEv_EVENT_NUM; i++) { + index_today[i] = 0xFF; } } static void init_time_seat() { - mEv_event_today_c* today_event = event_today; int i; for (i = 0; i < mEv_TODAY_EVENT_NUM; i++) { - today_event->active_hours = 0; - today_event->end_date.raw = 0; - today_event->begin_date.raw = 0; - today_event->status &= ~mEv_STATUS_EXIST; + mEv_event_today_c* ev_today = &event_today[i]; + + ev_today->active_hours = 0; + ev_today->begin_date.raw = ev_today->end_date.raw = 0; + ev_today->status &= ~mEv_STATUS_EXIST; } } @@ -778,10 +871,21 @@ static int get_special_event_end_time(s16 event_type) { return end_time; } -static int init_special_init(int new_event) { +#define mEv_MonthDay(m, d) (((u8)(m) << 8) | ((u8)(d))) +#define mEv_MonthDay_GetDay(md) ((md) & 0xFF) +#define mEv_MonthDay_GetMonth(md) (((md) >> 8) & 0xFF) +#define mEv_MonthDay_SetDay(md, d) (((md) & 0xFF00) | (u8)(d)) +#define mEv_MonthDay_SetMonth(md, m) (((md) & 0xFF) | ((u8)(m) << 8)) + +#define mEv_YearMonthDayHour(y, m, d, h) ((u32)(((u8)(y) << 24) | ((u8)(m) << 16) | ((u8)(d) << 8) | ((u8)(h)))) + +/* @nonmatching TODO: This function needs a lot of help matching. Current best scratch: https://decomp.me/scratch/0EXoP */ +static int init_special_event(int new_event) { + lbRTC_time_c* rtc_time = Common_GetPointer(time.rtc_time); + mEv_special_c* special_ev = &Save_Get(event_save_data).special; int res = FALSE; - switch (Save_Get(scene_no)) { + switch (Common_Get(last_scene_no)) { case SCENE_BUGGY: case SCENE_BROKER_SHOP: { @@ -804,7 +908,7 @@ static int init_special_init(int new_event) { case SCENE_DEPART: case SCENE_DEPART_2: { - if (Save_Get(event_save_data).special.type == mEv_EVENT_SHOP_SALE) { + if (Save_Get(event_save_common).special_event.type == mEv_EVENT_SHOP_SALE) { return FALSE; } } @@ -812,8 +916,2198 @@ static int init_special_init(int new_event) { // fallthrough case default: { - + mEv_ymdh_u rtc_ymdh; + mEv_ymdh_u special_ymdh; + mEv_ymdh_u special_end_ymdh; + mEv_MonthDay_u special_monthday; + mEv_schedule_date_u rtc_sched; + u16 special_end_monthday; + u16 sale_day_monthday; + mEv_save_common_data_c* ev_save_common = Save_GetPointer(event_save_common); + + //u16 rtc_monthday = mEv_MonthDay(Common_Get(time.rtc_time.month), Common_Get(time.rtc_time.day)); + //u32 rtc_ymdh = (u32)(((Common_Get(time.rtc_time.year) % 100) << 24) | (rtc_monthday << 8) | Common_Get(time.rtc_time.hour)); + // u32 special_ymdh = (u32)(((Save_Get(event_year_ymd.year) % 100) << 24) | (Save_Get(event_save_common).dates[mEv_SAVE_DATE_SPECIAL0] << 8)); + // u32 special_end_ymdh = (u32)( + // (((Save_Get(event_year_ymd.year) % 100) - ((Save_Get(event_save_common).dates[mEv_SAVE_DATE_SPECIAL2] < Save_Get(event_save_common).dates[mEv_SAVE_DATE_SPECIAL0] && rtc_monthday < Save_Get(event_save_common).dates[mEv_SAVE_DATE_SPECIAL0]) ? 1 : 2)) << 24) | + // (Save_Get(event_save_common).dates[mEv_SAVE_DATE_SPECIAL0] << 8) | + // (u8)get_special_event_end_time(Save_Get(event_save_common).special_event.type) + // ); + + rtc_sched.raw = 0; + rtc_sched.d.month = rtc_time->month; + rtc_sched.d.day = rtc_time->day; + + rtc_ymdh.raw = (rtc_sched.md) << 8; + rtc_ymdh.year = rtc_time->year % 100; + rtc_ymdh.hour = rtc_time->hour; + + special_ymdh.raw = ev_save_common->dates[mEv_SAVE_DATE_SPECIAL0] << 8; + special_ymdh.year = Save_Get(event_year) % 100; + + //special_end_ymdh.raw = (special_ymdh.month_day.raw) << 8; + special_end_ymdh.year = (Save_Get(event_year) % 100) + ((ev_save_common->dates[mEv_SAVE_DATE_SPECIAL0] > ev_save_common->dates[mEv_SAVE_DATE_SPECIAL2] && ev_save_common->dates[mEv_SAVE_DATE_SPECIAL0] > rtc_sched.md) ? 0 : -1); + special_end_ymdh.hour = get_special_event_end_time(ev_save_common->special_event.type); + + + if (check_ymdh_range(rtc_ymdh.raw, special_ymdh.raw, special_end_ymdh.raw) == FALSE || new_event) { + int seed = Common_Get(now_private)->player_ID.player_id; + s16 type; + int next_event_day_gap; + + res |= TRUE; + mEv_ClearSpecialEvent(special_ev); + seed += 1 + rtc_time->year - rtc_time->month + rtc_time->day + rtc_time->hour; + /* Sale Day */ + sale_day_monthday = after_n_day(((lbRTC_NOVEMBER) << 8) | m_weekday2day(lbRTC_NOVEMBER, mEv_SCHEDULE_4TH_WEEKDAY(lbRTC_THURSDAY)), 1); + + do { + sad_label: + /* Select a new unique random event */ + do { + type = special_event_types[seed % n_special_event_type]; + seed++; + } while (type == Save_Get(event_save_common).special_event.type); + + mFAs_SetFieldRank(); + next_event_day_gap = 1 + + ((rtc_time->day + rtc_time->month * rtc_time->sec) % + ((mFAs_FIELDRANK_SIX + 1) - mFAs_GetFieldRank())); + + if (next_event_day_gap == 1) { + next_event_day_gap = 2; // minimum of 2 days between special events + } + + special_monthday.raw = after_n_day(rtc_sched.md, next_event_day_gap); + if ((u16)rtc_sched.md <= sale_day_monthday && (u16)sale_day_monthday <= (u32)special_monthday.raw) { + /* Force the next special event to be Crazy Redd since Sale Day falls between now and the rolled event date */ + special_monthday.raw = sale_day_monthday; + type = mEv_EVENT_BROKER_SALE; + } + + /* Set event start hour */ + Save_Get(event_save_common).dates[mEv_SAVE_DATE_SPECIAL3] = 6; + + switch (type) { + case mEv_EVENT_GYPSY: + break; + + case mEv_EVENT_SHOP_SALE: + { + lbRTC_day_t last_day = last_day_of_month(special_monthday.month); + + if ( + special_monthday.day != last_day && + (special_monthday.raw < mEv_MonthDay(lbRTC_JANUARY, 1) || special_monthday.raw > mEv_MonthDay(lbRTC_JANUARY, 3)) && + mEv_CheckEvent(mEv_SAVED_RENEWSHOP) != TRUE + ) { + /* Set shop sale starting hour randomly between 12PM and 7PM */ + Save_Get(event_save_common).dates[mEv_SAVE_DATE_SPECIAL3] = 12 + RANDOM(8); + goto hate_gotos; + } + goto sad_label; + } + + case mEv_EVENT_BROKER_SALE: + { + if (special_monthday.raw != mEv_MonthDay(lbRTC_JULY, 4)) { + /* Set broker sale start hour to 6PM when it's not the Fireworks Festival */ + Save_Get(event_save_common).dates[mEv_SAVE_DATE_SPECIAL3] = 18; + goto hate_gotos; + } + goto sad_label; + } + + default: + goto hate_gotos; + break; + } + } while (special_monthday.raw == mEv_MonthDay(lbRTC_DECEMBER, 31)); + + Save_Get(event_save_common).dates[mEv_SAVE_DATE_SPECIAL3] = 21; // default event start time is 9pm? + + hate_gotos: + { + mEv_save_common_data_c* ev_save_common = Save_GetPointer(event_save_common); + u16 year; + + special_end_monthday = after_n_day(special_monthday.raw, type != mEv_EVENT_SHOP_SALE); // ?? + year = rtc_time->year; + ev_save_common->special_event.type = type; + ev_save_common->dates[mEv_SAVE_DATE_SPECIAL0] = rtc_sched.md; // current date + ev_save_common->dates[mEv_SAVE_DATE_SPECIAL1] = special_monthday.raw; // start date + ev_save_common->dates[mEv_SAVE_DATE_SPECIAL2] = special_end_monthday; // end date + Save_Set(event_year, year); + Save_Get(post_office).leaflet_recipient_flags.event_flags = 0b1111; // deliver leaflet to all players if necessary for event + } + } + break; + } + } + + return res; +} + +static int update_special_event(mEv_schedule_c* sched) { + s16 type = Save_Get(event_save_common).special_event.type; + int active = TRUE; + + switch (sched->type) { + case mEv_EVENT_ARTIST: + case mEv_EVENT_BROKER_SALE: + case mEv_EVENT_DESIGNER: + case mEv_EVENT_GYPSY: + case mEv_EVENT_SHOP_SALE: + case mEv_EVENT_CARPET_PEDDLER: + { + if (type != sched->type) { + sched->date[1].raw = 0; + sched->date[0].raw = 0; + active = FALSE; + } + break; + } + + case mEv_EVENT_HANDBILL_SHOP_SALE: + { + if (type != mEv_EVENT_SHOP_SALE) { + sched->date[1].raw = 0; + sched->date[0].raw = 0; + active = FALSE; + } + break; + } + + case mEv_EVENT_HANDBILL_BROKER: + { + if (type != mEv_EVENT_BROKER_SALE) { + sched->date[1].raw = 0; + sched->date[0].raw = 0; + active = FALSE; + } + break; + } + + default: + active = FALSE; + break; + } + + return active; +} + +extern u16 mEv_get_bargain_day() { + u16 bargain_day = 0; + + if (Save_Get(event_save_common).special_event.type == mEv_EVENT_SHOP_SALE) { + bargain_day = Save_Get(event_save_common).dates[mEv_SAVE_DATE_SPECIAL1]; + } + + return bargain_day; +} + +static int is_special_event_valid() { + mEv_schedule_date_u date; + + date.raw = 0; + date.d.month = Common_Get(time.rtc_time.month); + date.d.day = Common_Get(time.rtc_time.day); + + return check_date_range( + date.md, + Save_Get(event_save_common).dates[mEv_SAVE_DATE_SPECIAL0], + Save_Get(event_save_common).dates[mEv_SAVE_DATE_SPECIAL2] + ); +} + +extern u16 mEv_get_special_event_day() { + u16 day = 0; + + if (is_special_event_valid()) { + day = Save_Get(event_save_common).dates[mEv_SAVE_DATE_SPECIAL1]; + } + + return day; +} + +extern u16 mEv_get_special_event_type() { + u16 type = 0; + + if (is_special_event_valid()) { + type = Save_Get(event_save_common).special_event.type; + } + + return type; +} + +extern int mEv_get_event_place(int event, int* bx, int* bz) { + mEv_place_data_c* place; + + if (mEv_check_status(event, mEv_STATUS_RUN) != FALSE) { + place = mEv_get_common_place(event, 81); + + if (place != NULL) { + *bx = place->block.x; + *bz = place->block.z; + return TRUE; + } + } + + return FALSE; +} + +extern int mEv_bridge_time_check() { + lbRTC_time_c rtc_time = Common_Get(time.rtc_time); + + return lbRTC_IsEqualDate( + Save_Get(bridge).build_date.year, Save_Get(bridge).build_date.month, Save_Get(bridge).build_date.day, + rtc_time.year, rtc_time.month, rtc_time.day + ); +} + +static void init_weekly_event() { + u16 sched_date; + lbRTC_time_c* rtc_time = &Common_Get(time.rtc_time); + mEv_kabu_peddler_c* kabu_peddler_data = &Save_Get(event_save_data).weekly.kabu_peddler; + mEv_MonthDay_u today_date; + u8 flag = 0; + u16 ghost_date; + u16 ghost_date2; + u16 monday_date; + u16 friday_date; + u16* event_dates = Save_Get(event_save_common).dates; + + today_date.month = rtc_time->month; + today_date.day = rtc_time->day; + sched_date = event_dates[mEv_SAVE_DATE_WEEKLY]; + + switch (rtc_time->weekday) { + case lbRTC_SUNDAY: + { + /* Update Joan's data */ + if (today_date.raw != sched_date) { + mEv_ClearEventKabuPeddler(kabu_peddler_data); + sched_date = today_date.raw; + event_dates[mEv_SAVE_DATE_WEEKLY] = sched_date; + Save_Get(event_save_common).weekly_event.type = mEv_EVENT_KABU_PEDDLER; + flag = 1; + } + break; + } + + case lbRTC_SATURDAY: + { + /* Update K.K. Slider's data */ + if (today_date.raw != sched_date) { + sched_date = today_date.raw; + event_dates[mEv_SAVE_DATE_WEEKLY] = sched_date; + Save_Get(event_save_common).weekly_event.type = mEv_EVENT_KK_SLIDER; + flag = 1; + } + break; + } + + default: + { + monday_date = after_n_day(today_date.raw, lbRTC_MONDAY - rtc_time->weekday); + friday_date = after_n_day(today_date.raw, lbRTC_FRIDAY - rtc_time->weekday); + + /* Check if we should reschedule Gulliver */ + if (sched_date == 0 || check_date_range(sched_date, monday_date, friday_date) == FALSE) { + u8 ofs = 1 + (today_date.raw + rtc_time->hour) % 5; + /* Schedule a new date for the event between Monday & Friday */ + sched_date = after_n_day(today_date.raw, ofs - rtc_time->weekday); + event_dates[mEv_SAVE_DATE_WEEKLY] = sched_date; + Save_Get(event_save_common).weekly_event.type = mEv_EVENT_DOZAEMON; // Gulliver + Save_Get(event_save_common).current_event_state = 0; + } + + /* Check if Guillver should spawn today */ + if (sched_date == today_date.raw) { + flag = mEv_EVENT_DOZAEMON; + } + + break; + } + } + + /* Check if we should schedule Tortimer's 3rd bridge event */ + if (rtc_time->weekday == lbRTC_SATURDAY || (rtc_time->weekday != lbRTC_SUNDAY && sched_date != today_date.raw)) { + /* Gulliver wasn't scheduled today, so check the criteria is met */ + if ( + Common_Get(player_no) != mPr_FOREIGNER && + Save_Get(now_npc_max) >= ANIMAL_NUM_MAX && + Save_Get(bridge).exists != TRUE && + mSC_LightHouse_travel_check() == FALSE + ) { + flag = mEv_EVENT_SONCHO_BRIDGE_MAKE; + } + + /* Update bridge location seed and date */ + if (flag == mEv_EVENT_SONCHO_BRIDGE_MAKE && Save_Get(event_save_common).bridge_day != today_date.raw) { + Save_Get(event_save_common).bridge_day = today_date.raw; + Save_Get(event_save_common).bridge_flags.raw++; + } + } + + /* Check if Blanca should spawn */ + if ( + flag != mEv_EVENT_DOZAEMON && + flag != mEv_EVENT_SONCHO_BRIDGE_MAKE && + (mGH_check_birth2() || mMC_check_birth()) + ) { + flag = mEv_EVENT_MASK_NPC; + } + + /* Initialize Wisp */ + Save_Get(event_save_common).weekly_event.flags = flag; + Save_Get(event_save_common).ghost_event_type = mEv_EVENT_NUM; // Wisp is not set to spawn + ghost_date = Save_Get(event_save_common).ghost_day; + monday_date = after_n_day(today_date.raw, -lbRTC_WEEK); + friday_date = after_n_day(today_date.raw, 4); + + /* Check if we should refresh Wisp's spawn date */ + if (ghost_date == 0 || check_date_range(ghost_date, monday_date, friday_date) == FALSE) { + ghost_date = after_n_day(today_date.raw, 2 + RANDOM(3)); + Save_Get(event_save_common).ghost_day = ghost_date; + } + + /* Spawn Wisp if his scheduled appearance date is within [today-7, today] */ + if (check_date_range(ghost_date, monday_date, today_date.raw)) { + Save_Get(event_save_common).ghost_event_type = mEv_EVENT_GHOST; + } +} + +static void update_soncho_event(mEv_schedule_c* sched) { + switch (sched->type) { + case mEv_EVENT_SONCHO_VACATION_JANUARY: + case mEv_EVENT_SONCHO_VACATION_FEBRUARY: + { + if (mSC_LightHouse_Event_Start() == FALSE) { + sched->date[1].raw = 0; + sched->date[0].raw = 0; + } + + break; + } + + case mEv_EVENT_SONCHO_FISHING_TOURNEY_1: + { + if (Save_Get(event_save_common).soncho_event_type != 0xFF) { + sched->date[1].raw = 0; + sched->date[0].raw = 0; + } + + break; + } + + case mEv_EVENT_SONCHO_FISHING_TOURNEY_2: + { + if (Save_Get(event_save_common).soncho_event_type != 0xFF) { + sched->date[1].raw = 0; + sched->date[0].raw = 0; + } + break; } } } + +static void update_soncho_event2(mEv_schedule_c* sched) { + switch (sched->type) { + case mEv_EVENT_SONCHO_VACATION_JANUARY: + case mEv_EVENT_SONCHO_VACATION_FEBRUARY: + case mEv_EVENT_SONCHO_NEW_YEARS_DAY: + case mEv_EVENT_SONCHO_GROUNDHOG_DAY: + case mEv_EVENT_SONCHO_SPRING_SPORTS_FAIR: + case mEv_EVENT_SONCHO_APRILFOOLS_DAY: + case mEv_EVENT_SONCHO_CHERRY_BLOSSOM_FESTIVAL: + case mEv_EVENT_SONCHO_NATURE_DAY: + case mEv_EVENT_SONCHO_SPRING_CLEANING: + case mEv_EVENT_SONCHO_MOTHERS_DAY: + case mEv_EVENT_SONCHO_GRADUATION_DAY: + case mEv_EVENT_SONCHO_FATHERS_DAY: + case mEv_EVENT_SONCHO_FISHING_TOURNEY_1: + case mEv_EVENT_SONCHO_TOWN_DAY: + case mEv_EVENT_SONCHO_FIREWORKS_SHOW: + case mEv_EVENT_SONCHO_METEOR_SHOWER: + case mEv_EVENT_SONCHO_FOUNDERS_DAY: + case mEv_EVENT_SONCHO_LABOR_DAY: + case mEv_EVENT_SONCHO_FALL_SPORTS_FAIR: + case mEv_EVENT_SONCHO_HARVEST_MOON_FESTIVAL: + case mEv_EVENT_SONCHO_EXPLORERS_DAY: + case mEv_EVENT_SONCHO_HALLOWEEN: + case mEv_EVENT_SONCHO_MAYORS_DAY: + case mEv_EVENT_SONCHO_OFFICERS_DAY: + case mEv_EVENT_SONCHO_FISHING_TOURNEY_2: + case mEv_EVENT_SONCHO_HARVEST_FESTIVAL: + case mEv_EVENT_SONCHO_SALE_DAY: + case mEv_EVENT_SONCHO_SNOW_DAY: + case mEv_EVENT_SONCHO_TOY_DAY: + case mEv_EVENT_TALK_NEW_YEARS_COUNTDOWN: + { + if (Save_Get(event_save_common).weekly_event.flags == mEv_EVENT_SONCHO_BRIDGE_MAKE) { + Save_Get(event_save_common).weekly_event.flags = 0; + } + + break; + } + } + + /* Update the event type to prefer these events over the fishing tourney event if they coincide */ + switch (sched->type) { + case mEv_EVENT_SONCHO_FATHERS_DAY: + case mEv_EVENT_SONCHO_OFFICERS_DAY: + Save_Get(event_save_common).soncho_event_type = sched->type; + break; + } +} + +static void update_sports_fair(mEv_schedule_c* sched, lbRTC_day_t* equinox_day) { + lbRTC_time_c* rtc_time = Common_GetPointer(time.rtc_time); + + switch (sched->type) { + case mEv_EVENT_SPRING_EQUINOX: + case mEv_EVENT_SONCHO_SPRING_SPORTS_FAIR: + { + if ( + rtc_time->month != lbRTC_MARCH || + rtc_time->day != lbRk_VernalEquinoxDay(rtc_time->year) + ) { + sched->date[1].raw = 0; + sched->date[0].raw = 0; + } + else { + sched->date[0].d.day = rtc_time->day; + sched->date[1].d.day = rtc_time->day; + *equinox_day = rtc_time->day; + } + + break; + } + + case mEv_EVENT_RUMOR_SPRING_SPORTS_FAIR: + { + int vernal_day = lbRk_VernalEquinoxDay(rtc_time->year); + + sched->date[0].d.day = vernal_day - 10; + sched->date[1].d.day = vernal_day - 1; + break; + } + + case mEv_EVENT_AUTUMN_EQUINOX: + case mEv_EVENT_SONCHO_FALL_SPORTS_FAIR: + { + if ( + rtc_time->month != lbRTC_SEPTEMBER || + rtc_time->day != lbRk_AutumnalEquinoxDay(rtc_time->year) + ) { + sched->date[1].raw = 0; + sched->date[0].raw = 0; + } + else { + sched->date[0].d.day = rtc_time->day; + sched->date[1].d.day = rtc_time->day; + *equinox_day = rtc_time->day; + } + + break; + } + + case mEv_EVENT_RUMOR_FALL_SPORTS_FAIR: + { + int autumnal_day = lbRk_AutumnalEquinoxDay(rtc_time->year); + + sched->date[0].d.day = autumnal_day - 10; + sched->date[1].d.day = autumnal_day - 1; + break; + } + + case mEv_EVENT_SPORTS_FAIR_BALL_TOSS: + case mEv_EVENT_SPORTS_FAIR_AEROBICS: + case mEv_EVENT_SPORTS_FAIR_TUG_OF_WAR: + case mEv_EVENT_SPORTS_FAIR_FOOT_RACE: + case mEv_EVENT_SPORTS_FAIR: + case mEv_EVENT_WEATHER_SPORTS_FAIR: + { + if (*equinox_day == 0) { + sched->date[1].raw = 0; + sched->date[0].raw = 0; + } + else { + sched->date[0].d.day = *equinox_day; + sched->date[1].d.day = *equinox_day; + } + + break; + } + } +} + +static void update_event_rumor(mEv_schedule_c* sched) { + lbRTC_time_c* rtc_time = Common_GetPointer(time.rtc_time); + int equinox_day; + + switch (sched->type) { + case mEv_EVENT_RUMOR_SPRING_SPORTS_FAIR: + { + equinox_day = lbRk_VernalEquinoxDay(rtc_time->year); + sched->date[0].d.day = equinox_day - 10; + sched->date[1].d.day = equinox_day - 1; + break; + } + + case mEv_EVENT_TALK_FISHING_TOURNEY_1: + sched->date[1].d.day = lbRTC_Weekly_day(rtc_time->year, lbRTC_JUNE, mEv_SCHEDULE_LAST_WEEKDAY_OF_MONTH, lbRTC_SUNDAY); + break; + + case mEv_EVENT_RUMOR_HARVEST_MOON_DAY: + { + lbRTC_ymd_c harvest_moon_ymd; + lbRTC_time_c harvest_moon_day; + lbRTC_day_t beg_day; + lbRTC_month_t beg_month; + lbRTC_day_t end_day; + lbRTC_month_t end_month; + + lbRk_HarvestMoonDay(&harvest_moon_ymd, rtc_time->year); + harvest_moon_day.year = harvest_moon_ymd.year; + harvest_moon_day.month = harvest_moon_ymd.month; + harvest_moon_day.day = harvest_moon_ymd.day; + + /* Calculate rumor end date */ + lbRTC_Sub_DD(&harvest_moon_day, 1); + end_month = harvest_moon_day.month; + end_day = harvest_moon_day.day; + + /* Calculate rumor start date */ + lbRTC_Sub_DD(&harvest_moon_day, lbRTC_WEEK - 1); + + beg_month = harvest_moon_day.month; + beg_day = harvest_moon_day.day; + sched->date[0].d.month = beg_month; + sched->date[0].d.day = beg_day; + sched->date[1].d.month = end_month; + sched->date[1].d.day = end_day; + break; + } + + case mEv_EVENT_RUMOR_FALL_SPORTS_FAIR: + { + equinox_day = lbRk_AutumnalEquinoxDay(rtc_time->year); + sched->date[0].d.day = equinox_day - 10; + sched->date[1].d.day = equinox_day - 1; + break; + } + + case mEv_EVENT_TALK_FISHING_TOURNEY_2: + sched->date[1].d.day = lbRTC_Weekly_day(rtc_time->year, lbRTC_NOVEMBER, mEv_SCHEDULE_LAST_WEEKDAY_OF_MONTH, lbRTC_SUNDAY); + break; + + case mEv_EVENT_RUMOR_HARVEST_FESTIVAL: + sched->date[1].d.day = lbRTC_Weekly_day(rtc_time->year, lbRTC_NOVEMBER, 4, lbRTC_THURSDAY) - 1; // 4th Thursday in November + break; + } +} + +static void update_weekly_event(mEv_schedule_c* sched) { + s16 type = Save_Get(event_save_common).weekly_event.type; + + switch (sched->type) { + case mEv_EVENT_KK_SLIDER: + case mEv_EVENT_KABU_PEDDLER: + { + if (type != sched->type) { + sched->date[1].raw = 0; + sched->date[0].raw = 0; + } + + break; + } + + case mEv_EVENT_DOZAEMON: + { + if (Save_Get(event_save_common).weekly_event.flags == mEv_EVENT_SONCHO_BRIDGE_MAKE || type != sched->type) { + sched->date[1].raw = 0; + sched->date[0].raw = 0; + } + + break; + } + + case mEv_EVENT_SONCHO_BRIDGE_MAKE: + case mEv_EVENT_MASK_NPC: + { + if (Save_Get(event_save_common).weekly_event.flags != sched->type) { + sched->date[1].raw = 0; + sched->date[0].raw = 0; + } + + break; + } + + case mEv_EVENT_BRIDGE_MAKE: + { + if (Save_Get(bridge).pending != TRUE || Save_Get(bridge).exists || mEv_bridge_time_check() == lbRTC_OVER) { + sched->date[1].raw = 0; + sched->date[0].raw = 0; + } + + break; + } + + case mEv_EVENT_GHOST: + { + if (Save_Get(event_save_common).ghost_event_type != mEv_EVENT_GHOST) { + sched->date[1].raw = 0; + sched->date[0].raw = 0; + } + + break; + } + } +} + +// forward declarations +static int clear_active(int type); +static int set_active(int type); + +static void update_active(Event_c* event) { + mEv_place_data_c* place_data; + mEv_event_today_c* today_event; + int hour = Common_Get(time.rtc_time.hour); + int i; + + /* Update active events */ + for (i = 0; i < mEv_TODAY_EVENT_NUM; i++) { + today_event = &event_today[i]; + + if (today_event->type != -1 && index_today[today_event->type] != 0xFF) { + if (mEv_check_status(today_event->type, mEv_STATUS_ERROR) != FALSE) { + continue; + } + + if (today_event->type == mEv_EVENT_SPORTS_FAIR && + Common_Get(event_common).fieldday_event_over_status != today_event->type) { + if (clear_active(today_event->type)) { + event->changed_num++; + } + + continue; + } + + if ((today_event->active_hours & mEv_EVENT_HOUR_START_EVENT)) { + if (set_active(today_event->type)) { + event->changed_num++; + } + + today_event->active_hours &= ~mEv_EVENT_HOUR_START_EVENT; + } + else if ( + today_event->type >= mEv_EVENT_ARTIST && today_event->type <= mEv_EVENT_CARPET_PEDDLER && + today_event->type == Save_Get(event_save_common).delete_event_id + ) { + if (clear_active(today_event->type)) { + event->changed_num++; + } + + Save_Get(event_save_common).delete_event_id = 0; + today_event->active_hours = mEv_EVENT_HOUR_CLEAR_EVENT; + } + else if ((today_event->active_hours & (1 << hour))) { + if (Common_Get(event_common).fieldday_event_over_status != -1 && + (today_event->type == mEv_EVENT_SPORTS_FAIR_BALL_TOSS || + today_event->type == mEv_EVENT_SPORTS_FAIR_TUG_OF_WAR || + today_event->type == mEv_EVENT_SPORTS_FAIR_FOOT_RACE)) { + if (clear_active(today_event->type)) { + event->changed_num++; + } + + continue; + } + if (today_event->type != 0 && today_event->type == Common_Get(event_common).too_short) { + today_event->active_hours |= mEv_EVENT_HOUR_TOO_SHORT_EVENT; + } + else if (set_active(today_event->type)) { + event->changed_num++; + } + } + else { + place_data = mEv_get_common_place(today_event->type, 81); + + if (today_event->type != 0 && today_event->type == Common_Get(event_common).too_short) { + Common_Get(event_common).too_short = 0; + } + else if (place_data != NULL) { + if (place_data->block.x != event->block_x || place_data->block.z != event->block_z) { + if (clear_active(today_event->type)) { + event->changed_num++; + } + } + } else { + if (clear_active(today_event->type)) { + event->changed_num++; + } + } + } + } + + if ((today_event->active_hours & mEv_EVENT_HOUR_CLEAR_EVENT) && + mEv_check_status(today_event->type, mEv_STATUS_RUN) == FALSE) { + today_event->active_hours = 0; + } + } + + /* Update active rumors */ + mEv_clear_rumor(); + for (i = 0; i < n_event_rumors; i++) { + if (mEv_check_status(event_rumor_table[i], mEv_STATUS_ACTIVE)) { + mEv_spread_rumor(i); + } + } +} + +static u32 decode_date(u32 d) { + mEv_schedule_date_u date; + mEv_save_common_data_c* ev_common = Save_GetPointer(event_save_common); + lbRTC_time_c* rtc_time = Common_GetPointer(time.rtc_time); + int month; + int day; + int hour; + + date.raw = d; + + /* Process month */ + month = date.d.month; + if ((month & mEv_SCHEDULE_USE_SAVE_MONTH)) { + date.md = Save_Get(event_save_common).dates[month & 0xF]; + } + else if ((month & mEv_SCHEDULE_NOW_MONTH)) { + date.d.month = rtc_time->month; + } + else if ((month & mEv_SCHEDULE_HARVEST_MOON_DATE)) { + lbRTC_ymd_c harvest_moon_ymd; + + lbRk_HarvestMoonDay(&harvest_moon_ymd, rtc_time->year); + date.d.month = harvest_moon_ymd.month; + date.d.day = harvest_moon_ymd.day; + } + + /* Process day */ + day = date.d.day; + if ((day & mEv_SCHEDULE_WEEKLY)) { + date.d.day = m_weekday2day(date.d.month, day & ~mEv_SCHEDULE_DAY_AFTER); + + if ((day & mEv_SCHEDULE_DAY_AFTER)) { + date.md = after_n_day(date.md, 1); + } + } + else if ((day & mEv_SCHEDULE_LAST_DAY_OF_MONTH)) { + date.d.day = last_day_of_month(date.d.month); + } + else if ((day & mEv_SCHEDULE_TOWN_DAY)) { + date.d.day = (date.d.day & ~mEv_SCHEDULE_TOWN_DAY) | Save_Get(town_day); + } + + /* Process hour */ + hour = date.d.hour; + if ((hour & mEv_SCHEDULE_USE_SAVE_SLOT_VALUE)) { + date.d.hour = Save_Get(event_save_common).dates[(hour & 0x1F) % 8] | (hour & 0xC0); + } + + return date.raw; +} + +static int set_one_time_active(int event) { + u8 idx = index_today[event]; + + if (idx != 0xFF) { + mEv_event_today_c* ev_today = &event_today[idx]; + ev_today->active_hours |= mEv_EVENT_HOUR_START_EVENT; + return TRUE; + } + + return FALSE; +} + +static int first_enter_check() { + switch (Common_Get(last_scene_no)) { + case SCENE_START_DEMO: + case SCENE_START_DEMO2: + case SCENE_PLAYERSELECT: + case SCENE_PLAYERSELECT_2: + case SCENE_PLAYERSELECT_3: + case SCENE_PLAYERSELECT_SAVE: + case SCENE_START_DEMO3: + return TRUE; + + default: + return FALSE; + } +} + +static int effective_scene() { + switch (Save_Get(scene_no)) { + case SCENE_START_DEMO: + case SCENE_START_DEMO2: + case SCENE_PLAYERSELECT: + case SCENE_PLAYERSELECT_2: + case SCENE_PLAYERSELECT_3: + case SCENE_PLAYERSELECT_SAVE: + case SCENE_START_DEMO3: + return FALSE; + + default: + return TRUE; + } +} + +static void update_schedule_today(Event_c* event) { + int month; + u8 equinox_day = 0; + mEv_schedule_date_u today_date; + mEv_MonthDay_u birthday_date; + mEv_schedule_c sched; + lbRTC_time_c* rtc_time = Common_GetPointer(time.rtc_time); + mEv_schedule_c* sched_p = &sched; + Private_c* priv = &Save_Get(private[Common_Get(player_no)]); + int i; + int type; + + if (mEv_ArbeitPlayer_kari(Common_Get(player_no)) == FALSE) { + month = rtc_time->month; + + today_date.d.month = month; + today_date.d.day = rtc_time->day; + today_date.d.hour = rtc_time->hour; + today_date.d._2 = 0; + Save_Get(event_save_common).dates[mEv_SAVE_DATE_TODAY] = today_date.md; + + birthday_date.month = priv->birthday.month; + birthday_date.day = priv->birthday.day; + Save_Get(event_save_common).dates[mEv_SAVE_DATE_BIRTHDAY] = birthday_date.raw; + + Save_Get(event_save_common).soncho_event_type = 0xFF; + + /* Process every event */ + for (i = 0; i < ARRAY_COUNT(event_schedule_data); i++) { + memcpy(sched_p, &event_schedule_data[i], sizeof(mEv_schedule_c)); + + /* Perform necessary adjustments */ + update_soncho_event(sched_p); + update_sports_fair(sched_p, &equinox_day); + update_event_rumor(sched_p); + update_special_event(sched_p); + update_weekly_event(sched_p); + + if (sched.type == mEv_EVENT_SUMMER_CAMPER) { + mEv_MonthDay_u camper_date; + + switch (month) { + case lbRTC_JUNE: + case lbRTC_JULY: + case lbRTC_AUGUST: + sched.date[0].d.month = today_date.d.month; + break; + } + + sched.date[0].raw = decode_date(sched.date[0].raw); + camper_date.month = sched.date[0].d.month; + camper_date.day = sched.date[0].d.day; + + /* Move back to the previous week if processing on Sunday */ + if (rtc_time->weekday == lbRTC_SUNDAY) { + camper_date.raw = after_n_day(camper_date.raw, -lbRTC_WEEK); + sched.date[0].d.month = camper_date.month; + sched.date[0].d.day = camper_date.day; + } + + /* Summer campers only stick around for one day */ + camper_date.raw = after_n_day(camper_date.raw, 1); + sched.date[1].d.month = camper_date.month; + sched.date[1].d.day = camper_date.day; + } + else { + sched.date[0].raw = decode_date(sched.date[0].raw); + sched.date[1].raw = decode_date(sched.date[1].raw); + } + + /* Check & add event if it is currently active */ + if (check_date_range(today_date.md, sched.date[0].md, sched.date[1].md)) { + update_soncho_event2(sched_p); + add_event_today(today_date.md, sched_p); + } + } + + type = 0; + switch (Common_Get(last_scene_no)) { + case SCENE_KAMAKURA: + type = mEv_EVENT_KAMAKURA; + break; + case SCENE_BROKER_SHOP: + type = mEv_EVENT_BROKER_SALE; + break; + case SCENE_BUGGY: + type = mEv_EVENT_GYPSY; + break; + case SCENE_SHOP0: + case SCENE_CONVENI: + case SCENE_SUPER: + case SCENE_DEPART: + case SCENE_DEPART_2: + if (mEv_CheckEvent(mEv_SPNPC_EVENT)) { + type = mEv_EVENT_SHOP_SALE; + } + break; + case SCENE_TENT: + type = mEv_EVENT_SUMMER_CAMPER; + break; + } + + if (type != 0 && gamePT->frame_counter == 0) { + mEv_schedule_c new_ev_sched = { + { + { 100, 0, 0, 23 }, + { 100, 0, 0, 0 }, + }, + 0, + 0 + }; + + new_ev_sched.type = type; + new_ev_sched.date[1].d.month = rtc_time->month; + new_ev_sched.date[0].d.month = rtc_time->month; + new_ev_sched.date[1].d.day = rtc_time->day; + new_ev_sched.date[0].d.day = rtc_time->day; + add_event_today(today_date.md, &new_ev_sched); + set_one_time_active(type); + } + + type = 0; + switch (Save_Get(scene_no)) { + case SCENE_KAMAKURA: + type = mEv_EVENT_KAMAKURA; + break; + case SCENE_BROKER_SHOP: + type = mEv_EVENT_BROKER_SALE; + break; + case SCENE_BUGGY: + type = mEv_EVENT_GYPSY; + break; + case SCENE_SHOP0: + case SCENE_CONVENI: + case SCENE_SUPER: + case SCENE_DEPART: + case SCENE_DEPART_2: + if (mEv_CheckEvent(mEv_SPNPC_EVENT)) { + type = mEv_EVENT_SHOP_SALE; + } + break; + case SCENE_TENT: + type = mEv_EVENT_SUMMER_CAMPER; + break; + } + + if (type != 0) { + mEv_schedule_c new_ev_sched = { + { + { 100, 0, 0, 23 }, + { 100, 0, 0, 0 }, + }, + 0, + 0 + }; + + new_ev_sched.type = type; + new_ev_sched.date[1].d.month = rtc_time->month; + new_ev_sched.date[0].d.month = rtc_time->month; + new_ev_sched.date[1].d.day = rtc_time->day; + new_ev_sched.date[0].d.day = rtc_time->day; + add_event_today(today_date.md, &new_ev_sched); + } + + if (first_enter_check()) { + for (i = 0; i < mEv_EVENT_NUM; i++) { + delete_too_short_event(event, i, today_date.raw); + } + } + + for (i = 0; i < mEv_EVENT_NUM; i++) { + check_and_clear_event_today(event, i); + } + } +} + +static void calc_start_block(int* bx, int* bz) { + if (Common_Get(door_data).next_scene_id == 0) { + *bx = 3; + *bz = 2; + + if (Common_Get(clip).demo_clip != NULL && Common_Get(clip).demo_clip->type == mDemo_CLIP_TYPE_RIDE_OFF_DEMO) { + *bz = 1; + } + } + else if (Common_Get(door_data).next_scene_id == SCENE_RANDOM_NPC_TEST) { + *bx = Common_Get(door_data).exit_position.x / mFI_BK_WORLDSIZE_X; + *bz = Common_Get(door_data).exit_position.z / mFI_BK_WORLDSIZE_Z; + } +} + +static void init_event(Event_c* event, int renewal_flag) { + event->month = 99; + event->day = 99; + event->hour = 99; + event->state = 0; + event->_02 = 0; + event->changed_num = 0; + event->block_z = 0; + event->block_x = 0; + + calc_start_block(&event->block_x, &event->block_z); + funeral = FALSE; + dead = FALSE; + init_today_event(); + + if (renewal_flag != mEv_INIT_NO_RENEWAL) { + mEv_RenewalDataEveryDay(); + init_weekday1st(); + + if (init_special_event(FALSE)) { + Save_Get(event_save_common).special_event.flags = 1; + } + + init_weekly_event(); + + if (mEv_LivePlayer(Common_Get(player_no)) && mEv_LiveSonchoPresent() == FALSE) { + update_schedule_today(event); + event->month = Common_Get(time.rtc_time.month); + event->day = Common_Get(time.rtc_time.day); + event->hour = Common_Get(time.rtc_time.hour); + update_active(event); + update_save_area(); + } + } +} + +extern void mEv_init(Event_c* event) { + int renewal_flag = mEv_INIT_NO_RENEWAL; + + if (mEv_CheckTitleDemo() == 0 && effective_scene()) { + renewal_flag = mEv_INIT_RENEWAL; + } + + init_event(event, renewal_flag); +} + +extern void mEv_init_force(Event_c* event) { + int renewal_flag = mEv_INIT_NO_RENEWAL; + + if (mEv_CheckTitleDemo() == 0) { + renewal_flag = mEv_INIT_FORCE_RENEWAL; + } + + init_event(event, renewal_flag); +} + +extern void mEv_2nd_init(Event_c* event) { + /* Disable morning aerobics if it is scheduled and the weather is rain */ + if (Common_Get(weather) == mEnv_WEATHER_RAIN) { + u8 index = index_today[mEv_EVENT_MORNING_AEROBICS]; + + if (index != 0xFF) { + mEv_event_today_c* ev_today = &event_today[index]; + + mEv_clear_status(mEv_EVENT_MORNING_AEROBICS, mEv_STATUS_ACTIVE); + ev_today->type = -1; + index_today[mEv_EVENT_MORNING_AEROBICS] = 0xFF; + } + } +} + +extern int mEv_PlayerOK() { + int res = FALSE; + + if (mPlib_able_player_warp_forEvent() && mPlib_Get_unable_wade() == FALSE) { + res = TRUE; + } + + return res; +} + +extern void mEv_run(Event_c* event) { + status_edge = 0; + + if (mEv_CheckTitleDemo() == 0) { + if (Save_Get(scene_no) == SCENE_START_DEMO || Save_Get(scene_no) == SCENE_START_DEMO2 || + Save_Get(scene_no) == SCENE_START_DEMO3 || Save_Get(scene_no) == SCENE_PLAYERSELECT || + Save_Get(scene_no) == SCENE_PLAYERSELECT_2 || Save_Get(scene_no) == SCENE_PLAYERSELECT_3 || + Save_Get(scene_no) == SCENE_PLAYERSELECT_SAVE) { + return; + } + + /* If the player is transitioning acres update the event's acre */ + if (mFI_CheckPlayerWade(mFI_WADE_START) == TRUE) { + mFI_GetNextBlockNum(&event->block_x, &event->block_z); + } + + if (mDemo_CheckDemo() == FALSE && mEv_PlayerOK() && mEv_LivePlayer(Common_Get(player_no)) && + mEv_LiveSonchoPresent() == FALSE) { + lbRTC_day_t hour = (u32)Common_Get(time.rtc_time.hour); + lbRTC_day_t day = Common_Get(time.rtc_time.day); + + if (event->day != day) { + mEv_RenewalDataEveryDay(); + event->state = 2; + init_time_seat(); + init_weekly_event(); + update_schedule_today(event); + event->month = Common_Get(time.rtc_time.month); + event->day = day; + event->hour = hour; + update_active(event); + mEv_2nd_init(event); + mCD_calendar_wellcome_on(); + } else if ((event->hour != hour)) { + event->hour = hour; + event->state = 1; + update_active(event); + } else if (mFI_CheckPlayerWade(mFI_WADE_END) == TRUE) { + update_active(event); + } + + if (funeral) { + funeral = FALSE; + update_save_area(); + } + } + + if (dead != 0) { + dead--; + + if (dead < 0 || dead > 4) { + dead = 0; + } + } + } +} + +static mActor_name_t l_ev_structure_table[] = { + BROKER_TENT, + FORTUNE_TENT, + DESIGNER_CAR, + KAMAKURA, + SAKURA_TABLE0, + AEROBICS_RADIO, + FIREWORKS_STALL0, + FIREWORKS_STALL1, + NEWYEAR_SHRINE0, + NEWYEAR_SHRINE1, + NEWYEAR_TABLE, + NEWYEAR_COUNTDOWN0, + NEWYEAR_COUNTDOWN1, + SPORTSFAIR_BALLS_RED, + SPORTSFAIR_BALLS_WHITE, + SPORTSFAIR_BASKET_RED, + SPORTSFAIR_BASKET_WHITE, + FISHCHECK_STAND0, + FISHCHECK_STAND1, + GHOG, + TENT, + SAKURA_TABLE1 +}; + +static int num_of_l_ev_structure = ARRAY_COUNT(l_ev_structure_table); + +extern void mEv_finish(Event_c* event) { + int ut_x; + int ut_z; + int bx; + int bz; + int i; + int bx_max = mFI_GetBlockXMax() - 1; + int bz_max = mFI_GetBlockZMax() - 1; + + if (mFI_GET_TYPE(mFI_GetFieldId()) == mFI_FIELD_FG) { + + for (i = 0; i < num_of_l_ev_structure; i++) { + for (bx = 1; bx < bx_max; bx++) { + for (bz = 1; bz < bz_max; bz++) { + int ut; + mActor_name_t structure = l_ev_structure_table[i]; + + for (ut = 0; mFI_SearchFGInBlock(&ut_x, &ut_z, structure, bx, bz); ut) { + mFI_SetFGStructure_common(structure, bx, bz, ut_x, ut_z, mFI_SET_STRUCTURE_REMOVE); + ut++; + if (ut > UT_TOTAL_NUM) { + break; + } + } + } + } + } + } +} + +extern int mEv_check_schedule(int event) { + int hour = Common_Get(time.rtc_time.hour); + u8 index = index_today[event]; + mEv_event_today_c* ev_today = &event_today[index]; + + if (index == 0xFF) { + return FALSE; + } + + if ((ev_today->status & mEv_STATUS_STOP)) { + return FALSE; + } + + if ((ev_today->active_hours & mEv_EVENT_HOUR_TOO_SHORT_EVENT)) { + return FALSE; + } + + if ((ev_today->active_hours & (1 << hour)) != 0) { + return TRUE; + } + + return FALSE; +} + +extern int mEv_check_run_today(int event) { + u8 index = index_today[event]; + mEv_event_today_c* ev_today = &event_today[index]; + + if (index == 0xFF) { + return FALSE; + } + + if ((ev_today->status & mEv_STATUS_STOP)) { + return FALSE; + } + + if (ev_today->active_hours != 0) { + return TRUE; + } + + return FALSE; +} + +extern void mEv_set_status(int event, s16 status) { + u8 index = index_today[event]; + mEv_event_today_c* ev_today = &event_today[index]; + + if (index != 0xFF) { + if (status == mEv_STATUS_ERROR) { + ev_today->status = 0; + } + + status_edge |= status; + ev_today->status |= status; + } +} + +static int set_active(int event) { + u8 index = index_today[event]; + mEv_event_today_c* ev_today = &event_today[index]; + int res = FALSE; + + if (index != 0xFF) { + if ((ev_today->status & mEv_STATUS_ACTIVE) == 0) { + res = TRUE; // status updated + } + + status_edge |= mEv_STATUS_ACTIVE; + ev_today->status |= mEv_STATUS_ACTIVE; + } + + return res; +} + +extern void mEv_clear_status(int event, s16 status) { + u8 index = index_today[event]; + mEv_event_today_c* ev_today = &event_today[index]; + + if (index != 0xFF) { + ev_today->status &= ~status; + } +} + +static int clear_active(int event) { + u8 index = index_today[event]; + mEv_event_today_c* ev_today = &event_today[index]; + int res = FALSE; + + if (index != 0xFF) { + if ((ev_today->status & mEv_STATUS_ACTIVE) != 0) { + res = TRUE; // status updated + } + + ev_today->status &= ~mEv_STATUS_ACTIVE; + } + + return res; +} + +extern int mEv_check_status(int event, s16 status) { + u8 index = index_today[event]; + mEv_event_today_c* ev_today = &event_today[index]; + + if (index == 0xFF) { + return FALSE; + } + + /* Default to 'false' if the event is in an error state */ + if (status != mEv_STATUS_ERROR && (ev_today->status & mEv_STATUS_ERROR)) { + return FALSE; + } + + return (ev_today->status & status) != 0; +} + +extern int mEv_check_status_edge(s16 status) { + /* @BUG - developers almost certainly meant to use & here instead of | */ + #ifndef BUGFIXES + if ((status_edge | status) != 0) { + #else + if ((status_edge & status) != 0) { + #endif + return TRUE; + } + + return FALSE; +} + +extern void mEv_set_keep(int event) { + int flags = Common_Get(event_keep_flags[event >> 5]); + flags |= (1 << (event & 0x1F)); + Common_Set(event_keep_flags[event >> 5], flags); +} + +extern void mEv_clear_keep(int event) { + int flags = Common_Get(event_keep_flags[event >> 5]); + flags &= ~(1 << (event & 0x1F)); + Common_Set(event_keep_flags[event >> 5], flags); +} + +extern int mEv_check_keep(int event) { + if ((Common_Get(event_keep_flags[event >> 5]) & (1 << (event & 0x1F)))) { + return TRUE; + } + + return FALSE; +} + +extern u8* mEv_reserve_save_area(int type, u8 id) { + lbRTC_time_c* rtc_time = Common_GetPointer(time.rtc_time); + int index = index_today[type]; + mEv_event_today_c* ev_today = &event_today[index]; + mEv_save_common_data_c* ev_save_common = Save_GetPointer(event_save_common); + int i; + int free_slot_idx = -1; + u8* data; + u8* ret; + int exist_slot = -1; + + for (i = 0; i < mEv_AREA_NUM; i++) { + if (((1 << i) & ev_save_common->area_use_bitfield) == 0) { + free_slot_idx = i; + continue; + } + else if (id != mEv_EVENT_NUM && ev_save_common->area[i].info.id == mEv_EVENT_NUM) { + exist_slot = i; + } + + if (type == ev_save_common->area[i].info.type && id == ev_save_common->area[i].info.id) { + free_slot_idx = i; + break; + } + } + + if (free_slot_idx == -1 && exist_slot != -1) { + free_slot_idx = exist_slot; + } + + if (free_slot_idx != -1) { + mEv_area_c* const area = &ev_save_common->area[free_slot_idx]; + mEv_info_c* const info = &area->info; + ev_save_common->area_use_bitfield |= (1 << free_slot_idx); + ev_save_common->area[free_slot_idx].info.type = type; + ev_save_common->area[free_slot_idx].info.id = id; + + // issue seems to stem from ev_today->begin_date.month being used twice which promotes it to r11? + if ((u16)ev_today->begin_date.month > (u32)ev_today->end_date.month && (u16)ev_today->begin_date.month > (u32)rtc_time->month) { + ev_save_common->area[free_slot_idx].info.year = rtc_time->year - 1; + } + else { + ev_save_common->area[free_slot_idx].info.year = rtc_time->year; + } + + data = (u8*)ev_save_common->area[free_slot_idx].data; + ev_save_common->area[free_slot_idx].info.year = rtc_time->year; // ???? + ev_save_common->area[free_slot_idx].info.start_date.month = ev_today->begin_date.month; + ev_save_common->area[free_slot_idx].info.start_date.day = ev_today->begin_date.day; + ev_save_common->area[free_slot_idx].info.end_date.month = ev_today->end_date.month; + ev_save_common->area[free_slot_idx].info.end_date.day = ev_today->end_date.day; + memset(data, 0, sizeof(ev_save_common->area[free_slot_idx].data)); + ret = data; + } + else { + ret = NULL; + } + + return ret; +} + +extern u8* mEv_get_save_area(int type, u8 id) { + mEv_save_common_data_c* ev_save_common = Save_GetPointer(event_save_common); + int i; + + for (i = 0; i < mEv_AREA_NUM; i++) { + if (((1 << i) & ev_save_common->area_use_bitfield) != 0) { + if (type == ev_save_common->area[i].info.type && id == ev_save_common->area[i].info.id) { + return (u8*)ev_save_common->area[i].data; + } + } + } + + return NULL; +} + +extern int mEv_clear_save_area(int type, u8 id) { + mEv_save_common_data_c* ev_save_common = Save_GetPointer(event_save_common); + int i; + + for (i = 0; i < mEv_AREA_NUM; i++) { + if (((1 << i) & ev_save_common->area_use_bitfield) != 0) { + if (type == ev_save_common->area[i].info.type && id == ev_save_common->area[i].info.id) { + ev_save_common->area_use_bitfield &= ~(1 << i); + return sizeof(ev_save_common->area[i].data); + } + } + } + + return 0; +} + +static int update_save_area() { + lbRTC_time_c* rtc_time = Common_GetPointer(time.rtc_time); + mEv_save_common_data_c* ev_save_common = Save_GetPointer(event_save_common); + int i; + int num_updated = 0; + u16 today_date; + u16 year; + u16 begin_date; + u16 end_date; + + mEv_area_c* area; + + for (i = 0; i < mEv_AREA_NUM; i++) { + area = &ev_save_common->area[i]; + if (((1 << i) & ev_save_common->area_use_bitfield) != 0) { + if (area->info.start_date.month > area->info.end_date.month && + area->info.start_date.month > rtc_time->month) { + year = rtc_time->year - 1; + } else { + year = rtc_time->year; + } + + today_date = (rtc_time->month << 8) | rtc_time->day; + begin_date = (area->info.start_date.month << 8) | area->info.start_date.day; + end_date = (area->info.end_date.month << 8) | area->info.end_date.day; + + if ((mEv_check_status(area->info.type, mEv_STATUS_ACTIVE) == FALSE && + mEv_check_status(area->info.type, mEv_STATUS_RUN) == FALSE && + mEv_ArbeitPlayer(Common_Get(player_no)) == FALSE) || + check_date_range(today_date, begin_date, end_date) == FALSE || year != area->info.year) { + ev_save_common->area_use_bitfield &= ~(1 << i); + num_updated++; + } + } + } + + return num_updated; +} + +extern u8* mEv_reserve_common_area(int type, u8 id) { + mEv_common_data_c* ev_common = Common_GetPointer(event_common); + int i; + int exist_slot = -1; + u8* data; + u8* res; + + for (i = 0; i < mEv_AREA_NUM; i++) { + if (((1 << i) & ev_common->area_use_bitfield) == 0) { + exist_slot = i; + } + else if (type == ev_common->area[i].info.type && id == ev_common->area[i].info.id) { + exist_slot = i; + break; + } + } + + if (exist_slot != -1) { + ev_common->area_use_bitfield |= (1 << exist_slot); + data = (u8*)ev_common->area[exist_slot].data; + ev_common->area[exist_slot].info.type = type; + ev_common->area[exist_slot].info.id = id; + memset(data, 0, sizeof(ev_common->area[exist_slot].data)); + res = data; + } + else { + res = NULL; + } + + return res; +} + +extern u8* mEv_get_common_area(int type, u8 id) { + mEv_common_data_c* ev_common = Common_GetPointer(event_common); + int i; + + for (i = 0; i < mEv_AREA_NUM; i++) { + if (((1 << i) & ev_common->area_use_bitfield) != 0) { + if (type == ev_common->area[i].info.type && id == ev_common->area[i].info.id) { + return (u8*)ev_common->area[i].data; + } + } + } + + return NULL; +} + +extern int mEv_clear_common_area(int type, u8 id) { + mEv_common_data_c* ev_common = Common_GetPointer(event_common); + int i; + + for (i = 0; i < mEv_AREA_NUM; i++) { + if (((1 << i) & ev_common->area_use_bitfield) != 0) { + if (type == ev_common->area[i].info.type && id == ev_common->area[i].info.id) { + ev_common->area_use_bitfield &= ~(1 << i); + return sizeof(ev_common->area[i].data); + } + } + } + + return 0; +} + +extern mEv_place_data_c* mEv_reserve_common_place(int type, u8 id) { + mEv_common_data_c* ev_common = Common_GetPointer(event_common); + int i; + int exist_slot = -1; + mEv_place_data_c* data; + mEv_place_data_c* res; + + for (i = 0; i < mEv_PLACE_NUM; i++) { + if (((1 << i) & ev_common->place_use_bitfield) == 0) { + exist_slot = i; + } + else if (type == ev_common->place[i].info.type && id == ev_common->place[i].info.id) { + exist_slot = i; + break; + } + } + + if (exist_slot != -1) { + ev_common->place_use_bitfield |= (1 << exist_slot); + data = &ev_common->place[exist_slot].data; + ev_common->place[exist_slot].info.type = type; + ev_common->place[exist_slot].info.id = id; + memset(data, 0, sizeof(ev_common->place[exist_slot].data)); + res = data; + } + else { + res = NULL; + } + + return res; +} + +extern mEv_place_data_c* mEv_get_common_place(int type, u8 id) { + mEv_common_data_c* ev_common = Common_GetPointer(event_common); + int i; + + for (i = 0; i < mEv_PLACE_NUM; i++) { + if (((1 << i) & ev_common->place_use_bitfield) != 0) { + if (type == ev_common->place[i].info.type && id == ev_common->place[i].info.id) { + return &ev_common->place[i].data; + } + } + } + + return NULL; +} + +extern int mEv_clear_common_place(int type, u8 id) { + mEv_common_data_c* ev_common = Common_GetPointer(event_common); + int i; + + for (i = 0; i < mEv_PLACE_NUM; i++) { + if (((1 << i) & ev_common->place_use_bitfield) != 0) { + if (type == ev_common->place[i].info.type && id == ev_common->place[i].info.id) { + ev_common->place_use_bitfield &= ~(1 << i); + return sizeof(ev_common->place[i].data); + } + } + } + + return 0; +} + +extern int mEv_use_block_by_other_event(int type, BlockOrUnit_c* block) { + mEv_common_data_c* ev_common = Common_GetPointer(event_common); + int i; + + for (i = 0; i < mEv_PLACE_NUM; i++) { + if (((1 << i) & ev_common->place_use_bitfield) != 0) { + if ( + ev_common->place[i].data.block.x == block->x && + ev_common->place[i].data.block.z == block->z && + ev_common->place[i].info.type != type + ) { + return TRUE; + } + } + } + + return FALSE; +} + +extern void mEv_erase_FG_all_in_common_place() { + mEv_common_data_c* ev_common = Common_GetPointer(event_common); + int i; + + for (i = 0; i < mEv_PLACE_NUM; i++) { + if (((1 << i) & ev_common->place_use_bitfield) != 0) { + mEv_place_data_c* place_data = &ev_common->place[i].data; + + if (ITEM_NAME_GET_TYPE(place_data->actor_name) == NAME_TYPE_STRUCT) { + mFI_SetFGStructure_common( + place_data->actor_name, + place_data->block.x, + place_data->block.z, + place_data->unit.x, + place_data->unit.z, + mFI_SET_STRUCTURE_REMOVE + ); + } + } + } +} + +static int n_rumor = 0; +static int rumor_table[40]; + +extern void mEv_clear_rumor() { + n_rumor = 0; +} + +extern int mEv_spread_rumor(int type) { + rumor_table[n_rumor++] = type; + return n_rumor; +} + +extern int mEv_get_rumor() { + if (n_rumor != 0) { + return rumor_table[gamePT->frame_counter % n_rumor] | mEv_SET(mEv_TYPE3_EVENT, 0); + } + + return 0; +} + +extern void mEv_actor_dying_message(int type, ACTOR* actor) { + xyz_t pos = actor->world.position; + mEv_common_data_c* ev_common = Common_GetPointer(event_common); + mActor_name_t actor_name = actor->npc_id; + int i; + + for (i = 0; i < mEv_PLACE_NUM; i++) { + if (((1 << i) & ev_common->place_use_bitfield) != 0) { + mEv_place_data_c* place_data = &ev_common->place[i].data; + + if ( + ev_common->place[i].info.type == type && + place_data->actor_name == actor_name + ) { + /* Check if the actor world position should be transferred to event data */ + if (place_data->flag & 1) { + mFI_Wpos2BlockNum(&place_data->block.x, &place_data->block.z, pos); + mFI_Wpos2UtNum_inBlock(&place_data->unit.x, &place_data->unit.z, pos); + } + + funeral = TRUE; + break; + } + } + } + + mEv_set_status(type, mEv_STATUS_STOP); + dead = 3; +} + +extern int mEv_LiveSonchoPresent() { + if (Common_Get(demo_profiles[1]) == mAc_PROFILE_PRESENT_DEMO) { + return TRUE; + } + + if (Common_Get(clip).demo_clip2 != NULL && Common_Get(clip).demo_clip2->type == mDemo_CLIP_TYPE_PRESENT_DEMO) { + return TRUE; + } + + return FALSE; +} + +extern int mEv_LivePlayer(u32 player_no) { + if (mEv_CheckTitleDemo() != 0) { + return FALSE; + } + + if (Common_Get(reset_flag) != 0) { + return FALSE; + } + + if (player_no < mPr_FOREIGNER) { + if ( + mEv_CheckEvent(mEv_SAVED_GATEWAY_PLR0 + player_no) == TRUE || + mEv_CheckEvent(mEv_SAVED_FIRSTINTRO_PLR0 + player_no) == TRUE + ) { + return FALSE; + } + } + else if (player_no < mPr_PLAYER_NUM) { + if (mEv_CheckEvent(mEv_SAVED_GATEWAY_PLR0 + player_no) == TRUE) { + return FALSE; + } + } + else { + return FALSE; + } + + return TRUE; +} + +extern int mEv_ArbeitPlayer_kari(u32 player_no) { + if (player_no < mPr_FOREIGNER && mEv_CheckEvent(mEv_SAVED_FIRSTJOB_PLR0 + player_no) == TRUE) { + return TRUE; + } + + return FALSE; +} + +extern int mEv_ArbeitPlayer(u32 player_no) { + if ( + player_no < mPr_FOREIGNER && + (mEv_CheckEvent(mEv_SAVED_FIRSTJOB_PLR0 + player_no) == TRUE || + mEv_CheckEvent(mEv_SAVED_HRAWAIT_PLR0 + player_no) == TRUE) + ) { + return TRUE; + } + + return FALSE; +} + +extern void mEv_make_new_special_event() { + lbRTC_time_c* rtc_time = Common_GetPointer(time.rtc_time); + mEv_schedule_c sched; + mEv_schedule_date_u today_date; + mEv_schedule_c* sched_p = &sched; + + today_date.d.month = rtc_time->month; + today_date.d.day = rtc_time->day; + today_date.d._2 = 0; + today_date.d.hour = rtc_time->hour; + + if (init_special_event(TRUE)) { + int i; + + Save_Get(event_save_common).special_event.flags = 1; + for (i = 0; i < ARRAY_COUNT(event_schedule_data); i++) { + memcpy(sched_p, &event_schedule_data[i], sizeof(mEv_schedule_c)); + + if (update_special_event(sched_p)) { + sched.date[0].raw = decode_date(sched.date[0].raw); + sched.date[1].raw = decode_date(sched.date[1].raw); + + if (check_date_range(today_date.md, sched.date[0].md, sched.date[1].md)) { + add_event_today(today_date.md, sched_p); + } + } + } + } +} + +extern int mEv_GetMonth(Event_c* event) { + return event->month; +} + +extern int mEv_GetDay(Event_c* event) { + return event->day; +} + +extern int mEv_GetHour(Event_c* event) { + return event->hour; +} + +extern void mEv_debug_print4f(gfxprint_t* gfxprint) { + //int x = 0; + int i; + int event_idx = 0; + + for (i = 0; i < mEv_TODAY_EVENT_NUM; i++) { + if (event_today[i].type != -1 && mEv_check_status(event_today[i].type, mEv_STATUS_ACTIVE)) { + gfxprint_color(gfxprint, 245, 200, 170, 255); + gfxprint_locate8x8(gfxprint, 3 + event_idx * 3, 5); + gfxprint_printf(gfxprint, "%3d", event_today[i].type); + event_idx++; + //x += 3; + + if (event_idx >= 9) { + if (mEv_check_status(event_today[i].type, mEv_STATUS_ERROR) == FALSE) { + gfxprint_color(gfxprint, 245, 150, 120, 255); + } + else if (mEv_check_status(event_today[i].type, mEv_STATUS_RUN)) { + gfxprint_color(gfxprint, 180, 150, 160, 255); + } + else { + gfxprint_color(gfxprint, 140, 120, 120, 255); + } + + gfxprint_locate8x8(gfxprint, 9 + event_idx * 3, 5); + gfxprint_printf(gfxprint, "+"); + break; + } + + } + } +} + +extern void mEv_sp_debug_print4f(gfxprint_t* gfxprint) { + gfxprint_color(gfxprint, 245, 200, 170, 255); + gfxprint_locate8x8(gfxprint, 3, 11); + gfxprint_printf( + gfxprint, + "%3d %02d-%02d-%02d", + Save_Get(event_save_common).special_event.type, + Save_Get(event_save_common).dates[mEv_SAVE_DATE_SPECIAL0] & 0xFF, // event rtc (current) day + Save_Get(event_save_common).dates[mEv_SAVE_DATE_SPECIAL1] & 0xFF, // event begin day + Save_Get(event_save_common).dates[mEv_SAVE_DATE_SPECIAL2] & 0xFF // event end day + ); + + gfxprint_locate8x8(gfxprint, 30, 11); + gfxprint_printf( + gfxprint, + "%c%c%c%c%c%c%c%c", + mEv_CheckTitleDemo() ? 'T' : '.', + mEv_CheckFirstIntro() ? 'F' : '.', + mEv_CheckGateway() ? 'G' : '.', + mEv_CheckRealArbeit() ? 'R' : '.', + mEv_CheckArbeit() ? 'A' : '.', + mDemo_CheckDemo() ? 'D' : '.', + !mEv_PlayerOK() ? 'P' : '.', + !mEv_LivePlayer(Common_Get(player_no)) ? 'L' : '.' + ); +} + +extern int mEv_change(Event_c* event) { + return event->changed_num; +} + +extern int mEv_get_special_event_state() { + int special_events[] = { + mEv_EVENT_SHOP_SALE, + mEv_EVENT_DESIGNER, + mEv_EVENT_BROKER_SALE, + mEv_EVENT_ARTIST, + mEv_EVENT_CARPET_PEDDLER, + mEv_EVENT_GYPSY + }; + + int active = FALSE; + int res = mEv_SPECIAL_STATE_UNSCHEDULED; + mEv_ymdh_u event_date_start; + mEv_ymdh_u today_date; + mEv_ymdh_u event_date; + mEv_ymdh_u today_date_start; + int event_type; + + if (Save_Get(event_save_data).special.type <= mEv_SPNPC_END) { + event_type = special_events[Save_Get(event_save_data).special.type]; + } + else { + return FALSE; + } + + today_date.year = 0; + today_date.month = Common_Get(time.rtc_time.month); + today_date.day = Common_Get(time.rtc_time.day); + today_date.hour = Common_Get(time.rtc_time.hour); + + event_date.year = 0; + event_date.month = Save_Get(event_save_data).special.scheduled.month; + event_date.day = Save_Get(event_save_data).special.scheduled.day; + event_date.hour = Save_Get(event_save_data).special.scheduled.hour; + + event_date_start.raw = event_date.raw; + today_date_start.raw = today_date.raw; + + today_date_start.hour = 0; + event_date_start.hour = 0; + + if (event_type == mEv_EVENT_SHOP_SALE) { + if (event_date.raw == today_date.raw) { + active = TRUE; + } + } + else if (mEv_check_status(event_type, mEv_STATUS_ACTIVE)) { + active = TRUE; + } + + if (active) { + res = mEv_SPECIAL_STATE_ACTIVE; + } + else if (check_ymdh_range(today_date.raw, event_date_start.raw, event_date.raw)) { + res = mEv_SPECIAL_STATE_SCHEDULED_TODAY; + } + else if (Save_Get(event_save_data).special.type != 0xFFFFFFFF && event_date_start.raw > today_date_start.raw) { + res = mEv_SPECIAL_STATE_SCHEDULED_LATER; + } + + return res; +} + +extern int mEv_snowman_born_check() { + mEv_ymdh_u snowman_date; + mEv_ymdh_u today_date; + mEv_ymdh_u snowman_date_end; + + today_date.year = Common_Get(time.rtc_time).year % 100; + today_date.month = Common_Get(time.rtc_time).month; + today_date.day = Common_Get(time.rtc_time).day; + today_date.hour = Common_Get(time.rtc_time).hour; + + snowman_date.year = Save_Get(snowman_year); + snowman_date.month = Save_Get(snowman_month); + snowman_date.day = Save_Get(snowman_day); + snowman_date.hour = Save_Get(snowman_hour); + + snowman_date_end.raw = snowman_date.raw; + snowman_date_end.hour = 5; + + if (snowman_date.hour >= 6) { + mEv_MonthDay_u snowman_monthday; + mEv_MonthDay_u next_monthday; + + snowman_monthday.month = snowman_date.month; + snowman_monthday.day = snowman_date.day; + next_monthday.raw = after_n_day(snowman_monthday.raw, 1); + + if (next_monthday.raw == mEv_MonthDay(lbRTC_JANUARY, 1)) { + snowman_date_end.year = (snowman_date_end.year + 1) % 100; + } + + snowman_date_end.month = next_monthday.month; + snowman_date_end.day = next_monthday.day; + } + + if (check_ymdh_range(today_date.raw, snowman_date.raw, snowman_date_end.raw)) { + return FALSE; + } + + return TRUE; +} + +extern int mEv_someone_died() { + return dead; +} + +extern void mEv_special_event_soldout(int type) { + GAME_PLAY* play = (GAME_PLAY*)gamePT; + mEv_event_today_c* ev_today; + int i; + + for (i = 0; i < mEv_TODAY_EVENT_NUM; i++) { + ev_today = &event_today[i]; + + if ( + ev_today->type != -1 && + index_today[ev_today->type] != 0xFF && + mEv_check_status(ev_today->type, mEv_STATUS_ERROR) == FALSE && + ev_today->type == type + ) { + if (clear_active(ev_today->type)) { + play->event.changed_num++; + } + + ev_today->active_hours = mEv_EVENT_HOUR_CLEAR_EVENT; + } + } +} + +extern void mEv_toland_clear_common() { + int* keep_flags = Common_Get(event_keep_flags); + int i; + + for (i = 0; i < ARRAY_COUNT(Common_Get(event_keep_flags)); i++) { + keep_flags[i] = 0; + } + + mem_clear(Common_GetPointer(event_common), sizeof(Common_Get(event_common)), 0); + mem_clear(Common_GetPointer(special_event_common), sizeof(Common_Get(special_event_common)), 0); +} + +extern void mGH_animal_return_init() { + mem_clear(Save_GetPointer(return_animal), sizeof(Save_Get(return_animal)), 0); + Save_Get(return_animal).npc_id = EMPTY_NO; // ?? +} + +extern int mGH_check_birth2() { + lbRTC_time_c* rtc_time = Common_GetPointer(time.rtc_time); + Anmret_c* return_animal = Save_GetPointer(return_animal); + lbRTC_time_c time; + + if (return_animal->npc_id == EMPTY_NO) { + return FALSE; + } + + /* Check that it's been less than 1 week since go home event was scheduled */ + lbRTC_TimeCopy(&time, &return_animal->renew_time); + lbRTC_Add_DD(&time, lbRTC_WEEK); + + if ( + lbRTC_IsEqualDate( + time.year, time.month, time.day, + rtc_time->year, rtc_time->month, rtc_time->day + ) == lbRTC_LESS + ) { + return TRUE; + } + + return FALSE; +} + +extern int mGH_check_birth() { + if ((Save_Get(return_animal).talk_bit & (1 << Common_Get(player_no))) != 0) { + return FALSE; + } + + return mGH_check_birth2(); +} + +extern void mGH_check_delete() { + lbRTC_time_c* rtc_time = Common_GetPointer(time.rtc_time); + Anmret_c* return_animal = Save_GetPointer(return_animal); + Private_c* priv = Save_Get(private); + + if (return_animal->npc_id != EMPTY_NO) { + if (Save_Get(npc_force_go_home) == TRUE) { + mGH_animal_return_init(); + } + else { + lbRTC_time_c time; + + lbRTC_TimeCopy(&time, &return_animal->renew_time); + /* Devs did this to fix a 'bug' with lbRTC_Add_DD which only allows going at most one month in the future */ + lbRTC_Add_DD(&time, 20); + lbRTC_Add_DD(&time, 20); + lbRTC_Add_DD(&time, 20); + + if ( + lbRTC_IsEqualDate( + time.year, time.month, time.day, + rtc_time->year, rtc_time->month, rtc_time->day + ) != lbRTC_OVER + ) { + mGH_animal_return_init(); + } + else { + int i; + + if (mNpc_SearchAnimalinfo(Save_Get(animals), return_animal->npc_id, ANIMAL_NUM_MAX) != -1) { + mGH_animal_return_init(); // don't allow this animal to visit if a "version" of it lives in town + } + + for (i = 0; i < PLAYER_NUM; i++) { + if (mPr_NullCheckPersonalID(&priv->player_ID) == FALSE && (return_animal->talk_bit & (1 << i)) == 0) { + return; + } + + priv++; + } + + mGH_animal_return_init(); + } + } + } +} + +extern void mMC_mask_cat_init() { + MaskCat_c* mask_cat = Save_GetPointer(mask_cat); + u8 cloth_no = mask_cat->cloth_no; + + mem_clear(mask_cat, sizeof(Save_Get(mask_cat)), 0); + mPr_ClearPersonalID(&mask_cat->design.creator_pid); + Save_Get(mask_cat).cloth_no = cloth_no; +} + +extern int mMC_check_birth() { + if (Save_Get(mask_cat).design.creator_pid.player_id == 0xFFFF) { + return FALSE; + } + + if (Save_Get(mask_cat).talk_idx >= mMC_TALK_IDX_MAX) { + /* Talked more than the maximum amount of times allowed */ + mMC_mask_cat_init(); + return TRUE; + } + + return FALSE; +} + +extern int mMC_check_birth_day() { + switch (Common_Get(time.rtc_time.weekday)) { + case lbRTC_SUNDAY: + case lbRTC_MONDAY: + case lbRTC_WEDNESDAY: + case lbRTC_FRIDAY: + return FALSE; + + default: + return mMC_check_birth(); + } +} + +extern void mMC_check_delete() { + MaskCat_c* mask_cat = Save_GetPointer(mask_cat); + lbRTC_time_c* rtc_time = Common_GetPointer(time.rtc_time); + + if (mask_cat->design.creator_pid.player_id != 0xFFFF) { + lbRTC_time_c max_time; + lbRTC_time_c min_time; + + lbRTC_TimeCopy(&max_time, &mask_cat->time); + lbRTC_TimeCopy(&min_time, &mask_cat->time); + + lbRTC_Add_DD(&max_time, lbRTC_WEEK); + lbRTC_Sub_DD(&min_time, lbRTC_WEEK); + + if ( + mask_cat->talk_idx >= mMC_TALK_IDX_MAX || + lbRTC_IsEqualDate( + max_time.year, max_time.month, max_time.day, + rtc_time->year, rtc_time->month, rtc_time->day + ) != lbRTC_OVER || + lbRTC_IsEqualDate( + min_time.year, min_time.month, min_time.day, + rtc_time->year, rtc_time->month, rtc_time->day + ) != lbRTC_LESS + ) { + mMC_mask_cat_init(); + } + } +} + +extern void mMC_set_time() { + MaskCat_c* mask_cat = Save_GetPointer(mask_cat); + lbRTC_time_c* rtc_time = Common_GetPointer(time.rtc_time); + + lbRTC_TimeCopy(&mask_cat->time, rtc_time); +} diff --git a/src/m_event_schedule.c_inc b/src/m_event_schedule.c_inc new file mode 100644 index 00000000..ceb483e6 --- /dev/null +++ b/src/m_event_schedule.c_inc @@ -0,0 +1,138 @@ +/* Event schedule data */ + +static mEv_schedule_c event_schedule_data[] = { + {{{mEv_SCHEDULE_SAVE_MONTH(3), 0, 0x00, mEv_SCHEDULE_MULTIDAY | 4 }, {mEv_SCHEDULE_SAVE_MONTH(4), 0, 0x00, mEv_SCHEDULE_HOUR_SLOT(mEv_SAVE_DATE_SPECIAL3) }}, 0x0000, mEv_EVENT_HANDBILL_SHOP_SALE}, + {{{mEv_SCHEDULE_SAVE_MONTH(4), 0, 0x00, 0 }, {mEv_SCHEDULE_SAVE_MONTH(4), 0, 0x00, 23 }}, 0x0000, mEv_EVENT_SHOP_SALE}, + {{{mEv_SCHEDULE_SAVE_MONTH(4), 0, 0x00, mEv_SCHEDULE_MULTIDAY | 6 }, {mEv_SCHEDULE_SAVE_MONTH(5), 0, 0x00, 5 }}, 0x0000, mEv_EVENT_DESIGNER}, + {{{mEv_SCHEDULE_SAVE_MONTH(3), 0, 0x00, mEv_SCHEDULE_MULTIDAY | 0 }, {mEv_SCHEDULE_SAVE_MONTH(4), 0, 0x00, 17 }}, 0x0000, mEv_EVENT_HANDBILL_BROKER}, + {{{mEv_SCHEDULE_SAVE_MONTH(4), 0, 0x00, mEv_SCHEDULE_MULTIDAY | 18 }, {mEv_SCHEDULE_SAVE_MONTH(5), 0, 0x00, 17 }}, 0x0000, mEv_EVENT_BROKER_SALE}, + {{{mEv_SCHEDULE_SAVE_MONTH(4), 0, 0x00, mEv_SCHEDULE_MULTIDAY | 6 }, {mEv_SCHEDULE_SAVE_MONTH(5), 0, 0x00, 5 }}, 0x0000, mEv_EVENT_ARTIST}, + {{{mEv_SCHEDULE_SAVE_MONTH(4), 0, 0x00, mEv_SCHEDULE_MULTIDAY | 6 }, {mEv_SCHEDULE_SAVE_MONTH(5), 0, 0x00, 5 }}, 0x0000, mEv_EVENT_CARPET_PEDDLER}, + {{{mEv_SCHEDULE_SAVE_MONTH(4), 0, 0x00, mEv_SCHEDULE_MULTIDAY | 21 }, {mEv_SCHEDULE_SAVE_MONTH(5), 0, 0x00, 20 }}, 0x0000, mEv_EVENT_GYPSY}, + {{{mEv_SCHEDULE_NOW_MONTH, mEv_SCHEDULE_EVERY_WEEKDAY(lbRTC_SUNDAY), 0x00, 6 }, {mEv_SCHEDULE_NOW_MONTH, mEv_SCHEDULE_EVERY_WEEKDAY(lbRTC_SUNDAY), 0x00, 11 }}, 0x0000, mEv_EVENT_KABU_PEDDLER}, + {{{mEv_SCHEDULE_NOW_MONTH, mEv_SCHEDULE_EVERY_WEEKDAY(lbRTC_SATURDAY), 0x00, 20 }, {mEv_SCHEDULE_NOW_MONTH, mEv_SCHEDULE_EVERY_WEEKDAY(lbRTC_SATURDAY), 0x00, 23 }}, 0x0000, mEv_EVENT_KK_SLIDER}, + {{{mEv_SCHEDULE_SAVE_MONTH(mEv_SAVE_DATE_WEEKLY), 0, 0x00, 6 }, {mEv_SCHEDULE_SAVE_MONTH(mEv_SAVE_DATE_WEEKLY), 0, 0x00, 22 }}, 0x0000, mEv_EVENT_DOZAEMON}, + {{{mEv_SCHEDULE_NOW_MONTH, mEv_SCHEDULE_LAST_DAY_OF_MONTH, 0x00, 0 }, {mEv_SCHEDULE_NOW_MONTH, mEv_SCHEDULE_LAST_DAY_OF_MONTH, 0x00, 23 }}, 0x0000, mEv_EVENT_LOTTERY}, + {{{mEv_SCHEDULE_SAVE_MONTH(mEv_SAVE_DATE_BIRTHDAY), 0, 0x00, 0 }, {mEv_SCHEDULE_SAVE_MONTH(mEv_SAVE_DATE_BIRTHDAY), 0, 0x00, 23 }}, 0x0000, mEv_EVENT_PLAYER_BIRTHDAY}, + {{{lbRTC_DECEMBER, 25, 0x00, 0 }, {lbRTC_FEBRUARY, 17, 0x00, 23 }}, 0x0000, mEv_EVENT_SNOWMAN_SEASON}, + {{{lbRTC_APRIL, 3, 0x00, 0 }, {lbRTC_APRIL, 8, 0x00, 23 }}, 0x0000, mEv_EVENT_CHERRY_BLOSSOM_PETALS}, + {{{lbRTC_JANUARY, 1, 0x00, 0 }, {lbRTC_DECEMBER, 31, 0x00, 3 }}, 0x0000, mEv_EVENT_GHOST}, + {{{mEv_SCHEDULE_NOW_MONTH, mEv_SCHEDULE_EVERY_WEEKDAY(lbRTC_MONDAY), 0x00, 6 }, {mEv_SCHEDULE_NOW_MONTH, mEv_SCHEDULE_EVERY_WEEKDAY(lbRTC_MONDAY), 0x00, 23 }}, 0x0000, mEv_EVENT_MASK_NPC}, + {{{mEv_SCHEDULE_NOW_MONTH, mEv_SCHEDULE_EVERY_WEEKDAY(lbRTC_TUESDAY), 0x00, 6 }, {mEv_SCHEDULE_NOW_MONTH, mEv_SCHEDULE_EVERY_WEEKDAY(lbRTC_TUESDAY), 0x00, 23 }}, 0x0000, mEv_EVENT_MASK_NPC}, + {{{mEv_SCHEDULE_NOW_MONTH, mEv_SCHEDULE_EVERY_WEEKDAY(lbRTC_WEDNESDAY), 0x00, 6 }, {mEv_SCHEDULE_NOW_MONTH, mEv_SCHEDULE_EVERY_WEEKDAY(lbRTC_WEDNESDAY), 0x00, 23 }}, 0x0000, mEv_EVENT_MASK_NPC}, + {{{mEv_SCHEDULE_NOW_MONTH, mEv_SCHEDULE_EVERY_WEEKDAY(lbRTC_THURSDAY), 0x00, 6 }, {mEv_SCHEDULE_NOW_MONTH, mEv_SCHEDULE_EVERY_WEEKDAY(lbRTC_THURSDAY), 0x00, 23 }}, 0x0000, mEv_EVENT_MASK_NPC}, + {{{mEv_SCHEDULE_NOW_MONTH, mEv_SCHEDULE_EVERY_WEEKDAY(lbRTC_FRIDAY), 0x00, 6 }, {mEv_SCHEDULE_NOW_MONTH, mEv_SCHEDULE_EVERY_WEEKDAY(lbRTC_FRIDAY), 0x00, 23 }}, 0x0000, mEv_EVENT_MASK_NPC}, + {{{mEv_SCHEDULE_NOW_MONTH, mEv_SCHEDULE_EVERY_WEEKDAY(lbRTC_SATURDAY), 0x00, 6 }, {mEv_SCHEDULE_NOW_MONTH, mEv_SCHEDULE_EVERY_WEEKDAY(lbRTC_SATURDAY), 0x00, 18 }}, 0x0000, mEv_EVENT_MASK_NPC}, + {{{mEv_SCHEDULE_NOW_MONTH, mEv_SCHEDULE_EVERY_WEEKDAY(lbRTC_SUNDAY), 0x00, 13 }, {mEv_SCHEDULE_NOW_MONTH, mEv_SCHEDULE_EVERY_WEEKDAY(lbRTC_SUNDAY), 0x00, 23 }}, 0x0000, mEv_EVENT_MASK_NPC}, + {{{lbRTC_JANUARY, 1, 0x00, 0 }, {lbRTC_DECEMBER, 31, 0x00, 23 }}, 0x0000, mEv_EVENT_BRIDGE_MAKE}, + {{{lbRTC_JANUARY, 1, 0x00, 6 }, {lbRTC_JANUARY, 1, 0x00, 10 }}, 0x0000, mEv_EVENT_NEW_YEARS_DAY}, + {{{lbRTC_JANUARY, 1, 0x00, 6 }, {lbRTC_JANUARY, 1, 0x00, 10 }}, 0x0000, mEv_EVENT_SONCHO_NEW_YEARS_DAY}, + {{{lbRTC_DECEMBER, 25, 0x00, mEv_SCHEDULE_MULTIDAY | 0 }, {lbRTC_DECEMBER, 31, 0x00, 23 }}, 0x0000, mEv_EVENT_RUMOR_NEW_YEARS_DAY}, + {{{lbRTC_JANUARY, 2, 0x00, mEv_SCHEDULE_TODAY | 10 }, {lbRTC_FEBRUARY, 23, 0x00, 21 }}, 0x0000, mEv_EVENT_KAMAKURA}, + {{{lbRTC_JANUARY, 2, 0x00, mEv_SCHEDULE_MULTIDAY | 0 }, {lbRTC_FEBRUARY, 23, 0x00, 20 }}, 0x0000, mEv_EVENT_RUMOR_KAMAKURA}, + {{{lbRTC_FEBRUARY, 2, 0x00, 7 }, {lbRTC_FEBRUARY, 2, 0x00, 8 }}, 0x0000, mEv_EVENT_GROUNDHOG_DAY}, + {{{lbRTC_FEBRUARY, 2, 0x00, 9 }, {lbRTC_FEBRUARY, 2, 0x00, 16 }}, 0x0000, mEv_EVENT_SONCHO_GROUNDHOG_DAY}, + {{{lbRTC_JANUARY, 25, 0x00, mEv_SCHEDULE_MULTIDAY | 0 }, {lbRTC_FEBRUARY, 1, 0x00, 23 }}, 0x0000, mEv_EVENT_RUMOR_GROUNDHOG_DAY}, + {{{lbRTC_FEBRUARY, 14, 0x00, 0 }, {lbRTC_FEBRUARY, 14, 0x00, 23 }}, 0x0000, mEv_EVENT_VALENTINES_DAY}, + {{{lbRTC_FEBRUARY, 1, 0x00, mEv_SCHEDULE_MULTIDAY | 0 }, {lbRTC_FEBRUARY, 13, 0x00, 23 }}, 0x0000, mEv_EVENT_RUMOR_VALENTINES_DAY}, + {{{lbRTC_MARCH, 19, 0x00, 9 }, {lbRTC_MARCH, 21, 0x00, 16 }}, 0x0000, mEv_EVENT_SPRING_EQUINOX}, + {{{lbRTC_MARCH, 19, 0x00, 9 }, {lbRTC_MARCH, 21, 0x00, 16 }}, 0x0000, mEv_EVENT_SONCHO_SPRING_SPORTS_FAIR}, + {{{lbRTC_MARCH, 19, 0x00, 9 }, {lbRTC_MARCH, 21, 0x00, 10 }}, 0x0000, mEv_EVENT_SPORTS_FAIR_AEROBICS}, + {{{lbRTC_MARCH, 19, 0x00, 11 }, {lbRTC_MARCH, 21, 0x00, 12 }}, 0x0000, mEv_EVENT_SPORTS_FAIR_FOOT_RACE}, + {{{lbRTC_MARCH, 19, 0x00, 13 }, {lbRTC_MARCH, 21, 0x00, 14 }}, 0x0000, mEv_EVENT_SPORTS_FAIR_BALL_TOSS}, + {{{lbRTC_MARCH, 19, 0x00, 15 }, {lbRTC_MARCH, 21, 0x00, 16 }}, 0x0000, mEv_EVENT_SPORTS_FAIR_TUG_OF_WAR}, + {{{lbRTC_MARCH, 19, 0x00, 11 }, {lbRTC_MARCH, 21, 0x00, 16 }}, 0x0000, mEv_EVENT_SPORTS_FAIR}, + {{{lbRTC_MARCH, 19, 0x00, 0 }, {lbRTC_MARCH, 21, 0x00, 23 }}, 0x0000, mEv_EVENT_WEATHER_SPORTS_FAIR}, + {{{lbRTC_MARCH, 9, 0x00, mEv_SCHEDULE_MULTIDAY | 0 }, {lbRTC_MARCH, 20, 0x00, 23 }}, 0x0000, mEv_EVENT_RUMOR_SPRING_SPORTS_FAIR}, + {{{lbRTC_APRIL, 1, 0x00, 0 }, {lbRTC_APRIL, 1, 0x00, 23 }}, 0x0000, mEv_EVENT_APRILFOOLS_DAY}, + {{{lbRTC_APRIL, 1, 0x00, 10 }, {lbRTC_APRIL, 1, 0x00, 17 }}, 0x0000, mEv_EVENT_SONCHO_APRILFOOLS_DAY}, + {{{lbRTC_APRIL, 5, 0x00, 10 }, {lbRTC_APRIL, 7, 0x00, 21 }}, 0x0000, mEv_EVENT_CHERRY_BLOSSOM_FESTIVAL}, + {{{lbRTC_APRIL, 5, 0x00, 10 }, {lbRTC_APRIL, 7, 0x00, 21 }}, 0x0000, mEv_EVENT_SONCHO_CHERRY_BLOSSOM_FESTIVAL}, + {{{lbRTC_MARCH, 15, 0x00, mEv_SCHEDULE_MULTIDAY | 0 }, {lbRTC_MARCH, 31, 0x00, 23 }}, 0x0000, mEv_EVENT_RUMOR_APRILFOOLS_DAY}, + {{{lbRTC_APRIL, 1, 0x00, mEv_SCHEDULE_MULTIDAY | 0 }, {lbRTC_APRIL, 4, 0x00, 23 }}, 0x0000, mEv_EVENT_RUMOR_CHERRY_BLOSSOM_FESTIVAL}, + {{{lbRTC_APRIL, 22, 0x00, 10 }, {lbRTC_APRIL, 22, 0x00, 17 }}, 0x0000, mEv_EVENT_NATURE_DAY}, + {{{lbRTC_APRIL, 22, 0x00, 10 }, {lbRTC_APRIL, 22, 0x00, 17 }}, 0x0000, mEv_EVENT_SONCHO_NATURE_DAY}, + {{{lbRTC_MAY, 1, 0x00, 0 }, {lbRTC_MAY, 1, 0x00, 23 }}, 0x0000, mEv_EVENT_SPRING_CLEANING}, + {{{lbRTC_MAY, 1, 0x00, 10 }, {lbRTC_MAY, 1, 0x00, 17 }}, 0x0000, mEv_EVENT_SONCHO_SPRING_CLEANING}, + {{{lbRTC_MAY, mEv_SCHEDULE_2ND_WEEKDAY(lbRTC_SUNDAY), 0x00, 0 }, {lbRTC_MAY, mEv_SCHEDULE_2ND_WEEKDAY(lbRTC_SUNDAY), 0x00, 23 }}, 0x0000, mEv_EVENT_MOTHERS_DAY}, + {{{lbRTC_MAY, mEv_SCHEDULE_2ND_WEEKDAY(lbRTC_SUNDAY), 0x00, 10 }, {lbRTC_MAY, mEv_SCHEDULE_2ND_WEEKDAY(lbRTC_SUNDAY), 0x00, 17 }}, 0x0000, mEv_EVENT_SONCHO_MOTHERS_DAY}, + {{{lbRTC_JUNE, mEv_SCHEDULE_EVERY_WEEKDAY(lbRTC_SATURDAY), 0x00, mEv_SCHEDULE_MULTIDAY | 9 }, {lbRTC_JUNE, mEv_SCHEDULE_EVERY_WEEKDAY( lbRTC_SUNDAY), 0x00, 14 }}, 0x0000, mEv_EVENT_SUMMER_CAMPER}, + {{{lbRTC_JUNE, mEv_SCHEDULE_2ND_WEEKDAY(lbRTC_FRIDAY), 0x00, 10 }, {lbRTC_JUNE, mEv_SCHEDULE_2ND_WEEKDAY(lbRTC_FRIDAY), 0x00, 17 }}, 0x0000, mEv_EVENT_GRADUATION_DAY}, + {{{lbRTC_JUNE, mEv_SCHEDULE_2ND_WEEKDAY(lbRTC_FRIDAY), 0x00, 10 }, {lbRTC_JUNE, mEv_SCHEDULE_2ND_WEEKDAY(lbRTC_FRIDAY), 0x00, 17 }}, 0x0000, mEv_EVENT_SONCHO_GRADUATION_DAY}, + {{{lbRTC_JUNE, mEv_SCHEDULE_3RD_WEEKDAY(lbRTC_SUNDAY), 0x00, 0 }, {lbRTC_JUNE, mEv_SCHEDULE_3RD_WEEKDAY(lbRTC_SUNDAY), 0x00, 23 }}, 0x0000, mEv_EVENT_FATHERS_DAY}, + {{{lbRTC_JUNE, mEv_SCHEDULE_3RD_WEEKDAY(lbRTC_SUNDAY), 0x00, 10 }, {lbRTC_JUNE, mEv_SCHEDULE_3RD_WEEKDAY(lbRTC_SUNDAY), 0x00, 17 }}, 0x0000, mEv_EVENT_SONCHO_FATHERS_DAY}, + {{{lbRTC_JUNE, mEv_SCHEDULE_EVERY_WEEKDAY(lbRTC_SUNDAY), 0x00, 6 }, {lbRTC_JUNE, mEv_SCHEDULE_EVERY_WEEKDAY(lbRTC_SUNDAY), 0x00, 17 }}, 0x0000, mEv_EVENT_FISHING_TOURNEY_1}, + {{{lbRTC_JUNE, mEv_SCHEDULE_EVERY_WEEKDAY(lbRTC_SUNDAY), 0x00, 6 }, {lbRTC_JUNE, mEv_SCHEDULE_EVERY_WEEKDAY(lbRTC_SUNDAY), 0x00, 17 }}, 0x0000, mEv_EVENT_SONCHO_FISHING_TOURNEY_1}, + {{{lbRTC_MAY, 15, 0x00, mEv_SCHEDULE_MULTIDAY | 0 }, {lbRTC_MAY, 31, 0x00, 23 }}, 0x0000, mEv_EVENT_RUMOR_FISHING_TOURNEY_1}, + {{{lbRTC_JUNE, 1, 0x00, mEv_SCHEDULE_MULTIDAY | 0 }, {lbRTC_JUNE, mEv_SCHEDULE_LAST_WEEKDAY(lbRTC_SUNDAY), 0x00, 0 }}, 0x0000, mEv_EVENT_TALK_FISHING_TOURNEY_1}, + {{{lbRTC_JULY, 4, 0x00, 19 }, {lbRTC_JULY, 4, 0x00, 20 }}, 0x0000, mEv_EVENT_FIREWORKS_SHOW}, + {{{lbRTC_JULY, 4, 0x00, 19 }, {lbRTC_JULY, 4, 0x00, 20 }}, 0x0000, mEv_EVENT_SONCHO_FIREWORKS_SHOW}, + {{{lbRTC_JULY, 4, 0x00, 0 }, {lbRTC_JULY, 4, 0x00, 23 }}, 0x0000, mEv_EVENT_WEATHER_CLEAR}, + {{{lbRTC_JUNE, 25, 0x00, mEv_SCHEDULE_MULTIDAY | 0 }, {lbRTC_JULY, 3, 0x00, 23 }}, 0x0000, mEv_EVENT_RUMOR_FIREWORKS_SHOW}, + {{{lbRTC_JULY, mEv_SCHEDULE_TOWN_DAY, 0x00, 10 }, {lbRTC_JULY, mEv_SCHEDULE_TOWN_DAY, 0x00, 17 }}, 0x0000, mEv_EVENT_TOWN_DAY}, + {{{lbRTC_JULY, mEv_SCHEDULE_TOWN_DAY, 0x00, 10 }, {lbRTC_JULY, mEv_SCHEDULE_TOWN_DAY, 0x00, 17 }}, 0x0000, mEv_EVENT_SONCHO_TOWN_DAY}, + {{{lbRTC_JULY, 25, 0x00, mEv_SCHEDULE_TODAY | 6 }, {lbRTC_AUGUST, 31, 0x00, mEv_SCHEDULE_TODAY | 6 }}, 0x0000, mEv_EVENT_MORNING_AEROBICS}, + {{{lbRTC_JULY, 14, 0x00, mEv_SCHEDULE_MULTIDAY | 0 }, {lbRTC_JULY, 24, 0x00, 23 }}, 0x0000, mEv_EVENT_RUMOR_MORNING_AEROBICS}, + {{{lbRTC_JULY, 26, 0x00, mEv_SCHEDULE_MULTIDAY | 0 }, {lbRTC_AUGUST, 30, 0x00, 23 }}, 0x0000, mEv_EVENT_TALK_MORNING_AEROBICS}, + {{{lbRTC_AUGUST, 12, 0x00, 18 }, {lbRTC_AUGUST, 12, 0x00, 20 }}, 0x0000, mEv_EVENT_METEOR_SHOWER}, + {{{lbRTC_AUGUST, 12, 0x00, 18 }, {lbRTC_AUGUST, 12, 0x00, 20 }}, 0x0000, mEv_EVENT_SONCHO_METEOR_SHOWER}, + {{{lbRTC_AUGUST, 5, 0x00, mEv_SCHEDULE_MULTIDAY | 0 }, {lbRTC_AUGUST, 11, 0x00, 23 }}, 0x0000, mEv_EVENT_RUMOR_METEOR_SHOWER}, + {{{lbRTC_AUGUST, 12, 0x00, 0 }, {lbRTC_AUGUST, 12, 0x00, 23 }}, 0x0000, mEv_EVENT_WEATHER_CLEAR}, + {{{lbRTC_AUGUST, 21, 0x00, 10 }, {lbRTC_AUGUST, 21, 0x00, 17 }}, 0x0000, mEv_EVENT_FOUNDERS_DAY}, + {{{lbRTC_AUGUST, 21, 0x00, 10 }, {lbRTC_AUGUST, 21, 0x00, 17 }}, 0x0000, mEv_EVENT_SONCHO_FOUNDERS_DAY}, + {{{lbRTC_SEPTEMBER, mEv_SCHEDULE_1ST_WEEKDAY(lbRTC_MONDAY), 0x00, 10 }, {lbRTC_SEPTEMBER, mEv_SCHEDULE_1ST_WEEKDAY(lbRTC_MONDAY), 0x00, 17 }}, 0x0000, mEv_EVENT_LABOR_DAY}, + {{{lbRTC_SEPTEMBER, mEv_SCHEDULE_1ST_WEEKDAY(lbRTC_MONDAY), 0x00, 10 }, {lbRTC_SEPTEMBER, mEv_SCHEDULE_1ST_WEEKDAY(lbRTC_MONDAY), 0x00, 17 }}, 0x0000, mEv_EVENT_SONCHO_LABOR_DAY}, + {{{lbRTC_SEPTEMBER, 21, 0x00, 9 }, {lbRTC_SEPTEMBER, 23, 0x00, 16 }}, 0x0000, mEv_EVENT_AUTUMN_EQUINOX}, + {{{lbRTC_SEPTEMBER, 21, 0x00, 9 }, {lbRTC_SEPTEMBER, 23, 0x00, 16 }}, 0x0000, mEv_EVENT_SONCHO_FALL_SPORTS_FAIR}, + {{{lbRTC_SEPTEMBER, 21, 0x00, 9 }, {lbRTC_SEPTEMBER, 23, 0x00, 10 }}, 0x0000, mEv_EVENT_SPORTS_FAIR_AEROBICS}, + {{{lbRTC_SEPTEMBER, 21, 0x00, 11 }, {lbRTC_SEPTEMBER, 23, 0x00, 12 }}, 0x0000, mEv_EVENT_SPORTS_FAIR_FOOT_RACE}, + {{{lbRTC_SEPTEMBER, 21, 0x00, 13 }, {lbRTC_SEPTEMBER, 23, 0x00, 14 }}, 0x0000, mEv_EVENT_SPORTS_FAIR_BALL_TOSS}, + {{{lbRTC_SEPTEMBER, 21, 0x00, 15 }, {lbRTC_SEPTEMBER, 23, 0x00, 16 }}, 0x0000, mEv_EVENT_SPORTS_FAIR_TUG_OF_WAR}, + {{{lbRTC_SEPTEMBER, 21, 0x00, 11 }, {lbRTC_SEPTEMBER, 23, 0x00, 16 }}, 0x0000, mEv_EVENT_SPORTS_FAIR}, + {{{lbRTC_SEPTEMBER, 21, 0x00, 0 }, {lbRTC_SEPTEMBER, 23, 0x00, 23 }}, 0x0000, mEv_EVENT_WEATHER_SPORTS_FAIR}, + {{{lbRTC_SEPTEMBER, 11, 0x00, mEv_SCHEDULE_MULTIDAY | 0 }, {lbRTC_SEPTEMBER, 22, 0x00, 23 }}, 0x0000, mEv_EVENT_RUMOR_FALL_SPORTS_FAIR}, + {{{mEv_SCHEDULE_HARVEST_MOON_DATE | 8, 15, 0x00, 18 }, {mEv_SCHEDULE_HARVEST_MOON_DATE | 8, 15, 0x00, 20 }}, 0x0000, mEv_EVENT_HARVEST_MOON_FESTIVAL}, + {{{mEv_SCHEDULE_HARVEST_MOON_DATE | 8, 15, 0x00, 18 }, {mEv_SCHEDULE_HARVEST_MOON_DATE | 8, 15, 0x00, 20 }}, 0x0000, mEv_EVENT_SONCHO_HARVEST_MOON_FESTIVAL}, + {{{mEv_SCHEDULE_HARVEST_MOON_DATE | 8, 15, 0x00, 0 }, {mEv_SCHEDULE_HARVEST_MOON_DATE | 8, 15, 0x00, 23 }}, 0x0000, mEv_EVENT_WEATHER_CLEAR}, + {{{mEv_SCHEDULE_HARVEST_MOON_DATE | 8, 8, 0x00, mEv_SCHEDULE_MULTIDAY | 0 }, {mEv_SCHEDULE_HARVEST_MOON_DATE | 8, 14, 0x00, 23 }}, 0x0000, mEv_EVENT_RUMOR_HARVEST_MOON_DAY}, + {{{lbRTC_OCTOBER, mEv_SCHEDULE_2ND_WEEKDAY(lbRTC_MONDAY), 0x00, 10 }, {lbRTC_OCTOBER, mEv_SCHEDULE_2ND_WEEKDAY(lbRTC_MONDAY), 0x00, 17 }}, 0x0000, mEv_EVENT_EXPLORERS_DAY}, + {{{lbRTC_OCTOBER, mEv_SCHEDULE_2ND_WEEKDAY(lbRTC_MONDAY), 0x00, 10 }, {lbRTC_OCTOBER, mEv_SCHEDULE_2ND_WEEKDAY(lbRTC_MONDAY), 0x00, 17 }}, 0x0000, mEv_EVENT_SONCHO_EXPLORERS_DAY}, + {{{lbRTC_OCTOBER, 15, 0x00, 0 }, {lbRTC_OCTOBER, 25, 0x00, 23 }}, 0x0000, mEv_EVENT_MUSHROOM_SEASON}, + {{{lbRTC_OCTOBER, 10, 0x00, mEv_SCHEDULE_MULTIDAY | 0 }, {lbRTC_OCTOBER, 14, 0x00, 23 }}, 0x0000, mEv_EVENT_RUMOR_MUSHROOM_SEASON}, + {{{lbRTC_OCTOBER, 15, 0x00, mEv_SCHEDULE_MULTIDAY | 0 }, {lbRTC_OCTOBER, 25, 0x00, 23 }}, 0x0000, mEv_EVENT_TALK_MUSHROOM_SEASON}, + {{{lbRTC_OCTOBER, 31, 0x00, mEv_SCHEDULE_MULTIDAY | 18 }, {lbRTC_NOVEMBER, 1, 0x00, 0 }}, 0x0000, mEv_EVENT_HALLOWEEN}, + {{{lbRTC_OCTOBER, 31, 0x00, mEv_SCHEDULE_MULTIDAY | 18 }, {lbRTC_NOVEMBER, 1, 0x00, 0 }}, 0x0000, mEv_EVENT_SONCHO_HALLOWEEN}, + {{{lbRTC_OCTOBER, 31, 0x00, mEv_SCHEDULE_MULTIDAY | 0 }, {lbRTC_NOVEMBER, 1, 0x00, 0 }}, 0x0000, mEv_EVENT_WEATHER_CLEAR}, + {{{lbRTC_OCTOBER, 1, 0x00, mEv_SCHEDULE_MULTIDAY | 0 }, {lbRTC_OCTOBER, 30, 0x00, 23 }}, 0x0000, mEv_EVENT_RUMOR_HALLOWEEN}, + {{{lbRTC_NOVEMBER, mEv_SCHEDULE_DAY_AFTER | mEv_SCHEDULE_1ST_WEEKDAY(lbRTC_MONDAY), 0x00, 10 }, {lbRTC_NOVEMBER, mEv_SCHEDULE_DAY_AFTER | mEv_SCHEDULE_1ST_WEEKDAY(lbRTC_MONDAY), 0x00, 17 }}, 0x0000, mEv_EVENT_MAYORS_DAY}, + {{{lbRTC_NOVEMBER, mEv_SCHEDULE_DAY_AFTER | mEv_SCHEDULE_1ST_WEEKDAY(lbRTC_MONDAY), 0x00, 10 }, {lbRTC_NOVEMBER, mEv_SCHEDULE_DAY_AFTER | mEv_SCHEDULE_1ST_WEEKDAY(lbRTC_MONDAY), 0x00, 17 }}, 0x0000, mEv_EVENT_SONCHO_MAYORS_DAY}, + {{{lbRTC_NOVEMBER, 11, 0x00, 10 }, {lbRTC_NOVEMBER, 11, 0x00, 17 }}, 0x0000, mEv_EVENT_OFFICERS_DAY}, + {{{lbRTC_NOVEMBER, 11, 0x00, 10 }, {lbRTC_NOVEMBER, 11, 0x00, 17 }}, 0x0000, mEv_EVENT_SONCHO_OFFICERS_DAY}, + {{{lbRTC_NOVEMBER, mEv_SCHEDULE_EVERY_WEEKDAY(lbRTC_SUNDAY), 0x00, 6 }, {lbRTC_NOVEMBER, mEv_SCHEDULE_EVERY_WEEKDAY(lbRTC_SUNDAY), 0x00, 17 }}, 0x0000, mEv_EVENT_FISHING_TOURNEY_2}, + {{{lbRTC_NOVEMBER, mEv_SCHEDULE_EVERY_WEEKDAY(lbRTC_SUNDAY), 0x00, 6 }, {lbRTC_NOVEMBER, mEv_SCHEDULE_EVERY_WEEKDAY(lbRTC_SUNDAY), 0x00, 17 }}, 0x0000, mEv_EVENT_SONCHO_FISHING_TOURNEY_2}, + {{{lbRTC_OCTOBER, 15, 0x00, mEv_SCHEDULE_MULTIDAY | 0 }, {lbRTC_OCTOBER, 31, 0x00, 23 }}, 0x0000, mEv_EVENT_RUMOR_FISHING_TOURNEY_2}, + {{{lbRTC_NOVEMBER, 1, 0x00, mEv_SCHEDULE_MULTIDAY | 0 }, {lbRTC_NOVEMBER, mEv_SCHEDULE_LAST_WEEKDAY(lbRTC_SUNDAY), 0x00, 0 }}, 0x0000, mEv_EVENT_TALK_FISHING_TOURNEY_2}, + {{{lbRTC_NOVEMBER, mEv_SCHEDULE_4TH_WEEKDAY(lbRTC_THURSDAY), 0x00, 15 }, {lbRTC_NOVEMBER, mEv_SCHEDULE_4TH_WEEKDAY(lbRTC_THURSDAY), 0x00, 20 }}, 0x0000, mEv_EVENT_HARVEST_FESTIVAL}, + {{{lbRTC_NOVEMBER, mEv_SCHEDULE_4TH_WEEKDAY(lbRTC_THURSDAY), 0x00, 15 }, {lbRTC_NOVEMBER, mEv_SCHEDULE_4TH_WEEKDAY(lbRTC_THURSDAY), 0x00, 20 }}, 0x0000, mEv_EVENT_SONCHO_HARVEST_FESTIVAL}, + {{{lbRTC_NOVEMBER, mEv_SCHEDULE_4TH_WEEKDAY(lbRTC_THURSDAY), 0x00, 15 }, {lbRTC_NOVEMBER, mEv_SCHEDULE_4TH_WEEKDAY(lbRTC_THURSDAY), 0x00, 20 }}, 0x0000, mEv_EVENT_HARVEST_FESTIVAL_FRANKLIN}, + {{{lbRTC_NOVEMBER, 11, 0x00, mEv_SCHEDULE_MULTIDAY | 0 }, {lbRTC_NOVEMBER, mEv_SCHEDULE_DAY_AFTER | mEv_SCHEDULE_1ST_WEEKDAY(lbRTC_SUNDAY), 0x00, 23 }}, 0x0000, mEv_EVENT_RUMOR_HARVEST_FESTIVAL}, + {{{lbRTC_NOVEMBER, mEv_SCHEDULE_4TH_WEEKDAY(lbRTC_THURSDAY), 0x00, 0 }, {lbRTC_NOVEMBER, mEv_SCHEDULE_4TH_WEEKDAY(lbRTC_THURSDAY), 0x00, 23 }}, 0x0000, mEv_EVENT_WEATHER_CLEAR}, + {{{lbRTC_NOVEMBER, mEv_SCHEDULE_DAY_AFTER | mEv_SCHEDULE_4TH_WEEKDAY(lbRTC_THURSDAY), 0x00, 0 }, {lbRTC_NOVEMBER, mEv_SCHEDULE_DAY_AFTER | mEv_SCHEDULE_4TH_WEEKDAY(lbRTC_THURSDAY), 0x00, 23 }}, 0x0000, mEv_EVENT_SALE_DAY}, + {{{lbRTC_NOVEMBER, mEv_SCHEDULE_DAY_AFTER | mEv_SCHEDULE_4TH_WEEKDAY(lbRTC_THURSDAY), 0x00, 10 }, {lbRTC_NOVEMBER, mEv_SCHEDULE_DAY_AFTER | mEv_SCHEDULE_4TH_WEEKDAY(lbRTC_THURSDAY), 0x00, 17 }}, 0x0000, mEv_EVENT_SONCHO_SALE_DAY}, + {{{lbRTC_DECEMBER, 1, 0x00, 10 }, {lbRTC_DECEMBER, 1, 0x00, 17 }}, 0x0000, mEv_EVENT_SNOW_DAY}, + {{{lbRTC_DECEMBER, 1, 0x00, 10 }, {lbRTC_DECEMBER, 1, 0x00, 17 }}, 0x0000, mEv_EVENT_SONCHO_SNOW_DAY}, + {{{lbRTC_DECEMBER, 23, 0x00, 10 }, {lbRTC_DECEMBER, 23, 0x00, 17 }}, 0x0000, mEv_EVENT_TOY_DAY_SONCHO}, + {{{lbRTC_DECEMBER, 23, 0x00, 10 }, {lbRTC_DECEMBER, 23, 0x00, 17 }}, 0x0000, mEv_EVENT_SONCHO_TOY_DAY}, + {{{lbRTC_DECEMBER, 24, 0x00, mEv_SCHEDULE_MULTIDAY | 20 }, {lbRTC_DECEMBER, 25, 0x00, 0 }}, 0x0000, mEv_EVENT_TOY_DAY_JINGLE}, + {{{lbRTC_DECEMBER, 24, 0x00, 0 }, {lbRTC_DECEMBER, 24, 0x00, 23 }}, 0x0000, mEv_EVENT_TALK_TOY_DAY}, + {{{lbRTC_DECEMBER, 24, 0x00, 0 }, {lbRTC_DECEMBER, 24, 0x00, 23 }}, 0x0000, mEv_EVENT_WEATHER_SNOW}, + {{{lbRTC_DECEMBER, 10, 0x00, mEv_SCHEDULE_MULTIDAY | 0 }, {lbRTC_DECEMBER, 23, 0x00, 23 }}, 0x0000, mEv_EVENT_RUMOR_TOY_DAY}, + {{{lbRTC_DECEMBER, 31, 0x00, mEv_SCHEDULE_MULTIDAY | 23 }, {lbRTC_JANUARY, 1, 0x00, 0 }}, 0x0000, mEv_EVENT_NEW_YEARS_EVE_COUNTDOWN}, + {{{lbRTC_DECEMBER, 31, 0x00, mEv_SCHEDULE_MULTIDAY | 23 }, {lbRTC_JANUARY, 1, 0x00, 0 }}, 0x0000, mEv_EVENT_TALK_NEW_YEARS_COUNTDOWN}, + {{{lbRTC_DECEMBER, 25, 0x00, mEv_SCHEDULE_MULTIDAY | 0 }, {lbRTC_DECEMBER, 30, 0x00, 23 }}, 0x0000, mEv_EVENT_RUMOR_NEW_YEARS_EVE_COUNTDOWN}, + {{{lbRTC_DECEMBER, 31, 0x00, 0 }, {lbRTC_DECEMBER, 31, 0x00, 23 }}, 0x0000, mEv_EVENT_WEATHER_CLEAR}, + {{{lbRTC_JANUARY, 15, 0x00, 10 }, {lbRTC_JANUARY, 24, 0x00, 17 }}, 0x0000, mEv_EVENT_SONCHO_VACATION_JANUARY}, + {{{lbRTC_FEBRUARY, 12, 0x00, 10 }, {lbRTC_FEBRUARY, 21, 0x00, 17 }}, 0x0000, mEv_EVENT_SONCHO_VACATION_FEBRUARY}, + {{{lbRTC_JANUARY, 1, 0x00, 7 }, {lbRTC_DECEMBER, 31, 0x00, 23 }}, 0x0000, mEv_EVENT_SONCHO_BRIDGE_MAKE}, + {{{lbRTC_MAY, 1, 0x00, 0 }, {lbRTC_MAY, 5, 0x00, 23 }}, 0x0000, mEv_EVENT_KOINOBORI} +}; diff --git a/src/m_island.c b/src/m_island.c index 98838bb8..8b140b62 100644 --- a/src/m_island.c +++ b/src/m_island.c @@ -773,8 +773,8 @@ extern void mISL_gc_to_agb(Island_agb_c* agb, Island_c* gc) { zelda_free(temp); } - agb->last_song_male = gc->last_song_male; - agb->last_song_female = gc->last_song_female; + agb->last_song_to_island = gc->last_song_to_island; + agb->last_song_from_island = gc->last_song_from_island; // remove the land info portion from the checksum as it can change agb->checksum = mISL_GetFlatCheckSum((u8*)agb, sizeof(Island_agb_c), agb->checksum, mISL_ReturnCheckSum((u8*)&agb->landinfo, 16)); } @@ -820,8 +820,8 @@ extern void mISL_agb_to_gc(Island_c* gc, Island_agb_c* agb) { mISL_short((u16*)gc->deposit, (u16*)agb->deposit, sizeof(gc->deposit) / sizeof(u16)); bcopy(agb->bg_data, gc->bg_data, sizeof(gc->bg_data)); mISL_gc_to_agb_time(&gc->renew_time, &agb->renew_time); - gc->last_song_male = agb->last_song_male; - gc->last_song_female = agb->last_song_female; + gc->last_song_to_island = agb->last_song_to_island; + gc->last_song_from_island = agb->last_song_from_island; if (mFI_CheckFieldData() == TRUE) { bzero(island_x_blocks, sizeof(island_x_blocks)); diff --git a/src/m_npc.c b/src/m_npc.c index a9c949f8..98342310 100644 --- a/src/m_npc.c +++ b/src/m_npc.c @@ -3852,7 +3852,7 @@ extern void mNpc_SetReturnAnimal(Animal_c* return_animal) { } else { return_animal_p->npc_id = return_animal->id.npc_id; - return_animal_p->talk_bit = FALSE; + return_animal_p->talk_bit = 0b000; return_animal_p->exist = FALSE; lbRTC_TimeCopy(&return_animal_p->renew_time, Common_GetPointer(time.rtc_time)); mNpc_CopyAnimalPersonalID(Save_GetPointer(last_removed_animal_id), &return_animal->id); diff --git a/src/m_start_data_init.c b/src/m_start_data_init.c index 5d9177d6..c43e23aa 100644 --- a/src/m_start_data_init.c +++ b/src/m_start_data_init.c @@ -248,8 +248,8 @@ static int mSDI_StartInitNew(GAME* game, int player_no, int malloc_flag) { lbRTC_TimeCopy(Save_GetPointer(saved_auto_nwrite_time), &mTM_rtcTime_clear_code); Save_Set(station_type, RANDOM(15)); - Save_Set(island.last_song_male, -1); - Save_Set(island.last_song_female, -1); + Save_Set(island.last_song_to_island, -1); + Save_Set(island.last_song_from_island, -1); mPr_SetPossessionItem(Common_Get(now_private), 0, ITM_MONEY_1000, mPr_ITEM_COND_QUEST);