diff --git a/config/rel_slices.yml b/config/rel_slices.yml index 111ab002..4f7139a6 100644 --- a/config/rel_slices.yml +++ b/config/rel_slices.yml @@ -104,6 +104,9 @@ m_needlework.c: .text: [0x803C98EC, 0x803C9F7C] .data: [0x8065ABC0, 0x8065AE30] .bss: [0x81298F60, 0x81299180] +m_npc_schedule.c: + .text: [0x803D7570, 0x803D7890] + .data: [0x8065B638, 0x8065B7F0] m_olib.c: .text: [0x803D88E8, 0x803D8A34] .rodata: [0x80642A00, 0x80642A10] diff --git a/include/audio.h b/include/audio.h index bb574721..326d97ee 100644 --- a/include/audio.h +++ b/include/audio.h @@ -33,7 +33,7 @@ extern void sAdo_PlayerStatusLevel(f32 speed, int p); /* Not sure about the last param name */ extern void sAdo_VoiceSe(u8 num, u8 num2, u8 num3, s16 character_idx, u8 scale, u8 mode); -extern void sAdo_Inst(s8 num, void* p); +extern void sAdo_Inst(u16 num, u8* p); extern void sAdo_MessageStatus(u8 status); extern void sAdo_MessageSpeed(u8 speed); extern u8 sAdo_MessageSpeedGet(); diff --git a/include/jaudio_NES/melody.h b/include/jaudio_NES/melody.h index f446dc9a..284d8464 100644 --- a/include/jaudio_NES/melody.h +++ b/include/jaudio_NES/melody.h @@ -7,7 +7,7 @@ extern "C"{ #endif -extern void Na_Inst(s8, void*); +extern void Na_Inst(u16, u8*); extern void Na_FurnitureInst(int,s8,s32,u16,f32); extern int Na_InstCountGet(); diff --git a/include/m_common_data.h b/include/m_common_data.h index 294fa07f..b0833b34 100644 --- a/include/m_common_data.h +++ b/include/m_common_data.h @@ -28,11 +28,14 @@ #include "m_scene.h" #include "m_npc_walk.h" #include "m_mask_cat.h" +#include "m_npc_schedule_h.h" #ifdef __cplusplus extern "C" { #endif +#define SCHEDULE_NUM ANIMAL_NUM_MAX + mISL_ISLANDER_NUM + typedef struct time_s { u32 season; u32 term_idx; @@ -183,7 +186,7 @@ typedef struct common_data_s { /* 0x026678 */ u8 _26678[0x2669C - 0x26678]; /* 0x02669C */ mQst_not_saved_c quest; /* 0x0266A4 */ int scene_from_title_demo; /* next scene to be loaded when title demo finishes */ - /* 0x0266A8 */ u8 _266A8[0x267A8 - 0x266A8]; + /* 0x0266A8 */ mNPS_schedule_c npc_schedule[SCHEDULE_NUM]; /* 0x0267A8 */ mNpc_walk_c npc_walk; /* 0x026838 */ u8 _26838[0x2852C - 0x26838]; /* 0x02852C */ s16 money_power; diff --git a/include/m_event.h b/include/m_event.h index cdedc6c6..bc8d9719 100644 --- a/include/m_event.h +++ b/include/m_event.h @@ -115,6 +115,7 @@ enum event_table { mEv_EVENT_FATHERS_DAY = 26, mEv_EVENT_FISHING_TOURNEY_1 = 29, mEv_EVENT_MUSHROOM_SEASON = 47, + mEv_EVENT_HALLOWEEN = 49, mEv_EVENT_FISHING_TOURNEY_2 = 54, mEv_EVENT_GHOST = 64, mEv_EVENT_BROKER_SALE = 75, diff --git a/include/m_island.h b/include/m_island.h index a3afee99..383fb7a8 100644 --- a/include/m_island.h +++ b/include/m_island.h @@ -13,6 +13,8 @@ extern "C" { #endif +#define mISL_ISLANDER_NUM 1 + #define mISL_ISLAND_NAME_LEN 8 #define mISL_FG_BLOCK_X_NUM 2 diff --git a/include/m_npc_personal_id.h b/include/m_npc_personal_id.h index b503be91..31908b17 100644 --- a/include/m_npc_personal_id.h +++ b/include/m_npc_personal_id.h @@ -9,6 +9,17 @@ extern "C" { #endif +enum { + mNpc_LOOKS_GIRL, + mNpc_LOOKS_KO_GIRL, + mNpc_LOOKS_BOY, + mNpc_LOOKS_SPORT_MAN, + mNpc_LOOKS_GRIM_MAN, + mNpc_LOOKS_NANIWA_LADY, + + mNpc_LOOKS_NUM +}; + /* sizeof(AnmPersonalID_c) == 0xE */ typedef struct animal_personal_id_s { /* 0x00 */ mActor_name_t npc_id; /* id */ diff --git a/include/m_npc_schedule.h b/include/m_npc_schedule.h new file mode 100644 index 00000000..27fc28a1 --- /dev/null +++ b/include/m_npc_schedule.h @@ -0,0 +1,17 @@ +#ifndef M_NPC_SCHEDULE_H +#define M_NPC_SCHEDULE_H + +#include "types.h" +#include "m_npc_schedule_h.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/m_npc_schedule_h.h b/include/m_npc_schedule_h.h new file mode 100644 index 00000000..5b23b728 --- /dev/null +++ b/include/m_npc_schedule_h.h @@ -0,0 +1,45 @@ +#ifndef M_NPC_SCHEDULE_H_H +#define M_NPC_SCHEDULE_H_H + +#include "types.h" +#include "m_npc_personal_id.h" + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + mNPS_SCHED_FIELD, /* in same acre as their home */ + mNPS_SCHED_IN_HOUSE, /* inside their house */ + mNPS_SCHED_SLEEP, /* asleep in their house */ + mNPS_SCHED_STAND, /* standing around town?? */ + mNPS_SCHED_WANDER, /* wander around town */ + mNPS_SCHED_SPECIAL, /* unique schedule method for each NPC actor type */ + + mNPS_SCHED_TYPE_NUM +}; + +typedef struct schedule_data_s { + u32 type; + int end_time; +} mNPS_schedule_data_c; + +typedef struct schedule_data_table_s { + int count; + mNPS_schedule_data_c* sched_data; +} mNPS_schedule_data_table_c; + +typedef struct schedule_s { + AnmPersonalID_c* id; + mNPS_schedule_data_table_c* data_table; + u8 current_type; + u8 forced_type; + u8 saved_type; + int forced_timer; +} mNPS_schedule_c; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/rel/audio.c b/rel/audio.c index cf105f75..6e9472c4 100644 --- a/rel/audio.c +++ b/rel/audio.c @@ -106,8 +106,7 @@ extern void sAdo_VoiceSe(u8 num, u8 num2, u8 num3, s16 character_idx, u8 scale, Na_VoiceSe(num,num2,num3,character_idx, scale, mode); } -extern void sAdo_Inst(s8 num, void* p){ - +extern void sAdo_Inst(u16 num, u8* p){ Na_Inst(num,p); } diff --git a/rel/m_npc_schedule.c b/rel/m_npc_schedule.c new file mode 100644 index 00000000..e1147196 --- /dev/null +++ b/rel/m_npc_schedule.c @@ -0,0 +1,226 @@ +#include "m_npc_schedule.h" + +#include "m_common_data.h" + +#define mNPS_TIME_2_SEC(hour, min, sec) ((hour) * 3600 + (min) * 60 + (sec)) +#define mNPS_MAKE_SCHEDULE_TABLE(sched_data) { ARRAY_SIZE(sched_data, mNPS_schedule_data_c), sched_data } + +static mNPS_schedule_data_c girl_schedule_dt[] = { + { mNPS_SCHED_SLEEP, mNPS_TIME_2_SEC(5, 0, 0) }, + { mNPS_SCHED_IN_HOUSE, mNPS_TIME_2_SEC(6, 0, 0) }, + { mNPS_SCHED_FIELD, mNPS_TIME_2_SEC(12, 0, 0) }, + { mNPS_SCHED_IN_HOUSE, mNPS_TIME_2_SEC(13, 0, 0) }, + { mNPS_SCHED_FIELD, mNPS_TIME_2_SEC(18, 30, 0) }, + { mNPS_SCHED_IN_HOUSE, mNPS_TIME_2_SEC(21, 0, 0) }, + { mNPS_SCHED_SLEEP, mNPS_TIME_2_SEC(24, 0, 0) } +}; + +static mNPS_schedule_data_table_c girl_schedule = mNPS_MAKE_SCHEDULE_TABLE(girl_schedule_dt); + +static mNPS_schedule_data_c ko_girl_schedule_dt[] = { + { mNPS_SCHED_SLEEP, mNPS_TIME_2_SEC(7, 0, 0) }, + { mNPS_SCHED_IN_HOUSE, mNPS_TIME_2_SEC(8, 0, 0) }, + { mNPS_SCHED_FIELD, mNPS_TIME_2_SEC(13, 0, 0) }, + { mNPS_SCHED_IN_HOUSE, mNPS_TIME_2_SEC(14, 0, 0) }, + { mNPS_SCHED_FIELD, mNPS_TIME_2_SEC(22, 0, 0) }, + { mNPS_SCHED_IN_HOUSE, mNPS_TIME_2_SEC(23, 30, 0) }, + { mNPS_SCHED_SLEEP, mNPS_TIME_2_SEC(24, 0, 0) } +}; + +static mNPS_schedule_data_table_c ko_girl_schedule = mNPS_MAKE_SCHEDULE_TABLE(ko_girl_schedule_dt); + +static mNPS_schedule_data_c boy_schedule_dt[] = { + { mNPS_SCHED_SLEEP, mNPS_TIME_2_SEC(8, 0, 0) }, + { mNPS_SCHED_IN_HOUSE, mNPS_TIME_2_SEC(9, 0, 0) }, + { mNPS_SCHED_FIELD, mNPS_TIME_2_SEC(12, 0, 0) }, + { mNPS_SCHED_IN_HOUSE, mNPS_TIME_2_SEC(14, 0, 0) }, + { mNPS_SCHED_FIELD, mNPS_TIME_2_SEC(19, 30, 0) }, + { mNPS_SCHED_IN_HOUSE, mNPS_TIME_2_SEC(22, 0, 0) }, + { mNPS_SCHED_SLEEP, mNPS_TIME_2_SEC(24, 0, 0) } +}; + +static mNPS_schedule_data_table_c boy_schedule = mNPS_MAKE_SCHEDULE_TABLE(boy_schedule_dt); + +static mNPS_schedule_data_c sport_man_schedule_dt[] = { + { mNPS_SCHED_IN_HOUSE, mNPS_TIME_2_SEC(1, 0, 0) }, + { mNPS_SCHED_SLEEP, mNPS_TIME_2_SEC(5, 30, 0) }, + { mNPS_SCHED_IN_HOUSE, mNPS_TIME_2_SEC(6, 30, 0) }, + { mNPS_SCHED_FIELD, mNPS_TIME_2_SEC(12, 0, 0) }, + { mNPS_SCHED_IN_HOUSE, mNPS_TIME_2_SEC(12, 30, 0) }, + { mNPS_SCHED_FIELD, mNPS_TIME_2_SEC(23, 0, 0) }, + { mNPS_SCHED_IN_HOUSE, mNPS_TIME_2_SEC(24, 0, 0) } +}; + +static mNPS_schedule_data_table_c sport_man_schedule = mNPS_MAKE_SCHEDULE_TABLE(sport_man_schedule_dt); + +static mNPS_schedule_data_c grim_man_schedule_dt[] = { + { mNPS_SCHED_FIELD, mNPS_TIME_2_SEC(4, 0, 0) }, + { mNPS_SCHED_IN_HOUSE, mNPS_TIME_2_SEC(5, 0, 0) }, + { mNPS_SCHED_SLEEP, mNPS_TIME_2_SEC(10, 0, 0) }, + { mNPS_SCHED_IN_HOUSE, mNPS_TIME_2_SEC(11, 0, 0) }, + { mNPS_SCHED_FIELD, mNPS_TIME_2_SEC(15, 0, 0) }, + { mNPS_SCHED_IN_HOUSE, mNPS_TIME_2_SEC(16, 0, 0) }, + { mNPS_SCHED_FIELD, mNPS_TIME_2_SEC(22, 0, 0) }, + { mNPS_SCHED_IN_HOUSE, mNPS_TIME_2_SEC(23, 0, 0) }, + { mNPS_SCHED_FIELD, mNPS_TIME_2_SEC(24, 0, 0) } +}; + +static mNPS_schedule_data_table_c grim_man_schedule = mNPS_MAKE_SCHEDULE_TABLE(grim_man_schedule_dt); + +static mNPS_schedule_data_c naniwa_lady_schedule_dt[] = { + { mNPS_SCHED_FIELD, mNPS_TIME_2_SEC(1, 30, 0) }, + { mNPS_SCHED_IN_HOUSE, mNPS_TIME_2_SEC(2, 30, 0) }, + { mNPS_SCHED_SLEEP, mNPS_TIME_2_SEC(9, 0, 0) }, + { mNPS_SCHED_IN_HOUSE, mNPS_TIME_2_SEC(10, 0, 0) }, + { mNPS_SCHED_FIELD, mNPS_TIME_2_SEC(13, 0, 0) }, + { mNPS_SCHED_IN_HOUSE, mNPS_TIME_2_SEC(14, 0, 0) }, + { mNPS_SCHED_FIELD, mNPS_TIME_2_SEC(21, 0, 0) }, + { mNPS_SCHED_IN_HOUSE, mNPS_TIME_2_SEC(22, 0, 0) }, + { mNPS_SCHED_FIELD, mNPS_TIME_2_SEC(24, 0, 0) } +}; + +static mNPS_schedule_data_table_c naniwa_lady_schedule = mNPS_MAKE_SCHEDULE_TABLE(naniwa_lady_schedule_dt); + +static mNPS_schedule_data_table_c* mNPS_schedule[mNpc_LOOKS_NUM] = { + &girl_schedule, + &ko_girl_schedule, + &boy_schedule, + &sport_man_schedule, + &grim_man_schedule, + &naniwa_lady_schedule +}; + +extern mNPS_schedule_c* mNPS_get_schedule_area(AnmPersonalID_c* anm_id) { + mNPS_schedule_c* schedule = Common_Get(npc_schedule); + int i; + + for (i = 0; i < SCHEDULE_NUM; i++) { + if (schedule->id == anm_id) { + return schedule; + } + + schedule++; + } + + return NULL; +} + +static void mNPS_set_schedule_area(AnmPersonalID_c* anm_id) { + mNPS_schedule_c* schedule = mNPS_get_schedule_area(NULL); /* try to get an unused schedule */ + + if (schedule != NULL) { + schedule->id = anm_id; + schedule->data_table = mNPS_schedule[anm_id->looks]; + schedule->forced_timer = 0; + } +} + +extern void mNPS_set_island_schedule_area(AnmPersonalID_c* anm_id) { + if (Common_Get(npc_schedule[ANIMAL_NUM_MAX]).id != NULL) { + return; + } + + Common_Set(npc_schedule[ANIMAL_NUM_MAX].id, anm_id); + Common_Set(npc_schedule[ANIMAL_NUM_MAX].data_table, mNPS_schedule[anm_id->looks]); + Common_Set(npc_schedule[ANIMAL_NUM_MAX].forced_timer, 0); +} + +extern void mNPS_reset_schedule_area(AnmPersonalID_c* anm_id) { + mNPS_schedule_c* schedule = mNPS_get_schedule_area(anm_id); + + if (schedule != NULL) { + schedule->id = NULL; + } +} + +static void mNPS_schedule_manager_sub(mNPS_schedule_c* schedule) { + int now_sec = Common_Get(time.now_sec); + int count = schedule->data_table->count; + mNPS_schedule_data_c* schedule_entry = schedule->data_table->sched_data; + + /* Locate our current scehdule entry */ + for (count; count != 0; count--) { + if (schedule_entry->end_time > now_sec) { + break; + } + + schedule_entry++; + } + + schedule->saved_type = schedule_entry->type; + if (schedule->forced_timer > 0) { + schedule->current_type = schedule->forced_type; + schedule->forced_timer--; + } + else { + schedule->current_type = schedule->saved_type; + } +} + +static void mNPS_schedule_manager_sub0() { + mNPS_schedule_c* schedule = Common_Get(npc_schedule); + int i; + + /* Set all town animals to go outside in their home block */ + for (i = 0; i < ANIMAL_NUM_MAX; i++) { + if (schedule->id != NULL) { + schedule->current_type = mNPS_SCHED_FIELD; + } + + schedule++; + } +} + +static void mNPS_schedule_manager_sub1() { + mNPS_schedule_c* schedule = Common_Get(npc_schedule); + int i; + + /* Set all town animals to go about their intended schedule */ + for (i = 0; i < ANIMAL_NUM_MAX; i++) { + if (schedule->id != NULL) { + mNPS_schedule_manager_sub(schedule); + } + + schedule++; + } +} + +static void mNPS_island_schedule_manager() { + mNPS_schedule_c* schedule = Common_GetPointer(npc_schedule[ANIMAL_NUM_MAX]); + + if (schedule->id != NULL) { + mNPS_schedule_manager_sub(schedule); + } +} + +extern void mNPS_schedule_manager() { + int force_outside = FALSE; + + if (mEv_CheckFirstJob() == TRUE || mEv_check_status(mEv_EVENT_HALLOWEEN, mEv_STATUS_ACTIVE)) { + force_outside = TRUE; + } + + if (force_outside == TRUE) { + mNPS_schedule_manager_sub0(); + } + else { + mNPS_schedule_manager_sub1(); + } + + mNPS_island_schedule_manager(); +} + +extern void mNPS_set_all_schedule_area() { + Animal_c* animal = Save_Get(animals); + int i; + + for (i = 0; i < ANIMAL_NUM_MAX; i++) { + if (mNpc_CheckFreeAnimalInfo(animal) == FALSE) { + mNPS_set_schedule_area(&animal->id); + } + + animal++; + } + + mNPS_schedule_manager(); +}