Files
ac-decomp/src/m_event.c
T
2024-01-02 12:09:43 -05:00

3114 lines
83 KiB
C

#include "m_event.h"
#include "libultra/libultra.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"
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(special_event_common), sizeof(mEv_event_common_u));
}
extern void mEv_ClearEventKabuPeddler(mEv_kabu_peddler_c* kabu_peddler) {
if (kabu_peddler != NULL) {
mPr_ClearAnyPersonalID(kabu_peddler->spoken_pids, TOTAL_PLAYER_NUM);
}
}
extern void mEv_ClearEventSaveInfo(mEv_event_save_c* save_event) {
mEv_ClearSpecialEvent(&save_event->special);
mEv_ClearEventKabuPeddler(&save_event->weekly.kabu_peddler);
save_event->flags = 0;
}
extern void mEv_ClearEventInfo() {
mEv_event_save_c* event_save = Save_GetPointer(event_save_data);
u32* event_flag = Common_Get(event_flags);
int i;
for (i = 0; i < mEv_EVENT_TYPE_NUM; i++) {
event_flag[0] = 0;
event_flag++;
}
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) {
u32 type = mEv_GET_TYPE(event_kind);
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;
}
}
}
extern void mEv_EventOFF(u32 event_kind) {
u32 type = mEv_GET_TYPE(event_kind);
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;
}
}
}
extern int mEv_CheckEvent(u32 event_kind) {
u32 type = mEv_GET_TYPE(event_kind);
int res = FALSE;
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;
}
extern void mEv_ClearPersonalEventFlag(int player_no) {
mEv_EventOFF(mEv_SAVED_FIRSTJOB_PLR0 + player_no);
mEv_EventOFF(mEv_SAVED_FIRSTINTRO_PLR0 + player_no);
mEv_EventOFF(mEv_SAVED_HRAWAIT_PLR0 + player_no);
mEv_EventOFF(mEv_SAVED_HRATALK_PLR0 + player_no);
mEv_EventOFF(mEv_SAVED_FJOPENQUEST_PLR0 + player_no);
mEv_EventOFF(mEv_SAVED_GATEWAY_PLR0 + player_no);
{
aAPC_event_save_data_c* data = (aAPC_event_save_data_c*)mEv_get_save_area(mEv_EVENT_APRILFOOLS_DAY, 0);
if (data != NULL) {
data->talk_bitfield[player_no] = 0;
}
}
}
extern void mEv_SetFirstJob() {
if (Common_Get(player_no) < PLAYER_NUM) {
u32 ev = mEv_SAVED_FIRSTJOB_PLR0;
ev += Common_Get(player_no);
mEv_EventON(ev);
}
}
extern int mEv_CheckRealArbeit() {
u32 player_no = Common_Get(player_no);
int res = FALSE;
if (
player_no < PLAYER_NUM &&
(
mEv_CheckEvent(mEv_SAVED_FIRSTJOB_PLR0 + player_no) == TRUE ||
mEv_CheckEvent( mEv_SAVED_HRAWAIT_PLR0 + player_no) == TRUE
)
) {
res = TRUE;
}
return res;
}
extern int mEv_CheckArbeit() {
u32 player_no = Common_Get(player_no);
int res = FALSE;
if (
player_no < PLAYER_NUM &&
(
mEv_CheckEvent(mEv_SAVED_FIRSTJOB_PLR0 + player_no) == TRUE ||
mEv_CheckEvent( mEv_SAVED_HRAWAIT_PLR0 + player_no) == TRUE ||
mEv_CheckEvent( mEv_SAVED_HRATALK_PLR0 + player_no) == TRUE
)
) {
res = TRUE;
}
return res;
}
extern int mFI_CheckFirstJob() {
u32 player_no = Common_Get(player_no);
int res = FALSE;
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() {
u32 player_no = Common_Get(player_no);
if (player_no < PLAYER_NUM) {
mEv_EventOFF(mEv_SAVED_FIRSTJOB_PLR0 + player_no);
mEv_EventON(mEv_SAVED_HRAWAIT_PLR0 + player_no);
}
}
extern void mEv_SetFirstIntro() {
u32 player_no = Common_Get(player_no);
if (player_no < PLAYER_NUM) {
u32 ev = mEv_SAVED_FIRSTINTRO_PLR0;
ev += player_no;
mEv_EventON(ev);
}
}
extern int mEv_CheckFirstIntro() {
u32 player_no = Common_Get(player_no);
int res = FALSE;
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() {
u32 player_no = Common_Get(player_no);
if (player_no < PLAYER_NUM) {
u32 ev = mEv_SAVED_FIRSTINTRO_PLR0;
ev += player_no;
mEv_EventOFF(ev);
}
}
extern void mEv_SetGateway() {
u32 player_no = Common_Get(player_no);
if (player_no < TOTAL_PLAYER_NUM) {
u32 ev = mEv_SAVED_GATEWAY_PLR0;
ev += player_no;
mEv_EventON(ev);
}
}
extern int mEv_CheckGateway() {
u32 player_no = Common_Get(player_no);
int res = FALSE;
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() {
u32 player_no = Common_Get(player_no);
if (player_no < TOTAL_PLAYER_NUM) {
u32 ev = mEv_SAVED_GATEWAY_PLR0;
ev += player_no;
mEv_EventOFF(ev);
}
}
static int title_demo_number = -1;
extern int mEv_CheckTitleDemo() {
return title_demo_number;
}
extern void mEv_SetTitleDemo(int demo_number) {
title_demo_number = 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++) {
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(check_event);
mEv_EventON(mEv_SAVED_HRATALK_PLR0 + i);
}
}
}
}
extern void mEv_GetEventWeather(s16* weather, s16* intensity) {
intensity[0] = mEnv_WEATHER_INTENSITY_HEAVY;
if (mEv_check_schedule(mEv_EVENT_WEATHER_CLEAR)) {
weather[0] = mEnv_WEATHER_CLEAR;
}
else if (mEv_check_schedule(mEv_EVENT_WEATHER_SNOW)) {
weather[0] = mEnv_WEATHER_SNOW;
}
else if (mEv_check_schedule(mEv_EVENT_WEATHER_SPORTS_FAIR)) {
weather[0] = mEnv_WEATHER_CLEAR;
}
else {
weather[0] = -1; // no event weather
}
}
#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_year_t year = Common_Get(time.rtc_time.year);
lbRTC_day_t day = last_day[month - 1];
if (month != lbRTC_FEBRUARY) {
return day;
}
else if (lbRTC_IS_LEAPYEAR(year)) {
return 29;
}
else {
return 28;
}
}
static void init_weekday1st() {
lbRTC_time_c* rtc_time = Common_GetPointer(time.rtc_time);
lbRTC_month_t month;
lbRTC_month_t temp;
lbRTC_month_t i;
int weekday;
month = rtc_time->month & 0xF;
weekday1st_year = rtc_time->year;
weekday = (rtc_time->weekday + (1 - rtc_time->day)) % lbRTC_WEEK;
if (weekday < 0) {
weekday += lbRTC_WEEK;
}
weekday1st[month] = weekday;
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 (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[temp] = weekday;
}
}
static int check_date_range(u16 date, u16 lower_bound, u16 upper_bound) {
int res;
if (lower_bound > upper_bound) {
res = FALSE;
if (lower_bound <= date || date <= upper_bound) {
res = TRUE;
}
}
else {
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 (lower_bound <= ymdh && ymdh <= upper_bound) {
res = TRUE;
}
return res;
}
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) {
day = last_day_of_month(after.month);
after.day = after.day + n_day;
if (after.day > day) {
if (after.month == lbRTC_DECEMBER) {
after.month = lbRTC_JANUARY;
}
else {
after.month++;
}
after.day -= day;
}
}
else {
after.day = after.day + n_day;
if ((after.day & 0x80) != 0 || after.day == 0) {
if (after.month == lbRTC_JANUARY) {
after.month = lbRTC_DECEMBER;
}
else {
after.month--;
}
day = last_day_of_month(after.month);
after.day += day;
}
}
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 >= rtc_time->weekday) {
day = rtc_time->day + (weekday - rtc_time->weekday);
}
else {
day = rtc_time->day + (lbRTC_WEEK - (rtc_time->weekday - weekday));
}
last_day = last_day_of_month(rtc_time->month);
if (day > last_day) {
day -= last_day;
}
return day;
}
#define mEv_date_decode_weekday(day) ((day) & 0b00000111) // 0-6 (which weekday, Sunday-Saturday)
#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;
int last_day = last_day_of_month(month);
if (week == mEv_SCHEDULE_EVERY_WEEK) {
if (month > rtc_time->month) {
week = 1; /* 1st week of this month */
}
else if (month < rtc_time->month) {
week = mEv_SCHEDULE_LAST_WEEKDAY_OF_MONTH; /* last weekday of the month */
}
else {
day = rtc_time->day - (rtc_time->weekday - weekday);
if (day > (u8)last_day) {
week = mEv_SCHEDULE_LAST_WEEKDAY_OF_MONTH;
}
else {
week = 0; /* cleared */
}
}
}
if (week == mEv_SCHEDULE_LAST_WEEKDAY_OF_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 (weekday <= t_day) {
day = d - (t_day - weekday);
}
else {
day = (d - (t_day - weekday)) - lbRTC_WEEK;
}
}
else if (week != 0) {
int t_day = weekday1st[month];
if (weekday >= t_day) {
day = 1 + (week - 1) * lbRTC_WEEK + (weekday - t_day);
}
else {
day = 1 + week * lbRTC_WEEK + (weekday - t_day);
}
}
return day;
}
static lbRTC_weekday_t weekday1st[lbRTC_MONTHS_MAX];
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 < rtc_time->month) {
week = mEv_SCHEDULE_LAST_WEEKDAY_OF_MONTH; /* last weekday of the month */
}
else {
day = rtc_time->day - (rtc_time->weekday - weekday);
week = 0; /* cleared */
}
}
if (week == mEv_SCHEDULE_LAST_WEEKDAY_OF_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 (weekday <= t_day) {
day = last_day - (t_day - weekday);
}
else {
day = (last_day - (t_day - weekday)) - lbRTC_WEEK;
}
}
else if (week != 0) {
int t_day = weekday1st[month];
if (weekday >= t_day) {
day = 1 + (week - 1) * lbRTC_WEEK + (weekday - t_day);
}
else {
day = 1 + week * lbRTC_WEEK + (weekday - t_day);
}
}
return day;
}
static int get_end_time(u32 active_hours) {
int hour;
int i;
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)) != 0) {
break;
}
active_hours <<= 1; /* move hours left by one bit, MSB is latest hour */
hour--;
}
return hour;
}
static mEv_event_today_c event_today[mEv_TODAY_EVENT_NUM];
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(ev_today->active_hours);
}
}
static int search_empty_event_today() {
int i;
for (i = 0; i < mEv_TODAY_EVENT_NUM; i++) {
if (event_today[i].type == -1) {
return i;
}
}
return i;
}
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) {
ev_today = &event_today[idx];
res = FALSE;
}
else {
int idx = search_empty_event_today();
if (idx >= mEv_TODAY_EVENT_NUM) {
return FALSE;
}
index_today[schedule->type] = idx;
ev_today = &event_today[idx];
n_today_events++;
}
{
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) {
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 != schedule->date[0].md) {
start_hour = 0;
}
if (month_day != schedule->date[1].md) {
end_hour = 23;
}
}
n = 1;
for (i = 0; i < 24; i++) {
if (start_hour <= i && i <= end_hour) {
ev_today->active_hours |= n;
}
n <<= 1;
}
}
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[type];
if (idx != 0xFF) {
mEv_event_today_c* today_event = &event_today[idx];
if ((today_event->status & mEv_STATUS_EXIST) == FALSE) {
int flags = 0;
mEv_place_data_c* place = mEv_get_common_place(today_event->type, 81);
if (place != NULL && place->block.x == event->block_x && place->block.z == event->block_z) {
flags |= 0b00000001; // 1, in the block the event is supposed to exist
}
if (mEv_check_status(today_event->type, mEv_STATUS_RUN)) {
flags |= 0b00000010; // 2, event is currently running
today_event->active_hours = 0x20000000;
}
if (type == today_event->type && flags == 0) {
today_event->type = -1;
today_event->active_hours = 0;
today_event->end_date.raw = 0;
today_event->status = 0;
n_today_events--;
index_today[type] = 0xFF;
return TRUE;
}
}
}
return FALSE;
}
static int delete_too_short_event(Event_c* event, int type, u32 date) {
u8 idx = index_today[type];
if (idx != 0xFF) {
mEv_event_today_c* today_event = &event_today[idx];
mEv_schedule_date_u new_date;
switch (today_event->type) {
case mEv_EVENT_NEW_YEARS_DAY:
case mEv_EVENT_GROUNDHOG_DAY:
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_CHERRY_BLOSSOM_FESTIVAL:
case mEv_EVENT_FISHING_TOURNEY_1:
case mEv_EVENT_FIREWORKS_SHOW:
case mEv_EVENT_MORNING_AEROBICS:
case mEv_EVENT_HARVEST_MOON_FESTIVAL:
case mEv_EVENT_FISHING_TOURNEY_2:
case mEv_EVENT_HARVEST_FESTIVAL:
{
new_date.raw = date;
new_date.d.hour = mEv_get_end_time(today_event->type);
break;
}
case mEv_EVENT_HALLOWEEN:
case mEv_EVENT_TOY_DAY_JINGLE:
case mEv_EVENT_NEW_YEARS_EVE_COUNTDOWN:
{
new_date.raw = 0;
new_date.md = today_event->end_date.raw;
new_date.d.hour = mEv_get_end_time(today_event->type);
break;
}
default:
{
return FALSE;
}
}
if (new_date.raw != date) {
return FALSE;
}
if (Common_Get(time.rtc_time).min < 55) {
return FALSE;
}
Common_Get(event_common).too_short = type;
}
return TRUE;
}
static void init_today_event() {
int i;
for (i = 0; i < mEv_TODAY_EVENT_NUM; i++) {
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;
for (i = 0; i < mEv_EVENT_NUM; i++) {
index_today[i] = 0xFF;
}
}
static void init_time_seat() {
int i;
for (i = 0; i < mEv_TODAY_EVENT_NUM; i++) {
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;
}
}
static int get_special_event_end_time(s16 event_type) {
int end_time = 0;
switch (event_type) {
case mEv_EVENT_DESIGNER:
end_time = 5;
break;
case mEv_EVENT_ARTIST:
end_time = 5;
break;
case mEv_EVENT_CARPET_PEDDLER:
end_time = 5;
break;
case mEv_EVENT_GYPSY:
end_time = 20;
break;
case mEv_EVENT_BROKER_SALE:
end_time = 17;
break;
case mEv_EVENT_SHOP_SALE:
end_time = 23;
break;
}
return end_time;
}
#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 (Common_Get(last_scene_no)) {
case SCENE_BUGGY:
case SCENE_BROKER_SHOP:
{
if (gamePT->frame_counter == 0) {
return FALSE;
}
break;
}
}
switch (Save_Get(scene_no)) {
case SCENE_BUGGY:
case SCENE_BROKER_SHOP:
return FALSE;
case SCENE_SHOP0:
case SCENE_CONVENI:
case SCENE_SUPER:
case SCENE_DEPART:
case SCENE_DEPART_2:
{
if (Save_Get(event_save_common).special_event.type == mEv_EVENT_SHOP_SALE) {
return FALSE;
}
}
// 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);
}