diff --git a/include/z64schedule.h b/include/z64schedule.h index 07a942e903..aafa8520e9 100644 --- a/include/z64schedule.h +++ b/include/z64schedule.h @@ -28,10 +28,13 @@ */ // Macro to convert the time format used in the save struct into the format used in Schedule -#define SCHEDULE_CONVERT_TIME(time) ((u16)((time) - 0x10000 / 360 * 90)) +#define SCHEDULE_CONVERT_TIME(time) ((s32)((time) - 0x10000 / 360 * 90)) + +#define SCHEDULE_TIME(hour, minute) SCHEDULE_CONVERT_TIME((((hour)*60.0f) + (minute)) * (0x10000 / 60 / 24.0f)) + #define SCHEDULE_TIME_NOW SCHEDULE_CONVERT_TIME(gSaveContext.save.time) -typedef enum { +typedef enum ScheduleCommandId { /* 0x00 */ SCHEDULE_CMD_ID_CHECK_FLAG_S, // Checks if a weekEventReg flag is set and branches if so, short range branch /* 0x01 */ SCHEDULE_CMD_ID_CHECK_FLAG_L, // Checks if a weekEventReg flag is set and branches if so, long range branch /* 0x02 */ SCHEDULE_CMD_ID_CHECK_TIME_RANGE_S, // Checks if the current time is within the range of the two provided times and branches if so, short range branch diff --git a/src/code/z_kankyo.c b/src/code/z_kankyo.c index 30ea04e16b..6dda9090d1 100644 --- a/src/code/z_kankyo.c +++ b/src/code/z_kankyo.c @@ -702,9 +702,35 @@ s32 Environment_IsSceneUpsideDown(PlayState* play) { #pragma GLOBAL_ASM("asm/non_matchings/code/z_kankyo/Environment_UpdateSun.s") +void func_800F88C4(u16 weekEventFlag); #pragma GLOBAL_ASM("asm/non_matchings/code/z_kankyo/func_800F88C4.s") -#pragma GLOBAL_ASM("asm/non_matchings/code/z_kankyo/func_800F8970.s") +void func_800F8970(void) { + if (!CHECK_WEEKEVENTREG(WEEKEVENTREG_27_40) && (SCHEDULE_TIME_NOW >= SCHEDULE_TIME(9, 31))) { + SET_WEEKEVENTREG(WEEKEVENTREG_27_40); + func_800F88C4(WEEKEVENTREG_DEPOSITED_LETTER_TO_KAFEI_SOUTH_UPPER_CLOCKTOWN); + } + + if (!CHECK_WEEKEVENTREG(WEEKEVENTREG_27_80) && (SCHEDULE_TIME_NOW >= SCHEDULE_TIME(10, 3))) { + SET_WEEKEVENTREG(WEEKEVENTREG_27_80); + func_800F88C4(WEEKEVENTREG_DEPOSITED_LETTER_TO_KAFEI_NORTH_CLOCKTOWN); + } + + if (!CHECK_WEEKEVENTREG(WEEKEVENTREG_28_01) && (SCHEDULE_TIME_NOW >= SCHEDULE_TIME(10, 35))) { + SET_WEEKEVENTREG(WEEKEVENTREG_28_01); + func_800F88C4(WEEKEVENTREG_DEPOSITED_LETTER_TO_KAFEI_EAST_UPPER_CLOCKTOWN); + } + + if (!CHECK_WEEKEVENTREG(WEEKEVENTREG_28_02) && (SCHEDULE_TIME_NOW >= SCHEDULE_TIME(10, 53))) { + SET_WEEKEVENTREG(WEEKEVENTREG_28_02); + func_800F88C4(WEEKEVENTREG_DEPOSITED_LETTER_TO_KAFEI_EAST_LOWER_CLOCKTOWN); + } + + if (!CHECK_WEEKEVENTREG(WEEKEVENTREG_28_04) && (SCHEDULE_TIME_NOW >= SCHEDULE_TIME(11, 25))) { + SET_WEEKEVENTREG(WEEKEVENTREG_28_04); + func_800F88C4(WEEKEVENTREG_DEPOSITED_LETTER_TO_KAFEI_SOUTH_LOWER_CLOCKTOWN); + } +} #pragma GLOBAL_ASM("asm/non_matchings/code/z_kankyo/Environment_UpdatePostmanEvents.s") diff --git a/src/code/z_schedule.c b/src/code/z_schedule.c index fdefb0f426..38bcb58c32 100644 --- a/src/code/z_schedule.c +++ b/src/code/z_schedule.c @@ -4,7 +4,7 @@ (temp) = (hour)*60.0f; \ (temp) += (minute); \ (dest) = (temp) * (0x10000 / 60 / 24.0f); \ - (dest) = SCHEDULE_CONVERT_TIME(dest); + (dest) = SCHEDULE_CONVERT_TIME(dest) s32 Schedule_CheckFlagS(PlayState* play, u8** script, ScheduleOutput* output) { ScheduleCmdCheckFlagS* cmd = (ScheduleCmdCheckFlagS*)*script; @@ -239,34 +239,50 @@ s32 Schedule_BranchL(PlayState* play, u8** script, ScheduleOutput* output) { return false; } -static s32 (*sScheduleCmdFuncs[])(PlayState*, u8**, ScheduleOutput*) = { - Schedule_CheckFlagS, Schedule_CheckFlagL, Schedule_CheckTimeRangeS, Schedule_CheckTimeRangeL, - Schedule_ReturnValueL, Schedule_ReturnNone, Schedule_ReturnEmpty, Schedule_Nop, - Schedule_CheckMiscS, Schedule_ReturnValueS, Schedule_CheckNotInSceneS, Schedule_CheckNotInSceneL, - Schedule_CheckNotInDayS, Schedule_CheckNotInDayL, Schedule_ReturnTime, Schedule_CheckBeforeTimeS, - Schedule_CheckBeforeTimeL, Schedule_BranchS, Schedule_BranchL, +typedef s32 (*ScheduleCmdFunc)(PlayState*, u8**, ScheduleOutput*); + +static ScheduleCmdFunc sScheduleCmdFuncs[] = { + Schedule_CheckFlagS, // SCHEDULE_CMD_ID_CHECK_FLAG_S + Schedule_CheckFlagL, // SCHEDULE_CMD_ID_CHECK_FLAG_L + Schedule_CheckTimeRangeS, // SCHEDULE_CMD_ID_CHECK_TIME_RANGE_S + Schedule_CheckTimeRangeL, // SCHEDULE_CMD_ID_CHECK_TIME_RANGE_L + Schedule_ReturnValueL, // SCHEDULE_CMD_ID_RET_VAL_L + Schedule_ReturnNone, // SCHEDULE_CMD_ID_RET_NONE + Schedule_ReturnEmpty, // SCHEDULE_CMD_ID_RET_EMPTY + Schedule_Nop, // SCHEDULE_CMD_ID_NOP + Schedule_CheckMiscS, // SCHEDULE_CMD_ID_CHECK_MISC_S + Schedule_ReturnValueS, // SCHEDULE_CMD_ID_RET_VAL_S + Schedule_CheckNotInSceneS, // SCHEDULE_CMD_ID_CHECK_NOT_IN_SCENE_S + Schedule_CheckNotInSceneL, // SCHEDULE_CMD_ID_CHECK_NOT_IN_SCENE_L + Schedule_CheckNotInDayS, // SCHEDULE_CMD_ID_CHECK_NOT_IN_DAY_S + Schedule_CheckNotInDayL, // SCHEDULE_CMD_ID_CHECK_NOT_IN_DAY_L + Schedule_ReturnTime, // SCHEDULE_CMD_ID_RET_TIME + Schedule_CheckBeforeTimeS, // SCHEDULE_CMD_ID_CHECK_BEFORE_TIME_S + Schedule_CheckBeforeTimeL, // SCHEDULE_CMD_ID_CHECK_BEFORE_TIME_L + Schedule_BranchS, // SCHEDULE_CMD_ID_BRANCH_S + Schedule_BranchL, // SCHEDULE_CMD_ID_BRANCH_L }; static u8 sScheduleCmdSizes[] = { - sizeof(ScheduleCmdCheckFlagS), - sizeof(ScheduleCmdCheckFlagL), - sizeof(ScheduleCmdCheckTimeRangeS), - sizeof(ScheduleCmdCheckTimeRangeL), - sizeof(ScheduleCmdReturnValueL), - sizeof(ScheduleCmdBase), - sizeof(ScheduleCmdBase), - sizeof(ScheduleCmdNop), - sizeof(ScheduleCmdCheckMiscS), - sizeof(ScheduleCmdReturnValueS), - sizeof(ScheduleCmdCheckNotInSceneS), - sizeof(ScheduleCmdCheckNotInSceneL), - sizeof(ScheduleCmdCheckNotInDayS), - sizeof(ScheduleCmdCheckNotInDayL), - sizeof(ScheduleCmdReturnTime), - sizeof(ScheduleCmdCheckBeforeTimeS), - sizeof(ScheduleCmdCheckBeforeTimeL), - sizeof(ScheduleCmdBranchS), - sizeof(ScheduleCmdBranchL), + sizeof(ScheduleCmdCheckFlagS), // SCHEDULE_CMD_ID_CHECK_FLAG_S + sizeof(ScheduleCmdCheckFlagL), // SCHEDULE_CMD_ID_CHECK_FLAG_L + sizeof(ScheduleCmdCheckTimeRangeS), // SCHEDULE_CMD_ID_CHECK_TIME_RANGE_S + sizeof(ScheduleCmdCheckTimeRangeL), // SCHEDULE_CMD_ID_CHECK_TIME_RANGE_L + sizeof(ScheduleCmdReturnValueL), // SCHEDULE_CMD_ID_RET_VAL_L + sizeof(ScheduleCmdBase), // SCHEDULE_CMD_ID_RET_NONE + sizeof(ScheduleCmdBase), // SCHEDULE_CMD_ID_RET_EMPTY + sizeof(ScheduleCmdNop), // SCHEDULE_CMD_ID_NOP + sizeof(ScheduleCmdCheckMiscS), // SCHEDULE_CMD_ID_CHECK_MISC_S + sizeof(ScheduleCmdReturnValueS), // SCHEDULE_CMD_ID_RET_VAL_S + sizeof(ScheduleCmdCheckNotInSceneS), // SCHEDULE_CMD_ID_CHECK_NOT_IN_SCENE_S + sizeof(ScheduleCmdCheckNotInSceneL), // SCHEDULE_CMD_ID_CHECK_NOT_IN_SCENE_L + sizeof(ScheduleCmdCheckNotInDayS), // SCHEDULE_CMD_ID_CHECK_NOT_IN_DAY_S + sizeof(ScheduleCmdCheckNotInDayL), // SCHEDULE_CMD_ID_CHECK_NOT_IN_DAY_L + sizeof(ScheduleCmdReturnTime), // SCHEDULE_CMD_ID_RET_TIME + sizeof(ScheduleCmdCheckBeforeTimeS), // SCHEDULE_CMD_ID_CHECK_BEFORE_TIME_S + sizeof(ScheduleCmdCheckBeforeTimeL), // SCHEDULE_CMD_ID_CHECK_BEFORE_TIME_L + sizeof(ScheduleCmdBranchS), // SCHEDULE_CMD_ID_BRANCH_S + sizeof(ScheduleCmdBranchL), // SCHEDULE_CMD_ID_BRANCH_L }; s32 Schedule_RunScript(PlayState* play, u8* script, ScheduleOutput* output) { @@ -275,7 +291,7 @@ s32 Schedule_RunScript(PlayState* play, u8* script, ScheduleOutput* output) { do { size = sScheduleCmdSizes[*script]; - stop = (*sScheduleCmdFuncs[*script])(play, &script, output); + stop = sScheduleCmdFuncs[*script](play, &script, output); script += size; } while (!stop); diff --git a/src/overlays/actors/ovl_Dm_Tag/z_dm_tag.c b/src/overlays/actors/ovl_Dm_Tag/z_dm_tag.c index 6eb910d2dd..4abce0d2fb 100644 --- a/src/overlays/actors/ovl_Dm_Tag/z_dm_tag.c +++ b/src/overlays/actors/ovl_Dm_Tag/z_dm_tag.c @@ -187,10 +187,12 @@ s32* func_80C22880(DmTag* this, PlayState* play) { switch (this->unk_18E) { case 1: - time = gSaveContext.save.time - 0x3FFC; - if ((time >= 0xA54B) && (time < 0xB54A) && (gSaveContext.save.day == 2)) { - this->msgEventCallback = func_80C227E8; - return D_80C22BF0; + time = SCHEDULE_TIME_NOW; + if ((time >= SCHEDULE_TIME(21, 30)) && (time < SCHEDULE_TIME(23, 0))) { + if (gSaveContext.save.day == 2) { + this->msgEventCallback = func_80C227E8; + return D_80C22BF0; + } } return D_80C22C30; @@ -201,6 +203,7 @@ s32* func_80C22880(DmTag* this, PlayState* play) { default: break; } + return NULL; } diff --git a/src/overlays/actors/ovl_En_Pm/z_en_pm.c b/src/overlays/actors/ovl_En_Pm/z_en_pm.c index ab80d3d576..838fbf2c9e 100644 --- a/src/overlays/actors/ovl_En_Pm/z_en_pm.c +++ b/src/overlays/actors/ovl_En_Pm/z_en_pm.c @@ -581,7 +581,7 @@ s32 func_80AF7BAC(EnPm* this) { case 2: if (CHECK_WEEKEVENTREG(WEEKEVENTREG_89_40)) { - D_801F4E78 = 0; + D_801F4E78 = CLOCK_TIME(0, 0); this->unk_38C++; } break; diff --git a/src/overlays/actors/ovl_En_Sob1/z_en_sob1.c b/src/overlays/actors/ovl_En_Sob1/z_en_sob1.c index 901e49126f..a18d567539 100644 --- a/src/overlays/actors/ovl_En_Sob1/z_en_sob1.c +++ b/src/overlays/actors/ovl_En_Sob1/z_en_sob1.c @@ -188,7 +188,7 @@ u16 EnSob1_GetTalkOption(EnSob1* this, PlayState* play) { Player* player = GET_PLAYER(play); if (this->shopType == BOMB_SHOP) { - if ((gSaveContext.save.day == 1) && (gSaveContext.save.time >= CLOCK_TIME(6, 00))) { + if ((gSaveContext.save.day == 1) && (gSaveContext.save.time >= CLOCK_TIME(6, 0))) { return 0x648; } else if (CHECK_WEEKEVENTREG(WEEKEVENTREG_RECOVERED_STOLEN_BOMB_BAG)) { return 0x649; diff --git a/src/overlays/actors/ovl_En_Test3/z_en_test3.c b/src/overlays/actors/ovl_En_Test3/z_en_test3.c index 90ea18d05b..d3676daa26 100644 --- a/src/overlays/actors/ovl_En_Test3/z_en_test3.c +++ b/src/overlays/actors/ovl_En_Test3/z_en_test3.c @@ -701,7 +701,7 @@ s32 func_80A3F9A4(EnTest3* this, PlayState* play) { } s32 func_80A3F9E4(EnTest3* this, PlayState* play, struct_80A41828* arg2, ScheduleOutput* scheduleOutput) { - scheduleOutput->time0 = SCHEDULE_TIME_NOW; + scheduleOutput->time0 = (u16)SCHEDULE_TIME_NOW; scheduleOutput->time1 = (u16)(scheduleOutput->time0 + 70); func_80A40098(this, play, arg2, scheduleOutput); if (this->player.actor.xzDistToPlayer < 300.0f) { @@ -729,7 +729,7 @@ s32 func_80A3FA58(EnTest3* this, PlayState* play) { if (cond || this->unk_D8A <= 0) { func_80A3F114(this, play); sp40.unk_1_0 = 5; - scheduleOutput.time0 = SCHEDULE_TIME_NOW; + scheduleOutput.time0 = (u16)SCHEDULE_TIME_NOW; scheduleOutput.time1 = (u16)(scheduleOutput.time0 + (cond ? 80 : 140)); func_80A40098(this, play, &sp40, &scheduleOutput); @@ -805,7 +805,7 @@ s32 func_80A3FE20(EnTest3* this, PlayState* play) { if (D_80A41D64 == 0) { if (func_80A3E9DC(this, play)) { sp2C.unk_1_0 = 2; - scheduleOutput.time0 = SCHEDULE_TIME_NOW; + scheduleOutput.time0 = (u16)SCHEDULE_TIME_NOW; scheduleOutput.time1 = (u16)(scheduleOutput.time0 + 1000); func_80A40098(this, play, &sp2C, &scheduleOutput); D_80A41D64 = 1; diff --git a/src/overlays/gamestates/ovl_file_choose/z_file_choose_NES.c b/src/overlays/gamestates/ovl_file_choose/z_file_choose_NES.c index 65d26a97e4..1136632fbc 100644 --- a/src/overlays/gamestates/ovl_file_choose/z_file_choose_NES.c +++ b/src/overlays/gamestates/ovl_file_choose/z_file_choose_NES.c @@ -2484,7 +2484,7 @@ void FileSelect_InitContext(GameState* thisx) { ShrinkWindow_Letterbox_SetSizeTarget(0); gSaveContext.skyboxTime = 0; - gSaveContext.save.time = 0; + gSaveContext.save.time = CLOCK_TIME(0, 0); Skybox_Init(&this->state, &this->skyboxCtx, 1); R_TIME_SPEED = 10; diff --git a/tools/schedule_timeconv.py b/tools/schedule_timeconv.py new file mode 100755 index 0000000000..49a1e50dab --- /dev/null +++ b/tools/schedule_timeconv.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python3 + +# SPDX-FileCopyrightText: © 2023 ZeldaRET +# SPDX-License-Identifier: MIT + +# Convert time values such as 0x1AA9 to their schedule clock time, i.e. 8,30 + +from __future__ import annotations + +import sys + +def u16(x: int|float) -> int: + return int(x) & 0xFFFF + +def SCHEDULE_CONVERT_TIME(time: int|float) -> int: + return u16(time - 0x10000 // 360 * 90) + +def SCHEDULE_UNCONVERT_TIME(time: int) -> int: + return time + 0x10000 // 360 * 90 + +time = sys.argv[1] +time = int(time, 0) + +minutes = round(((24 * 60) / 0x10000) * SCHEDULE_UNCONVERT_TIME(time)) + +hours = int(minutes // 60) +minutes = round(minutes - 60 * hours) + +# Since multiple values are mapped to the same clock time, check that it +# still matches once converted. If it doesn't match as it is, print a warning. +macro_val = SCHEDULE_CONVERT_TIME((hours * 60.0 + minutes) * ((0x10000 // 60) / 24.0)) + +print(f"{hours},{minutes:02} -> 0x{macro_val:04X}") +print(f"SCHEDULE_TIME({hours}, {minutes})") +if time != macro_val: + print("Warning: Result does not match as-is")