2024-01-01 21:41:28 +00:00
-- name: Day Night Cycle DX
2024-06-30 19:38:31 +00:00
-- incompatible: light day-night-cycle
2024-09-01 16:44:29 +00:00
-- 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.
2023-12-18 22:01:33 +00:00
2024-06-30 19:38:31 +00:00
--- @class Vec2f
--- @field public x number
--- @field public y number
2023-12-18 22:01:33 +00:00
gGlobalSyncTable.dncEnabled = true
2024-06-30 19:38:31 +00:00
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
2024-09-01 16:44:29 +00:00
local timeModifier = 0
2023-12-18 22:01:33 +00:00
-- localize functions to improve performance
2024-09-01 16:44:29 +00:00
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
2024-06-30 19:38:31 +00:00
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 ] = { } ,
2024-09-01 16:44:29 +00:00
[ DNC_HOOK_SET_TIME ] = { } ,
[ DNC_HOOK_SET_SKYBOX_MODEL ] = { }
2024-06-30 19:38:31 +00:00
}
--- @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 )
2023-12-18 22:01:33 +00:00
end
2024-06-30 19:38:31 +00:00
--- @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
2023-12-18 22:01:33 +00:00
end
2024-06-30 19:38:31 +00:00
--- Returns whether or not Day Night Cycle is globally enabled
function is_dnc_enabled ( )
return gGlobalSyncTable.dncEnabled and dayNightCycleApi.enabled
2023-12-18 22:01:33 +00:00
end
2024-06-30 19:38:31 +00:00
--- 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
2023-12-18 22:01:33 +00:00
2024-07-15 14:48:01 +00:00
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
2024-06-30 19:38:31 +00:00
local function update ( )
if not is_dnc_enabled ( ) then
2024-07-15 14:48:01 +00:00
reset_lighting ( )
2023-12-18 22:01:33 +00:00
return
end
2024-06-30 19:38:31 +00:00
if network_check_singleplayer_pause ( ) then return end
2024-07-15 14:48:01 +00:00
if network_player_connected_count ( ) == 1 and obj_get_first_with_behavior_id ( id_bhvActSelector ) ~= nil then return end
2024-06-30 19:38:31 +00:00
if network_is_server ( ) then time_tick ( ) end
2024-07-15 14:48:01 +00:00
if not init then update_night_music ( ) end
2023-12-18 22:01:33 +00:00
-- spawn skyboxes
local skybox = get_skybox ( )
2024-06-30 19:38:31 +00:00
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
2023-12-18 22:01:33 +00:00
-- spawn day, sunset and night skyboxes
2024-06-30 19:38:31 +00:00
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 )
2023-12-18 22:01:33 +00:00
end
2024-09-01 16:44:29 +00:00
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
2023-12-18 22:01:33 +00:00
spawn_non_sync_object (
2024-06-30 19:38:31 +00:00
bhvDNCSkybox ,
2024-09-01 16:44:29 +00:00
model ,
2023-12-18 22:01:33 +00:00
0 , 0 , 0 ,
--- @param o Object
function ( o )
o.oBehParams2ndByte = i
2024-06-30 19:38:31 +00:00
o.oAnimState = thisSkybox
obj_scale ( o , SKYBOX_SCALE - 10 * i )
2023-12-18 22:01:33 +00:00
end
)
end
else
-- spawn static skybox
spawn_non_sync_object (
2024-06-30 19:38:31 +00:00
bhvDNCSkybox ,
2024-07-15 14:48:01 +00:00
E_MODEL_DNC_SKYBOX ,
2023-12-18 22:01:33 +00:00
0 , 0 , 0 ,
--- @param o Object
function ( o )
o.oBehParams2ndByte = 0
2024-06-30 19:38:31 +00:00
o.oAnimState = skybox
2023-12-18 22:01:33 +00:00
obj_scale ( o , SKYBOX_SCALE )
end
)
end
end
2024-06-30 19:38:31 +00:00
local minutes = if_then_else ( skybox ~= BACKGROUND_HAUNTED , get_time_minutes ( ) , 12 )
2023-12-18 22:01:33 +00:00
local actSelector = obj_get_first_with_behavior_id ( id_bhvActSelector )
2024-06-30 19:38:31 +00:00
if actSelector == nil and show_day_night_cycle ( ) then
2023-12-18 22:01:33 +00:00
-- 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
2024-06-30 19:38:31 +00:00
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 ) )
2024-07-15 14:48:01 +00:00
if overrideAmbientColor ~= nil and type ( overrideColor ) == " table " then ambientColor = overrideAmbientColor end
2023-12-18 22:01:33 +00:00
-- 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
2024-06-30 19:38:31 +00:00
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
2023-12-18 22:01:33 +00:00
-- 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
2024-06-30 19:38:31 +00:00
local overrideDir = dnc_call_hook ( DNC_HOOK_SET_LIGHTING_DIR , dir )
if overrideDir ~= nil and type ( overrideDir ) == " number " then dir = overrideDir end
2023-12-18 22:01:33 +00:00
-- calculate fog intensity
2024-06-30 19:38:31 +00:00
local intensity = FOG_INTENSITY_NORMAL
2023-12-18 22:01:33 +00:00
if minutes >= HOUR_SUNRISE_START and minutes <= HOUR_SUNRISE_END then
2024-06-30 19:38:31 +00:00
intensity = lerp ( FOG_INTENSITY_DENSE , FOG_INTENSITY_NORMAL , clampf ( ( minutes - HOUR_SUNRISE_START ) / ( HOUR_SUNRISE_DURATION ) , 0 , 1 ) )
2023-12-18 22:01:33 +00:00
elseif minutes >= HOUR_SUNSET_START and minutes <= HOUR_NIGHT_START then
2024-06-30 19:38:31 +00:00
intensity = lerp ( FOG_INTENSITY_NORMAL , FOG_INTENSITY_DENSE , clampf ( ( minutes - HOUR_SUNSET_START ) / ( HOUR_NIGHT_START - HOUR_SUNSET_START ) , 0 , 1 ) )
2023-12-18 22:01:33 +00:00
elseif minutes < HOUR_SUNRISE_START or minutes > HOUR_NIGHT_START then
2024-06-30 19:38:31 +00:00
intensity = FOG_INTENSITY_DENSE
2023-12-18 22:01:33 +00:00
elseif minutes > HOUR_SUNRISE_END and minutes < HOUR_SUNSET_START then
2024-06-30 19:38:31 +00:00
intensity = FOG_INTENSITY_NORMAL
2023-12-18 22:01:33 +00:00
end
2024-06-30 19:38:31 +00:00
local overrideIntensity = dnc_call_hook ( DNC_HOOK_SET_FOG_INTENSITY , intensity )
if overrideIntensity ~= nil and type ( overrideIntensity ) == " number " then intensity = overrideIntensity end
2023-12-18 22:01:33 +00:00
set_lighting_dir ( 1 , - ( 1 - dir ) )
set_lighting_dir ( 2 , - ( 1 - dir ) )
2024-06-30 19:38:31 +00:00
-- make the castle still 25% ambient lit
if in_vanilla_level ( LEVEL_CASTLE ) then
color = color_lerp ( COLOR_DAY , color , 0.75 )
end
2023-12-18 22:01:33 +00:00
set_lighting_color ( 0 , color.r )
set_lighting_color ( 1 , color.g )
set_lighting_color ( 2 , color.b )
2024-06-30 19:38:31 +00:00
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 )
2023-12-18 22:01:33 +00:00
set_fog_color ( 0 , fogColor.r )
set_fog_color ( 1 , fogColor.g )
set_fog_color ( 2 , fogColor.b )
set_fog_intensity ( intensity )
else
2024-07-15 14:48:01 +00:00
reset_lighting ( )
2023-12-18 22:01:33 +00:00
end
2024-06-30 19:38:31 +00:00
init = false
2023-12-18 22:01:33 +00:00
end
local function on_hud_render_behind ( )
2024-06-30 19:38:31 +00:00
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
2023-12-18 22:01:33 +00:00
djui_hud_set_resolution ( RESOLUTION_N64 )
2024-06-30 19:38:31 +00:00
djui_hud_set_font ( FONT_NORMAL )
2023-12-18 22:01:33 +00:00
2024-06-30 19:38:31 +00:00
local scale = 0.5
local text = get_time_string ( gGlobalSyncTable.time )
2023-12-18 22:01:33 +00:00
2024-07-15 14:48:01 +00:00
local hidden = hud_is_hidden ( ) or ( hud_get_value ( HUD_DISPLAY_FLAGS ) & HUD_DISPLAY_FLAG_LIVES ) == 0
2023-12-18 22:01:33 +00:00
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 )
2024-06-30 19:38:31 +00:00
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
2023-12-18 22:01:33 +00:00
2024-06-30 19:38:31 +00:00
local minutes = if_then_else ( get_skybox ( ) ~= BACKGROUND_HAUNTED , get_time_minutes ( ) , 0 )
2023-12-18 22:01:33 +00:00
2024-06-30 19:38:31 +00:00
local color = COLOR_DISPLAY_BRIGHT
2023-12-18 22:01:33 +00:00
if minutes >= HOUR_SUNRISE_START and minutes <= HOUR_SUNRISE_END then
2024-06-30 19:38:31 +00:00
color = color_lerp ( COLOR_DISPLAY_DARK , COLOR_DISPLAY_BRIGHT , ( minutes - HOUR_SUNRISE_START ) / HOUR_SUNRISE_DURATION )
2023-12-18 22:01:33 +00:00
elseif minutes >= HOUR_SUNSET_END and minutes <= HOUR_NIGHT_START then
2024-06-30 19:38:31 +00:00
color = color_lerp ( COLOR_DISPLAY_BRIGHT , COLOR_DISPLAY_DARK , ( minutes - HOUR_SUNSET_END ) / HOUR_SUNSET_DURATION )
2023-12-18 22:01:33 +00:00
elseif minutes > HOUR_NIGHT_START or minutes < HOUR_SUNRISE_START then
2024-06-30 19:38:31 +00:00
color = COLOR_DISPLAY_DARK
2023-12-18 22:01:33 +00:00
elseif minutes > HOUR_SUNRISE_END and minutes < HOUR_SUNSET_END then
2024-06-30 19:38:31 +00:00
color = COLOR_DISPLAY_BRIGHT
2023-12-18 22:01:33 +00:00
end
2024-06-30 19:38:31 +00:00
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 )
2023-12-18 22:01:33 +00:00
end
local function on_level_init ( )
2024-06-30 19:38:31 +00:00
if not is_dnc_enabled ( ) then return end
2023-12-18 22:01:33 +00:00
playingNightMusic = false
2024-06-30 19:38:31 +00:00
if gNetworkPlayers [ 0 ] . currActNum ~= 99 then
if network_is_server ( ) then
save_time ( )
2023-12-18 22:01:33 +00:00
end
2024-06-30 19:38:31 +00:00
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 )
2023-12-18 22:01:33 +00:00
end
end
local function on_warp ( )
2024-06-30 19:38:31 +00:00
if not is_dnc_enabled ( ) then return end
2023-12-18 22:01:33 +00:00
if network_is_server ( ) then save_time ( ) end
2024-06-30 19:38:31 +00:00
playingNightMusic = false
2023-12-18 22:01:33 +00:00
end
local function on_exit ( )
if network_is_server ( ) then save_time ( ) end
end
2024-06-30 19:38:31 +00:00
--- @param msg string
2023-12-18 22:01:33 +00:00
local function on_set_command ( msg )
2024-09-01 16:44:29 +00:00
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
2023-12-18 22:01:33 +00:00
if msg == " " then
djui_chat_message_create ( " /time \\ #00ffff \\ set \\ #ffff00 \\ [TIME] \\ #dcdcdc \\ to set the time " )
return true
end
2024-06-30 19:38:31 +00:00
local oldTime = gGlobalSyncTable.time
2023-12-18 22:01:33 +00:00
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
2024-06-30 19:38:31 +00:00
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 ) )
2023-12-18 22:01:33 +00:00
end
end
2024-06-30 19:38:31 +00:00
dnc_call_hook ( DNC_HOOK_SET_TIME , oldTime , gGlobalSyncTable.time )
save_time ( )
2023-12-18 22:01:33 +00:00
end
2024-06-30 19:38:31 +00:00
--- @param msg string
2023-12-18 22:01:33 +00:00
local function on_add_command ( msg )
2024-09-01 16:44:29 +00:00
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
2023-12-18 22:01:33 +00:00
local amount = tonumber ( msg )
if amount == nil then
djui_chat_message_create ( " /time \\ #00ffff \\ add \\ #ffff00 \\ [AMOUNT] \\ #dcdcdc \\ to add to the time " )
2024-09-01 16:44:29 +00:00
return true
2023-12-18 22:01:33 +00:00
end
2024-06-30 19:38:31 +00:00
local oldTime = gGlobalSyncTable.time
2023-12-18 22:01:33 +00:00
gGlobalSyncTable.time = gGlobalSyncTable.time + ( amount * SECOND )
2024-06-30 19:38:31 +00:00
dnc_call_hook ( DNC_HOOK_SET_TIME , oldTime , gGlobalSyncTable.time )
2023-12-18 22:01:33 +00:00
djui_chat_message_create ( " [Day Night Cycle] Time set to " .. math_floor ( gGlobalSyncTable.time / SECOND ) )
2024-06-30 19:38:31 +00:00
save_time ( )
2023-12-18 22:01:33 +00:00
end
2024-06-30 19:38:31 +00:00
--- @param msg string
2023-12-18 22:01:33 +00:00
local function on_scale_command ( msg )
2024-09-01 16:44:29 +00:00
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
2023-12-18 22:01:33 +00:00
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 " )
2024-09-01 16:44:29 +00:00
return true
2023-12-18 22:01:33 +00:00
end
gGlobalSyncTable.timeScale = scale
2024-06-30 19:38:31 +00:00
mod_storage_save_number ( " scale " , scale )
2023-12-18 22:01:33 +00:00
djui_chat_message_create ( " [Day Night Cycle] Time scale set to " .. scale )
2024-06-30 19:38:31 +00:00
save_time ( )
2023-12-18 22:01:33 +00:00
end
local function on_query_command ( )
2024-06-30 19:38:31 +00:00
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 ( ) ) )
2023-12-18 22:01:33 +00:00
end
local function on_24h_command ( )
use24h = not use24h
mod_storage_save_bool ( " 24h " , use24h )
end
local function on_sync_command ( )
2024-09-01 16:44:29 +00:00
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
2023-12-18 22:01:33 +00:00
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
2024-06-30 19:38:31 +00:00
save_time ( )
2023-12-18 22:01:33 +00:00
end
2024-06-30 19:38:31 +00:00
local function on_music_command ( )
2024-09-01 16:44:29 +00:00
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
2024-06-30 19:38:31 +00:00
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
2023-12-18 22:01:33 +00:00
local function on_time_command ( msg )
local args = split ( msg )
2024-06-30 19:38:31 +00:00
2023-12-18 22:01:33 +00:00
if args [ 1 ] == " set " then
2024-06-30 19:38:31 +00:00
if not network_is_server ( ) then
djui_chat_message_create ( " \\ #ffa0a0 \\ [Day Night Cycle] You do not have permission to run /time set " )
2023-12-18 22:01:33 +00:00
else
on_set_command ( args [ 2 ] or " " )
end
elseif args [ 1 ] == " add " then
2024-06-30 19:38:31 +00:00
if not network_is_server ( ) then
djui_chat_message_create ( " \\ #ffa0a0 \\ [Day Night Cycle] You do not have permission to run /time add " )
2023-12-18 22:01:33 +00:00
else
on_add_command ( args [ 2 ] or " " )
end
elseif args [ 1 ] == " scale " then
2024-06-30 19:38:31 +00:00
if not network_is_server ( ) then
djui_chat_message_create ( " \\ #ffa0a0 \\ [Day Night Cycle] You do not have permission to run /time scale " )
2023-12-18 22:01:33 +00:00
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
2024-06-30 19:38:31 +00:00
if not network_is_server ( ) then
djui_chat_message_create ( " \\ #ffa0a0 \\ [Day Night Cycle] You do not have permission to run /time sync " )
2023-12-18 22:01:33 +00:00
else
on_sync_command ( )
end
2024-06-30 19:38:31 +00:00
elseif args [ 1 ] == " music " then
on_music_command ( )
2023-12-18 22:01:33 +00:00
else
2024-06-30 19:38:31 +00:00
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 " )
2023-12-18 22:01:33 +00:00
else
gGlobalSyncTable.dncEnabled = not gGlobalSyncTable.dncEnabled
djui_chat_message_create ( " [Day Night Cycle] Status: " .. on_or_off ( gGlobalSyncTable.dncEnabled ) )
end
end
return true
end
2024-06-30 19:38:31 +00:00
--- @param value boolean
local function on_set_dnc_enabled ( _ , value )
2024-09-01 16:44:29 +00:00
if _G.dayNightCycleApi . lockTime then
play_sound ( SOUND_MENU_CAMERA_BUZZ , gGlobalSoundSource )
return
end
2024-06-30 19:38:31 +00:00
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 )
2024-09-01 16:44:29 +00:00
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
2024-06-30 19:38:31 +00:00
playNightMusic = value
mod_storage_save_bool ( " night_music " , value )
end
--- @param value integer
local function on_set_time_scale ( index , value )
2024-09-01 16:44:29 +00:00
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
2024-06-30 19:38:31 +00:00
gGlobalSyncTable.timeScale = value
mod_storage_save_number ( " scale " , value )
update_mod_menu_element_name ( index , " Time Scale: " .. value )
end
2024-09-01 16:44:29 +00:00
--- @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
2024-06-30 19:38:31 +00:00
local function on_add_hour ( )
2024-09-01 16:44:29 +00:00
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
2024-06-30 19:38:31 +00:00
local oldTime = gGlobalSyncTable.time
2024-09-01 16:44:29 +00:00
gGlobalSyncTable.time = gGlobalSyncTable.time + timeModifier * SECOND
2024-06-30 19:38:31 +00:00
dnc_call_hook ( DNC_HOOK_SET_TIME , oldTime , gGlobalSyncTable.time )
save_time ( )
end
2024-09-01 16:44:29 +00:00
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
2024-06-30 19:38:31 +00:00
2024-09-01 16:44:29 +00:00
gGlobalSyncTable.time = timeModifier * SECOND
2024-06-30 19:38:31 +00:00
end
local sReadonlyMetatable = {
__index = function ( table , key )
return rawget ( table , key )
end ,
__newindex = function ( )
2024-09-01 16:44:29 +00:00
error ( " Attempt to update a read-only table " , 2 )
2024-06-30 19:38:31 +00:00
end
}
2023-12-18 22:01:33 +00:00
_G.dayNightCycleApi = {
2024-09-01 16:44:29 +00:00
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
2024-06-30 19:38:31 +00:00
is_dnc_enabled = is_dnc_enabled ,
2023-12-18 22:01:33 +00:00
get_day_count = get_day_count ,
get_raw_time = get_raw_time ,
set_raw_time = set_raw_time ,
2024-06-30 19:38:31 +00:00
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 ,
2024-07-15 14:48:01 +00:00
should_play_night_music = should_play_night_music ,
night_music_register = night_music_register ,
2024-06-30 19:38:31 +00:00
dnc_hook_event = dnc_hook_event ,
constants = {
2024-09-01 16:44:29 +00:00
DNC_VERSION_MAJOR = DNC_VERSION_MAJOR ,
DNC_VERSION_MINOR = DNC_VERSION_MINOR ,
DNC_VERSION_PATCH = DNC_VERSION_PATCH ,
DNC_VERSION = DNC_VERSION ,
2024-06-30 19:38:31 +00:00
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
2024-09-01 16:44:29 +00:00
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
2024-06-30 19:38:31 +00:00
}
2023-12-18 22:01:33 +00:00
}
2024-06-30 19:38:31 +00:00
setmetatable ( _G.dayNightCycleApi , sReadonlyMetatable )
2023-12-18 22:01:33 +00:00
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 )
2024-09-01 16:44:29 +00:00
hook_event ( HOOK_ON_HUD_RENDER_BEHIND , on_hud_render_behind )
2023-12-18 22:01:33 +00:00
2024-06-30 19:38:31 +00:00
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 )
2024-09-01 16:44:29 +00:00
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 )
2024-06-30 19:38:31 +00:00
if network_is_server ( ) then
hook_mod_menu_checkbox ( " Enable Day Night Cycle " , gGlobalSyncTable.dncEnabled , on_set_dnc_enabled )
2024-07-15 14:48:01 +00:00
hook_mod_menu_slider ( " Time Scale: " .. gGlobalSyncTable.timeScale , gGlobalSyncTable.timeScale , 0 , 20 , on_set_time_scale )
2024-09-01 16:44:29 +00:00
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 )
2024-06-30 19:38:31 +00:00
end