-- name: Day Night Cycle DX -- incompatible: light day-night-cycle -- description: Day Night Cycle DX v2.2.2\nBy \\#ec7731\\Agent X\n\n\\#dcdcdc\\This mod adds a fully featured day & night cycle system with night, sunrise, day and sunset to sm64coopdx. It includes an API and hook system for interfacing with several components of the mod externally. This mod was originally made for sm64ex-coop but has been practically rewritten for sm64coopdx.\n\nDays last 24 minutes and with the /time command, you can get/set the time or change your settings.\n\nThere is also now a new menu in the pause menu for Day Night Cycle DX!\n\nSpecial thanks to \\#e06de4\\MaiskX3\\#dcdcdc\\ for the night time music.\nSpecial thanks to \\#00ffff\\AngelicMiracles\\#dcdcdc\\ for the sunset, sunrise and night time skyboxes.\nSpecial thanks to \\#344ee1\\eros71\\#dcdcdc\\ for salvaging\nthe mod files. --- @class Vec2f --- @field public x number --- @field public y number gGlobalSyncTable.dncEnabled = true gGlobalSyncTable.time = if_then_else(network_is_server(), load_time(), HOUR_DAY_START) gGlobalSyncTable.timeScale = tonumber(mod_storage_load("scale")) or 1.0 local init = true local timeModifier = 0 -- localize functions to improve performance local type,math_floor,error,table_insert,get_skybox,set_lighting_dir,set_lighting_color,set_vertex_color,set_fog_color,set_fog_intensity,network_check_singleplayer_pause,network_player_connected_count,obj_get_first_with_behavior_id,network_is_server,spawn_non_sync_object,obj_scale,clampf,set_lighting_color_ambient,djui_hud_set_resolution,djui_hud_set_font,hud_get_value,hud_is_hidden,djui_hud_get_screen_width,djui_hud_measure_text,djui_hud_get_screen_height,djui_hud_set_color,play_sound,djui_chat_message_create,tonumber,string_format,mod_storage_save_number,mod_storage_save_bool,get_date_and_time = type,math.floor,error,table.insert,get_skybox,set_lighting_dir,set_lighting_color,set_vertex_color,set_fog_color,set_fog_intensity,network_check_singleplayer_pause,network_player_connected_count,obj_get_first_with_behavior_id,network_is_server,spawn_non_sync_object,obj_scale,clampf,set_lighting_color_ambient,djui_hud_set_resolution,djui_hud_set_font,hud_get_value,hud_is_hidden,djui_hud_get_screen_width,djui_hud_measure_text,djui_hud_get_screen_height,djui_hud_set_color,play_sound,djui_chat_message_create,tonumber,string.format,mod_storage_save_number,mod_storage_save_bool,get_date_and_time local sDncHooks = { [DNC_HOOK_SET_LIGHTING_COLOR] = {}, [DNC_HOOK_SET_AMBIENT_LIGHTING_COLOR] = {}, [DNC_HOOK_SET_LIGHTING_DIR] = {}, [DNC_HOOK_SET_FOG_COLOR] = {}, [DNC_HOOK_SET_FOG_INTENSITY] = {}, [DNC_HOOK_SET_DISPLAY_TIME_COLOR] = {}, [DNC_HOOK_SET_DISPLAY_TIME_POS] = {}, [DNC_HOOK_DELETE_AT_DARK] = {}, [DNC_HOOK_SET_TIME] = {}, [DNC_HOOK_SET_SKYBOX_MODEL] = {} } --- @param hookEventType integer --- @param func function --- Hooks a function to the Day Night Cycle hook system local function dnc_hook_event(hookEventType, func) if type(hookEventType) ~= "number" or math_floor(hookEventType) ~= hookEventType then error("dnc_hook_event: Parameter 'hookEventType' must be an integer") return end if type(func) ~= "function" then error("dnc_hook_event: Parameter 'func' must be a function") return end if sDncHooks[hookEventType] == nil then return end table_insert(sDncHooks[hookEventType], func) end --- @param hookEventType integer function dnc_call_hook(hookEventType, ...) if sDncHooks[hookEventType] == nil then return end local ret = nil for hook in ipairs(sDncHooks[hookEventType]) do ret = sDncHooks[hookEventType][hook](...) end return ret end --- Returns whether or not Day Night Cycle is globally enabled function is_dnc_enabled() return gGlobalSyncTable.dncEnabled and dayNightCycleApi.enabled end --- Returns whether or not the game should visually show the day night cycle function show_day_night_cycle() local skybox = get_skybox() return (skybox ~= -1 and skybox ~= BACKGROUND_CUSTOM and skybox ~= BACKGROUND_FLAMING_SKY and skybox ~= BACKGROUND_GREEN_SKY and skybox ~= BACKGROUND_PURPLE_SKY) or in_vanilla_level(LEVEL_DDD) or in_vanilla_level(LEVEL_THI) or (in_vanilla_level(LEVEL_CASTLE) and gNetworkPlayers[0].currAreaIndex ~= 3) or in_vanilla_level(LEVEL_WDW) end local function reset_lighting() set_lighting_dir(1, 0) set_lighting_dir(2, 0) set_lighting_color(0, 255) set_lighting_color(1, 255) set_lighting_color(2, 255) set_vertex_color(0, 255) set_vertex_color(1, 255) set_vertex_color(2, 255) set_fog_color(0, 255) set_fog_color(1, 255) set_fog_color(2, 255) set_fog_intensity(1) end local function update() if not is_dnc_enabled() then reset_lighting() return end if network_check_singleplayer_pause() then return end if network_player_connected_count() == 1 and obj_get_first_with_behavior_id(id_bhvActSelector) ~= nil then return end if network_is_server() then time_tick() end if not init then update_night_music() end -- spawn skyboxes local skybox = get_skybox() if skybox >= BACKGROUND_CUSTOM then skybox = BACKGROUND_OCEAN_SKY end if obj_get_first_with_behavior_id(bhvDNCSkybox) == nil and skybox ~= -1 and obj_get_first_with_behavior_id(bhvDNCNoSkybox) == nil then if show_day_night_cycle() and skybox ~= BACKGROUND_HAUNTED then -- spawn day, sunset and night skyboxes for i = SKYBOX_DAY, SKYBOX_NIGHT do local thisSkybox = skybox if i == SKYBOX_SUNSET then thisSkybox = if_then_else(skybox == BACKGROUND_BELOW_CLOUDS, BACKGROUND_BELOW_CLOUDS_SUNSET, BACKGROUND_SUNSET) elseif i == SKYBOX_NIGHT then thisSkybox = if_then_else(skybox == BACKGROUND_BELOW_CLOUDS, BACKGROUND_BELOW_CLOUDS_NIGHT, BACKGROUND_NIGHT) end local model = E_MODEL_DNC_SKYBOX local overrideModel = dnc_call_hook(DNC_HOOK_SET_SKYBOX_MODEL, i, thisSkybox) if overrideModel ~= nil and type(overrideModel) == "number" then model = overrideModel end spawn_non_sync_object( bhvDNCSkybox, model, 0, 0, 0, --- @param o Object function(o) o.oBehParams2ndByte = i o.oAnimState = thisSkybox obj_scale(o, SKYBOX_SCALE - 10 * i) end ) end else -- spawn static skybox spawn_non_sync_object( bhvDNCSkybox, E_MODEL_DNC_SKYBOX, 0, 0, 0, --- @param o Object function(o) o.oBehParams2ndByte = 0 o.oAnimState = skybox obj_scale(o, SKYBOX_SCALE) end ) end end local minutes = if_then_else(skybox ~= BACKGROUND_HAUNTED, get_time_minutes(), 12) local actSelector = obj_get_first_with_behavior_id(id_bhvActSelector) if actSelector == nil and show_day_night_cycle() then -- calculate lighting color local color = COLOR_DAY if minutes >= HOUR_SUNRISE_START and minutes <= HOUR_SUNRISE_END then color = color_lerp(COLOR_NIGHT, COLOR_SUNRISE, (minutes - HOUR_SUNRISE_START) / HOUR_SUNRISE_DURATION) elseif minutes >= HOUR_SUNRISE_END and minutes <= HOUR_DAY_START then color = color_lerp(COLOR_SUNRISE, COLOR_DAY, (minutes - HOUR_SUNRISE_END) / HOUR_SUNRISE_DURATION) elseif minutes >= HOUR_SUNSET_START and minutes <= HOUR_SUNSET_END then color = color_lerp(COLOR_DAY, COLOR_SUNSET, (minutes - HOUR_SUNSET_START) / HOUR_SUNSET_DURATION) elseif minutes >= HOUR_SUNSET_END and minutes <= HOUR_NIGHT_START then color = color_lerp(COLOR_SUNSET, COLOR_NIGHT, (minutes - HOUR_SUNSET_END) / HOUR_SUNSET_DURATION) elseif minutes > HOUR_NIGHT_START or minutes < HOUR_SUNRISE_START then color = COLOR_NIGHT elseif minutes > HOUR_DAY_START and minutes < HOUR_SUNSET_START then color = COLOR_DAY end local overrideColor = dnc_call_hook(DNC_HOOK_SET_LIGHTING_COLOR, table_clone(color)) if overrideColor ~= nil and type(overrideColor) == "table" then color = overrideColor end -- calculate ambient lighting color local ambientColor = COLOR_AMBIENT_DAY if minutes >= HOUR_SUNRISE_START and minutes <= HOUR_SUNRISE_END then ambientColor = color_lerp(COLOR_AMBIENT_NIGHT, COLOR_AMBIENT_SUNRISE, (minutes - HOUR_SUNRISE_START) / HOUR_SUNRISE_DURATION) elseif minutes >= HOUR_SUNRISE_END and minutes <= HOUR_DAY_START then ambientColor = color_lerp(COLOR_AMBIENT_SUNRISE, COLOR_AMBIENT_DAY, (minutes - HOUR_SUNRISE_END) / HOUR_SUNRISE_DURATION) elseif minutes >= HOUR_SUNSET_START and minutes <= HOUR_SUNSET_END then ambientColor = color_lerp(COLOR_AMBIENT_DAY, COLOR_AMBIENT_SUNSET, (minutes - HOUR_SUNSET_START) / HOUR_SUNSET_DURATION) elseif minutes >= HOUR_SUNSET_END and minutes <= HOUR_NIGHT_START then ambientColor = color_lerp(COLOR_AMBIENT_SUNSET, COLOR_AMBIENT_NIGHT, (minutes - HOUR_SUNSET_END) / HOUR_SUNSET_DURATION) elseif minutes > HOUR_NIGHT_START or minutes < HOUR_SUNRISE_START then ambientColor = COLOR_AMBIENT_NIGHT elseif minutes > HOUR_DAY_START and minutes < HOUR_SUNSET_START then ambientColor = COLOR_AMBIENT_DAY end local overrideAmbientColor = dnc_call_hook(DNC_HOOK_SET_AMBIENT_LIGHTING_COLOR, table_clone(ambientColor)) if overrideAmbientColor ~= nil and type(overrideColor) == "table" then ambientColor = overrideAmbientColor end -- calculate fog color local fogColor = COLOR_DAY if minutes >= HOUR_SUNRISE_START and minutes <= HOUR_SUNRISE_END then fogColor = color_lerp(FOG_COLOR_NIGHT, COLOR_SUNRISE, (minutes - HOUR_SUNRISE_START) / HOUR_SUNRISE_DURATION) elseif minutes >= HOUR_SUNRISE_END and minutes <= HOUR_DAY_START then fogColor = color_lerp(COLOR_SUNRISE, COLOR_DAY, (minutes - HOUR_SUNRISE_END) / HOUR_SUNRISE_DURATION) elseif minutes >= HOUR_SUNSET_START and minutes <= HOUR_SUNSET_END then fogColor = color_lerp(COLOR_DAY, COLOR_SUNSET, (minutes - HOUR_SUNSET_START) / HOUR_SUNSET_DURATION) elseif minutes >= HOUR_SUNSET_END and minutes <= HOUR_NIGHT_START then fogColor = color_lerp(COLOR_SUNSET, FOG_COLOR_NIGHT, (minutes - HOUR_SUNSET_END) / HOUR_SUNSET_DURATION) elseif minutes > HOUR_NIGHT_START or minutes < HOUR_SUNRISE_START then fogColor = FOG_COLOR_NIGHT elseif minutes > HOUR_DAY_START and minutes < HOUR_SUNSET_START then fogColor = COLOR_DAY end fogColor = color_lerp(fogColor, ambientColor, 0.5) local overrideFogColor = dnc_call_hook(DNC_HOOK_SET_FOG_COLOR, table_clone(fogColor)) if overrideFogColor ~= nil and type(overrideFogColor) == "table" then fogColor = overrideFogColor end -- calculate lighting direction local dir = DIR_BRIGHT if minutes >= HOUR_SUNRISE_START and minutes <= HOUR_SUNRISE_END then dir = lerp(DIR_DARK, DIR_BRIGHT, clampf((minutes - HOUR_SUNRISE_START) / (HOUR_SUNRISE_DURATION), 0, 1)) elseif minutes >= HOUR_SUNSET_START and minutes <= HOUR_NIGHT_START then dir = lerp(DIR_BRIGHT, DIR_DARK, clampf((minutes - HOUR_SUNSET_START) / (HOUR_NIGHT_START - HOUR_SUNSET_START), 0, 1)) elseif minutes < HOUR_SUNRISE_START or minutes > HOUR_NIGHT_START then dir = DIR_DARK elseif minutes > HOUR_SUNRISE_END and minutes < HOUR_SUNSET_START then dir = DIR_BRIGHT end local overrideDir = dnc_call_hook(DNC_HOOK_SET_LIGHTING_DIR, dir) if overrideDir ~= nil and type(overrideDir) == "number" then dir = overrideDir end -- calculate fog intensity local intensity = FOG_INTENSITY_NORMAL if minutes >= HOUR_SUNRISE_START and minutes <= HOUR_SUNRISE_END then intensity = lerp(FOG_INTENSITY_DENSE, FOG_INTENSITY_NORMAL, clampf((minutes - HOUR_SUNRISE_START) / (HOUR_SUNRISE_DURATION), 0, 1)) elseif minutes >= HOUR_SUNSET_START and minutes <= HOUR_NIGHT_START then intensity = lerp(FOG_INTENSITY_NORMAL, FOG_INTENSITY_DENSE, clampf((minutes - HOUR_SUNSET_START) / (HOUR_NIGHT_START - HOUR_SUNSET_START), 0, 1)) elseif minutes < HOUR_SUNRISE_START or minutes > HOUR_NIGHT_START then intensity = FOG_INTENSITY_DENSE elseif minutes > HOUR_SUNRISE_END and minutes < HOUR_SUNSET_START then intensity = FOG_INTENSITY_NORMAL end local overrideIntensity = dnc_call_hook(DNC_HOOK_SET_FOG_INTENSITY, intensity) if overrideIntensity ~= nil and type(overrideIntensity) == "number" then intensity = overrideIntensity end set_lighting_dir(1, -(1 - dir)) set_lighting_dir(2, -(1 - dir)) -- make the castle still 25% ambient lit if in_vanilla_level(LEVEL_CASTLE) then color = color_lerp(COLOR_DAY, color, 0.75) end set_lighting_color(0, color.r) set_lighting_color(1, color.g) set_lighting_color(2, color.b) set_lighting_color_ambient(0, ambientColor.r) set_lighting_color_ambient(1, ambientColor.g) set_lighting_color_ambient(2, ambientColor.b) local mix = color_lerp(color, ambientColor, 0.5) set_vertex_color(0, mix.r) set_vertex_color(1, mix.g) set_vertex_color(2, mix.b) set_fog_color(0, fogColor.r) set_fog_color(1, fogColor.g) set_fog_color(2, fogColor.b) set_fog_intensity(intensity) else reset_lighting() end init = false end local function on_hud_render_behind() if not is_dnc_enabled() or not dayNightCycleApi.displayTime then return end -- api checks if check_common_hud_render_cancels() then return end -- game checks djui_hud_set_resolution(RESOLUTION_N64) djui_hud_set_font(FONT_NORMAL) local scale = 0.5 local text = get_time_string(gGlobalSyncTable.time) local hidden = hud_is_hidden() or (hud_get_value(HUD_DISPLAY_FLAGS) & HUD_DISPLAY_FLAG_LIVES) == 0 local x = if_then_else(hidden, (djui_hud_get_screen_width() * 0.5) - (djui_hud_measure_text(text) * (0.5 * scale)), 24) local y = if_then_else(hidden, (djui_hud_get_screen_height() - 20), 32) local overridePos = dnc_call_hook(DNC_HOOK_SET_DISPLAY_TIME_POS, { x = x, y = y }) if overridePos ~= nil and type(overridePos) == "table" then x = overridePos.x y = overridePos.y end local minutes = if_then_else(get_skybox() ~= BACKGROUND_HAUNTED, get_time_minutes(), 0) local color = COLOR_DISPLAY_BRIGHT if minutes >= HOUR_SUNRISE_START and minutes <= HOUR_SUNRISE_END then color = color_lerp(COLOR_DISPLAY_DARK, COLOR_DISPLAY_BRIGHT, (minutes - HOUR_SUNRISE_START) / HOUR_SUNRISE_DURATION) elseif minutes >= HOUR_SUNSET_END and minutes <= HOUR_NIGHT_START then color = color_lerp(COLOR_DISPLAY_BRIGHT, COLOR_DISPLAY_DARK, (minutes - HOUR_SUNSET_END) / HOUR_SUNSET_DURATION) elseif minutes > HOUR_NIGHT_START or minutes < HOUR_SUNRISE_START then color = COLOR_DISPLAY_DARK elseif minutes > HOUR_SUNRISE_END and minutes < HOUR_SUNSET_END then color = COLOR_DISPLAY_BRIGHT end local overrideColor = dnc_call_hook(DNC_HOOK_SET_DISPLAY_TIME_COLOR, table_clone(color)) if overrideColor ~= nil and type(overrideColor) == "table" then color = overrideColor end djui_hud_set_color(color.r, color.g, color.b, 255) djui_hud_print_outlined_text(text, x, y, scale, 0.0) end local function on_level_init() if not is_dnc_enabled() then return end playingNightMusic = false if gNetworkPlayers[0].currActNum ~= 99 then if network_is_server() then save_time() end return end --- @type NetworkPlayer local np = gNetworkPlayers[0] if np.currLevelNum == LEVEL_CASTLE_GROUNDS and gMarioStates[0].action ~= ACT_END_WAVING_CUTSCENE then gGlobalSyncTable.time = get_day_count() * (MINUTE * 24) + (MINUTE * (HOUR_SUNSET_START - 0.7)) gGlobalSyncTable.timeScale = 1.0 elseif np.currLevelNum == LEVEL_THI and np.currAreaIndex == 1 then gGlobalSyncTable.time = (get_day_count() + 1) * (MINUTE * 24) + (MINUTE * HOUR_SUNRISE_START) end end local function on_warp() if not is_dnc_enabled() then return end if network_is_server() then save_time() end playingNightMusic = false end local function on_exit() if network_is_server() then save_time() end end --- @param msg string local function on_set_command(msg) if _G.dayNightCycleApi.lockTime then play_sound(SOUND_MENU_CAMERA_BUZZ, gGlobalSoundSource) djui_chat_message_create("\\#ffa0a0\\[Day Night Cycle] The Day Night Cycle settings have been locked by another mod.") return true end if msg == "" then djui_chat_message_create("/time \\#00ffff\\set\\#ffff00\\ [TIME]\\#dcdcdc\\ to set the time") return true end local oldTime = gGlobalSyncTable.time if msg == "morning" then gGlobalSyncTable.time = get_day_count() * (MINUTE * 24) + (MINUTE * 6) elseif msg == "day" or msg == "noon" then gGlobalSyncTable.time = get_day_count() * (MINUTE * 24) + (MINUTE * 12) elseif msg == "night" then gGlobalSyncTable.time = get_day_count() * (MINUTE * 24) + (MINUTE * 21) elseif msg == "midnight" then gGlobalSyncTable.time = get_day_count() * (MINUTE * 24) elseif msg == "sunrise" then gGlobalSyncTable.time = get_day_count() * (MINUTE * 24) + (MINUTE * 5) elseif msg == "sunset" then gGlobalSyncTable.time = get_day_count() * (MINUTE * 24) + (MINUTE * 20) else local amount = tonumber(msg) if amount ~= nil then gGlobalSyncTable.time = amount * SECOND djui_chat_message_create("[Day Night Cycle] Time set to " .. math_floor(gGlobalSyncTable.time / SECOND)) else djui_chat_message_create(string.format("\\#ffa0a0\\[Day Night Cycle] Could not set time to '%s'", msg)) end end dnc_call_hook(DNC_HOOK_SET_TIME, oldTime, gGlobalSyncTable.time) save_time() end --- @param msg string local function on_add_command(msg) if _G.dayNightCycleApi.lockTime then play_sound(SOUND_MENU_CAMERA_BUZZ, gGlobalSoundSource) djui_chat_message_create("\\#ffa0a0\\[Day Night Cycle] The Day Night Cycle settings have been locked by another mod.") return true end local amount = tonumber(msg) if amount == nil then djui_chat_message_create("/time \\#00ffff\\add\\#ffff00\\ [AMOUNT]\\#dcdcdc\\ to add to the time") return true end local oldTime = gGlobalSyncTable.time gGlobalSyncTable.time = gGlobalSyncTable.time + (amount * SECOND) dnc_call_hook(DNC_HOOK_SET_TIME, oldTime, gGlobalSyncTable.time) djui_chat_message_create("[Day Night Cycle] Time set to " .. math_floor(gGlobalSyncTable.time / SECOND)) save_time() end --- @param msg string local function on_scale_command(msg) if _G.dayNightCycleApi.lockTime then play_sound(SOUND_MENU_CAMERA_BUZZ, gGlobalSoundSource) djui_chat_message_create("\\#ffa0a0\\[Day Night Cycle] The Day Night Cycle settings have been locked by another mod.") return true end local scale = tonumber(msg) if scale == nil then djui_chat_message_create("/time \\#00ffff\\scale\\#ffff00\\ [SCALE]\\#dcdcdc\\ to scale the rate at which time passes") return true end gGlobalSyncTable.timeScale = scale mod_storage_save_number("scale", scale) djui_chat_message_create("[Day Night Cycle] Time scale set to " .. scale) save_time() end local function on_query_command() djui_chat_message_create(string.format("[Day Night Cycle] Time is %d (%s), day %d", math_floor(gGlobalSyncTable.time / SECOND), get_time_string(gGlobalSyncTable.time), get_day_count())) end local function on_24h_command() use24h = not use24h mod_storage_save_bool("24h", use24h) end local function on_sync_command() if _G.dayNightCycleApi.lockTime then play_sound(SOUND_MENU_CAMERA_BUZZ, gGlobalSoundSource) djui_chat_message_create("\\#ffa0a0\\[Day Night Cycle] The Day Night Cycle settings have been locked by another mod.") return true end djui_chat_message_create("[Day Night Cycle] Attempting to sync in-game time with real world time...") local dateTime = get_date_and_time() gGlobalSyncTable.time = get_day_count() * (MINUTE * 24) + (MINUTE * dateTime.hour) + (SECOND * dateTime.minute) gGlobalSyncTable.timeScale = REAL_MINUTE save_time() end local function on_music_command() if _G.dayNightCycleApi.lockTime then play_sound(SOUND_MENU_CAMERA_BUZZ, gGlobalSoundSource) djui_chat_message_create("\\#ffa0a0\\[Day Night Cycle] The Day Night Cycle settings have been locked by another mod.") return true end playNightMusic = not playNightMusic mod_storage_save_bool("night-music", playNightMusic) djui_chat_message_create("[Day Night Cycle] Night music status: " .. on_or_off(playNightMusic)) end --- @param msg string local function on_time_command(msg) local args = split(msg) if args[1] == "set" then if not network_is_server() then djui_chat_message_create("\\#ffa0a0\\[Day Night Cycle] You do not have permission to run /time set") else on_set_command(args[2] or "") end elseif args[1] == "add" then if not network_is_server() then djui_chat_message_create("\\#ffa0a0\\[Day Night Cycle] You do not have permission to run /time add") else on_add_command(args[2] or "") end elseif args[1] == "scale" then if not network_is_server() then djui_chat_message_create("\\#ffa0a0\\[Day Night Cycle] You do not have permission to run /time scale") else on_scale_command(args[2] or "") end elseif args[1] == "query" then on_query_command() elseif args[1] == "24h" then on_24h_command() elseif args[1] == "sync" then if not network_is_server() then djui_chat_message_create("\\#ffa0a0\\[Day Night Cycle] You do not have permission to run /time sync") else on_sync_command() end elseif args[1] == "music" then on_music_command() else if not network_is_server() then djui_chat_message_create("\\#ffa0a0\\[Day Night Cycle] You do not have permission to enable or disable Day Night Cycle") else gGlobalSyncTable.dncEnabled = not gGlobalSyncTable.dncEnabled djui_chat_message_create("[Day Night Cycle] Status: " .. on_or_off(gGlobalSyncTable.dncEnabled)) end end return true end --- @param value boolean local function on_set_dnc_enabled(_, value) if _G.dayNightCycleApi.lockTime then play_sound(SOUND_MENU_CAMERA_BUZZ, gGlobalSoundSource) return end gGlobalSyncTable.dncEnabled = value end --- @param value boolean local function on_set_24h_time(_, value) use24h = value mod_storage_save_bool("24h", value) end --- @param value boolean local function on_set_night_time_music(_, value) if _G.dayNightCycleApi.lockTime then play_sound(SOUND_MENU_CAMERA_BUZZ, gGlobalSoundSource) djui_chat_message_create("\\#ffa0a0\\[Day Night Cycle] The Day Night Cycle settings have been locked by another mod.") return end playNightMusic = value mod_storage_save_bool("night_music", value) end --- @param value integer local function on_set_time_scale(index, value) if _G.dayNightCycleApi.lockTime then play_sound(SOUND_MENU_CAMERA_BUZZ, gGlobalSoundSource) djui_chat_message_create("\\#ffa0a0\\[Day Night Cycle] The Day Night Cycle settings have been locked by another mod.") return end gGlobalSyncTable.timeScale = value mod_storage_save_number("scale", value) update_mod_menu_element_name(index, "Time Scale: " .. value) end --- @param value string local function on_set_time_modifier(_, value) if _G.dayNightCycleApi.lockTime then play_sound(SOUND_MENU_CAMERA_BUZZ, gGlobalSoundSource) djui_chat_message_create("\\#ffa0a0\\[Day Night Cycle] The Day Night Cycle settings have been locked by another mod.") return end local number = tonumber(value) timeModifier = number or 0 end local function on_add_hour() if _G.dayNightCycleApi.lockTime then play_sound(SOUND_MENU_CAMERA_BUZZ, gGlobalSoundSource) djui_chat_message_create("\\#ffa0a0\\[Day Night Cycle] The Day Night Cycle settings have been locked by another mod.") return end local oldTime = gGlobalSyncTable.time gGlobalSyncTable.time = gGlobalSyncTable.time + timeModifier * SECOND dnc_call_hook(DNC_HOOK_SET_TIME, oldTime, gGlobalSyncTable.time) save_time() end local function on_set_time() if _G.dayNightCycleApi.lockTime then play_sound(SOUND_MENU_CAMERA_BUZZ, gGlobalSoundSource) djui_chat_message_create("\\#ffa0a0\\[Day Night Cycle] The Day Night Cycle settings have been locked by another mod.") return end gGlobalSyncTable.time = timeModifier * SECOND end local sReadonlyMetatable = { __index = function(table, key) return rawget(table, key) end, __newindex = function() error("Attempt to update a read-only table", 2) end } _G.dayNightCycleApi = { version = DNC_VERSION, -- The version of the mod enabled = true, -- Whether or not the day night cycle is enabled lockTime = false, -- Whether or not the player should be prevented from changing the time displayTime = true, -- Whether or not to display the time on the HUD playNightMusic = true, -- Whether or not to play the night time music is_dnc_enabled = is_dnc_enabled, get_day_count = get_day_count, get_raw_time = get_raw_time, set_raw_time = set_raw_time, get_time_minutes = get_time_minutes, get_time_scale = get_time_scale, set_time_scale = set_time_scale, get_time_string = get_time_string, delete_at_dark = delete_at_dark, show_day_night_cycle = show_day_night_cycle, should_play_night_music = should_play_night_music, night_music_register = night_music_register, dnc_hook_event = dnc_hook_event, constants = { DNC_VERSION_MAJOR = DNC_VERSION_MAJOR, DNC_VERSION_MINOR = DNC_VERSION_MINOR, DNC_VERSION_PATCH = DNC_VERSION_PATCH, DNC_VERSION = DNC_VERSION, SECOND = SECOND, MINUTE = MINUTE, HOUR_SUNRISE_START = HOUR_SUNRISE_START, HOUR_SUNRISE_END = HOUR_SUNRISE_END, HOUR_SUNRISE_DURATION = HOUR_SUNRISE_DURATION, HOUR_SUNSET_START = HOUR_SUNSET_START, HOUR_SUNSET_END = HOUR_SUNSET_END, HOUR_SUNSET_DURATION = HOUR_SUNSET_DURATION, HOUR_DAY_START = HOUR_DAY_START, HOUR_NIGHT_START = HOUR_NIGHT_START, DIR_DARK = DIR_DARK, DIR_BRIGHT = DIR_BRIGHT, FOG_INTENSITY_NORMAL = FOG_INTENSITY_NORMAL, FOG_INTENSITY_DENSE = FOG_INTENSITY_DENSE, COLOR_NIGHT = COLOR_NIGHT, COLOR_AMBIENT_NIGHT = COLOR_AMBIENT_NIGHT, COLOR_SUNRISE = COLOR_SUNRISE, COLOR_AMBIENT_SUNRISE = COLOR_AMBIENT_SUNRISE, COLOR_DAY = COLOR_DAY, COLOR_AMBIENT_DAY = COLOR_AMBIENT_DAY, COLOR_SUNSET = COLOR_SUNSET, COLOR_AMBIENT_SUNSET = COLOR_AMBIENT_SUNSET, FOG_COLOR_NIGHT = FOG_COLOR_NIGHT, COLOR_DISPLAY_DARK = COLOR_DISPLAY_DARK, COLOR_DISPLAY_BRIGHT = COLOR_DISPLAY_BRIGHT, SKYBOX_SCALE = SKYBOX_SCALE, SKYBOX_DAY = SKYBOX_DAY, SKYBOX_SUNSET = SKYBOX_SUNSET, SKYBOX_NIGHT = SKYBOX_NIGHT, -- * Called whenever the lighting color is calculated -- * Parameters: `Color` color -- * Return: `Color` DNC_HOOK_SET_LIGHTING_COLOR = DNC_HOOK_SET_LIGHTING_COLOR, -- * Called whenever the ambient lighting color is calculated -- * Parameters: `Color` ambientColor -- * Return: `Color` DNC_HOOK_SET_AMBIENT_LIGHTING_COLOR = DNC_HOOK_SET_AMBIENT_LIGHTING_COLOR, -- * Called whenever the lighting direction is calculated -- * Parameters: `number` dir -- * Return: `number` DNC_HOOK_SET_LIGHTING_DIR = DNC_HOOK_SET_LIGHTING_DIR, -- * Called whenever the fog color is calculated -- * Parameters: `Color` color -- * Return: `Color` DNC_HOOK_SET_FOG_COLOR = DNC_HOOK_SET_FOG_COLOR, -- * Called whenever the fog intensity is calculated -- * Parameters: `number` intensity -- * Return: `number` DNC_HOOK_SET_FOG_INTENSITY = DNC_HOOK_SET_FOG_INTENSITY, -- * Called whenever the HUD display time color is calculated -- * Parameters: `Color` color -- * Return: `Color` DNC_HOOK_SET_DISPLAY_TIME_COLOR = DNC_HOOK_SET_DISPLAY_TIME_COLOR, -- * Called whenever the HUD display time position is calculated -- * Parameters: `Vec2f` pos -- * Return: `Vec2f` DNC_HOOK_SET_DISPLAY_TIME_POS = DNC_HOOK_SET_DISPLAY_TIME_POS, -- * Called whenever `delete_at_dark` is run -- * Parameters: `Object` obj, `boolean` shouldDelete -- * Return: `boolean` DNC_HOOK_DELETE_AT_DARK = DNC_HOOK_DELETE_AT_DARK, -- * Called whenever `/time set` or `/time add` is ran -- * Parameters: `number` oldTime, `number` newTime -- * Return: nil DNC_HOOK_SET_TIME = DNC_HOOK_SET_TIME, -- * Called when the skyboxes are spawned in. Index 0 is day, index 1 is sunset, and index 2 is night. -- * Parameters: `integer` index, `integer` skybox -- * Return `ModelExtendedId` DNC_HOOK_SET_SKYBOX_MODEL = DNC_HOOK_SET_SKYBOX_MODEL } } setmetatable(_G.dayNightCycleApi, sReadonlyMetatable) night_music_register(SEQ_LEVEL_GRASS, "03_level_grass") night_music_register(SEQ_LEVEL_WATER, "05_level_water") night_music_register(SEQ_LEVEL_HOT, "06_level_hot") night_music_register(SEQ_LEVEL_SNOW, "08_level_snow") hook_event(HOOK_UPDATE, update) hook_event(HOOK_ON_LEVEL_INIT, on_level_init) hook_event(HOOK_ON_WARP, on_warp) hook_event(HOOK_ON_EXIT, on_exit) hook_event(HOOK_ON_HUD_RENDER_BEHIND, on_hud_render_behind) hook_chat_command("time", "\\#00ffff\\[set|add|scale|query|24h|sync|music]\\#dcdcdc\\ - The command handle for Day Night Cycle DX \\#7f7f7f\\(leave blank to toggle Day Night Cycle on or off)", on_time_command) hook_mod_menu_checkbox("24 Hour Time", use24h, on_set_24h_time) hook_mod_menu_checkbox("Night Time Music", playNightMusic, on_set_night_time_music) if network_is_server() then hook_mod_menu_checkbox("Enable Day Night Cycle", gGlobalSyncTable.dncEnabled, on_set_dnc_enabled) hook_mod_menu_slider("Time Scale: " .. gGlobalSyncTable.timeScale, gGlobalSyncTable.timeScale, 0, 20, on_set_time_scale) hook_mod_menu_inputbox("Time Modifier", "0", 8, on_set_time_modifier) hook_mod_menu_button("Add To Time", on_add_hour) hook_mod_menu_button("Set Time", on_set_time) hook_mod_menu_button("Query Time", on_query_command) end