diff --git a/include/datetime.h b/include/datetime.h new file mode 100644 index 0000000000..979fc47f6f --- /dev/null +++ b/include/datetime.h @@ -0,0 +1,28 @@ +#ifndef GUARD_DATETIME_H +#define GUARD_DATETIME_H + +#include "global.h" +#include "siirtc.h" + +struct DateTime +{ + u16 year; + enum Month month; + u8 day; + enum Weekday dayOfWeek; + u8 hour; + u8 minute; + u8 second; +}; + +extern const struct DateTime gGen3Epoch; + +void ConvertTimeToDateTime(struct DateTime *result, struct Time *timeSinceEpoch); +void DateTime_AddDays(struct DateTime *dateTime, u32 days); +void DateTime_AddHours(struct DateTime *dateTime, u32 hours); +void DateTime_AddMinutes(struct DateTime *dateTime, u32 minutes); +void DateTime_AddSeconds(struct DateTime *dateTime, u32 seconds); +void ConvertDateTimeToRtc(struct SiiRtcInfo *result, struct DateTime *dateTime); +void ConvertRtcToDateTime(struct DateTime *result, struct SiiRtcInfo *rtc); + +#endif // GUARD_DATETIME_H diff --git a/include/fake_rtc.h b/include/fake_rtc.h index d74849614e..92599b987a 100644 --- a/include/fake_rtc.h +++ b/include/fake_rtc.h @@ -3,10 +3,11 @@ #include "siirtc.h" -struct Time* FakeRtc_GetCurrentTime(void); +void FakeRtc_Reset(void); +struct SiiRtcInfo* FakeRtc_GetCurrentTime(void); void FakeRtc_GetRawInfo(struct SiiRtcInfo *rtc); -void FakeRtc_AdvanceTimeBy(u32 hours, u32 minutes, u32 seconds); -void FakeRtc_ManuallySetTime(u32 hour, u32 minute, u32 second); +void FakeRtc_AdvanceTimeBy(u32 days, u32 hours, u32 minutes, u32 seconds); +void FakeRtc_ManuallySetTime(u32 day, u32 hour, u32 minute, u32 second); void FakeRtc_TickTimeForward(void); u32 FakeRtc_GetSecondsRatio(void); diff --git a/include/global.h b/include/global.h index b263322651..ecf35b9777 100644 --- a/include/global.h +++ b/include/global.h @@ -5,6 +5,7 @@ #include #include "config/general.h" // we need to define config before gba headers as print stuff needs the functions nulled before defines. #include "gba/gba.h" +#include "siirtc.h" #include "fpmath.h" #include "metaprogram.h" #include "constants/global.h" @@ -205,7 +206,7 @@ struct Time struct SaveBlock3 { #if OW_USE_FAKE_RTC - struct Time fakeRTC; + struct SiiRtcInfo fakeRTC; #endif #if OW_SHOW_ITEM_DESCRIPTIONS == OW_ITEM_DESCRIPTIONS_FIRST_TIME u8 itemFlags[ITEM_FLAGS_COUNT]; diff --git a/include/rtc.h b/include/rtc.h index ba69286716..549ab9019b 100644 --- a/include/rtc.h +++ b/include/rtc.h @@ -98,6 +98,7 @@ enum TimeOfDay STATIC_ASSERT(OW_TIME_OF_DAY_DEFAULT == 0, TimeOfDayDefaultMustBeFirstElementInTimeOfDayEnum) extern struct Time gLocalTime; +extern const s32 sNumDaysInMonths[12]; void RtcDisableInterrupts(void); void RtcRestoreInterrupts(void); @@ -129,6 +130,10 @@ void CalcTimeDifference(struct Time *result, struct Time *t1, struct Time *t2); u32 RtcGetMinuteCount(void); u32 RtcGetLocalDayCount(void); void FormatDecimalTimeWithoutSeconds(u8 *dest, s8 hour, s8 minute, bool32 is24Hour); +u16 GetFullYear(void); +enum Month GetMonth(void); +u8 GetDay(void); +enum Weekday GetDayOfWeek(void); enum TimeOfDay TryIncrementTimeOfDay(enum TimeOfDay timeOfDay); enum TimeOfDay TryDecrementTimeOfDay(enum TimeOfDay timeOfDay); diff --git a/include/siirtc.h b/include/siirtc.h index ad13fc62f3..8e6958ca08 100644 --- a/include/siirtc.h +++ b/include/siirtc.h @@ -13,7 +13,19 @@ #define MINUTES_PER_HOUR 60 #define SECONDS_PER_MINUTE 60 -enum +enum Weekday +{ + WEEKDAY_SUN, + WEEKDAY_MON, + WEEKDAY_TUE, + WEEKDAY_WED, + WEEKDAY_THU, + WEEKDAY_FRI, + WEEKDAY_SAT, + WEEKDAY_COUNT, +}; + +enum Month { MONTH_JAN = 1, MONTH_FEB, diff --git a/src/datetime.c b/src/datetime.c new file mode 100644 index 0000000000..1f02813b69 --- /dev/null +++ b/src/datetime.c @@ -0,0 +1,115 @@ +#include "global.h" +#include "datetime.h" +#include "rtc.h" + + +const struct DateTime gGen3Epoch = +{ + .year = 2000, + .month = MONTH_JAN, + .day = 1, + .dayOfWeek = WEEKDAY_SAT, + .hour = 0, + .minute = 0, + .second = 0, +}; + +void DateTime_AddDays(struct DateTime *dateTime, u32 days) +{ + while (days > 0) + { + u32 remainingDaysInMonth = (sNumDaysInMonths[dateTime->month - 1] + (dateTime->month == MONTH_FEB && IsLeapYear(dateTime->year)) - dateTime->day); + + if (days > remainingDaysInMonth) + { + dateTime->day = 1; + dateTime->month++; + if (dateTime->month > MONTH_DEC) + { + dateTime->month = MONTH_JAN; + dateTime->year++; + } + days -= (remainingDaysInMonth + 1); + dateTime->dayOfWeek = (dateTime->dayOfWeek + remainingDaysInMonth + 1) % WEEKDAY_COUNT; + } + else + { + dateTime->day += days; + dateTime->dayOfWeek = (dateTime->dayOfWeek + days) % WEEKDAY_COUNT; + days = 0; + } + } +} + +void DateTime_AddHours(struct DateTime *dateTime, u32 hours) +{ + u32 days = 0; + + dateTime->hour += hours; + while (dateTime->hour >= HOURS_PER_DAY) + { + days++; + dateTime->hour -= HOURS_PER_DAY; + } + + DateTime_AddDays(dateTime, days); +} + +void DateTime_AddMinutes(struct DateTime *dateTime, u32 minutes) +{ + u32 hours = 0; + + dateTime->minute += minutes; + while(dateTime->minute >= MINUTES_PER_HOUR) + { + hours++; + dateTime->minute -= MINUTES_PER_HOUR; + } + + DateTime_AddHours(dateTime, hours); +} + +void DateTime_AddSeconds(struct DateTime *dateTime, u32 seconds) +{ + u32 minutes = 0; + + dateTime->second += seconds; + while(dateTime->second >= SECONDS_PER_MINUTE) + { + minutes++; + dateTime->second -= SECONDS_PER_MINUTE; + } + + DateTime_AddMinutes(dateTime, minutes); +} + +void ConvertDateTimeToRtc(struct SiiRtcInfo *result, struct DateTime *dateTime) +{ + result->second = dateTime->second; + result->minute = dateTime->minute; + result->hour = dateTime->hour; + result->day = dateTime->day; + result->dayOfWeek = dateTime->dayOfWeek; + result->month = dateTime->month; + result->year = dateTime->year - gGen3Epoch.year; +} + +void ConvertRtcToDateTime(struct DateTime *result, struct SiiRtcInfo *rtc) +{ + result->second = rtc->second; + result->minute = rtc->minute; + result->hour = rtc->hour; + result->day = rtc->day; + result->dayOfWeek = rtc->dayOfWeek; + result->month = rtc->month; + result->year = gGen3Epoch.year + rtc->year; +} + +void ConvertTimeToDateTime(struct DateTime *result, struct Time *timeSinceEpoch) +{ + result = memcpy(result, &gGen3Epoch, sizeof(struct DateTime)); + DateTime_AddSeconds(result, timeSinceEpoch->seconds); + DateTime_AddMinutes(result, timeSinceEpoch->minutes); + DateTime_AddHours(result, timeSinceEpoch->hours); + DateTime_AddDays(result, timeSinceEpoch->days); +} diff --git a/src/fake_rtc.c b/src/fake_rtc.c index 4dbf7837ba..e5c745bf1d 100644 --- a/src/fake_rtc.c +++ b/src/fake_rtc.c @@ -2,12 +2,24 @@ #include "string_util.h" #include "strings.h" #include "text.h" +#include "datetime.h" #include "rtc.h" #include "fake_rtc.h" #include "event_data.h" #include "script.h" -struct Time *FakeRtc_GetCurrentTime(void) +void FakeRtc_Reset(void) +{ +#if OW_USE_FAKE_RTC + memset(&gSaveBlock3Ptr->fakeRTC, 0, sizeof(gSaveBlock3Ptr->fakeRTC)); + gSaveBlock3Ptr->fakeRTC.year = 0; // offset by gGen3Epoch.year + gSaveBlock3Ptr->fakeRTC.month = gGen3Epoch.month; + gSaveBlock3Ptr->fakeRTC.day = gGen3Epoch.day; + gSaveBlock3Ptr->fakeRTC.dayOfWeek = gGen3Epoch.dayOfWeek; +#endif +} + +struct SiiRtcInfo *FakeRtc_GetCurrentTime(void) { #if OW_USE_FAKE_RTC return &gSaveBlock3Ptr->fakeRTC; @@ -18,11 +30,9 @@ struct Time *FakeRtc_GetCurrentTime(void) void FakeRtc_GetRawInfo(struct SiiRtcInfo *rtc) { - struct Time* time = FakeRtc_GetCurrentTime(); - rtc->second = time->seconds; - rtc->minute = time->minutes; - rtc->hour = time->hours; - rtc->day = time->days; + struct SiiRtcInfo *fakeRtc = FakeRtc_GetCurrentTime(); + if (fakeRtc != NULL) + memcpy(rtc, fakeRtc, sizeof(struct SiiRtcInfo)); } void FakeRtc_TickTimeForward(void) @@ -33,51 +43,31 @@ void FakeRtc_TickTimeForward(void) if (FlagGet(OW_FLAG_PAUSE_TIME)) return; - FakeRtc_AdvanceTimeBy(0, 0, FakeRtc_GetSecondsRatio()); + FakeRtc_AdvanceTimeBy(0, 0, 0, FakeRtc_GetSecondsRatio()); } -void FakeRtc_AdvanceTimeBy(u32 hours, u32 minutes, u32 seconds) +void FakeRtc_AdvanceTimeBy(u32 days, u32 hours, u32 minutes, u32 seconds) { - struct Time* time = FakeRtc_GetCurrentTime(); - seconds += time->seconds; - minutes += time->minutes; - hours += time->hours; + struct DateTime dateTime; + struct SiiRtcInfo *rtc = FakeRtc_GetCurrentTime(); - while(seconds >= SECONDS_PER_MINUTE) - { - minutes++; - seconds -= SECONDS_PER_MINUTE; - } - - while(minutes >= MINUTES_PER_HOUR) - { - hours++; - minutes -= MINUTES_PER_HOUR; - } - - while(hours >= HOURS_PER_DAY) - { - time->days++; - hours -= HOURS_PER_DAY; - } - - time->seconds = seconds; - time->minutes = minutes; - time->hours = hours; + ConvertRtcToDateTime(&dateTime, rtc); + DateTime_AddSeconds(&dateTime, seconds); + DateTime_AddMinutes(&dateTime, minutes); + DateTime_AddHours(&dateTime, hours); + DateTime_AddDays(&dateTime, days); + ConvertDateTimeToRtc(rtc, &dateTime); } -void FakeRtc_ManuallySetTime(u32 hour, u32 minute, u32 second) +void FakeRtc_ManuallySetTime(u32 day, u32 hour, u32 minute, u32 second) { - struct Time diff, target; - RtcCalcLocalTime(); + FakeRtc_Reset(); + FakeRtc_AdvanceTimeBy(day, hour, minute, second); +} - target.hours = hour; - target.minutes = minute; - target.seconds = second; - target.days = gLocalTime.days; - - CalcTimeDifference(&diff, &gLocalTime, &target); - FakeRtc_AdvanceTimeBy(diff.hours, diff.minutes, diff.seconds); +void AdvanceScript(void) +{ + FakeRtc_AdvanceTimeBy(300, 0, 0, 0); } u32 FakeRtc_GetSecondsRatio(void) diff --git a/src/load_save.c b/src/load_save.c index 9c94808536..e4f77911fc 100644 --- a/src/load_save.c +++ b/src/load_save.c @@ -1,6 +1,7 @@ #include "global.h" #include "malloc.h" #include "berry_powder.h" +#include "fake_rtc.h" #include "item.h" #include "load_save.h" #include "main.h" @@ -63,6 +64,7 @@ void CheckForFlashMemory(void) void ClearSav3(void) { CpuFill16(0, &gSaveblock3, sizeof(struct SaveBlock3)); + FakeRtc_Reset(); } void ClearSav2(void) diff --git a/src/reset_rtc_screen.c b/src/reset_rtc_screen.c index 98ccb71b64..4d3015fa19 100644 --- a/src/reset_rtc_screen.c +++ b/src/reset_rtc_screen.c @@ -1,6 +1,7 @@ #include "global.h" #include "reset_rtc_screen.h" #include "event_data.h" +#include "fake_rtc.h" #include "main.h" #include "menu.h" #include "palette.h" @@ -41,7 +42,10 @@ enum { #define tWindowId data[8] enum { - SELECTION_DAYS = 1, + SELECTION_DAYS_1000 = 1, + SELECTION_DAYS_100, + SELECTION_DAYS_10, + SELECTION_DAYS_1, SELECTION_HOURS, SELECTION_MINS, SELECTION_SECS, @@ -59,6 +63,7 @@ struct ResetRtcInputMap /*0x0*/ u8 dataIndex; /*0x2*/ u16 minVal; /*0x4*/ u16 maxVal; + u16 increment; /*0x6*/ u8 left; /*0x7*/ u8 right; /*0x8*/ u8 unk; // never read @@ -117,43 +122,75 @@ static const struct WindowTemplate sInputTimeWindow = { static const struct ResetRtcInputMap sInputMap[] = { - [SELECTION_DAYS - 1] = { + [SELECTION_DAYS_1000 - 1] = { .dataIndex = DATAIDX_DAYS, .minVal = 1, .maxVal = 9999, + .increment = 1000, .left = 0, .right = 2, .unk = 0, }, + [SELECTION_DAYS_100 - 1] = { + .dataIndex = DATAIDX_DAYS, + .minVal = 1, + .maxVal = 9999, + .increment = 100, + .left = 1, + .right = 3, + .unk = 0, + }, + [SELECTION_DAYS_10 - 1] = { + .dataIndex = DATAIDX_DAYS, + .minVal = 1, + .maxVal = 9999, + .increment = 10, + .left = 2, + .right = 4, + .unk = 0, + }, + [SELECTION_DAYS_1 - 1] = { + .dataIndex = DATAIDX_DAYS, + .minVal = 1, + .maxVal = 9999, + .increment = 1, + .left = 3, + .right = 5, + .unk = 0, + }, [SELECTION_HOURS - 1] = { .dataIndex = DATAIDX_HOURS, .minVal = 0, .maxVal = 23, - .left = 1, - .right = 3, + .increment = 1, + .left = 4, + .right = 6, .unk = 0, }, [SELECTION_MINS - 1] = { .dataIndex = DATAIDX_MINS, .minVal = 0, .maxVal = 59, - .left = 2, - .right = 4, + .increment = 1, + .left = 5, + .right = 7, .unk = 0, }, [SELECTION_SECS - 1] = { .dataIndex = DATAIDX_SECS, .minVal = 0, .maxVal = 59, - .left = 3, - .right = 5, + .increment = 1, + .left = 6, + .right = 8, .unk = 0, }, [SELECTION_CONFIRM - 1] = { .dataIndex = DATAIDX_CONFIRM, .minVal = 0, .maxVal = 0, - .left = 4, + .increment = 1, + .left = 7, .right = 0, .unk = 6, }, @@ -244,7 +281,28 @@ static void SpriteCB_Cursor_UpOrRight(struct Sprite *sprite) sprite->sState = state; switch (state) { - case SELECTION_DAYS: + case SELECTION_DAYS_1000: + sprite->invisible = FALSE; + sprite->animNum = ARROW_UP; + sprite->animDelayCounter = 0; + sprite->x = 35; + sprite->y = 68; + break; + case SELECTION_DAYS_100: + sprite->invisible = FALSE; + sprite->animNum = ARROW_UP; + sprite->animDelayCounter = 0; + sprite->x = 41; + sprite->y = 68; + break; + case SELECTION_DAYS_10: + sprite->invisible = FALSE; + sprite->animNum = ARROW_UP; + sprite->animDelayCounter = 0; + sprite->x = 47; + sprite->y = 68; + break; + case SELECTION_DAYS_1: sprite->invisible = FALSE; sprite->animNum = ARROW_UP; sprite->animDelayCounter = 0; @@ -294,7 +352,28 @@ static void SpriteCB_Cursor_Down(struct Sprite *sprite) sprite->sState = state; switch (state) { - case SELECTION_DAYS: + case SELECTION_DAYS_1000: + sprite->invisible = FALSE; + sprite->animNum = ARROW_DOWN; + sprite->animDelayCounter = 0; + sprite->x = 35; + sprite->y = 92; + break; + case SELECTION_DAYS_100: + sprite->invisible = FALSE; + sprite->animNum = ARROW_DOWN; + sprite->animDelayCounter = 0; + sprite->x = 41; + sprite->y = 92; + break; + case SELECTION_DAYS_10: + sprite->invisible = FALSE; + sprite->animNum = ARROW_DOWN; + sprite->animDelayCounter = 0; + sprite->x = 47; + sprite->y = 92; + break; + case SELECTION_DAYS_1: sprite->invisible = FALSE; sprite->animNum = ARROW_DOWN; sprite->animDelayCounter = 0; @@ -397,17 +476,17 @@ static void ShowChooseTimeWindow(u8 windowId, u16 days, u8 hours, u8 minutes, u8 ScheduleBgCopyTilemapToVram(0); } -static bool32 MoveTimeUpDown(s16 *val, int minVal, int maxVal, u16 keys) +static bool32 MoveTimeUpDown(s16 *val, int minVal, int maxVal, int increment, u16 keys) { if (keys & DPAD_DOWN) { - *val -= 1; + *val -= increment; if (*val < minVal) *val = maxVal; } else if (keys & DPAD_UP) { - *val += 1; + *val += increment; if (*val > maxVal) *val = minVal; } @@ -494,7 +573,7 @@ static void Task_ResetRtc_HandleInput(u8 taskId) tSelection = SELECTION_NONE; } } - else if (MoveTimeUpDown(&data[selectionInfo->dataIndex], selectionInfo->minVal, selectionInfo->maxVal, JOY_REPEAT(DPAD_UP | DPAD_DOWN))) + else if (MoveTimeUpDown(&data[selectionInfo->dataIndex], selectionInfo->minVal, selectionInfo->maxVal, selectionInfo->increment, JOY_REPEAT(DPAD_UP | DPAD_DOWN))) { PlaySE(SE_SELECT); PrintTime(tWindowId, 0, 1, tDays, tHours, tMinutes, tSeconds); diff --git a/src/rtc.c b/src/rtc.c index 10be64b31e..178e6b24ad 100644 --- a/src/rtc.c +++ b/src/rtc.c @@ -1,6 +1,7 @@ #include "global.h" #include "battle_pike.h" #include "battle_pyramid.h" +#include "datetime.h" #include "rtc.h" #include "string_util.h" #include "strings.h" @@ -21,7 +22,7 @@ COMMON_DATA struct Time gLocalTime = {0}; static const struct SiiRtcInfo sRtcDummy = {0, MONTH_JAN, 1}; // 2000 Jan 1 -static const s32 sNumDaysInMonths[MONTH_COUNT] = +const s32 sNumDaysInMonths[MONTH_COUNT] = { [MONTH_JAN - 1] = 31, [MONTH_FEB - 1] = 28, @@ -98,9 +99,6 @@ u16 RtcGetDayCount(struct SiiRtcInfo *rtc) { u8 year, month, day; - if (OW_USE_FAKE_RTC) - return rtc->day; - year = ConvertBcdToBinary(rtc->year); month = ConvertBcdToBinary(rtc->month); day = ConvertBcdToBinary(rtc->day); @@ -233,7 +231,7 @@ void RtcReset(void) { if (OW_USE_FAKE_RTC) { - memset(FakeRtc_GetCurrentTime(), 0, sizeof(struct Time)); + FakeRtc_Reset(); return; } @@ -421,6 +419,42 @@ void FormatDecimalTimeWithoutSeconds(u8 *txtPtr, s8 hour, s8 minute, bool32 is24 *txtPtr = EOS; } +u16 GetFullYear(void) +{ + struct DateTime dateTime; + RtcCalcLocalTime(); + ConvertTimeToDateTime(&dateTime, &gLocalTime); + + return dateTime.year; +} + +enum Month GetMonth(void) +{ + struct DateTime dateTime; + RtcCalcLocalTime(); + ConvertTimeToDateTime(&dateTime, &gLocalTime); + + return dateTime.month; +} + +u8 GetDay(void) +{ + struct DateTime dateTime; + RtcCalcLocalTime(); + ConvertTimeToDateTime(&dateTime, &gLocalTime); + + return dateTime.day; +} + +enum Weekday GetDayOfWeek(void) +{ + struct DateTime dateTime; + RtcCalcLocalTime(); + ConvertTimeToDateTime(&dateTime, &gLocalTime); + + return dateTime.dayOfWeek; +} + enum TimeOfDay TryIncrementTimeOfDay(enum TimeOfDay timeOfDay) { return timeOfDay == TIME_NIGHT ? TIME_MORNING : timeOfDay + 1;