496 lines
15 KiB
Lua

--debug_status = 1
debug_mod_name = "TimeTools"
debug_file = debug_mod_name .. "-debug.txt"
require("utils")
--require("config")
local ticks_per_day = 25000
--------------------------------------------------------------------------------------
local function init_day()
global.day = 1 + math.floor((game.tick+(ticks_per_day/2)) / ticks_per_day)
end
--------------------------------------------------------------------------------------
local function get_time()
-- daytime : 0.0 to 1.0, noon to noon (midnight at 0.5), max light to min light to max light...
-- game starts at daytime = 0, so noon of day 1.
local daytime
local always_day = global.surface.always_day or 0
if global.always_day ~= always_day then
global.refresh_always_day = true
end
if always_day then
daytime = game.tick / ticks_per_day
daytime = daytime - math.floor(daytime)
else
if global.always_day == true then
daytime = ((global.h + 12) + (global.m / 60)) / 24
global.surface.daytime = daytime - math.floor(daytime)
end
daytime = global.surface.daytime
end
daytime = (daytime*24+12) % 24
global.h = math.floor(daytime)
global.m = math.floor((daytime-global.h)*60)
-- day calculation independant of hour
global.day = math.floor((game.tick+(ticks_per_day/2)) / ticks_per_day) + 1
global.always_day = always_day
global.h_prev = global.h
end
--------------------------------------------------------------------------------------
local function init_globals()
-- initialize or update general globals of the mod
debug_print( "init_globals" )
global.ticks = global.ticks or 0
global.cycles = global.cycles or 0
global.surface = game.surfaces.nauvis
if global.offset == nil then global.offset = 0 end
if global.h == nil then global.h = 12 end
if global.m == nil then global.m = 0 end
global.h_prev = global.h_prev or 23
global.always_day = global.always_day or -1 -- -1 to force update of the icon at first install
global.refresh_always_day = true
if not settings.global["timetools-always-day"].value then global.surface.always_day = false end
if global.day == nil then
init_day()
get_time()
end
if global.frozen == nil then global.frozen = false end
if global.display == nil then global.display = true end
global.clocks = global.clocks or {}
global.speed_mem = global.speed_mem or settings.global["timetools-maximum-speed"].value
end
--------------------------------------------------------------------------------------
local function init_player(player)
if global.ticks == nil then return end
-- initialize or update per player globals of the mod, and reset the gui
debug_print( "init_player ", player.name, " connected=", player.connected )
if player.connected then
build_gui(player)
end
end
--------------------------------------------------------------------------------------
local function init_players()
for _, player in pairs(game.players) do
init_player(player)
end
end
--------------------------------------------------------------------------------------
local function init_forces()
for _,force in pairs(game.forces) do
force.recipes["clock-combinator"].enabled = force.technologies["circuit-network"].researched
end
end
--------------------------------------------------------------------------------------
local function on_init()
-- called once, the first time the mod is loaded on a game (new or existing game)
debug_print( "on_init" )
init_globals()
init_forces()
init_players()
end
script.on_init(on_init)
--------------------------------------------------------------------------------------
local function on_configuration_changed(data)
-- detect any mod or game version change
if data.mod_changes ~= nil then
local changes = data.mod_changes[debug_mod_name]
if changes ~= nil then
debug_print( "update mod: ", debug_mod_name, " ", tostring(changes.old_version), " to ", tostring(changes.new_version) )
init_globals()
global.always_day = -1 -- to force update of icon
init_forces()
-- migrations
for _, player in pairs(game.players) do
if player.gui.top.timebar_frame then player.gui.top.timebar_frame.destroy() end -- destroy old bar
end
if changes.old_version ~= nil and older_version(changes.old_version, "1.0.18") then
init_day()
end
if changes.old_version ~= nil and older_version(changes.old_version, "1.0.34") then
for _, player in pairs(game.players) do
if player.gui.top.timetools_flow then player.gui.top.timetools_flow.destroy() end -- rebuild bar
end
end
if changes.old_version ~= nil and older_version(changes.old_version, "2.0.41") then
for _, player in pairs(game.players) do
if player.gui.top.timetools_flow then player.gui.top.timetools_flow.destroy() end -- rebuild bar
end
end
init_players()
update_guis()
end
end
end
script.on_configuration_changed(on_configuration_changed)
--------------------------------------------------------------------------------------
local function on_player_created(event)
-- called at player creation
local player = game.players[event.player_index]
debug_print( "player created ", player.name )
init_player(player)
end
script.on_event(defines.events.on_player_created, on_player_created )
--------------------------------------------------------------------------------------
local function on_player_joined_game(event)
-- called in SP(once) and MP(every connect), eventually after on_player_created
local player = game.players[event.player_index]
debug_print( "player joined ", player.name )
init_player(player)
end
script.on_event(defines.events.on_player_joined_game, on_player_joined_game )
--------------------------------------------------------------------------------------
local function on_creation( event )
local ent = event.created_entity
if ent.name == "clock-combinator" then
debug_print( "clock-combinator created" )
table.insert( global.clocks,
{
entity = ent,
}
)
debug_print( "clocks=" .. #global.clocks )
end
end
script.on_event(defines.events.on_built_entity, on_creation )
script.on_event(defines.events.on_robot_built_entity, on_creation )
--------------------------------------------------------------------------------------
local function on_destruction( event )
local ent = event.entity
if ent.name == "clock-combinator" then
debug_print( "clock-combinator destroyed" )
for i, clock in ipairs(global.clocks) do
if clock.entity == ent then
table.remove( global.clocks, i )
break
end
end
debug_print( "clocks=" .. #global.clocks )
end
end
script.on_event(defines.events.on_entity_died, on_destruction )
script.on_event(defines.events.on_robot_pre_mined, on_destruction )
script.on_event(defines.events.on_pre_player_mined_item, on_destruction )
--------------------------------------------------------------------------------------
local function format_time()
local sTime = ""
sTime = string.format("%u-%02u:%02u", global.day, global.h, global.m )
return sTime
end
local function on_tick(event)
if global.speed_mem > settings.global["timetools-maximum-speed"].value then
-- User changed the speed mid acceleration or on the fly
global.speed_mem = settings.global["timetools-maximum-speed"].value
if game.speed > global.speed_mem then
game.speed = global.speed_mem
update_guis()
end
end
if (game.tick % settings.global["timetools-clock-update-interval"].value) == 0 then
get_time()
-- update time display on button
if global.display then
local s_time = format_time()
local flow
for _, player in pairs(game.players) do
if player.connected and player.gui.top.timetools_flow then
flow = player.gui.top.timetools_flow
if flow.timetools_but_time == nil or (debug_status and flow.timetools_but_tick == nil) then
flow.destroy()
init_player(player)
update_guis()
flow = player.gui.top.timetools_flow -- re-assign
end
flow.timetools_but_time.caption = s_time
if global.refresh_always_day then
if global.surface.always_day then
flow.timetools_but_always.sprite = "sprite_timetools_alwday"
else
flow.timetools_but_always.sprite = "sprite_timetools_night"
end
end
if debug_status then
flow.timetools_but_tick.caption = game.tick
end
end
end
global.refresh_always_day = false
end
end
if (game.tick % settings.global["timetools-combinator-interval"].value) == 0 then
for i, clock in pairs(global.clocks) do
if clock.entity.valid then
params = {
{index=1,signal={type="virtual",name="signal-clock-gametick"},count=math.floor(game.tick)},
{index=2,signal={type="virtual",name="signal-clock-day"},count=global.day},
{index=3,signal={type="virtual",name="signal-clock-hour"},count=global.h},
{index=4,signal={type="virtual",name="signal-clock-minute"},count=global.m},
{index=5,signal={type="virtual",name="signal-clock-alwaysday"},count=iif(global.surface.always_day,1,0)},
{index=6,signal={type="virtual",name="signal-clock-darkness"},count=math.floor(global.surface.darkness*100)},
{index=7,signal={type="virtual",name="signal-clock-lightness"},count=math.floor((1-global.surface.darkness)*100)},
}
clock.entity.get_control_behavior().parameters = params
else
table.remove(global.clocks,i)
end
end
end
end
script.on_event(defines.events.on_tick, on_tick)
--------------------------------------------------------------------------------------
local function on_gui_click(event)
local player = game.players[event.player_index]
if string.match(event.element.name, "timetools_") == nil then
-- not for us
return
end
if player.admin then
if event.element.name == "timetools_but_time" then
if not global.surface.always_day then
global.frozen = not global.frozen
global.surface.freeze_daytime = global.frozen
update_guis()
end
elseif event.element.name == "timetools_but_always" then
if settings.global["timetools-always-day"].value then
global.surface.always_day = not global.surface.always_day
if global.surface.always_day then
global.frozen = false
end
end
update_guis()
elseif event.element.name == "timetools_but_slower" then
if game.speed >= 0.2 then game.speed = game.speed / 2 end -- minimum 0.1
if game.speed ~= 1 then global.speed_mem = game.speed end
update_guis()
elseif event.element.name == "timetools_but_faster" then
if game.speed < settings.global["timetools-maximum-speed"].value then game.speed = game.speed * 2 end
if game.speed ~= 1 then global.speed_mem = game.speed end
update_guis()
elseif event.element.name == "timetools_but_speed" then
if game.speed == 1 then game.speed = global.speed_mem else game.speed = 1 end
update_guis()
end
else
player.print({"mod-messages.timetools-message-admins-only"})
end
end
script.on_event(defines.events.on_gui_click, on_gui_click )
--------------------------------------------------------------------------------------
function build_gui( player )
local gui1 = player.gui.top.timetools_flow
if gui1 == nil and global.display then
debug_print("create frame player" .. player.name)
gui1 = player.gui.top.add({type = "flow", name = "timetools_flow", direction = "horizontal", style = "timetools_flow_style"})
local gui2 = gui1.add({type = "button", name = "timetools_but_time", caption = "0-00:00", font_color = colors.white, style = "timetools_botton_time_style"})
if global.frozen then
gui2.style.font_color = colors.lightred
else
gui2.style.font_color = colors.green
end
gui2 = gui1.add({type = "sprite-button", name = "timetools_but_always", style = "timetools_sprite_style"})
if global.surface.always_day then
gui2.sprite = "sprite_timetools_alwday"
else
gui2.sprite = "sprite_timetools_night"
end
gui1.add({type = "button", name = "timetools_but_slower", caption = "<" , font_color = colors.white, style = "timetools_button_style"})
gui1.add({type = "button", name = "timetools_but_faster", caption = ">" , font_color = colors.white, style = "timetools_button_style"})
gui1.add({type = "button", name = "timetools_but_speed", caption = "x1" , font_color = colors.white, style = "timetools_button_style"})
if debug_status then
gui1.add({type = "button", name = "timetools_but_tick", caption = "0" , font_color = colors.white, style = "timetools_button_style"})
end
end
return( gui1 )
end
--------------------------------------------------------------------------------------
function update_guis()
if global.display then
for _, player in pairs(game.players) do
if player.connected then
local flow = build_gui(player)
local s
if game.speed == 1 then
flow.timetools_but_speed.caption = "x1"
flow.timetools_but_speed.style.font_color = colors.white
elseif game.speed < 1 then
s = string.format("/%1.0f", 1/game.speed )
flow.timetools_but_speed.caption = s
flow.timetools_but_speed.style.font_color = colors.green
elseif game.speed > 1 then
s = string.format("x%1.0f", game.speed )
flow.timetools_but_speed.caption = s
flow.timetools_but_speed.style.font_color = colors.lightred
end
if global.surface.always_day then
flow.timetools_but_always.sprite = "sprite_timetools_alwday"
else
flow.timetools_but_always.sprite = "sprite_timetools_night"
end
if global.frozen then
flow.timetools_but_time.style.font_color = colors.lightred
else
flow.timetools_but_time.style.font_color = colors.green
end
end
end
end
end
--------------------------------------------------------------------------------------
local interface = {}
function interface.reset()
debug_print( "reset" )
init_day()
for _,force in pairs(game.forces) do
force.reset_recipes()
force.reset_technologies()
end
for _, player in pairs(game.players) do
if player.gui.top.timetools_flow then
player.gui.top.timetools_flow.destroy()
end
end
update_guis()
end
function interface.setclock( hhmm )
debug_print( "setclock" )
if hhmm == nil then hhmm = 0 end
if hhmm < 0 then hhmm = 0 end
if hhmm >= 24 then hhmm = 23.59 end
local mm = (hhmm - math.floor(hhmm)) * 100
local hh = math.floor(hhmm)
if mm >= 60 then mm = 59 end
global.surface.always_day = false
global.surface.daytime = math.min((((hh+12)%24) * 60 + mm) / 24 / 60,1)
global.frozen = false
global.h = hh
global.m = mm
update_guis()
end
function interface.setspeed(speed)
debug_print( "set time" )
if speed == nil then speed = 1 end
speed = math.floor(speed) -- ensure integer
if speed < 1 then speed = 1 end
if speed > settings.global["timetools-maximum-speed"].value then
speed = settings.global["timetools-maximum-speed"].value
end
global.speed = speed
update_guis()
end
function interface.setfrozen( frozen )
debug_print( "frozen" )
global.frozen = frozen
update_guis()
end
function interface.off( )
debug_print( "off" )
global.display = false
for _, player in pairs(game.players) do
if player.connected and player.gui.top.timetools_flow then player.gui.top.timetools_flow.destroy() end
end
end
function interface.on( )
debug_print( "on" )
global.display = true
update_guis()
end
remote.add_interface( "timetools", interface )
-- /c remote.call( "timetools", "setclock", 20.15 )
-- /c remote.call( "timetools", "reset" )
-- /c remote.call( "timetools", "on" )
-- /c remote.call( "timetools", "off" )
-- /c remote.call( "timetools", "setfrozen", true )
-- /c remote.call( "timetools", "setspeed", 2 )