--[[ | This file was obtained through the combined efforts | of Madbluntz & Plymouth Antiquarian Society. | | Credits: lifestorm, Gregory Wayne Rossel JR., | Maloy, DrPepper10 @ RIP, Atle! | | Visit for more: https://plymouth.thetwilightzone.ru/ --]] --[[------------------------------------------------------------------------- My god, look at the time. StormFox2.Time.GetTime(bNearestSecond) [nTime] -- Returns the time number. Between 0 and 1440 StormFox2.Time.TimeToString(nTime = current time,bUse12Hour) [sTime] -- Returns the time as a string. StormFox2.Time.IsDay() [bIsDay] -- Returns true if its day StormFox2.Time.IsNight() [bIsNight] -- Returns true if its night StormFox2.Time.GetStamp(nTime = current time) [nTimeStamp] -- Returns a timestamp. SERVER StormFox2.Time.Set(nTime or string) -- Sets the time. Also supports a string "12:00" or "5:00 AM". StormFox2.Time.SetSpeed(nSpeed) -- Sets the timespeed. Hooks: StormFox2.Time.Set -- Called when the time gets set. StormFox2.Time.NewStamp NewStamp OldStamp -- Callend when the time matches a new stamp BASE_TIME is CurTime + StartTime ---------------------------------------------------------------------------]] ---A number between 0 and 1440. Where 720 is midday and 0 / 1440 is midnight. ---@class TimeNumber : number local floor,ceil,random = math.floor, math.ceil, math.random StormFox2.Time = StormFox2.Time or {} -- Settings local s_start = StormFox2.Setting.AddSV("start_time",-1,nil, "Time", -1, 1440) -- Sets the starttime local s_real = StormFox2.Setting.AddSV("real_time",false,nil, "Time") -- Sets the startime to match OS local s_random = StormFox2.Setting.AddSV("random_time",false,nil,"Time") -- Makes the time random local s_continue = StormFox2.Setting.AddSV("continue_time",true,nil,"Time"):SetRadioDefault() -- Make the time continue from last s_start:SetRadioAll( s_real, s_random, s_continue ) StormFox2.Setting.SetType("start_time","Time_toggle") local day_length = StormFox2.Setting.AddSV("day_length", 12,nil,"Time",-1, 24 * 60 * 7 ) :SetMenuType("special_float") local night_length = StormFox2.Setting.AddSV("night_length", 12,nil,"Time",-1, 24 * 60 * 7 ) :SetMenuType("special_float") local sun_rise = StormFox2.Setting.AddSV("sunrise",360,nil, "Time", 0, 1440) StormFox2.Setting.SetType("sunrise", "Time") local sun_set = StormFox2.Setting.AddSV("sunset",1080,nil, "Time", 0, 1440) StormFox2.Setting.SetType("sunset", "Time") --[[ Pause day_length = <= 0 night_length = <= 0 Only day day_length = > 0 night_length = < 0 Only night day_length = < 0 night_length = >= 0 ]] --[[ ---- EDIT NOTE ---- x Instead of using Settings directly in UpdateMath. MAke UpdateMath use arguments instead. These settings are send from the server to client on SetTime or join-data. When changing settings on the server, wait a few ticks to set them. Sometimes there are multiple settings being changed at the same time. Best to wait a bit. StartTime also got removed .. need to fix that. ]] -- Returns the total time in minutes for a day local BASE_TIME = 0 --[[ Calculates the regular time cycleTime - The total time it takes for a day to pass Enums to keep me sane - finishTime = The finished number between 0 and 1440. This is the ingame time - cycleTime = The total seconds it takes for a day to pass - dayTime = The total seconds it takes for "day-light" to pass - nightTime = The total seconds it takes for a night to pass - sunTime = The total of ingame the sun is up - nightTime = The total of ingame the sun is down - cyclePercentDay= The percent of the day, being day-light (Only with day and night on) ]] -- Math Box to set and get time local Get, Set, UpdateMath, isInDay, isDay, dayLength, nightLength, netWriteData local GetCache, IsDayCache, CycleCache, FinsihToCycle, GetCycleRaw local CR do local SF_PAUSE = 0 local SF_NORMAL = 1 local SF_DAYONLY = 2 local SF_NIGHTONLY = 3 local SF_REAL = 4 local cycleLength local curType -- The time-type -- Returns the percent from the given time ( 0 - 1440) between starttime and endtime -- Also loops around if from is higer than to local function lerp1440( time, from, to ) if from < to then return ( time - from ) / ( to - from ) elseif time >= from then return ( time - from ) / ( 1440 - from + to ) else local ex = 1440 - from return ( time + ex ) / ( to + ex ) end end local sunTimeUp, nightTimeUp, sunSet, sunRise function isInDay( finishTime ) if not sunRise then return true end -- Not loaded yet if sunRise < sunSet then return finishTime >= sunRise and finishTime <= sunSet end return (finishTime >= sunRise and finishTime <= 1440 ) or finishTime <= sunSet end -- Splits cycletime into dayPercent and nightPercent local function CycleToPercent( cycleTime ) if cycleTime <= dayLength then -- It is day return cycleTime / dayLength, nil else -- It is night return nil, (cycleTime - dayLength) / nightLength end end -- Takes dayPercent or nightPercent and convert it to cycletime local function PercentToCycle( dayPercent, nightPercent ) if dayPercent then return dayPercent * dayLength else return dayLength + nightLength * nightPercent end end -- returns percent of the day that has passed at the given time local function finishDayToPercent( finishTime ) return lerp1440( finishTime, sunRise, sunSet ) end -- returns percent of the night that has passed at the given time local function finishNightToPercent( finishTime ) return lerp1440( finishTime, sunSet, sunRise ) end -- Takes the ingame 0-1440 and converts it to the cycle-area function FinsihToCycle( finishTime ) if isInDay( finishTime ) then -- If day return finishDayToPercent( finishTime ) * dayLength else return dayLength + finishNightToPercent( finishTime ) * nightLength end end local function CycleToFinish( cycle ) if cycle <= dayLength then -- Day time local percent = cycle / dayLength return ( sunRise + sunTimeUp * percent ) % 1440 else -- NightTime local percent = ( cycle - dayLength ) / nightLength return ( sunSet + nightTimeUp * percent ) % 1440 end end -- Get local function TimeFromSettings( ) -- The seconds passed in the day local chunk = ((CurTime() - BASE_TIME) % cycleLength) return CycleToFinish( chunk ) end local function TimeFromSettings_DAY( ) local p_chunk = ((CurTime() - BASE_TIME) % cycleLength) / cycleLength return (sunRise + p_chunk * sunTimeUp) % 1440 end local function TimeFromSettings_NIGHT( ) local p_chunk = ((CurTime() - BASE_TIME) % cycleLength) / cycleLength return (sunSet + p_chunk * nightTimeUp) % 1440 end local function TimeFromPause() return BASE_TIME end -- Is cheaper than converting things around function isDay() if not cycleLength then return true end -- Not loaded yet if curType == SF_NIGHTONLY then return false elseif curType == SF_DAYONLY then return true else local l = (CurTime() - BASE_TIME) % cycleLength return l <= dayLength end end function Get() if not cycleLength then return 720 end -- Not loaded yet local num if not curType or curType == SF_NORMAL then num = TimeFromSettings( ) GetCache = num IsDayCache = isDay() elseif curType == SF_REAL then num = ( CurTime() / 60 - BASE_TIME ) % 1440 GetCache = num IsDayCache = isInDay( num ) elseif curType == SF_PAUSE then num = TimeFromPause( ) GetCache = num IsDayCache = isInDay( num ) elseif curType == SF_DAYONLY then num = TimeFromSettings_DAY( ) GetCache = num IsDayCache = true else num = TimeFromSettings_NIGHT( ) GetCache = num IsDayCache = false end return num end function Set( snTime ) if not curType or curType == SF_NORMAL then BASE_TIME = CurTime() - FinsihToCycle( snTime ) elseif curType == SF_REAL then BASE_TIME = CurTime() / 60 - snTime elseif curType == SF_PAUSE then BASE_TIME = snTime -- If you pause the time, we should save it if we got s_continue on. if SERVER and StormFox2.Loaded and s_continue:GetValue() then cookie.Set("sf2_lasttime", tostring(snTime)) end elseif curType == SF_DAYONLY then local p = math.Clamp(lerp1440( snTime, sunRise, sunSet ), 0, 1) BASE_TIME = CurTime() - p * dayLength elseif curType == SF_NIGHTONLY then local p = math.Clamp(lerp1440( snTime, sunSet, sunRise ), 0, 1) BASE_TIME = CurTime() - p * nightLength end GetCache = nil -- Delete time cache -- Gets called when the user changes the time, or time variables. Tells scripts to recalculate things. if not StormFox2.Loaded then return end hook.Run("StormFox2.Time.Changed") end function UpdateMath(nsTime, blockSetTime) local nsTime = nsTime or ( cycleLength and Get() ) sunSet = sun_set:GetValue() sunRise = sun_rise:GetValue() dayLength = day_length:GetValue() * 60 nightLength = night_length:GetValue() * 60 --print(sunSet) --print(sunRise) --print(dayLength) --print(nightLength) if s_real:GetValue() then -- Real time cycleLength = 60 * 60 * 24 curType = SF_REAL elseif dayLength <= 0 and nightLength <= 0 or sunSet == sunRise then -- Pause type curType = SF_PAUSE cycleLength = 0 elseif nightLength <= 0 then -- Day only cycleLength = dayLength curType = SF_DAYONLY elseif dayLength <= 0 then -- Night only cycleLength = nightLength curType = SF_NIGHTONLY else cycleLength = dayLength + nightLength curType = SF_NORMAL end if sunRise < sunSet then sunTimeUp = sunSet - sunRise else sunTimeUp = (1440 - sunRise) + sunSet end nightTimeUp = 1440 - sunTimeUp if not nsTime or blockSetTime then return end -- No valid time currently Set( nsTime ) if SERVER then net.Start( StormFox2.Net.Time ) net.WriteString( tostring( BASE_TIME ) ) net.Broadcast() end end local function GetDayPercent() if not IsDayCache then return -1 end local chunk = ((CurTime() - BASE_TIME) % cycleLength) return chunk / dayLength end local function GetNightPercent() if IsDayCache then return -1 end local chunk = ((CurTime() - BASE_TIME) % cycleLength) return (chunk - dayLength) / nightLength end function GetCycleRaw() if not cycleLength then return 0 end -- Not loaded, or pause on launch if CR then return CR end CR = ((CurTime() - BASE_TIME) % cycleLength) return CR end -- Returns how far the day has progressed 0 = sunRise, 0.5 = sunSet, 1 = sunRise function StormFox2.Time.GetCycleTime() if CycleCache then return CycleCache end if curType == SF_REAL then local t = Get() if isInDay( t ) then CycleCache = lerp1440( t, sunRise, sunSet ) / 2 else CycleCache = 0.5 + lerp1440( t, sunSet, sunRise ) / 2 end return CycleCache end if curType == SF_PAUSE then -- When paused, use the time to calculate if isInDay( BASE_TIME ) then CycleCache = lerp1440( BASE_TIME, sunRise, sunSet ) / 2 else CycleCache = 0.5 + lerp1440( BASE_TIME, sunSet, sunRise ) / 2 end return math.Clamp(CycleCache, 0, 1) end if IsDayCache then CycleCache = GetDayPercent() / 2 return math.Clamp(CycleCache, 0, 1) elseif cycleLength then CycleCache = GetNightPercent() / 2 + 0.5 return math.Clamp(CycleCache, 0, 1) else -- Idk return 0.5 end end end -- Cache clear. Wait 4 frames to update the time-cache, calculating it for every function is too costly. do local i = 0 hook.Add("Think", "StormFox2.Time.ClearCache", function() CR = nil i = i + 1 if i >= 2 then i = 0 GetCache = nil CycleCache = nil end end) end -- In most cases, multiple settings will update at the same time. Wait a second. local function updateTimeSettings( ) if timer.Exists("SF_SETTIME") then return end timer.Create("SF_SETTIME", 0.2, 1, function() UpdateMath( nil, CLIENT ) -- If we're the client, then don't update the BASE_TIME end) end -- If any of the settings change, update the math behind it. This will also fix time and update clients if done on server. day_length:AddCallback( updateTimeSettings,"SF_TIMEUPDATE") night_length:AddCallback( updateTimeSettings,"SF_TIMEUPDATE") sun_rise:AddCallback( updateTimeSettings,"SF_TIMEUPDATE") sun_set:AddCallback( updateTimeSettings,"SF_TIMEUPDATE") s_real:AddCallback( updateTimeSettings,"SF_TIMEUPDATE") -- Make real-time change day and night length if SERVER then s_real:AddCallback( function( b ) if not b then return end local dt = string.Explode(":",os.date("%H:%M:%S")) nsTime = tonumber(dt[1]) * 60 + tonumber(dt[2]) + tonumber(dt[3]) / 60 StormFox2.Time.Set(nsTime) end,"SF_REALTIME_S") end -- Update the math within Get and Set. Will also try and adjust the time if SERVER then -- Server controls the time local start_time = math.Clamp(cookie.GetNumber("sf2_lasttime",-1) or -1, -1, 1439) if s_continue:GetValue() and start_time >= 0 then -- Continue time from last else if s_start:GetValue() >= 0 then -- Start time is on start_time = s_start:GetValue() elseif s_real:GetValue() then -- Real time local dt = string.Explode(":",os.date("%H:%M:%S")) start_time = tonumber(dt[1]) * 60 + tonumber(dt[2]) + tonumber(dt[3]) / 60 else -- if s_random:GetValue() or start_time < 0 then Make it random if all options are invalid start_time = math.Rand(0, 1400) end end UpdateMath( start_time, false ) ---Sets the time. TimeNumber is a number between 0 and 1440. ---@param nsTime TimeNumber ---@return boolean success ---@see TimeNumber ---@server function StormFox2.Time.Set( nsTime ) if nsTime and type( nsTime ) == "string" then nsTime = StormFox2.Time.StringToTime(nsTime) end if not nsTime then return false end Set( nsTime ) net.Start( StormFox2.Net.Time ) net.WriteString( tostring( BASE_TIME ) ) -- Sending the current time might add a delay to clients. Better to send the new base. net.Broadcast() return true end -- Tell new clients the settings hook.Add("StormFox2.data.initspawn", "StormFox2.Time.SendOnJoin", function( ply ) net.Start( StormFox2.Net.Time ) net.WriteString( tostring( BASE_TIME ) ) net.Send( ply ) end) else UpdateMath( 720, true ) -- Set the starting time to 720. We don't know any settings yet. net.Receive( StormFox2.Net.Time, function(len) BASE_TIME = tonumber( net.ReadString() ) or 0 end) end ---Returns the current time. TimeNumber is a number between 0 and 1440. ---@param bNearestSecond boolean ---@return TimeNumber ---@shared function StormFox2.Time.Get( bNearestSecond ) if bNearestSecond then return math.floor(GetCache and GetCache or Get()) end return GetCache and GetCache or Get() end ---Returns the current timespeed / 60. Used for internal calculations. ---@deprecated ---@return number ---@shared function StormFox2.Time.GetSpeed_RAW() if not nightLength or StormFox2.Time.IsPaused() then return 0 end if IsDayCache then return 1 / dayLength end return 1 / nightLength end ---Returns the current timespeed. "How many seconds pr real second". ---@return number ---@shared function StormFox2.Time.GetSpeed() return StormFox2.Time.GetSpeed_RAW() * 60 end -- Be able to load time local function thinkingBox(sVar) -- Converts string to something useful local h,m = string.match(sVar,"(%d?%d):?(%d?%d)") local ampm = string.match(sVar,"[ampAMP]+") or "" if not h or not m then return end if #ampm > 0 then if tonumber(h) > 12 then ampm = "" end end if #ampm < 1 then ampm = "" end return h .. ":" .. m .. " " .. ampm end ---Returns the given time as a number. Supports both "13:00" and "1:00 PM" ---@param sTime string ---@return TimeNumber|string ---@shared function StormFox2.Time.StringToTime(sTime) sTime = sTime or StormFox2.Time.Get() str = thinkingBox(sTime) if not str then return end local a = string.Explode( ":", str ) if #a < 2 then return end local h,m = string.match(a[1],"%d+"),string.match(a[2],"%d+") local ex = string.match(a[2]:lower(),"[amp]+") if not h or not m then return end h,m = tonumber(h),tonumber(m) if ex then -- 12clock to 24clock if ex == "am" and h == 12 then h = h - 12 end if h < 12 and ex == "pm" then h = h + 12 end end return ( h * 60 + m ) % 1440 end ---A syncronised number used by the client to calculate the time. Use instead StormFox2.Time.Get to get the current time. ---@return number ---@shared function StormFox2.Time.GetBASE_TIME() return BASE_TIME end ---Returns the given or current time in a string format. Will use client setting if bUse12Hour is nil. ---@param nTime? TimeNumber ---@param bUse12Hour? boolean ---@return string ---@shared function StormFox2.Time.TimeToString(nTime,bUse12Hour) if CLIENT and bUse12Hour == nil then bUse12Hour = StormFox2.Setting.GetCache("12h_display") end if not nTime then nTime = StormFox2.Time.Get(true) end local h = floor(nTime / 60) local m = floor(nTime % 60 ) if not bUse12Hour then return h .. ":" .. (m < 10 and "0" or "") .. m end local e = "PM" if h < 12 or h == 0 then e = "AM" end if h == 0 then h = 12 elseif h > 12 then h = h - 12 end return h .. ":" .. (m < 10 and "0" or "") .. m .. " " .. e end -- Easy functions ---Returns true if the current or given time is doing the day. ---@param nsTime? TimeNumber ---@return boolean ---@shared function StormFox2.Time.IsDay( nsTime ) if not nsTime then -- Cheaper and faster than to convert things around. return IsDayCache end return isInDay( nsTime ) end ---Returns true if the current or given time is doing the night. ---@param nTime? TimeNumber ---@return boolean ---@shared function StormFox2.Time.IsNight(nTime) return not StormFox2.Time.IsDay(nTime) end ---Returns true if the current or given time is between FromTime to ToTime. -- E.g Dinner = StormFox2.Time.IsBetween(700,740) ---@param nFromTime TimeNumber ---@param nToTime TimeNumber ---@param nCurrentTime? TimeNumber ---@return boolean ---@shared function StormFox2.Time.IsBetween(nFromTime,nToTime,nCurrentTime) if not nCurrentTime then nCurrentTime = StormFox2.Time.Get() end if nFromTime > nToTime then return nCurrentTime >= nFromTime or nCurrentTime <= nToTime end return nFromTime <= nCurrentTime and nToTime >= nCurrentTime end ---Returns the time between Time and Time2 in minutes. ---@param nTime TimeNumber ---@param nTime2 TimeNumber ---@return number ---@shared function StormFox2.Time.DeltaTime(nTime,nTime2) if nTime2 >= nTime then return nTime2 - nTime end return (1440 - nTime) + nTime2 end -- Time stamp ---Returns the current (or given time) hour-number. E.g at 11:43 will return 11. ---@param nTime? TimeNumber ---@param b12Hour? boolean ---@return number ---@shared function StormFox2.Time.GetHours( nTime, b12Hour ) if not nTime then nTime = StormFox2.Time.Get() end if not b12Hour then return floor( nTime / 60 ) end local h = floor( nTime / 60 ) if h == 0 then h = 12 elseif h > 12 then h = h - 12 end return h end ---Returns the current (or given time) minute-number. E.g at 11:43 will return 43. ---@param nTime? TimeNumber ---@return number ---@shared function StormFox2.Time.GetMinutes( nTime ) if not nTime then nTime = StormFox2.Time.Get() end return floor( nTime % 60 ) end ---Returns the current (or given time) seconds-number. E.g at 11:43:22 will return 22. ---@param nTime? TimeNumber ---@return number ---@shared function StormFox2.Time.GetSeconds( nTime ) if not nTime then nTime = StormFox2.Time.Get() end return floor( nTime % 1 ) * 60 end ---Returns the current (or given time) "AM" or "PM" string. E.g 20:00 / 8:00 PM will return "PM". ---@param nTime? TimeNumber ---@return string ---@shared function StormFox2.Time.GetAMPM( nTime ) if not nTime then nTime = StormFox2.Time.Get() end local h = floor( nTime / 60 ) if h < 12 or h == 0 then return "AM" end return "PM" end --[[ Allows to pause and resume time ]] local lastT -- (Internal) Second argument is nil or a table of the old settings from StormFox2.Time.Pause() ---Returns true if the time is paused. ---@return boolean ---@shared function StormFox2.Time.IsPaused() local dl = day_length:GetValue() local nl = night_length:GetValue() return dl <= 0 and nl <= 0, lastT end if SERVER then ---Pauses the time. ---@server function StormFox2.Time.Pause() local dl = day_length:GetValue() local nl = night_length:GetValue() if dl <= 0 and nl <= 0 then return end -- Already paused time lastT = { dl, nl } day_length:SetValue( 0 ) night_length:SetValue( 0 ) end ---Resumes the time. ---@server function StormFox2.Time.Resume() if not StormFox2.Time.IsPaused() then return end if lastT then day_length:SetValue( lastT[1] ) night_length:SetValue( lastT[2] ) lastT = nil else day_length:SetValue( 12 ) night_length:SetValue( 12 ) end end end ---Returns the seconds until we reached the given time. ---Remember to lisen for the hook: "StormFox2.Time.Changed". In case an admin changes the time / time-settings. ---@param nTime TimeNumber ---@return number ---@shared function StormFox2.Time.SecondsUntil( nTime ) if StormFox2.Time.IsPaused() then return -1 end local c_cycleTime = GetCycleRaw() -- Seconds past sunrise local t_cycleTime = FinsihToCycle( nTime ) -- Seconds past sunrise to said time return ( t_cycleTime - c_cycleTime ) % ( dayLength + nightLength ) end -- Default Time Display if CLIENT then -- 12h countries local country = system.GetCountry() or "GB" local h12_countries = {"GB","IE","US","CA","AU","NZ","IN","PK","BD","MY","MT","EG","MX","PH"} --[[United Kingdom, Republic of Ireland, the United States, Canada (sorry Quebec), Australia, New Zealand, India, Pakistan, Bangladesh, Malaysia, Malta, Egypt, Mexico and the former American colony of the Philippines ]] local default_12 = table.HasValue(h12_countries, country) StormFox2.Setting.AddCL("12h_display",default_12,"Changes how time is displayed.","Time") StormFox2.Setting.SetType( "12h_display", { [false] = "24h clock", [true] = "12h clock" } ) ---Returns the current time as a string. Useful for displays. ---@param nTime? TimeNumber ---@return string ---@client function StormFox2.Time.GetDisplay(nTime) local use_12 = StormFox2.Setting.GetCache("12h_display",default_12) return StormFox2.Time.TimeToString(nTime,use_12) end -- In case the date changes, call the next-day hook hook.Add("StormFox2.data.change","StormFox2.Date.NextDay", function(sKey, zVar, nDelta) if sKey == "day" then hook.Run("StormFox2.Time.NextDay") end end) else local nextDay = -1 local _b = false hook.Add("Think", "StormFox2.Time.NextDayCheck", function() if nextDay <= CurTime() then -- Calculate next day local sec = StormFox2.Time.SecondsUntil( 1440 ) if sec == -1 then -- Time is paused, will never be next day nextDay = CurTime() + 500 else nextDay = CurTime() + sec if _b then hook.Run("StormFox2.Time.NextDay") end _b = true end end end) -- The time and or timespeed changed. Recalculate when the day changes hook.Add("StormFox2.Time.Changed", "StormFox2.Time.NextDayCalc", function() nextDay = -1 _b = false end) -- We use the date-functions to increase the day hook.Add("StormFox2.Time.NextDay", "StormFox2.Data.NextDay", function() local nDay = StormFox2.Date.GetYearDay() + 1 StormFox2.Date.SetYearDay( nDay ) end) end -- A few hooks do local last = -1 local loaded = false local function checkDNTrigger() if not loaded then return end local stamp, mapLight = StormFox2.Sky.GetLastStamp() local dN if stamp >= SF_SKY_CEVIL then dN = 1 else dN = 0 end if last == dN then return end last = dN if dN == 0 then -- Day hook.Run("StormFox2.Time.OnDay") else -- Night hook.Run("StormFox2.Time.OnNight") end end hook.Add("StormFox2.InitPostEntity", "StormFox2.time.strigger",function() timer.Simple(5, function() loaded = true checkDNTrigger() end) end) -- StormFox2.weather.postchange will be called after something changed. We check the stamp in there. hook.Add("StormFox2.weather.postchange", "StormFox2.time.trigger2", checkDNTrigger) end --[[ Make sure to save the time on shutdown, or when we switch to s_continue while pause is on. ]] if SERVER then local function onSave() cookie.Set("sf2_lasttime", tostring( StormFox2.Time.Get( true ) ) ) StormFox2.Msg("Saved time.") end if s_continue:GetValue() then hook.Add("ShutDown", "StormFox2.TimeSave",onSave) end s_continue:AddCallback(function(var) if var then hook.Add("ShutDown", "StormFox2.TimeSave",onSave) if curType == SF_PAUSE then cookie.Set("sf2_lasttime", tostring( StormFox2.Time.Get( true ) ) ) end else hook.Remove("ShutDown", "StormFox2.TimeSave",onSave) end end, "sf2_savetime") end