From 42642aa339bb05b6626d8527ae52c4fefc72b865 Mon Sep 17 00:00:00 2001 From: Cuyler36 Date: Tue, 4 Apr 2023 05:50:31 -0400 Subject: [PATCH] Implement m_time.c --- config/rel_slices.yml | 5 + include/game.h | 2 + include/m_common_data.h | 12 +- include/m_field_info.h | 28 +++ include/m_kabu_manager.h | 16 ++ include/m_time.h | 76 ++++++ rel/m_time.c | 509 +++++++++++++++++++++++++++++++++++++++ 7 files changed, 643 insertions(+), 5 deletions(-) create mode 100644 include/m_field_info.h create mode 100644 include/m_kabu_manager.h create mode 100644 include/m_time.h create mode 100644 rel/m_time.c diff --git a/config/rel_slices.yml b/config/rel_slices.yml index 9f8f3737..48c1843d 100644 --- a/config/rel_slices.yml +++ b/config/rel_slices.yml @@ -2,6 +2,11 @@ sys_vimgr.c: .text: [0x803703F8, 0x80370418] m_room_type/mRmTp_FtrItemNo2FtrIdx.c: .text: [0x803E7878, 0x803E78BC] +m_time.c: + .text: [0x803F33DC, 0x803F3E58] + .rodata: [0x806433B0, 0x806433D8] + .data: [0x8065E378, 0x8065E438] + .bss: [0x81294008, 0x81294018] #m_skin_matrix.c: # .text: [0x803f1528, 0x803f1bb4] # .rodata: [0x80643310, 0x80643318] diff --git a/include/game.h b/include/game.h index d0e80f90..20973f5e 100644 --- a/include/game.h +++ b/include/game.h @@ -56,6 +56,8 @@ extern void game_get_controller(GAME* game); extern GAME* game_class_p; +extern GAME* gamePT; + #ifdef __cplusplus }; #endif diff --git a/include/m_common_data.h b/include/m_common_data.h index a8cf95d2..46394876 100644 --- a/include/m_common_data.h +++ b/include/m_common_data.h @@ -12,8 +12,8 @@ extern "C" { typedef struct time_s { u32 season; u32 term_idx; - s16 bg_item_profile; - s16 bg_item_bank; + s16 bgitem_profile; + s16 bgitem_bank; int now_sec; lbRTC_time_c rtc_time; s16 rad_min; /* clock hand radial position for mins */ @@ -28,9 +28,11 @@ typedef struct time_s { } Time_c; typedef struct Save_s { - u8 _tmp0[0x22528]; - OSTime time_delta; - u8 _tmp1[0x3AD0]; + u8 _tmp0[0x20F14]; + /* 0x020F14 */ lbRTC_ymd_t renew_time; + u8 _tmp1[0x1610]; + /* 0x022528 */ OSTime time_delta; + u8 _tmp2[0x3AD0]; } Save_t; typedef union save_u { diff --git a/include/m_field_info.h b/include/m_field_info.h new file mode 100644 index 00000000..f9c8bfcb --- /dev/null +++ b/include/m_field_info.h @@ -0,0 +1,28 @@ +#ifndef M_FIELD_INFO_H +#define M_FIELD_INFO_H + +#include "types.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Not sure about these other than the island one */ +enum { + mFI_CLIMATE_0, + mFI_CLIMATE_ISLAND, + mFI_CLIMATE_2, + mFI_CLIMATE_3, + mFI_CLIMATE_4, + mFI_CLIMATE_5, + mFI_CLIMATE_NUM +}; + +extern int mFI_GetClimate(); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/m_kabu_manager.h b/include/m_kabu_manager.h new file mode 100644 index 00000000..7a7c6059 --- /dev/null +++ b/include/m_kabu_manager.h @@ -0,0 +1,16 @@ +#ifndef M_KABU_MANAGER_H +#define M_KABU_MANAGER_H + +#include "types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern void Kabu_manager(); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/m_time.h b/include/m_time.h new file mode 100644 index 00000000..3a680933 --- /dev/null +++ b/include/m_time.h @@ -0,0 +1,76 @@ +#ifndef M_TIME_H +#define M_TIME_H + +#include "types.h" +#include "lb_rtc.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define mTM_MIN_YEAR 2001 +#define mTM_MAX_YEAR 2030 + +enum { + mTM_SEASON_BEGIN = 0, + mTM_SEASON_SPRING = mTM_SEASON_BEGIN, + mTM_SEASON_SUMMER, + mTM_SEASON_AUTUMN, + mTM_SEASON_WINTER, + mTM_SEASON_NUM +}; + +enum { + mTM_TERM_BEGIN = 0, + mTM_TERM_0 = mTM_TERM_BEGIN, + mTM_TERM_1, + mTM_TERM_2, + mTM_TERM_3, + mTM_TERM_4, + mTM_TERM_5, + mTM_TERM_6, + mTM_TERM_7, + mTM_TERM_8, + mTM_TERM_9, + mTM_TERM_10, + mTM_TERM_11, + mTM_TERM_12, + mTM_TERM_13, + mTM_TERM_14, + mTM_TERM_15, + mTM_TERM_16, + mTM_TERM_17, + mTM_TERM_NUM +}; + +#define mTM_RENEW_TIME_NONE 0 +#define mTM_RENEW_TIME_ALL 0xFF + +enum { + mTM_RENEW_TIME_BEGIN = 0, + mTM_RENEW_TIME_WEATHER = mTM_RENEW_TIME_BEGIN, + mTM_RENEW_TIME_DAILY +}; + +#define mTM_SECONDS_IN_MINUTE 60 +#define mTM_SECONDS_IN_HOUR 60*60 +#define mTM_SECONDS_IN_HALFDAY 12*60*60 +#define mTM_SECONDS_IN_DAY 24*60*60 + +typedef struct time_calendar_term_s { + lbRTC_month_t month; + lbRTC_day_t day; + u16 season; + s16 bgitem_profile; + s16 bgitem_bank; +} mTM_calendar_term_t; + +extern const lbRTC_time_c mTM_rtcTime_clear_code; +extern const lbRTC_ymd_t mTM_rtcTime_ymd_clear_code; +extern const lbRTC_time_c mTM_rtcTime_default_code; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/rel/m_time.c b/rel/m_time.c new file mode 100644 index 00000000..3b43229c --- /dev/null +++ b/rel/m_time.c @@ -0,0 +1,509 @@ +#include "m_time.h" + +#include "game.h" +#include "gfxalloc.h" +#include "libu64/gfxprint.h" +#include "m_common_data.h" +#include "m_debug.h" +#include "m_field_info.h" +#include "m_kabu_manager.h" +#include "zurumode.h" + +const lbRTC_time_c mTM_rtcTime_clear_code = { + 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, + 0xFFFF +}; + +const lbRTC_ymd_t mTM_rtcTime_ymd_clear_code = { + 0xFFFF, + 0xFF, 0xFF +}; + +const lbRTC_time_c mTM_rtcTime_default_code = { + 0, 0, 12, + 1, 6, 1, + 2000 +}; + +static mTM_calendar_term_t mTM_calender[mTM_TERM_NUM] = { + { + 2, 3, + mTM_SEASON_WINTER, + 0x0050, 0x0025 + }, + { + 2, 17, + mTM_SEASON_WINTER, + 0x0050, 0x0025 + }, + { + 2, 24, + mTM_SEASON_WINTER, + 0x0050, 0x0025 + }, + { + 3, 31, + mTM_SEASON_SPRING, + 0x0001, 0x0004 + }, + { + 4, 8, + mTM_SEASON_SPRING, + 0x004f, 0x0024 + }, + { + 5, 25, + mTM_SEASON_SPRING, + 0x0001, 0x0004 + }, + { + 7, 22, + mTM_SEASON_SUMMER, + 0x0001, 0x0004 + }, + { + 8, 31, + mTM_SEASON_SUMMER, + 0x0001, 0x0004 + }, + { + 9, 15, + mTM_SEASON_SUMMER, + 0x0001, 0x0004 + }, + { + 9, 30, + mTM_SEASON_AUTUMN, + 0x0001, 0x0004 + }, + { + 10, 15, + mTM_SEASON_AUTUMN, + 0x0001, 0x0004 + }, + { + 10, 29, + mTM_SEASON_AUTUMN, + 0x0001, 0x0004 + }, + { + 11, 12, + mTM_SEASON_AUTUMN, + 0x0001, 0x0004 + }, + { + 11, 28, + mTM_SEASON_AUTUMN, + 0x0001, 0x0004 + }, + { + 12, 9, + mTM_SEASON_AUTUMN, + 0x0001, 0x0004 + }, + { + 12, 17, + mTM_SEASON_WINTER, + 0x0051, 0x0026 + }, + { + 12, 25, + mTM_SEASON_WINTER, + 0x0051, 0x0026 + }, + { + 12, 31, + mTM_SEASON_WINTER, + 0x0050, 0x0025 + } +}; + +static u8 l_renew_is; +static int debug_disp; + +/** + * Get the index of the current term based on the current date and climate. + * + * @return The index of the current term. + */ +static int mTM_get_termIdx() { + lbRTC_month_t month = Common_Get(time.rtc_time.month); + lbRTC_day_t day = Common_Get(time.rtc_time.day); + mTM_calendar_term_t* term_info = mTM_calender; + int term; + + + if (mFI_GetClimate() == mFI_CLIMATE_ISLAND) { + return mTM_TERM_7; + } + + for (term = 0; term < mTM_TERM_NUM; term_info++, term++) { + if (month < term_info->month || (month == term_info->month && day <= term_info->day)) { + return term; + } + } + + return -1; +} + +/** + * Set the season, term index, and background item properties based on the term index provided. + * + * @param term_idx The index of the term used to set the season and associated properties. + */ +extern void mTM_set_season_com(int term_idx) { + const mTM_calendar_term_t* term_info = mTM_calender + term_idx; + + Common_Set(time.season, term_info->season); + Common_Set(time.term_idx, term_idx); + Common_Set(time.bgitem_profile, term_info->bgitem_profile); + Common_Set(time.bgitem_bank, term_info->bgitem_bank); +} + +/** + * Set the season and associated properties based on the current date and climate. + */ +extern void mTM_set_season() { + mTM_set_season_com(mTM_get_termIdx()); +} + +/** + * Clear the renewal flags. + */ +extern void mTM_clear_renew_is() { + l_renew_is = 0; +} + +/** + * Check if a given renew_flag is set. + * + * @param renew_flag The flag to check for renewal status. + * @return TRUE if the renew_flag is set, FALSE otherwise. + */ +extern int mTM_check_renew_time(u8 renew_flag) { + int renew = FALSE; + + if (((l_renew_is >> renew_flag) & 1) == 1) { + renew = TRUE; + } + + return renew; +} + +/** + * Turn off a given renew_flag. + * + * @param renew_flag The flag to be turned off. + */ +extern void mTM_off_renew_time(u8 renew_flag) { + l_renew_is &= ~(1 << renew_flag); +} + +/** + * Set all the renewal flags. + */ +extern void mTM_set_renew_is() { + l_renew_is = mTM_RENEW_TIME_ALL; +} + + +/** + * Set the renewal time based on the given lbRTC_time_c struct. + * + * @param renew_time Pointer to the lbRTC_ymd_t struct where the renewal time will be stored. + * @param time Pointer to the lbRTC_time_c struct from which the renewal time will be taken. + */ +extern void mTM_set_renew_time(lbRTC_ymd_t* renew_time, const lbRTC_time_c* time) { + renew_time->year = time->year; + renew_time->month = time->month; + renew_time->day = time->day; +} + +/** + * Convert lbRTC_ymd_t to lbRTC_time_c, setting time to midnight and calculating the weekday. + * + * @param time Pointer to the lbRTC_time_c struct where the converted time will be stored. + * @param ymd Pointer to the lbRTC_ymd_t struct containing the date to be converted. + */ +extern void mTM_ymd_2_time(lbRTC_time_c* time, const lbRTC_ymd_t* ymd) { + time->year = ymd->year; + time->month = ymd->month; + time->day = ymd->day; + time->hour = 0; + time->min = 0; + time->sec = 0; + time->weekday = lbRTC_Week(ymd->year, ymd->month, ymd->day); +} + +/** + * Check if the renewal time has changed, and if so, update the renewal time and set renewal flags. + */ +extern void mTM_renewal_renew_time() { + lbRTC_ymd_t* renew_time = Save_GetPointer(renew_time); + const lbRTC_time_c* rtc_time = Common_GetPointer(time.rtc_time); + + // Check if the renewal time has changed + if ( + (renew_time->year != rtc_time->year) || + (renew_time->month != rtc_time->month) || + (renew_time->day != rtc_time->day) + ) { + // If the renewal time has changed, update the renewal time and set renewal flags + mTM_set_renew_time(renew_time, rtc_time); + mTM_set_renew_is(); + } +} + +// TODO: Hack. This fixes an issue where pooling data is necessary. +#pragma pool_data on +/** + * Display the current time in debug mode if certain conditions are met. + * + * @param unused An unused parameter. + */ +static void mTM_disp_time(int unused) { + static int disp; + + // Check if debug mode is enabled and the appropriate button is pressed + if (Common_Get(time.add_idx) != 1 && zurumode_flag != 0 && (gamePT->pads[1].on.button & BUTTON_A) == BUTTON_A) { + disp ^= TRUE; + Common_Set(time.disp, disp); + } + + // If the display flag is set, draw the time on screen + if (Common_Get(time.disp) == TRUE) { + gfxprint_t gfxprint; + GRAPH* g; + Gfx* line_xlu; + Gfx* line_opa; + Gfx* gfx_temp; + + g = gamePT->graph; + gfxprint_init(&gfxprint); + + OPEN_DISP(g); + + line_xlu = NOW_LINE_XLU_DISP; + gfx_temp = gfxopen(line_xlu); + + gSPDisplayList(NOW_LINE_OPA_DISP++, gfx_temp); + + /* Debug mode draw time in format: YYYY MM/DD hh:mm ss */ + gfxprint_open(&gfxprint, gfx_temp); + gfxprint_color(&gfxprint, 255, 255, 255, 255); /* White */ + gfxprint_locate8x8(&gfxprint, 3, 3); + gfxprint_printf(&gfxprint, "%04d", Common_Get(time.rtc_time.year)); + gfxprint_locate8x8(&gfxprint, 8, 3); + gfxprint_printf(&gfxprint, "%02d/", Common_Get(time.rtc_time.month)); + gfxprint_locate8x8(&gfxprint, 11, 3); + gfxprint_printf(&gfxprint, "%02d", Common_Get(time.rtc_time.day)); + gfxprint_locate8x8(&gfxprint, 14, 3); + gfxprint_printf(&gfxprint, "%02d:", Common_Get(time.rtc_time.hour)); + gfxprint_locate8x8(&gfxprint, 17, 3); + gfxprint_printf(&gfxprint, "%02d", Common_Get(time.rtc_time.min)); + gfxprint_locate8x8(&gfxprint, 20, 3); + gfxprint_printf(&gfxprint, "%02d", Common_Get(time.rtc_time.sec)); + + gfx_temp = gfxprint_close(&gfxprint); + gSPEndDisplayList(gfx_temp++); + gfxclose(line_xlu, gfx_temp); + NOW_LINE_XLU_DISP = gfx_temp; + gfxprint_cleanup(&gfxprint); + + CLOSE_DISP(g); + } +} +#pragma pool_data reset + +#define mTM_TIMESTEP_NUM 4 + +/** + * Control the time step based on certain input conditions. + * + * @return TRUE if the time step control is active, FALSE otherwise. + */ +static int mTM_TimestepControl() { + // Define time step values and an index for tracking the current time step + static int timestep[mTM_TIMESTEP_NUM] = {2, 4, 120, 240}; + static int id; + + int add_sec; + int tstep; + + // Check if certain input conditions are met, and if so, adjust the time step and flags accordingly + if (zurumode_flag >= 2 && debug_disp == 1 && (gamePT->pads[1].on.button & BUTTON_R) == BUTTON_R) { + if (id < mTM_TIMESTEP_NUM) { + Common_Set(time.rtc_crashed, TRUE); + + tstep = timestep[id]; + Common_Set(time.add_sec, tstep); + + add_sec = tstep - 1; + if (add_sec > 10) { + add_sec = 10; + } + + SETREG(SREG, 3, add_sec); + id++; + } else { + Common_Set(time.rtc_crashed, FALSE); + Common_Set(time.add_idx, 0); + lbRTC_SetTime(Common_GetPointer(time.rtc_time)); + + SETREG(SREG, 3, 0); + id = 0; + } + } + + return id != 0; +} + +#define mTM_SECONDS_IN_HOUR_F 3600.0f +#define mTM_SECONDS_IN_HALFDAY_F 43200.0f +#define SHORT_ANGLE_MAX 65536.0f + +/** + * Initialize time-related values. + */ +extern void mTM_time_init() { + u8 day; + int add_sec; + int add_min; + int time_add_sec; + int temp;; + + day = Common_Get(time.rtc_time.day); + if (Common_Get(time.rtc_enabled) == TRUE && Common_Get(time.rtc_crashed) == FALSE) { + // If the RTC is enabled and not crashed, get the current time + lbRTC_GetTime(Common_GetPointer(time.rtc_time)); + } + else { + // Else, calculate the time based on the stored values + add_sec = Common_Get(time.under_sec); + add_sec += Common_Get(time.add_sec); + add_min = add_sec / mTM_SECONDS_IN_MINUTE; + + for (time_add_sec = 0; add_sec >= 60; add_min--) { + add_sec -= mTM_SECONDS_IN_MINUTE; + time_add_sec++; + } + + + lbRTC_Add_ss(Common_GetPointer(time.rtc_time), time_add_sec); + Common_Set(time.rtc_time.weekday, lbRTC_Week(Common_Get(time.rtc_time.year), Common_Get(time.rtc_time.month), Common_Get(time.rtc_time.day))); + Common_Set(time.under_sec, add_sec); + } + + // Update current time and trigger Stalk Market change if the day changed + Common_Set(time.now_sec, Common_Get(time.rtc_time.sec) + Common_Get(time.rtc_time.min) * mTM_SECONDS_IN_MINUTE + Common_Get(time.rtc_time.hour) * mTM_SECONDS_IN_HOUR); + if (Common_Get(time.rtc_time.day) != day) { + Kabu_manager(); + } + + // Calculate rad_hour and rad_min values for clock hands + temp = Common_Get(time.rtc_time.sec) + Common_Get(time.rtc_time.min) * mTM_SECONDS_IN_MINUTE; + Common_Set(time.rad_min, (temp / mTM_SECONDS_IN_HOUR_F) * SHORT_ANGLE_MAX); + Common_Set(time.rad_hour, ((temp + Common_Get(time.rtc_time.hour) * mTM_SECONDS_IN_HOUR) / mTM_SECONDS_IN_HALFDAY_F) * SHORT_ANGLE_MAX); +} + +/** + * Update time-related values and handle debug display. + */ +extern void mTM_time() { + lbRTC_day_t day; + int add_sec; + int add_min; + int time_add_sec; + int temp; + + day = Common_Get(time.rtc_time.day); + + // Control the time step based on certain input conditions + mTM_TimestepControl(); + + if (Common_Get(time.rtc_enabled) == TRUE && Common_Get(time.rtc_crashed) == FALSE) { + // If the RTC is enabled and not crashed, get the current time and handle debug display + lbRTC_GetTime(Common_GetPointer(time.rtc_time)); + if (zurumode_flag != 0 && (gamePT->pads[1].on.button & BUTTON_A) == BUTTON_A) { + debug_disp ^= TRUE; + } + + if (debug_disp == TRUE) { + mTM_disp_time(0); + } + } + else { + // Else, calculate the time based on the stored values and handle debug display + add_sec = Common_Get(time.under_sec); + add_sec += Common_Get(time.add_sec); + add_min = add_sec / mTM_SECONDS_IN_MINUTE; + + for (time_add_sec = 0; add_sec >= 60; add_min--) { + add_sec -= mTM_SECONDS_IN_MINUTE; + time_add_sec++; + } + + lbRTC_Add_ss(Common_GetPointer(time.rtc_time), time_add_sec); + Common_Set( + time.rtc_time.weekday, + lbRTC_Week( + Common_Get(time.rtc_time.year), + Common_Get(time.rtc_time.month), + Common_Get(time.rtc_time.day) + ) + ); + + Common_Set(time.under_sec, add_sec); + + if (zurumode_flag != 0 && (gamePT->pads[1].on.button & BUTTON_A) == BUTTON_A) { + debug_disp ^= TRUE; + } + + if (debug_disp == TRUE) { + mTM_disp_time(add_sec); + } + } + + Common_Set( + time.now_sec, + Common_Get(time.rtc_time.sec) + + Common_Get(time.rtc_time.min) * mTM_SECONDS_IN_MINUTE + + Common_Get(time.rtc_time.hour) * mTM_SECONDS_IN_HOUR + ); + + // Update current time and trigger Stalk Market change if the day changed + if (Common_Get(time.rtc_time.day) != day) { + Kabu_manager(); + } + + // Calculate rad_hour and rad_min values for clock hands + temp = Common_Get(time.rtc_time.sec) + Common_Get(time.rtc_time.min) * mTM_SECONDS_IN_MINUTE; + Common_Set(time.rad_min, (temp / mTM_SECONDS_IN_HOUR_F) * SHORT_ANGLE_MAX); + Common_Set(time.rad_hour, ((temp + Common_Get(time.rtc_time.hour) * mTM_SECONDS_IN_HOUR) / mTM_SECONDS_IN_HALFDAY_F) * SHORT_ANGLE_MAX); + + // Check if the renewal time has changed, and if so, update the renewal time and set renewal flags + mTM_renewal_renew_time(); +} + +/** + * Check if the RTC time is within the allowed limits and adjust if necessary. + */ +extern void mTM_rtcTime_limit_check() { + lbRTC_time_c time; + + // Get the current time from the RTC + lbRTC_GetTime(&time); + + // Check if the year is within the allowed limits and adjust if necessary + if (time.year > mTM_MAX_YEAR) { + time.year = mTM_MAX_YEAR; + lbRTC_SetTime(&time); + return; + } + + if (time.year < mTM_MIN_YEAR) { + time.year = mTM_MIN_YEAR; + lbRTC_SetTime(&time); + } +}