mirror of
https://github.com/lifestorm/wnsrc.git
synced 2025-12-17 21:53:46 +03:00
Upload
This commit is contained in:
69
lua/stormfox2/framework/cl_clientquality.lua
Normal file
69
lua/stormfox2/framework/cl_clientquality.lua
Normal file
@@ -0,0 +1,69 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
--[[-------------------------------------------------------------------------
|
||||
This scripts job is to sort out the computers and potatoes.
|
||||
---------------------------------------------------------------------------]]
|
||||
|
||||
StormFox2.Client = StormFox2.Client or {}
|
||||
StormFox2.Setting.AddCL("quality_ultra",false)
|
||||
StormFox2.Setting.AddCL("quality_target",60,nil,nil, 0, 300)
|
||||
|
||||
local conDetect = 1
|
||||
local t_num = {1, 1, 1, 1, 1, 1}
|
||||
local i = 1
|
||||
local q_num = 1
|
||||
-- Calculate the avageFPS for the client and make a value we can use.
|
||||
local bi,buffer = 0,0
|
||||
local avagefps = 1 / RealFrameTime()
|
||||
timer.Create("StormFox2.Client.PotatoSupport",0.25,0,function()
|
||||
if not system.HasFocus() then -- The player tabbed out.
|
||||
bi,buffer = 0,0
|
||||
return
|
||||
end
|
||||
if bi < 10 then
|
||||
buffer = buffer + 1 / RealFrameTime()
|
||||
bi = bi + 1
|
||||
else
|
||||
avagefps = buffer / bi
|
||||
bi,buffer = 0,0
|
||||
local q = StormFox2.Setting.GetCache("quality_ultra",false)
|
||||
local delta_fps = avagefps - StormFox2.Setting.GetCache("quality_target",80)
|
||||
local delta = math.Clamp(delta_fps / 8,-3,3)
|
||||
conDetect = math.Clamp(math.Round(conDetect + delta, 1),0,q and 20 or 7)
|
||||
table.insert(t_num, conDetect)
|
||||
table.remove(t_num, 1)
|
||||
|
||||
local a = 0
|
||||
for _,v in ipairs( t_num ) do
|
||||
a = a + v
|
||||
end
|
||||
q_num = (q_num + (a / #t_num)) / 2
|
||||
end
|
||||
end)
|
||||
--[[<Client>-----------------------------------------------------------------
|
||||
Returns a number based on the clients FPS.
|
||||
7 is the max without the user enabling 'sf_quality_ultra', where it then goes up to 20.
|
||||
---------------------------------------------------------------------------]]
|
||||
|
||||
---Returns a number based on the clients FPS. Where 7 is max (or 20 if sf_quality_ultra is enabled)
|
||||
---@return number qualityNumber
|
||||
---@return number avagefps
|
||||
---@client
|
||||
function StormFox2.Client.GetQualityNumber()
|
||||
if not system.HasFocus() then
|
||||
return 1, 1 / RealFrameTime()
|
||||
end
|
||||
-- Players have complained not seeing the particles when their FPS is low
|
||||
--if game.SinglePlayer() then I've now had multiplayer complaints.
|
||||
q_num = math.max(0.5, q_num)
|
||||
--end
|
||||
return q_num, avagefps
|
||||
end
|
||||
1317
lua/stormfox2/framework/cl_envioment.lua
Normal file
1317
lua/stormfox2/framework/cl_envioment.lua
Normal file
File diff suppressed because it is too large
Load Diff
374
lua/stormfox2/framework/cl_heavens.lua
Normal file
374
lua/stormfox2/framework/cl_heavens.lua
Normal file
@@ -0,0 +1,374 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
-- Fix overlapping tables
|
||||
StormFox2.Time = StormFox2.Time or {}
|
||||
local clamp,max,min = math.Clamp,math.max,math.min
|
||||
StormFox2.Sun = StormFox2.Sun or {}
|
||||
StormFox2.Moon = StormFox2.Moon or {}
|
||||
StormFox2.Sky = StormFox2.Sky or {}
|
||||
local sunVisible
|
||||
|
||||
-- Pipe Dawg
|
||||
|
||||
---Returns an obstruction-number between 0 - 1 fot the sun.
|
||||
---@return number sunVisible
|
||||
---@client
|
||||
function StormFox2.Sun.GetVisibility()
|
||||
return sunVisible or 1
|
||||
end
|
||||
-- Pixel are a bit crazy if called twice
|
||||
hook.Add("Think","StormFox2.Sun.PixUpdater",function()
|
||||
if not StormFox2.Loaded then return end
|
||||
if not _STORMFOX_SUNPIX then -- Create pixel
|
||||
_STORMFOX_SUNPIX = util.GetPixelVisibleHandle()
|
||||
else
|
||||
sunVisible = util.PixelVisible( LocalPlayer():GetPos() + StormFox2.Sun.GetAngle():Forward() * 4096, StormFox2.Mixer.Get("sun_size",30), _STORMFOX_SUNPIX )
|
||||
end
|
||||
end)
|
||||
|
||||
-- Sun overwrite
|
||||
SF_OLD_SUNINFO = SF_OLD_SUNINFO or util.GetSunInfo() -- Just in case
|
||||
|
||||
---Overrides util.GetSunInfo to use SF2 variables.
|
||||
---@ignore
|
||||
---@client
|
||||
---@return table GetSunInfo
|
||||
function util.GetSunInfo()
|
||||
if not StormFox2.Loaded or not sunVisible then -- In case we mess up
|
||||
if SF_OLD_SUNINFO then
|
||||
return SF_OLD_SUNINFO
|
||||
else
|
||||
return {}
|
||||
end
|
||||
end
|
||||
local tab = {
|
||||
["direction"] = StormFox2.Sun.GetAngle():Forward(),
|
||||
["obstruction"] = sunVisible * (StormFox2.Mixer.Get("skyVisibility") / 100)}
|
||||
return tab
|
||||
end
|
||||
|
||||
-- SkyRender
|
||||
--[[-------------------------------------------------------------------------
|
||||
Render layers
|
||||
StarRender = Stars
|
||||
SunRender
|
||||
BlockStarRender (Will allow you to block out stars/sun)
|
||||
Moon
|
||||
CloudBox (Like a skybox, just with transparency. Will fade between states)
|
||||
CloudLayer (Moving clouds)
|
||||
---------------------------------------------------------------------------]]
|
||||
hook.Add("PostDraw2DSkyBox", "StormFox2.SkyBoxRender", function()
|
||||
if not StormFox2 then return end
|
||||
if not StormFox2.Loaded then return end
|
||||
-- Just to be sure. I hate errors in render hooks.
|
||||
if not StormFox2.util then return end
|
||||
if not StormFox2.Sun then return end
|
||||
if not StormFox2.Moon then return end
|
||||
if not StormFox2.Moon.GetAngle then return end
|
||||
if not StormFox2.Setting.SFEnabled() then return end
|
||||
local c_pos = StormFox2.util.RenderPos()
|
||||
local sky = StormFox2.Setting.GetCache("enable_skybox", true)
|
||||
local use_2d = StormFox2.Setting.GetCache("use_2dskybox",false)
|
||||
cam.Start3D( Vector( 0, 0, 0 ), EyeAngles() ,nil,nil,nil,nil,nil,1,32000) -- 2d maps fix
|
||||
render.OverrideDepthEnable( false,false )
|
||||
render.SuppressEngineLighting(true)
|
||||
render.SetLightingMode( 0 )
|
||||
if not use_2d or not sky then
|
||||
hook.Run("StormFox2.2DSkybox.StarRender", c_pos)
|
||||
-- hook.Run("StormFox2.2DSkybox.BlockStarRender",c_pos)
|
||||
hook.Run("StormFox2.2DSkybox.SunRender", c_pos) -- No need to block, shrink the sun.
|
||||
|
||||
hook.Run("StormFox2.2DSkybox.Moon", c_pos)
|
||||
end
|
||||
hook.Run("StormFox2.2DSkybox.CloudBox", c_pos)
|
||||
hook.Run("StormFox2.2DSkybox.CloudLayer", c_pos)
|
||||
hook.Run("StormFox2.2DSkybox.PostCloudLayer",c_pos)
|
||||
hook.Run("StormFox2.2DSkybox.FogLayer", c_pos)
|
||||
render.SuppressEngineLighting(false)
|
||||
render.SetLightingMode( 0 )
|
||||
render.OverrideDepthEnable( false, false )
|
||||
cam.End3D()
|
||||
|
||||
render.SetColorMaterial()
|
||||
end)
|
||||
|
||||
-- Render Sun
|
||||
local sunMat = Material("stormfox2/effects/sun/sun_mat")
|
||||
local sunMat2 = Material("stormfox2/effects/sun/sun_mat2")
|
||||
local sunMat3 = Material("stormfox2/effects/sun/sunflare")
|
||||
|
||||
local sunDot = 1
|
||||
hook.Add("StormFox2.2DSkybox.SunRender","StormFox2.RenderSun",function(c_pos)
|
||||
local SunA = StormFox2.Sun.GetAngle()
|
||||
local SunN = -SunA:Forward()
|
||||
|
||||
local sun = util.GetSunInfo()
|
||||
local viewAng = StormFox2.util.RenderAngles()
|
||||
-- Calculate dot
|
||||
local rawDot = ( SunA:Forward():Dot( viewAng:Forward() ) - 0.8 ) * 5
|
||||
if sun and sun.obstruction and sun.obstruction > 0 then
|
||||
sunDot = rawDot
|
||||
else
|
||||
sunDot = 0
|
||||
end
|
||||
-- Calculate close to edge
|
||||
local z = 1
|
||||
local p = math.abs(math.sin(math.rad(SunA.p))) -- How far we are away from sunset
|
||||
if p < 0.1 then
|
||||
z = 0.8 + p * 0.2
|
||||
end
|
||||
local s_size = StormFox2.Sun.GetSize() / 2
|
||||
local s_size2 = s_size * 1.2
|
||||
local s_size3 = s_size * 3 -- * math.max(0, rawDot)
|
||||
local c_c = StormFox2.Sun.GetColor() or color_white
|
||||
local c = Color(c_c.r,c_c.g,c_c.b,c_c.a)
|
||||
render.SetMaterial(sunMat)
|
||||
-- render.DrawQuadEasy( SunN * -200, SunN, s_size, s_size, c, 0 )
|
||||
render.SuppressEngineLighting(true)
|
||||
render.SetMaterial(sunMat2)
|
||||
render.DrawQuadEasy( SunN * -200, SunN, s_size2, s_size2, c, 0 )
|
||||
if sunDot > 0 then
|
||||
local a = (StormFox2.Mixer.Get("skyVisibility") / 100 - 0.5) * 2
|
||||
if a > 0 then
|
||||
c.a = a * 255
|
||||
render.SetMaterial(sunMat3)
|
||||
render.DrawQuadEasy( SunN * -200, SunN, s_size3 * sunDot , s_size3 * sunDot, c, 0 )
|
||||
end
|
||||
end
|
||||
render.SuppressEngineLighting(false)
|
||||
end)
|
||||
-- Sun and moon beams
|
||||
local beams = StormFox2.Setting.AddCL("enable_sunbeams", true)
|
||||
local matSunbeams = Material( "pp/sunbeams" )
|
||||
matSunbeams:SetTexture( "$fbtexture", render.GetScreenEffectTexture() )
|
||||
|
||||
local function SunRender( sunAltitude )
|
||||
if sunDot <= 0 then return false end
|
||||
-- Check if we see the sun at all
|
||||
local vis = StormFox2.Sun.GetVisibility()
|
||||
if ( vis == 0 ) then return false end
|
||||
|
||||
-- Brightness multiplier
|
||||
local bright
|
||||
if sunAltitude > 0 and sunAltitude < 30 then
|
||||
bright = 1
|
||||
elseif sunAltitude >= 30 then
|
||||
bright = 1.3 - 0.02 * sunAltitude
|
||||
else -- Under 0
|
||||
bright = 0.06 * sunAltitude + 1
|
||||
end
|
||||
if bright < 0 then return end -- Too far up in the sky
|
||||
local direciton = StormFox2.Sun.GetAngle():Forward()
|
||||
local beampos = EyePos() + direciton * 4096
|
||||
-- And screenpos
|
||||
local scrpos = beampos:ToScreen()
|
||||
local mul = vis * sunDot * bright
|
||||
if mul >= 0 then
|
||||
local s_size = StormFox2.Sun.GetSize()
|
||||
render.UpdateScreenEffectTexture()
|
||||
matSunbeams:SetFloat( "$darken", .96 )
|
||||
matSunbeams:SetFloat( "$multiply",0.7 * mul)
|
||||
matSunbeams:SetFloat( "$sunx", scrpos.x / ScrW() )
|
||||
matSunbeams:SetFloat( "$suny", scrpos.y / ScrH() )
|
||||
matSunbeams:SetFloat( "$sunsize", s_size / 850 )
|
||||
render.SetMaterial( matSunbeams )
|
||||
render.DrawScreenQuad()
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
local function MoonRender( sunAltitude )
|
||||
-- Calculate brightness
|
||||
local skyVis = StormFox2.Mixer.Get("skyVisibility") / 100
|
||||
if skyVis <= 0 then return end
|
||||
-- Brightness of the moon
|
||||
local mP = StormFox2.Moon.GetPhase()
|
||||
if mP == SF_MOON_NEW then return end -- No moon
|
||||
-- Sun checkk
|
||||
local mul = 1
|
||||
if sunAltitude > -20 then
|
||||
mul = -0.2 * sunAltitude - 3
|
||||
end
|
||||
-- Phase multiplier (Full moon is 1, goes down to 0.25)
|
||||
local pmul = math.min(1, (-0.0714286 * mP^2 + 0.571429 * mP - 0.285714) * 1.17)
|
||||
local brightness = skyVis * mul * pmul
|
||||
if brightness <= 0 then return end
|
||||
local viewAng = StormFox2.util.RenderAngles()
|
||||
-- Calculate dot
|
||||
local moonAng = StormFox2.Moon.GetAngle()
|
||||
local rawDot = ( moonAng:Forward():Dot( viewAng:Forward() ) - 0.8 ) * 5
|
||||
brightness = brightness * rawDot
|
||||
if brightness <= 0 then return end
|
||||
|
||||
local direciton = StormFox2.Moon.GetAngle():Forward()
|
||||
local beampos = EyePos() + direciton * 4096
|
||||
-- And screenpos
|
||||
local scrpos = beampos:ToScreen()
|
||||
local s_size = StormFox2.Moon.GetSize()
|
||||
render.UpdateScreenEffectTexture()
|
||||
matSunbeams:SetFloat( "$darken", .5 )
|
||||
matSunbeams:SetFloat( "$multiply",0.15 * brightness)
|
||||
matSunbeams:SetFloat( "$sunx", scrpos.x / ScrW() )
|
||||
matSunbeams:SetFloat( "$suny", scrpos.y / ScrH() )
|
||||
matSunbeams:SetFloat( "$sunsize", s_size / 950 )
|
||||
render.SetMaterial( matSunbeams )
|
||||
render.DrawScreenQuad()
|
||||
end
|
||||
|
||||
hook.Add( "RenderScreenspaceEffects", "StormFox2.Sun.beams", function()
|
||||
if ( not render.SupportsPixelShaders_2_0() ) then return end
|
||||
if not StormFox2.Setting.SFEnabled() or not beams:GetValue() then return end
|
||||
local sunAltitude = StormFox2.Sun.GetAltitude()
|
||||
if sunAltitude > -15 then
|
||||
SunRender(sunAltitude)
|
||||
--else TODO: Looks kinda aweful sadly.
|
||||
--MoonRender(sunAltitude)
|
||||
end
|
||||
end )
|
||||
|
||||
-- Render moon
|
||||
-- Setup params and vars
|
||||
local CurrentMoonTexture = Material("stormfox2/effects/moon/rt_moon")
|
||||
local Mask_25 = Material("stormfox2/effects/moon/25.png")
|
||||
local Mask_0 = Material("stormfox2/effects/moon/0.png")
|
||||
local Mask_50 = Material("stormfox2/effects/moon/50.png")
|
||||
local Mask_75 = Material("stormfox2/effects/moon/75.png")
|
||||
local texscale = 512
|
||||
local RTMoonTexture = GetRenderTargetEx( "StormFox_RTMoon", texscale, texscale, 1, MATERIAL_RT_DEPTH_NONE, 2, CREATERENDERTARGETFLAGS_UNFILTERABLE_OK, IMAGE_FORMAT_RGBA8888)
|
||||
-- Functions to update the moon phase
|
||||
local lastRotation = -1
|
||||
local lastCurrentPhase = -1
|
||||
local lastMoonMat
|
||||
local function RenderMoonPhase(rotation,currentPhase)
|
||||
|
||||
--currentPhase = SF_MOON_FIRST_QUARTER - 0.01
|
||||
if currentPhase == SF_MOON_NEW then return end -- New moon. No need to render.
|
||||
-- Check if there is a need to re-render
|
||||
local moonMat = StormFox2.Mixer.Get("moonTexture",lastMoonMat)
|
||||
if type(moonMat) ~= "string" then return end -- Something went wrong. Lets wait.
|
||||
if lastCurrentPhase == currentPhase and lastMoonMat and lastMoonMat == moonMat then
|
||||
-- Already rendered
|
||||
return true
|
||||
end
|
||||
lastCurrentPhase = currentPhase
|
||||
lastMoonMat = moonMat
|
||||
moonMat = Material(moonMat)
|
||||
render.PushRenderTarget( RTMoonTexture )
|
||||
render.OverrideAlphaWriteEnable( true, true )
|
||||
|
||||
render.ClearDepth()
|
||||
render.Clear( 0, 0, 0, 0 )
|
||||
cam.Start2D()
|
||||
-- Render moon
|
||||
surface.SetDrawColor(color_white)
|
||||
surface.SetMaterial(moonMat)
|
||||
surface.DrawTexturedRectUV(0,0,texscale,texscale,-0.01,-0.01,1.01,1.01)
|
||||
-- Mask Start
|
||||
-- render.OverrideBlendFunc( true, BLEND_ZERO, BLEND_SRC_ALPHA, BLEND_DST_ALPHA, BLEND_ZERO )
|
||||
render.OverrideBlend(true, BLEND_ZERO, BLEND_SRC_ALPHA,0,BLEND_DST_ALPHA, BLEND_ZERO,0)
|
||||
-- Render mask
|
||||
surface.SetDrawColor(color_white)
|
||||
-- New to first q; 0 to 50%
|
||||
if currentPhase < SF_MOON_FIRST_QUARTER then
|
||||
local s = 7 - 3.5 * currentPhase
|
||||
surface.SetMaterial(Mask_25)
|
||||
surface.DrawTexturedRectRotated(texscale / 2,texscale / 2,texscale * s,texscale,rotation)
|
||||
if currentPhase >= SF_MOON_WAXIN_CRESCENT then
|
||||
-- Ex step
|
||||
local x,y = math.cos(math.rad(-rotation)),math.sin(math.rad(-rotation))
|
||||
surface.SetMaterial(Mask_0)
|
||||
surface.DrawTexturedRectRotated(texscale / 2 + x * (-texscale * 0.51),texscale / 2 + y * (-texscale * 0.51),texscale * 1,texscale,rotation)
|
||||
end
|
||||
elseif currentPhase == SF_MOON_FIRST_QUARTER then -- 50%
|
||||
surface.SetMaterial(Mask_50)
|
||||
surface.DrawTexturedRectRotated(texscale / 2,texscale / 2,texscale,texscale,rotation)
|
||||
elseif currentPhase < SF_MOON_FULL then -- 50% to 100%
|
||||
local s = (currentPhase - SF_MOON_FIRST_QUARTER) * 3
|
||||
surface.SetMaterial(Mask_75)
|
||||
surface.DrawTexturedRectRotated(texscale / 2,texscale / 2,texscale * s,texscale,rotation + 180)
|
||||
local x,y = math.cos(math.rad(-rotation)),math.sin(math.rad(-rotation))
|
||||
surface.SetMaterial(Mask_0)
|
||||
if s < 0.2 then
|
||||
surface.DrawTexturedRectRotated(texscale / 2 + x * (-texscale * 0.5),texscale / 2 + y * (-texscale * 0.51),texscale * 1,texscale,rotation + 180)
|
||||
elseif s < 1 then
|
||||
surface.DrawTexturedRectRotated(texscale / 2 + x * (-texscale * 0.5),texscale / 2 + y * (-texscale * 0.51),texscale * 0.9,texscale,rotation + 180)
|
||||
end
|
||||
elseif currentPhase == SF_MOON_FULL then
|
||||
-- FULL MOON
|
||||
elseif currentPhase < SF_MOON_LAST_QUARTER then
|
||||
local s = 12 - (currentPhase - SF_MOON_FIRST_QUARTER) * 3
|
||||
surface.SetMaterial(Mask_75)
|
||||
surface.DrawTexturedRectRotated(texscale / 2,texscale / 2,texscale * s,texscale,rotation)
|
||||
local x,y = math.cos(math.rad(-rotation)),math.sin(math.rad(-rotation))
|
||||
surface.SetMaterial(Mask_0)
|
||||
if s < 0.05 then
|
||||
surface.DrawTexturedRectRotated(texscale / 2 + x * (texscale * 0.5),texscale / 2 + y * (texscale * 0.51),texscale * 1,texscale,rotation)
|
||||
elseif s < 1 then
|
||||
surface.DrawTexturedRectRotated(texscale / 2 + x * (texscale * 0.5),texscale / 2 + y * (texscale * 0.51),texscale * 0.9,texscale,rotation)
|
||||
end
|
||||
elseif currentPhase == SF_MOON_LAST_QUARTER then
|
||||
surface.SetMaterial(Mask_50)
|
||||
surface.DrawTexturedRectRotated(texscale / 2,texscale / 2,texscale,texscale,rotation + 180)
|
||||
elseif currentPhase < SF_MOON_WANING_CRESCENT + 1 then
|
||||
local s = (currentPhase - (SF_MOON_WANING_CRESCENT - 1)) * 3.5
|
||||
surface.SetMaterial(Mask_25)
|
||||
surface.DrawTexturedRectRotated(texscale / 2,texscale / 2,texscale * s,texscale,rotation + 180)
|
||||
if currentPhase >= SF_MOON_WAXIN_CRESCENT then
|
||||
-- Ex step
|
||||
local x,y = math.cos(math.rad(-rotation)),math.sin(math.rad(-rotation))
|
||||
surface.SetMaterial(Mask_0)
|
||||
surface.DrawTexturedRectRotated(texscale / 2 + x * (texscale * 0.51),texscale / 2 + y * (texscale * 0.51),texscale,texscale,rotation)
|
||||
end
|
||||
end
|
||||
-- Mask End
|
||||
render.OverrideBlend(false)
|
||||
render.OverrideAlphaWriteEnable( false )
|
||||
cam.End2D()
|
||||
render.OverrideAlphaWriteEnable( false )
|
||||
render.PopRenderTarget()
|
||||
CurrentMoonTexture:SetTexture("$basetexture",RTMoonTexture)
|
||||
end
|
||||
hook.Add("StormFox2.2DSkybox.Moon","StormFox2.RenderMoon",function(c_pos)
|
||||
local phase = StormFox2.Moon.GetPhase()
|
||||
if phase <= 0 then return end
|
||||
local moonScale = StormFox2.Mixer.Get("moonSize",20)
|
||||
local moonAng = StormFox2.Moon.GetAngle()
|
||||
local N = moonAng:Forward()
|
||||
local NN = -N
|
||||
local sa = moonAng.y
|
||||
-- Render texture
|
||||
-- currentYaw
|
||||
RenderMoonPhase( ((moonAng.p < 270 and moonAng.p > 90) and 180 or 0),phase)
|
||||
local c = StormFox2.Mixer.Get("moonColor",Color(170,170,170))
|
||||
local a = StormFox2.Mixer.Get("skyVisibility",100) * 2
|
||||
-- Dark moonarea
|
||||
-- PrintTable(CurrentMoonTexture:GetKeyValues())
|
||||
render.SetMaterial( CurrentMoonTexture )
|
||||
local aa = max(0,(3.125 * a) - 57.5)
|
||||
render.DrawQuadEasy( N * 200, NN, moonScale , moonScale, Color(c.r,c.g,c.b, aa ), sa )
|
||||
end)
|
||||
|
||||
if true then return end
|
||||
-- Render Sky
|
||||
local scale = 256 * 1.5
|
||||
local galixmat = Material("stormfox2/effects/nightsky3")
|
||||
local c = Color(255,255,255)
|
||||
hook.Add("StormFox2.2DSkybox.StarRender", "StormFox2.2DSkyBox.NS", function(c_pos)
|
||||
render.SetMaterial( galixmat )
|
||||
c.a = StormFox2.Mixer.Get("starFade",100) * 2.55
|
||||
c.a = 255
|
||||
local p = (0.001) * StormFox2.Time.GetSpeed_RAW()
|
||||
local ang = Angle((RealTime() * p) % 360,0,0)
|
||||
local n = ang:Forward() * 256
|
||||
-- render.DrawQuadEasy(n, -n, scale * 4, scale, c, (ang.p < 270 and ang.p > 90) and 30 or 30 + 180)
|
||||
-- render.DrawSphere(Vector(0,0,0), -10, 30, 30, c)
|
||||
|
||||
end)
|
||||
175
lua/stormfox2/framework/sh_date.lua
Normal file
175
lua/stormfox2/framework/sh_date.lua
Normal file
@@ -0,0 +1,175 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
--[[
|
||||
Date
|
||||
|
||||
SV StormFox2.Date.SetYearDay( nDay ) Sets the yearday.
|
||||
SH StormFox2.Date.GetYearDay() Gets the yearday.
|
||||
SH StormFox2.Date.GetWeekDay( bNumbers ) Returns the weekday. Returns a number if bNumbers is true.
|
||||
SH StormFox2.Date.GetMonth( bNumbers ) Returns the month. Returns a number if bNumbers is true.
|
||||
SH StormFox2.Date.GetShortMonth() Returns the month in a 3-letter string.
|
||||
Sh StormFox2.Date.GetDay() Returns the day within the month.
|
||||
Sh StormFox2.Date.Get( bNumbers ) Returns the date in string format. MM/DD or DD/MM depending on location and settings. Returns in numbers if bNumbers is true.
|
||||
]]
|
||||
|
||||
StormFox2.Setting.AddSV("real_time",false)
|
||||
StormFox2.Date = {}
|
||||
|
||||
if SERVER then
|
||||
---Sets the yearday. [0-365]
|
||||
---@param nDay number
|
||||
---@server
|
||||
function StormFox2.Date.SetYearDay( nDay )
|
||||
StormFox2.Network.Set("day", nDay % 365)
|
||||
end
|
||||
end
|
||||
|
||||
---Returns the day within the year. [0 - 364]
|
||||
---@return number
|
||||
---@shared
|
||||
function StormFox2.Date.GetYearDay()
|
||||
return StormFox2.Data.Get("day",0)
|
||||
end
|
||||
|
||||
local day, month, weekday = -1,-1,-1
|
||||
local function calcDate( nDay )
|
||||
local t = string.Explode("-", os.date( "%d-%m-%w", nDay * 86400 ), false)
|
||||
return tonumber(t[1]),tonumber(t[2]),tonumber(t[3])
|
||||
end
|
||||
hook.Add("StormFox2.data.change", "StormFox2.date.update", function(sKey, nDay)
|
||||
if sKey ~= "day" then return end
|
||||
day,month,weekday = calcDate( nDay )
|
||||
end)
|
||||
do
|
||||
local t = {
|
||||
[0] = "Sunday",
|
||||
[1] = "Monday",
|
||||
[2] = "Tuesday",
|
||||
[3] = "Wednesday",
|
||||
[4] = "Thursday",
|
||||
[5] = "Friday",
|
||||
[6] = "Saturday"
|
||||
}
|
||||
|
||||
---Returns the current weekday ["Monday" - "Sunday"]. Does also accept a number between 0 - 6.
|
||||
---@param number nil|number
|
||||
---@return string
|
||||
---@shared
|
||||
function StormFox2.Date.GetWeekDay( number )
|
||||
if type(number) == "number" then -- FFS people
|
||||
return t[ number % 7 ] or "Unknown"
|
||||
end
|
||||
return t[ weekday ] or "Unknown"
|
||||
end
|
||||
end
|
||||
do
|
||||
local t = {
|
||||
[1] = "January",
|
||||
[2] = "February",
|
||||
[3] = "March",
|
||||
[4] = "April",
|
||||
[5] = "May",
|
||||
[6] = "June",
|
||||
[7] = "July",
|
||||
[8] = "August",
|
||||
[9] = "September",
|
||||
[10] = "October",
|
||||
[11] = "November",
|
||||
[12] = "December"
|
||||
}
|
||||
---Returns the current month ["January" - "December"]. Also accepts a number between 1 - 12.
|
||||
---@param number nil|number
|
||||
---@return string
|
||||
---@shared
|
||||
function StormFox2.Date.GetMonth( number )
|
||||
if type(number) == "number" then -- FFS people
|
||||
return t[ number % 13 ] or "Unknown"
|
||||
end
|
||||
return t[ month ] or "Unknown"
|
||||
end
|
||||
end
|
||||
|
||||
---Returns the current month in short ["Jan" - "Dec"]. Also accepts a number between 1 - 12.
|
||||
---@param number nil|number
|
||||
---@return string
|
||||
---@shared
|
||||
function StormFox2.Date.GetShortMonth( number )
|
||||
return string.sub(StormFox2.Date.GetMonth( number ),0,3)
|
||||
end
|
||||
|
||||
--- Returns the day of the month: 1 - 31.
|
||||
---@return number
|
||||
---@shared
|
||||
function StormFox2.Date.GetDay()
|
||||
return day
|
||||
end
|
||||
|
||||
local country = system.GetCountry() or "UK"
|
||||
local crazy_countries = {"AS", "BT", "CN", "FM", "GU", "HU", "JP", "KP", "KR", "LT", "MH", "MN", "MP", "TW", "UM", "US", "VI"}
|
||||
local default = table.HasValue(crazy_countries, country)
|
||||
if CLIENT then
|
||||
StormFox2.Setting.AddCL("use_monthday",default,"Display MM/DD instead of DD/MM.")
|
||||
end
|
||||
|
||||
local tOrdinal = {"st", "nd", "rd"}
|
||||
local function ordinal(n)
|
||||
local digit = tonumber(string.sub(n, -1))
|
||||
local two_dig = tonumber(string.sub(n,-2))
|
||||
if digit > 0 and digit <= 3 and two_dig ~= 11 and two_dig ~= 12 and two_dig ~= 13 then
|
||||
return n .. tOrdinal[digit]
|
||||
else
|
||||
return n .. "th"
|
||||
end
|
||||
end
|
||||
|
||||
---Returns the current date-format: "6/11/22". Based on systems country location or clients setting.
|
||||
---@return string
|
||||
---@shared
|
||||
function StormFox2.Date.Get( )
|
||||
local m = StormFox2.Date.GetMonth( )
|
||||
local d = StormFox2.Date.GetDay()
|
||||
if bNumbers and m < 10 then
|
||||
m = "0" .. m
|
||||
elseif not bNumbers then
|
||||
d = ordinal(d)
|
||||
end
|
||||
local rev
|
||||
if CLIENT then
|
||||
rev = StormFox2.Setting.GetCache("use_monthday",default)
|
||||
else
|
||||
rev = default
|
||||
end
|
||||
local e = bNumbers and " / " or " "
|
||||
|
||||
if not rev then
|
||||
return d .. e .. m
|
||||
else
|
||||
return m .. e .. d
|
||||
end
|
||||
end
|
||||
|
||||
if SERVER then
|
||||
-- Sets the starting day.
|
||||
if StormFox2.Setting.Get("real_time", false) then
|
||||
StormFox2.Network.Set("day", tonumber(os.date("%j")))
|
||||
else
|
||||
StormFox2.Network.Set("day", cookie.GetNumber("sf_date", math.random(0,364)))
|
||||
end
|
||||
-- Saves the day for next start.
|
||||
hook.Add("ShutDown","StormFox2.Day.Save",function()
|
||||
cookie.Set("sf_date",StormFox2.Date.GetYearDay())
|
||||
end)
|
||||
-- Sets the day to the current day, if real_time gets switched on.
|
||||
StormFox2.Setting.Callback("real_time",function(switch)
|
||||
if not switch then return end
|
||||
StormFox2.Network.Set("day", os.date("%j"))
|
||||
end,"sf_convar_data")
|
||||
end
|
||||
89
lua/stormfox2/framework/sh_defaultgamemodes.lua
Normal file
89
lua/stormfox2/framework/sh_defaultgamemodes.lua
Normal file
@@ -0,0 +1,89 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
StormFox2.Setting.AddSV("random_round_weather",true,nil,"Weather")
|
||||
|
||||
local gamemodes = {"terrortown"}
|
||||
local isRGame = table.HasValue(gamemodes, engine.ActiveGamemode())
|
||||
|
||||
local nightBlock = false
|
||||
|
||||
local function SelectRandom()
|
||||
-- Temp
|
||||
local tmin,tmax = StormFox2.Setting.Get("min_temp",-10), StormFox2.Setting.Get("max_temp",20)
|
||||
StormFox2.Temperature.Set( math.random(tmin, tmax) )
|
||||
-- Wind
|
||||
StormFox2.Wind.SetForce( math.random(1, 20))
|
||||
StormFox2.Wind.SetYaw( math.random(360))
|
||||
-- Select random weather
|
||||
local w_name
|
||||
local w_p = math.Rand(0.4, 0.9)
|
||||
if math.random(0,10) > 5 then
|
||||
w_name = table.Random(StormFox2.Weather.GetAllSpawnable())
|
||||
elseif math.random(1, 2) > 1 then
|
||||
w_name = "Cloud"
|
||||
else
|
||||
w_name = "Clear"
|
||||
end
|
||||
local w_t = StormFox2.Weather.Get(w_name)
|
||||
if w_t.thunder and w_t.thunder(w_p) then
|
||||
StormFox2.Thunder.SetEnabled( true, w_t.thunder(w_p), math.random(1,3) * 60 )
|
||||
else
|
||||
StormFox2.Thunder.SetEnabled( false )
|
||||
end
|
||||
-- Set random time
|
||||
local start = StormFox2.Setting.Get("start_time",-1) or -1
|
||||
if start < 0 then
|
||||
if nightBlock then
|
||||
StormFox2.Time.Set( math.random(500, 900 ) )
|
||||
w_p = math.Rand(0.4, 0.75) -- Reroll
|
||||
else
|
||||
StormFox2.Time.Set( math.random(60, 1080) )
|
||||
end
|
||||
end
|
||||
StormFox2.Weather.Set( w_name, w_p )
|
||||
end
|
||||
|
||||
hook.Add("StormFox2.Settings.PGL", "StormFox2.DefaultGamemodeSettings", function()
|
||||
local GM = gmod.GetGamemode()
|
||||
if not StormFox2.Setting.Get("random_round_weather", true) then return end
|
||||
if not isRGame and not GM.OnPreRoundStart then return end
|
||||
if not GM.SF2_Settings then
|
||||
GM.SF2_Settings = {
|
||||
["auto_weather"] = 0,
|
||||
["hide_forecast"] = 1,
|
||||
["openweathermap_enabled"] = 0,
|
||||
["time_speed"] = 1,
|
||||
["maplight_auto"] = 1
|
||||
}
|
||||
-- These gamemodes are quick-roundbased. 2~6 mins or so. Block the exspensive light-changes.
|
||||
if not StormFox2.Ent.light_environments then
|
||||
GM.SF2_Settings["allow_weather_lightchange"] = 0
|
||||
nightBlock = true
|
||||
end
|
||||
end
|
||||
if GM.PreRoundStart then
|
||||
_SFGMPRERS = _SFGMPRERS or GM.PreRoundStart
|
||||
function GM.PreRoundStart( ... )
|
||||
_SFGMPRERS( ... )
|
||||
if not StormFox2.Setting.Get("random_round_weather") then return end
|
||||
SelectRandom()
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
-- Random TTT round
|
||||
if SERVER then
|
||||
hook.Add("TTTPrepareRound", "StormFox2.TTT", function()
|
||||
if not StormFox2.Setting.Get("random_round_weather") then return end
|
||||
SelectRandom()
|
||||
end)
|
||||
end
|
||||
333
lua/stormfox2/framework/sh_heavens.lua
Normal file
333
lua/stormfox2/framework/sh_heavens.lua
Normal file
@@ -0,0 +1,333 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
--[[-------------------------------------------------------------------------
|
||||
StormFox2.Sun.SetTimeUp(nTime) Sets how long the sun is on the sky.
|
||||
StormFox2.Sun.IsUp() Returns true if the sun is on the sky.
|
||||
|
||||
|
||||
StormFox2.Moon.SetTimeUp(nTime) Sets how long the moon is on the sky.
|
||||
|
||||
---------------------------------------------------------------------------]]
|
||||
local clamp = math.Clamp
|
||||
|
||||
StormFox2.Sun = StormFox2.Sun or {}
|
||||
StormFox2.Moon = StormFox2.Moon or {}
|
||||
StormFox2.Sky = StormFox2.Sky or {}
|
||||
|
||||
-- SF_SKY_DAY = 0
|
||||
-- SF_SKY_SUNRISE = 1
|
||||
-- SF_SKY_SUNSET = 2
|
||||
-- SF_SKY_CEVIL = 3
|
||||
-- SF_SKY_BLUE_HOUR = 4
|
||||
-- SF_SKY_NAUTICAL = 5
|
||||
-- SF_SKY_ASTRONOMICAL = 6
|
||||
-- SF_SKY_NIGHT = 7
|
||||
|
||||
StormFox2.Setting.AddSV("sunyaw",88,nil, "Effects", 0, 360)
|
||||
StormFox2.Setting.AddSV("moonlock",true,nil,"Effects")
|
||||
local phase = StormFox2.Setting.AddSV("moonphase",true,nil,"Effects")
|
||||
|
||||
StormFox2.Setting.AddSV("enable_skybox",true,nil, "Effect")
|
||||
StormFox2.Setting.AddSV("use_2dskybox",false,nil, "Effects")
|
||||
StormFox2.Setting.AddSV("overwrite_2dskybox","",nil, "Effects")
|
||||
|
||||
if CLIENT then -- From another file
|
||||
StormFox2.Setting.AddSV("darken_2dskybox", false, nil, "Effect")
|
||||
end
|
||||
|
||||
-- Sun and Sun functions
|
||||
---Returns the time when the sun rises.
|
||||
---@return TimeNumber
|
||||
---@shared
|
||||
function StormFox2.Sun.GetSunRise()
|
||||
return StormFox2.Setting.Get("sunrise")
|
||||
end
|
||||
|
||||
---Returns the time when the sun sets.
|
||||
---@return TimeNumber
|
||||
---@shared
|
||||
function StormFox2.Sun.GetSunSet()
|
||||
return StormFox2.Setting.Get("sunset")
|
||||
end
|
||||
|
||||
---Returns the time when sun is at its higest.
|
||||
---@return TimeNumber
|
||||
---@shared
|
||||
function StormFox2.Sun.GetSunAtHigest()
|
||||
return (StormFox2.Sun.GetSunRise() + StormFox2.Sun.GetSunSet()) / 2
|
||||
end
|
||||
|
||||
---Returns the sun and moon-yaw. (Normal 90)
|
||||
---@return number yaw
|
||||
function StormFox2.Sun.GetYaw()
|
||||
return StormFox2.Setting.Get("sunyaw")
|
||||
end
|
||||
|
||||
---Returns true if the sun is up
|
||||
---@param nTime? TimeNumber
|
||||
---@return boolean
|
||||
function StormFox2.Sun.IsUp(nTime)
|
||||
return StormFox2.Time.IsBetween(StormFox2.Sun.GetSunRise(), StormFox2.Sun.GetSunSet(),nTime)
|
||||
end
|
||||
--[[-------------------------------------------------------------------------
|
||||
Returns the sun-size. (Normal 30)
|
||||
---------------------------------------------------------------------------]]
|
||||
|
||||
---Returns the sunsize.
|
||||
---@return number
|
||||
---@shared
|
||||
function StormFox2.Sun.GetSize()
|
||||
return StormFox2.Mixer.Get("sun_size",30) or 30
|
||||
end
|
||||
--[[-------------------------------------------------------------------------
|
||||
Returns the sun-color.
|
||||
---------------------------------------------------------------------------]]
|
||||
function StormFox2.Sun.GetColor()
|
||||
return StormFox2.Mixer.Get("sunColor",Color(255,255,255))
|
||||
end
|
||||
local sunVisible = 0
|
||||
--[[-------------------------------------------------------------------------
|
||||
Returns the sunangle for the current or given time.
|
||||
---------------------------------------------------------------------------]]
|
||||
local function GetSunPitch()
|
||||
local p = StormFox2.Time.GetCycleTime() * 360
|
||||
return p
|
||||
end
|
||||
function StormFox2.Sun.GetAngle()
|
||||
local a = Angle(-GetSunPitch(),StormFox2.Sun.GetYaw(),0)
|
||||
return a
|
||||
end
|
||||
-- Returns the sun altitude. 0 degree at sunrise/set and 90 degrees at noon.
|
||||
function StormFox2.Sun.GetAltitude()
|
||||
local a = GetSunPitch(nTime)
|
||||
if a > 90 and a < 270 then
|
||||
return 180 - a
|
||||
elseif a > 270 then
|
||||
return -(360 - a)
|
||||
end
|
||||
return a
|
||||
end
|
||||
|
||||
-- We need a sun-stamp. We can't go by time.
|
||||
local sunOffset = 5 -- Sunset needs to be pushed
|
||||
local stamp = {
|
||||
[0] = {SF_SKY_SUNRISE,6,"SunRise"}, -- 6
|
||||
[6] = {SF_SKY_DAY, 168,"Day"}, -- 180 - 6
|
||||
[174 + sunOffset] = {SF_SKY_SUNSET,6,"SunSet"}, -- 174 + 6
|
||||
[180 + sunOffset] = {SF_SKY_CEVIL,4,"Cevil"}, -- 4
|
||||
[184 + sunOffset] = {SF_SKY_BLUE_HOUR,2,"Blue Hour"}, -- 6
|
||||
[186 + sunOffset] = {SF_SKY_NAUTICAL,6,"Nautical"}, -- 12
|
||||
[192 + sunOffset] = {SF_SKY_ASTRONOMICAL,6,"Astronomical"}, -- 18
|
||||
[198 + sunOffset] = {SF_SKY_NIGHT,168,"Night"}, -- 144
|
||||
[342] = {SF_SKY_ASTRONOMICAL,6,"Astronomical"}, -- 18
|
||||
[348] = {SF_SKY_NAUTICAL,6,"Nautical"}, -- 12
|
||||
[354] = {SF_SKY_BLUE_HOUR,2,"Blue Hour"}, -- 6
|
||||
[356] = {SF_SKY_CEVIL,4,"Cevil"}, -- 4
|
||||
[360] = {SF_SKY_SUNRISE,6,"SunRise"},
|
||||
[370] = {SF_SKY_SUNRISE,6,"SunRise"}, -- 6
|
||||
}
|
||||
-- Make an array of keys
|
||||
local stamp_arr = table.GetKeys(stamp)
|
||||
table.sort(stamp_arr, function(a,b) return a < b end)
|
||||
-- Fix calculating second argument
|
||||
for id, pitch in pairs(stamp_arr) do
|
||||
local n_pitch = stamp_arr[id + 1] or stamp_arr[1]
|
||||
local ad = math.AngleDifference(n_pitch, pitch)
|
||||
if ad == 0 then
|
||||
ad = stamp[n_pitch][2]
|
||||
end
|
||||
stamp[pitch][2] = ad
|
||||
end
|
||||
-- Calculate the sunsize
|
||||
local lC,lCV = -1,-1
|
||||
local function GetsunSize()
|
||||
if lC > CurTime() then return lCV end
|
||||
lC = CurTime() + 2
|
||||
local x = StormFox2.Sun.GetSize() or 20
|
||||
lCV = (-0.00019702 * x^2 + 0.149631 * x - 0.0429803) / 2
|
||||
return lCV
|
||||
end
|
||||
-- Returns: Stamp-ptch, Sun-pitch, Stamp-pitch
|
||||
local function GetStamp(nTime,nOffsetDegree)
|
||||
local sunSize = GetsunSize()
|
||||
local p = ( GetSunPitch(nTime) + (nOffsetDegree or 0) ) % 360
|
||||
-- Offset the sunsize
|
||||
if p > 90 and p < 270 then -- Sunrise
|
||||
p = (p - sunSize) % 360
|
||||
else -- Sunset
|
||||
p = (p + sunSize) % 360
|
||||
end
|
||||
-- Locate the sunstamp by angle
|
||||
local c_pitch, id = -1
|
||||
for n, pitch in pairs(stamp_arr) do
|
||||
if p >= pitch and c_pitch < pitch then
|
||||
id = n
|
||||
c_pitch = pitch
|
||||
end
|
||||
end
|
||||
return stamp_arr[id], p, stamp_arr[id + 1] or stamp_arr[1]
|
||||
end
|
||||
--[[-------------------------------------------------------------------------
|
||||
Returns the sun-stamp.
|
||||
First argument:
|
||||
0 = day, 1 = golden hour, 2 = cevil, 3 = blue hour
|
||||
4 = nautical, 5 = astronomical, 6 = night
|
||||
|
||||
Second argument:
|
||||
Pitch
|
||||
|
||||
Second argument
|
||||
Next stamp
|
||||
0 = day, 1 = golden hour, 2 = cevil, 3 = blue hour
|
||||
4 = nautical, 5 = astronomical, 6 = night
|
||||
---------------------------------------------------------------------------]]
|
||||
local function GetStamp(nTime,nOffsetDegree)
|
||||
local sunSize = GetsunSize()
|
||||
local p = ( GetSunPitch(nTime) + (nOffsetDegree or 0) ) % 360
|
||||
-- Offset the sunsize
|
||||
if p > 90 and p < 270 then -- Sunrise
|
||||
p = (p - sunSize) % 360
|
||||
else -- Sunset
|
||||
p = (p + sunSize) % 360
|
||||
end
|
||||
-- Locate the sunstamp by angle
|
||||
local c_pitch, id = -1
|
||||
for n, pitch in pairs(stamp_arr) do
|
||||
if p >= pitch and c_pitch < pitch then
|
||||
id = n
|
||||
c_pitch = pitch
|
||||
end
|
||||
end
|
||||
if not id then
|
||||
return SF_SKY_DAY, p, SF_SKY_CEVIL
|
||||
end
|
||||
return stamp_arr[id],p,stamp_arr[id + 1] or stamp_arr[1]
|
||||
end
|
||||
--[[-------------------------------------------------------------------------
|
||||
Returns the sun-stamp.
|
||||
First argument:
|
||||
0 = day, 1 = golden hour, 2 = cevil, 3 = blue hour
|
||||
4 = nautical, 5 = astronomical, 6 = night
|
||||
|
||||
Second argument:
|
||||
Percent used of the current stamp
|
||||
|
||||
Third argument
|
||||
Next stamp
|
||||
0 = day, 1 = golden hour, 2 = cevil, 3 = blue hour
|
||||
4 = nautical, 5 = astronomical, 6 = night
|
||||
|
||||
Forth argument
|
||||
Stamps pitch length
|
||||
---------------------------------------------------------------------------]]
|
||||
local nP = 0
|
||||
function StormFox2.Sky.GetStamp(nTime,nOffsetDegree)
|
||||
local c_stamp,p,n_stamp = GetStamp(nTime,nOffsetDegree) -- p is current angle
|
||||
local per = (p - c_stamp) / (n_stamp - c_stamp)
|
||||
return stamp[c_stamp][1], per, stamp[n_stamp][1],stamp[c_stamp][2] -- 1 = Stamp, 2 = Type of stamp
|
||||
end
|
||||
-- Returns the last stamp
|
||||
local lastStamp = 0
|
||||
function StormFox2.Sky.GetLastStamp()
|
||||
return lastStamp
|
||||
end
|
||||
-- Sky hook. Used to update the sky colors and other things.
|
||||
local nextStamp = -1
|
||||
hook.Add("StormFox2.Time.Changed","StormFox2.Sky.UpdateStamp",function()
|
||||
nextStamp = -1
|
||||
end)
|
||||
timer.Create("StormFox2.Sky.Stamp", 1, 0, function()
|
||||
--local c_t = CurTime()
|
||||
--if c_t < nextStamp then return end
|
||||
local stamp,n_t = StormFox2.Sky.GetStamp(nil,6) -- Look 6 degrees into the furture so we can lerp the colors.
|
||||
--nextStamp = c_t + (n_t * SunDelta) / StormFox2.Time.GetSpeed()
|
||||
--[[-------------------------------------------------------------------------
|
||||
This hook gets called when the sky-stamp changes. This is used to change the sky-colors and other things.
|
||||
First argument:
|
||||
0 = day, 1 = golden hour, 2 = cevil, 3 = blue hour
|
||||
4 = nautical, 5 = astronomical, 6 = night
|
||||
|
||||
Second argument:
|
||||
The lerp-time to change the variable.
|
||||
---------------------------------------------------------------------------]]
|
||||
if lastStamp == stamp then return end -- Don't call it twice.
|
||||
lastStamp = stamp
|
||||
local delta = 180 / (StormFox2.Setting.Get("sunset") - StormFox2.Setting.Get("sunrise"))
|
||||
hook.Run("StormFox2.Sky.StampChange", stamp, 6 / math.max(1, delta) )
|
||||
end)
|
||||
-- Moon and its functions
|
||||
--[[-------------------------------------------------------------------------
|
||||
Moon phases
|
||||
---------------------------------------------------------------------------]]
|
||||
SF_MOON_NEW = 0
|
||||
SF_MOON_WAXIN_CRESCENT = 1
|
||||
SF_MOON_FIRST_QUARTER = 2
|
||||
SF_MOON_WAXING_GIBBOUS = 3
|
||||
SF_MOON_FULL = 4
|
||||
SF_MOON_WANING_GIBBOUS = 5
|
||||
SF_MOON_LAST_QUARTER = 6
|
||||
SF_MOON_WANING_CRESCENT = 7
|
||||
--[[-------------------------------------------------------------------------
|
||||
Returns the moon phase for the current day
|
||||
---------------------------------------------------------------------------]]
|
||||
function StormFox2.Moon.GetPhase()
|
||||
if not phase:GetValue() then return SF_MOON_FULL end
|
||||
return StormFox2.Data.Get("moon_phase",SF_MOON_FULL)
|
||||
end
|
||||
--[[-------------------------------------------------------------------------
|
||||
Returns the moon phase name
|
||||
---------------------------------------------------------------------------]]
|
||||
function StormFox2.Moon.GetPhaseName(nTime)
|
||||
local n = StormFox2.Moon.GetPhase(nTime)
|
||||
if n == SF_MOON_NEW then return "New Moon" end
|
||||
if n == SF_MOON_WAXIN_CRESCENT then return "Waxin Crescent" end
|
||||
if n == SF_MOON_FIRST_QUARTER then return "First Quarter" end
|
||||
if n == SF_MOON_WAXING_GIBBOUS then return "Waxing Gibbous" end
|
||||
if n == SF_MOON_FULL then return "Full Moon" end
|
||||
if n == SF_MOON_WANING_GIBBOUS then return "Waning Gibbous" end
|
||||
if n == SF_MOON_LAST_QUARTER then return "Last Quarter" end
|
||||
if n == SF_MOON_WANING_CRESCENT then return "Waning Crescent" end
|
||||
end
|
||||
|
||||
--[[-------------------------------------------------------------------------
|
||||
Returns the angle for the moon. First argument can also be a certain time.
|
||||
---------------------------------------------------------------------------]]
|
||||
local tf = 0
|
||||
local a = 7 / 7.4
|
||||
function StormFox2.Moon.GetAngle(nTime)
|
||||
local p = 180 + StormFox2.Time.GetCycleTime() * 360
|
||||
if StormFox2.Setting.Get("moonlock",false) then
|
||||
return Angle(-p % 360, StormFox2.Sun.GetYaw(),0)
|
||||
end
|
||||
--if true then return Angle(200,StormFox2.Data.Get("sun_yaw",90),0) end
|
||||
local rDay = StormFox2.Date.GetYearDay()
|
||||
p = p + ( StormFox2.Moon.GetPhase() - 4 ) * 45
|
||||
return Angle(-p % 360,StormFox2.Sun.GetYaw(),0)
|
||||
end
|
||||
-- It might take a bit for the server to tell us the day changed.
|
||||
hook.Add("StormFox2.data.change", "StormFox2.moon.datefix", function(sKey, nDay)
|
||||
if sKey ~= "day" then return end
|
||||
tf = 0
|
||||
end)
|
||||
--[[-------------------------------------------------------------------------
|
||||
Returns true if the moon is up.
|
||||
---------------------------------------------------------------------------]]
|
||||
function StormFox2.Moon.IsUp()
|
||||
local t = StormFox2.Moon.GetAngle().p
|
||||
local s = StormFox2.Mixer.Get("moonSize",20) / 6.9
|
||||
return t > 180 - s or t < s
|
||||
end
|
||||
--[[-------------------------------------------------------------------------
|
||||
Returns the moon size
|
||||
---------------------------------------------------------------------------]]
|
||||
function StormFox2.Moon.GetSize()
|
||||
return StormFox2.Mixer.Get("moonSize",20)
|
||||
end
|
||||
788
lua/stormfox2/framework/sh_maplight.lua
Normal file
788
lua/stormfox2/framework/sh_maplight.lua
Normal file
@@ -0,0 +1,788 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
StormFox2.Setting.AddSV("maplight_min",0,mil, "Effects", 0, 100)
|
||||
StormFox2.Setting.AddSV("maplight_max",80,nil, "Effects", 0, 100)
|
||||
StormFox2.Setting.AddSV("maplight_smooth",true,nil, "Effects",0,1)
|
||||
|
||||
StormFox2.Setting.AddSV("maplight_auto", true, nil, "Effects")
|
||||
StormFox2.Setting.AddSV("maplight_lightenv", false,nil, "Effects")
|
||||
StormFox2.Setting.AddSV("maplight_colormod", false,nil, "Effects")
|
||||
StormFox2.Setting.AddSV("maplight_dynamic", false,nil, "Effects")
|
||||
StormFox2.Setting.AddSV("maplight_lightstyle", false,nil, "Effects")
|
||||
|
||||
--[[----------------------------------------------------------------]]--
|
||||
StormFox2.Setting.AddSV("maplight_updaterate",game.SinglePlayer() and 6 or 3,nil, "Effects")
|
||||
|
||||
|
||||
StormFox2.Setting.AddSV("overwrite_extra_darkness",-1,nil, "Effects", -1, 1)
|
||||
StormFox2.Setting.SetType( "overwrite_extra_darkness", "special_float")
|
||||
|
||||
StormFox2.Setting.AddSV("allow_weather_lightchange",true,nil, "Weather")
|
||||
|
||||
if CLIENT then
|
||||
StormFox2.Setting.AddCL("extra_darkness",render.SupportsPixelShaders_2_0(),nil,"Effects",0,1)
|
||||
StormFox2.Setting.AddCL("extra_darkness_amount",0.75,nil, "Effects",0,1)
|
||||
StormFox2.Setting.SetType( "extra_darkness_amount", "float" )
|
||||
end
|
||||
|
||||
-- Converts a lightlvl to char
|
||||
local function convertToBZ( nNum ) -- From b to z
|
||||
local byte = math.Round(6 * nNum / 25 + 98)
|
||||
return string.char(byte)
|
||||
end
|
||||
local function convertToAZ( nNum )
|
||||
return string.char(97 + nNum / 4)
|
||||
end
|
||||
|
||||
local SetLightStyle, SetLightEnv
|
||||
if SERVER then
|
||||
-- Sets the lightstyle
|
||||
local function _SetLightStyle( char )
|
||||
engine.LightStyle(0,char)
|
||||
net.Start(StormFox2.Net.LightStyle)
|
||||
net.WriteUInt(string.byte(char), 7)
|
||||
net.Broadcast()
|
||||
end
|
||||
local var = 'm'
|
||||
-- Making it a timer, gives other scripts time to overwrite it.
|
||||
SetLightStyle = function( char )
|
||||
if char == 'a' then char = 'b' end -- 'a' will break all light on the map
|
||||
if char == var then return end
|
||||
var = char
|
||||
if timer.Exists("sf_lightstyleset") then return end
|
||||
timer.Create( "sf_lightstyleset", 1, 1, function()
|
||||
_SetLightStyle( var )
|
||||
end)
|
||||
end
|
||||
local oldLight = 'm'
|
||||
local has_faded = false
|
||||
SetLightEnv = function( char)
|
||||
if not StormFox2.Ent.light_environments then return end
|
||||
if char == oldLight then return end
|
||||
oldLight = char
|
||||
for _,light in ipairs(StormFox2.Ent.light_environments) do -- Doesn't lag
|
||||
if not IsValid(light) then continue end
|
||||
if has_faded then
|
||||
light:Fire("FadeToPattern", char ,0)
|
||||
else
|
||||
light:Fire("SetPattern", char ,0)
|
||||
end
|
||||
if char == "a" then
|
||||
light:Fire("TurnOff","",0)
|
||||
else
|
||||
light:Fire("TurnOn","",0)
|
||||
end
|
||||
light:Activate()
|
||||
end
|
||||
has_faded = true
|
||||
end
|
||||
else
|
||||
local last_sv
|
||||
net.Receive(StormFox2.Net.LightStyle, function(len)
|
||||
local c_var = net.ReadUInt(7)
|
||||
if last_sv and last_sv == c_var then return end -- No need
|
||||
last_sv = c_var
|
||||
timer.Simple(1, function()
|
||||
render.RedownloadAllLightmaps( true, true )
|
||||
--MsgC(color_white,"Redownload ligthmap [" .. last_sv .. "]\n")
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
||||
--[[ Diffrent types of maplight options.
|
||||
available = Return true to indicate this option is available. No function = always.
|
||||
on = When you switch it on
|
||||
off = When you switch it off
|
||||
change = When the lightvl changes. Secondary is when the smoothness ends.
|
||||
]]
|
||||
|
||||
local mapLights = {}
|
||||
local e_light_env = 0
|
||||
local e_lightstyle = 1
|
||||
local e_colormod = 2
|
||||
local e_lightdynamic = 3
|
||||
|
||||
local lastSetting = {}
|
||||
-- light_environment (SV) Fast, but not all maps have it
|
||||
mapLights[e_light_env] = {}
|
||||
mapLights[e_light_env]["available"] = function()
|
||||
return StormFox2.Ent.light_environments and true or false
|
||||
end
|
||||
if SERVER then
|
||||
mapLights[e_light_env]["on"] = function(lightLvl)
|
||||
SetLightEnv( convertToAZ(lightLvl) )
|
||||
end
|
||||
mapLights[e_light_env]["off"] = function(lightLvl)
|
||||
if lastSetting[e_lightdynamic] then
|
||||
SetLightEnv('b')
|
||||
else
|
||||
SetLightEnv('m')
|
||||
end
|
||||
end
|
||||
mapLights[e_light_env]["change"] = mapLights[e_light_env]["on"]
|
||||
end
|
||||
|
||||
-- light_style (SV) Laggy on large maps
|
||||
mapLights[e_lightstyle] = {}
|
||||
if SERVER then
|
||||
mapLights[e_lightstyle]["on"] = function(lightLvl)
|
||||
SetLightStyle( convertToBZ(lightLvl) )
|
||||
end
|
||||
mapLights[e_lightstyle]["off"] = function(lightLvl)
|
||||
SetLightStyle('m')
|
||||
timer.Remove( "sf_lightstyle" )
|
||||
end
|
||||
local nextSet
|
||||
mapLights[e_lightstyle]["change"] = function(lightLvl, full) -- We make this a 30sec timer, since lightstyle is so slow and laggy.
|
||||
if not full then return end -- Ignore 'smoothness' light
|
||||
if timer.Exists("sf_lightstyle") then
|
||||
nextSet = convertToBZ(lightLvl)
|
||||
else
|
||||
SetLightStyle(convertToBZ(lightLvl))
|
||||
timer.Create("sf_lightstyle", 5, 1, function()
|
||||
if not nextSet then return end
|
||||
SetLightStyle(nextSet)
|
||||
nextSet = nil
|
||||
end)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- ColorMod (CL) A fast alternative
|
||||
mapLights[e_colormod] = {}
|
||||
local cmod_on
|
||||
if CLIENT then
|
||||
local fardetarget = 0
|
||||
mapLights[e_colormod]["on"] = function(lightLvl)
|
||||
cmod_on = (1 - (lightLvl / 80)) * 0.7
|
||||
fardetarget = 0
|
||||
end
|
||||
mapLights[e_colormod]["off"] = function(lightLvl)
|
||||
cmod_on = nil
|
||||
end
|
||||
mapLights[e_colormod]["change"] = function(lightLvl)
|
||||
cmod_on = (1 - (lightLvl / 80)) * 0.7
|
||||
end
|
||||
local tab = {
|
||||
[ "$pp_colour_addr" ] = -0.09,
|
||||
[ "$pp_colour_addg" ] = -0.1,
|
||||
[ "$pp_colour_addb" ] = -0.05,
|
||||
[ "$pp_colour_brightness" ] = 0,
|
||||
[ "$pp_colour_contrast" ] = 1,
|
||||
[ "$pp_colour_colour" ] = 1,
|
||||
[ "$pp_colour_mulr" ] = 0,
|
||||
[ "$pp_colour_mulg" ] = 0,
|
||||
[ "$pp_colour_mulb" ] = 0
|
||||
}
|
||||
|
||||
hook.Add( "RenderScreenspaceEffects", "StormFox2.MapLightCMod", function()
|
||||
if not cmod_on then return end
|
||||
local darkness = cmod_on
|
||||
local env = StormFox2.Environment.Get()
|
||||
if not env.outside then
|
||||
if not env.nearest_outside then
|
||||
darkness = 0
|
||||
else
|
||||
local dis = 1 - ( env.nearest_outside:DistToSqr(StormFox2.util.RenderPos() or EyePos()) / 90000 )
|
||||
dis = math.Clamp(dis, 0, 1)
|
||||
darkness = darkness * 0.2 + darkness * 0.8 * dis
|
||||
end
|
||||
end
|
||||
fardetarget = math.Approach(fardetarget, darkness, FrameTime() * 0.5)
|
||||
local r_var = fardetarget
|
||||
local tL = math.min(255,StormFox2.Thunder.GetLight() or 0) / 255
|
||||
if tL > 0 then
|
||||
r_var = r_var * (1 - tL)
|
||||
end
|
||||
tab[ "$pp_colour_addr" ] = -0.09 * r_var
|
||||
tab[ "$pp_colour_addg" ] = -0.1 * r_var
|
||||
tab[ "$pp_colour_addb" ] = -0.05 * r_var
|
||||
tab[ "$pp_colour_brightness" ] = 0 -r_var * 0.15
|
||||
tab[ "$pp_colour_colour" ] = 1 - r_var * 0.5 -- We're not good at seeing colors in the dark.
|
||||
tab[ "$pp_colour_contrast" ] = 1 + r_var * 0.08 -- Lower the contrast, however; Bright things are still bright
|
||||
DrawColorModify( tab )
|
||||
end)
|
||||
end
|
||||
|
||||
-- Dynamic Light
|
||||
local dsize = 3000
|
||||
local dlengh = 9000 - 30
|
||||
mapLights[e_lightdynamic] = {}
|
||||
local dLight = -1
|
||||
local function tick()
|
||||
if not SF_SUN_PROTEX then return end
|
||||
local vis = dLight
|
||||
|
||||
-- While the best option is to delete the project-texture.
|
||||
-- Sadly, doing so would allow another mod to override it, as they're limited.
|
||||
if vis < 0 then return end
|
||||
local sunang = StormFox2.Sun.GetAngle() -- Angle towards sun
|
||||
local p = sunang.p % 360
|
||||
local tL = math.min(255,StormFox2.Thunder.GetLight() or 0)
|
||||
if tL > 0 then
|
||||
p = 270
|
||||
sunang.p = p
|
||||
vis = tL / 2
|
||||
else
|
||||
if p > 350 then -- 15 before
|
||||
SF_SUN_PROTEX:SetBrightness(0)
|
||||
SF_SUN_PROTEX:Update()
|
||||
return
|
||||
elseif p > 345 then
|
||||
vis = vis * math.Clamp(-p / 5 + 70, 0, 1)
|
||||
elseif p <= 190 then
|
||||
SF_SUN_PROTEX:SetBrightness(0)
|
||||
SF_SUN_PROTEX:Update()
|
||||
return
|
||||
elseif p <= 195 then
|
||||
vis = vis * math.Clamp(p / 5 - 38, 0, 1)
|
||||
end
|
||||
end
|
||||
local sunnorm = sunang:Forward() -- Norm of sun
|
||||
local viewpos = StormFox2.util.RenderPos() -- Point of render
|
||||
|
||||
local pos = viewpos + sunnorm * dlengh
|
||||
pos.x = math.Round(pos.x / 50) * 50
|
||||
pos.y = math.Round(pos.y / 50) * 50
|
||||
|
||||
SF_SUN_PROTEX:SetPos(pos)
|
||||
if math.Round(sunang.p) == 0 then -- All source light gets a bit, glitchy at 0 or 180 pitch
|
||||
SF_SUN_PROTEX:SetAngles(Angle(179,sunang.y,0))
|
||||
else
|
||||
SF_SUN_PROTEX:SetAngles(Angle(sunang.p + 180,sunang.y,0))
|
||||
end
|
||||
SF_SUN_PROTEX:SetBrightness(vis * 2)
|
||||
SF_SUN_PROTEX:Update()
|
||||
end
|
||||
mapLights[e_lightdynamic]["on"] = function(lightLvl)
|
||||
if SERVER then
|
||||
SetLightStyle( 'b' )
|
||||
SetLightEnv('b')
|
||||
StormFox2.Shadows.SetDisabled( true )
|
||||
else
|
||||
RunConsoleCommand("r_flashlightdepthres", 8192)
|
||||
dLight = lightLvl
|
||||
if IsValid(SF_SUN_PROTEX) then
|
||||
SF_SUN_PROTEX:Remove()
|
||||
end
|
||||
SF_SUN_PROTEX = ProjectedTexture()
|
||||
SF_SUN_PROTEX:SetTexture("stormfox2/effects/dynamic_light")
|
||||
SF_SUN_PROTEX:SetOrthographic( true , dsize, dsize, dsize, dsize)
|
||||
SF_SUN_PROTEX:SetNearZ(0)
|
||||
SF_SUN_PROTEX:SetFarZ( 12000 )
|
||||
SF_SUN_PROTEX:SetQuadraticAttenuation( 0 )
|
||||
SF_SUN_PROTEX:SetShadowDepthBias(0.000005)
|
||||
SF_SUN_PROTEX:SetShadowFilter(0.05) -- Meed tp blur the shadows a bit.
|
||||
SF_SUN_PROTEX:SetShadowSlopeScaleDepthBias(2)
|
||||
SF_SUN_PROTEX:SetEnableShadows(true)
|
||||
hook.Add("Think", "StormFox2.MapLightDynamic", tick)
|
||||
end
|
||||
end
|
||||
mapLights[e_lightdynamic]["off"] = function(lightLvl)
|
||||
if SERVER then
|
||||
SetLightStyle( 'm' )
|
||||
SetLightEnv('m')
|
||||
StormFox2.Shadows.SetDisabled( false )
|
||||
else
|
||||
dLight = 0
|
||||
if SF_SUN_PROTEX then
|
||||
SF_SUN_PROTEX:Remove()
|
||||
SF_SUN_PROTEX = nil
|
||||
end
|
||||
hook.Remove("Think", "StormFox2.MapLightDynamic")
|
||||
end
|
||||
end
|
||||
if CLIENT then
|
||||
mapLights[e_lightdynamic]["change"] = function(lightlvl)
|
||||
dLight = lightlvl
|
||||
end
|
||||
end
|
||||
-- MapLight functions
|
||||
local function EnableMapLight(str, lightlvl)
|
||||
if not mapLights[str] then
|
||||
error("Unknown light")
|
||||
end
|
||||
if not mapLights[str]["on"] then return end
|
||||
mapLights[str]["on"](lightlvl)
|
||||
end
|
||||
local function DisableMapLight(str, lightlvl)
|
||||
if not mapLights[str] then
|
||||
error("Unknown light")
|
||||
end
|
||||
if not mapLights[str]["off"] then return end
|
||||
mapLights[str]["off"](lightlvl)
|
||||
end
|
||||
local function ChangeMapLight(str, lightlvl, full)
|
||||
if not mapLights[str] then
|
||||
error("Unknown light")
|
||||
end
|
||||
if not mapLights[str]["change"] then return end
|
||||
mapLights[str]["change"](lightlvl, full)
|
||||
end
|
||||
-- Function that will remember and enable / disable a setting.
|
||||
local function checkSetting(e_type, bool, lightlvl)
|
||||
if bool and lastSetting[e_type] then return end
|
||||
if not bool and not lastSetting[e_type] then return end
|
||||
if bool then
|
||||
EnableMapLight(e_type, lightlvl)
|
||||
else
|
||||
DisableMapLight(e_type, lightlvl)
|
||||
end
|
||||
lastSetting[e_type] = bool
|
||||
end
|
||||
-- Called when one of the settings change
|
||||
local function SettingMapLight( lightlvl )
|
||||
-- Stop all light-settings when SF gets turned off.
|
||||
if not StormFox2.Setting.GetCache("enable", true) then
|
||||
checkSetting(e_lightstyle, false, lightlvl)
|
||||
checkSetting(e_colormod, false, lightlvl)
|
||||
checkSetting(e_lightdynamic,false, lightlvl)
|
||||
checkSetting(e_light_env, false, lightlvl)
|
||||
return
|
||||
end
|
||||
-- Choose e_light_env or e_colormod
|
||||
if StormFox2.Setting.Get("maplight_auto") then
|
||||
checkSetting(e_lightdynamic,false, lightlvl)
|
||||
checkSetting(e_lightstyle, false, lightlvl)
|
||||
if StormFox2.Ent.light_environments then
|
||||
checkSetting(e_colormod, false, lightlvl)
|
||||
checkSetting(e_light_env, true, lightlvl)
|
||||
else
|
||||
checkSetting(e_light_env, false, lightlvl)
|
||||
checkSetting(e_colormod, true, lightlvl)
|
||||
end
|
||||
else
|
||||
-- Can be enabled for all
|
||||
checkSetting(e_colormod, StormFox2.Setting.Get("maplight_colormod", false), lightlvl)
|
||||
-- Choose dynamic or lightstyle
|
||||
if StormFox2.Setting.Get("maplight_dynamic", false) then
|
||||
checkSetting(e_lightstyle, false, lightlvl)
|
||||
checkSetting(e_light_env, false, lightlvl)
|
||||
checkSetting(e_lightdynamic,true, lightlvl)
|
||||
else
|
||||
checkSetting(e_lightdynamic,false, lightlvl)
|
||||
checkSetting(e_lightstyle, StormFox2.Setting.Get("maplight_lightstyle", false),lightlvl)
|
||||
checkSetting(e_light_env, StormFox2.Setting.Get("maplight_lightenv", false), lightlvl)
|
||||
end
|
||||
end
|
||||
end
|
||||
-- Called when lightlvl has changed
|
||||
local function ChangedMapLight( lightlvl, isSmoothLight)
|
||||
local LastUpdate = not isSmoothLight
|
||||
if StormFox2.Setting.GetCache("maplight_auto", true) then
|
||||
if StormFox2.Ent.light_environments then
|
||||
ChangeMapLight(e_light_env, lightlvl, LastUpdate)
|
||||
return true
|
||||
else
|
||||
ChangeMapLight(e_colormod, lightlvl, LastUpdate)
|
||||
end
|
||||
else
|
||||
local a = false
|
||||
if StormFox2.Setting.GetCache("maplight_dynamic", false) then
|
||||
ChangeMapLight(e_lightdynamic, lightlvl, LastUpdate)
|
||||
a = true
|
||||
end
|
||||
if StormFox2.Setting.GetCache("maplight_lightstyle", false) then
|
||||
ChangeMapLight(e_lightstyle, lightlvl, LastUpdate)
|
||||
a = true
|
||||
end
|
||||
if StormFox2.Setting.GetCache("maplight_lightenv", false) then
|
||||
ChangeMapLight(e_light_env, lightlvl, LastUpdate)
|
||||
a = true
|
||||
end
|
||||
if StormFox2.Setting.GetCache("maplight_colormod", false) then
|
||||
ChangeMapLight(e_colormod, lightlvl, LastUpdate)
|
||||
end
|
||||
return a
|
||||
end
|
||||
end
|
||||
|
||||
-- Sets the detail-light
|
||||
local SetDetailLight
|
||||
if CLIENT then
|
||||
-- Detail MapLight
|
||||
-- Use default detail material (Just in case)
|
||||
local detailstr = {["detail/detailsprites"] = true}
|
||||
-- Find map detail from BSP
|
||||
local mE = StormFox2.Map.Entities()[1]
|
||||
if mE and mE["detailmaterial"] then
|
||||
detailstr[mE["detailmaterial"]] = true
|
||||
end
|
||||
-- Add EP2 by default
|
||||
local ep2m = Material("detail/detailsprites_ep2")
|
||||
if ep2m and not ep2m:IsError() then
|
||||
detailstr["detail/detailsprites_ep2"] = true
|
||||
end
|
||||
local detail = {}
|
||||
for k,v in pairs(detailstr) do
|
||||
table.insert(detail, (Material(k)))
|
||||
end
|
||||
SetDetailLight = function(lightAmount)
|
||||
lightAmount = math.Clamp(lightAmount / 100, 0, 1)
|
||||
local v = Vector(lightAmount,lightAmount,lightAmount)
|
||||
for i, m in ipairs(detail) do
|
||||
m:SetVector("$color",v)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Returns light-variables
|
||||
local f_mapLight = StormFox2.Setting.GetCache("maplight_max",80)
|
||||
local f_mapLightRaw = 100
|
||||
local c_last_char = 'm'
|
||||
---Returns the current light-amount.
|
||||
---@return number
|
||||
---@shared
|
||||
function StormFox2.Map.GetLight()
|
||||
return f_mapLight
|
||||
end
|
||||
|
||||
---Returns the current raw light-amount. Ignores settings.
|
||||
---@return number
|
||||
---@shared
|
||||
function StormFox2.Map.GetLightRaw()
|
||||
return f_mapLightRaw
|
||||
end
|
||||
|
||||
---Returns the current light-char. Source use letters to indecate light.
|
||||
---@return string
|
||||
---@shared
|
||||
function StormFox2.Map.GetLightChar()
|
||||
return c_last_char
|
||||
end
|
||||
|
||||
local function getMaxLight(curLight)
|
||||
if curLight <= 0 then return 0 end
|
||||
local n = StormFox2.Setting.GetCache("maplight_max",80)
|
||||
if n <= 0 then return 0 end
|
||||
return math.Clamp(curLight / n, 0, 1) * 100
|
||||
end
|
||||
|
||||
-- On launch. Setup light
|
||||
local init = false
|
||||
do
|
||||
local chicken, egg = false, false
|
||||
local function tryInit()
|
||||
if not chicken or not egg then return end
|
||||
SettingMapLight(f_mapLight)
|
||||
hook.Run("StormFox2.lightsystem.new", f_mapLight, getMaxLight(f_mapLight))
|
||||
if CLIENT then SetDetailLight(f_mapLight) end
|
||||
init = true
|
||||
end
|
||||
hook.Add("StormFox2.PostEntityScan", "stormfox2.lightsystem.init", function()
|
||||
chicken = true
|
||||
tryInit()
|
||||
end)
|
||||
hook.Add("stormfox2.postinit", "stormfox2.lightsystem.init2", function()
|
||||
egg = true
|
||||
tryInit()
|
||||
end)
|
||||
end
|
||||
-- On settings change
|
||||
for _, conv in ipairs({"enable","maplight_auto", "maplight_lightenv", "maplight_colormod", "maplight_dynamic", "maplight_lightstyle"}) do
|
||||
StormFox2.Setting.Callback(conv,function(var)
|
||||
SettingMapLight(f_mapLight)
|
||||
end, conv .. "MLCheck")
|
||||
end
|
||||
|
||||
-- Allows us to use SetLight, without removing the lerp.
|
||||
local lil = true
|
||||
local function SetLightInternal(f, isSmoothLight)
|
||||
if f < 0 then f = 0 elseif
|
||||
f > 100 then f = 100 end
|
||||
if f_mapLight == f and lil == isSmoothLight then return end -- Ignore
|
||||
f_mapLight = f
|
||||
lil = isSmoothLight
|
||||
c_last_char = convertToAZ(f)
|
||||
if not init then return end
|
||||
-- 2D Skybox
|
||||
if SERVER then
|
||||
local str = StormFox2.Setting.GetCache("overwrite_2dskybox","")
|
||||
local use_2d = StormFox2.Setting.GetCache("use_2dskybox",false)
|
||||
if use_2d and str ~= "painted" then
|
||||
StormFox2.Map.Set2DSkyBoxDarkness( f * 0.009 + 0.1, true )
|
||||
end
|
||||
end
|
||||
-- SetMapLight
|
||||
ChangedMapLight(f, isSmoothLight)
|
||||
if CLIENT then SetDetailLight(f) end
|
||||
-- Tell scripts to update
|
||||
hook.Run("StormFox2.lightsystem.new", f, getMaxLight(f))
|
||||
end
|
||||
|
||||
local t = {}
|
||||
|
||||
---Sets the maplight using a number between 0 - 100. last_update should be true, if we aren't lerping.
|
||||
---Clients need to run this too for internal stuff, but won't change the maplight.
|
||||
---@param int number
|
||||
---@param last_update boolean
|
||||
---@shared
|
||||
function StormFox2.Map.SetLight( int, last_update )
|
||||
t = {} -- Remove light lerping
|
||||
SetLightInternal(int, last_update)
|
||||
end
|
||||
|
||||
--[[ Lerp light
|
||||
People complain if we use lightStyle too much (Even with settings), so I've removed lerp from maps without light_environment.
|
||||
]]
|
||||
|
||||
---Lerps the light towards the goal. Make "isSmooth" false if you're calling it rapidly.
|
||||
---@param int number
|
||||
---@param nLerpTime number
|
||||
---@param isSmooth boolean
|
||||
---@shared
|
||||
function StormFox2.Map.SetLightLerp(int, nLerpTime, isSmooth )
|
||||
local smooth = StormFox2.Setting.GetCache("maplight_smooth",true)
|
||||
local num = StormFox2.Setting.GetCache("maplight_updaterate", 3)
|
||||
-- No lights to smooth and/or setting is off
|
||||
local _5sec = 0.08 * StormFox2.Time.GetSpeed_RAW()
|
||||
t = {}
|
||||
if not smooth or nLerpTime <= _5sec or not f_mapLight or num <= 1 then
|
||||
SetLightInternal( int )
|
||||
return
|
||||
end
|
||||
-- Are we trying to lerp towards current value?
|
||||
if f_mapLight and f_mapLight == int then
|
||||
return
|
||||
end
|
||||
-- Start lerping ..
|
||||
-- We make a time-list of said values.
|
||||
local st = StormFox2.Time.Get() -- Start Time
|
||||
local st_lerpt = nLerpTime / num -- Each "step"'s time
|
||||
-- Too fast of a light change. Can bug out.
|
||||
if st_lerpt < 5 then -- Set the each step to min 5 seconds.
|
||||
st_lerpt = 5
|
||||
num = math.floor(nLerpTime / 5)
|
||||
if num <= 1 then -- Only change once.
|
||||
SetLightInternal( int )
|
||||
return
|
||||
end
|
||||
end
|
||||
local st_lerp = math.abs(f_mapLight - int) / num -- Each "step"'s value
|
||||
-- from: f_mapLight
|
||||
-- to: f
|
||||
for i = 0, num - 1 do
|
||||
table.insert(t, {
|
||||
(st + (i * st_lerpt)) % 1440, -- Time when applied
|
||||
math.floor(math.Approach(f_mapLight, int, st_lerp * (i + 1))),-- The light value
|
||||
i ~= num - 1 or isSmooth -- Isn't last
|
||||
})
|
||||
end
|
||||
--print("From:",f_mapLight, "TO:", f, "step:",st_lerp, "nums:",num)
|
||||
--StormFox2.Map.SetLight( math.Approach(f_mapLight, f, n), true )
|
||||
end
|
||||
timer.Create("StormFox2.lightupdate", 2, 0, function()
|
||||
if #t <= 0 then return end
|
||||
local n = t[1]
|
||||
local time = StormFox2.Time.Get()
|
||||
if n[1] > time or math.abs(time - n[1]) > 720 then return end -- Wait.
|
||||
-- Trigger
|
||||
local v = table.remove(t, 1)
|
||||
SetLightInternal( v[2], v[3] ) -- Set the light, and lightsystel if last.
|
||||
--print("SetLight", v[2], v[3])
|
||||
end)
|
||||
if SERVER then
|
||||
-- Control light
|
||||
hook.Add("StormFox2.weather.postchange", "StormFox2.weather.setlight", function( sName ,nPercentage, nDelta )
|
||||
local night, day
|
||||
if StormFox2.Setting.GetCache("allow_weather_lightchange") then
|
||||
night,day = StormFox2.Data.GetFinal("mapNightLight", 0), StormFox2.Data.GetFinal("mapDayLight",100) -- Maplight
|
||||
else
|
||||
local c = StormFox2.Weather.Get("Clear")
|
||||
night,day = c:Get("mapNightLight",0), c:Get("mapDayLight",80) -- Maplight
|
||||
end
|
||||
local minlight,maxlight = StormFox2.Setting.GetCache("maplight_min",0),StormFox2.Setting.GetCache("maplight_max",80) -- Settings
|
||||
local smooth = StormFox2.Setting.GetCache("maplight_smooth",game.SinglePlayer())
|
||||
-- Calc maplight
|
||||
local isSmooth = false
|
||||
local stamp, mapLight = StormFox2.Sky.GetLastStamp()
|
||||
if stamp >= SF_SKY_CEVIL then
|
||||
mapLight = night
|
||||
elseif stamp <= SF_SKY_DAY then
|
||||
mapLight = day
|
||||
else
|
||||
local delta = math.abs( SF_SKY_DAY - SF_SKY_CEVIL )
|
||||
local f = StormFox2.Sky.GetLastStamp() / delta
|
||||
if smooth then
|
||||
mapLight = Lerp((f + 0.5) / 2, day, night)
|
||||
isSmooth = true
|
||||
elseif f <= 0.5 then
|
||||
mapLight = day
|
||||
else
|
||||
mapLight = night
|
||||
end
|
||||
end
|
||||
f_mapLightRaw = mapLight
|
||||
-- Apply settings
|
||||
local newLight = minlight + mapLight * (maxlight - minlight) / 100
|
||||
local sec = 15 * StormFox2.Time.GetSpeed_RAW()
|
||||
StormFox2.Map.SetLightLerp(newLight, math.min(sec, nDelta or sec), isSmooth )
|
||||
end)
|
||||
|
||||
-- Min and maxlight hotupdate
|
||||
local function hotUpdate()
|
||||
local night, day
|
||||
if StormFox2.Setting.GetCache("allow_weather_lightchange") then
|
||||
night,day = StormFox2.Data.GetFinal("mapNightLight", 0), StormFox2.Data.GetFinal("mapDayLight",100) -- Maplight
|
||||
else
|
||||
local c = StormFox2.Weather.Get("Clear")
|
||||
night,day = c:Get("mapNightLight",0), c:Get("mapDayLight",80) -- Maplight
|
||||
end
|
||||
local minlight,maxlight = StormFox2.Setting.GetCache("maplight_min",0),StormFox2.Setting.GetCache("maplight_max",80) -- Settings
|
||||
local smooth = StormFox2.Setting.GetCache("maplight_smooth",game.SinglePlayer())
|
||||
-- Calc maplight
|
||||
local isSmooth = false
|
||||
local stamp, mapLight = StormFox2.Sky.GetLastStamp()
|
||||
if stamp >= SF_SKY_CEVIL then
|
||||
mapLight = night
|
||||
elseif stamp <= SF_SKY_DAY then
|
||||
mapLight = day
|
||||
else
|
||||
local delta = math.abs( SF_SKY_DAY - SF_SKY_CEVIL )
|
||||
local f = StormFox2.Sky.GetLastStamp() / delta
|
||||
if smooth then
|
||||
mapLight = Lerp((f + 0.5) / 2, day, night)
|
||||
isSmooth = true
|
||||
elseif f <= 0.5 then
|
||||
mapLight = day
|
||||
else
|
||||
mapLight = night
|
||||
end
|
||||
end
|
||||
f_mapLightRaw = mapLight
|
||||
-- Apply settings
|
||||
local newLight = minlight + mapLight * (maxlight - minlight) / 100
|
||||
StormFox2.Map.SetLight( newLight )
|
||||
end
|
||||
StormFox2.Setting.Callback("maplight_min", hotUpdate)
|
||||
StormFox2.Setting.Callback("maplight_max", hotUpdate)
|
||||
|
||||
else -- Fake darkness. Since some maps are bright
|
||||
|
||||
hook.Add("StormFox2.weather.postchange", "StormFox2.weather.setlight", function( sName ,nPercentage, nDelta )
|
||||
if not StormFox2.Map or not StormFox2.Map.SetLightLerp then return end
|
||||
local minlight,maxlight = StormFox2.Setting.GetCache("maplight_min",0),StormFox2.Setting.GetCache("maplight_max",80) -- Settings
|
||||
local smooth = StormFox2.Setting.GetCache("maplight_smooth",game.SinglePlayer())
|
||||
local night, day
|
||||
if StormFox2.Setting.GetCache("allow_weather_lightchange") then
|
||||
night,day = StormFox2.Data.GetFinal("mapNightLight", 0), StormFox2.Data.GetFinal("mapDayLight",100) -- Maplight
|
||||
else
|
||||
local c = StormFox2.Weather.Get("Clear")
|
||||
night,day = c:Get("mapNightLight",0), c:Get("mapDayLight",80) -- Maplight
|
||||
end
|
||||
-- Calc maplight
|
||||
local isSmooth = false
|
||||
local stamp, mapLight = StormFox2.Sky.GetLastStamp()
|
||||
if stamp >= SF_SKY_CEVIL then
|
||||
mapLight = night
|
||||
elseif stamp <= SF_SKY_DAY then
|
||||
mapLight = day
|
||||
else
|
||||
local delta = math.abs( SF_SKY_DAY - SF_SKY_CEVIL )
|
||||
local f = StormFox2.Sky.GetLastStamp() / delta
|
||||
if smooth then
|
||||
mapLight = Lerp((f + 0.5) / 2, day, night)
|
||||
isSmooth = true
|
||||
elseif f <= 0.5 then
|
||||
mapLight = day
|
||||
else
|
||||
mapLight = night
|
||||
end
|
||||
end
|
||||
f_mapLightRaw = mapLight
|
||||
-- Apply settings
|
||||
local newLight = minlight + mapLight * (maxlight - minlight) / 100
|
||||
local sec = 15 * StormFox2.Time.GetSpeed_RAW()
|
||||
StormFox2.Map.SetLightLerp(newLight, math.min(sec, nDelta or sec), isSmooth )
|
||||
end)
|
||||
|
||||
local function exp(n)
|
||||
return n * n
|
||||
end
|
||||
local mat_screen = Material( "stormfox2/shader/pp_dark" )
|
||||
local mat_ColorMod = Material( "stormfox2/shader/color" )
|
||||
mat_ColorMod:SetTexture( "$fbtexture", render.GetScreenEffectTexture() )
|
||||
local texMM = GetRenderTargetEx( "_SF_DARK", -1, -1, RT_SIZE_FULL_FRAME_BUFFER, MATERIAL_RT_DEPTH_NONE, 0, 0, IMAGE_FORMAT_RGB888 )
|
||||
|
||||
-- Renders pp_dark
|
||||
local function UpdateStencil( darkness )
|
||||
if not render.SupportsPixelShaders_2_0() then return end -- How old is the GPU!?
|
||||
render.UpdateScreenEffectTexture()
|
||||
render.PushRenderTarget(texMM)
|
||||
render.Clear( 255 * darkness, 255 * darkness, 255 * darkness, 255 * darkness )
|
||||
render.ClearDepth()
|
||||
render.OverrideBlend( true, BLEND_ONE_MINUS_SRC_COLOR, BLEND_ONE_MINUS_SRC_COLOR, 0, BLEND_ONE, BLEND_ZERO, BLENDFUNC_ADD )
|
||||
render.SetMaterial(mat_ColorMod)
|
||||
render.DrawScreenQuad()
|
||||
render.OverrideBlend( false )
|
||||
render.PopRenderTarget()
|
||||
mat_screen:SetTexture( "$basetexture", texMM )
|
||||
end
|
||||
local fade = 0
|
||||
hook.Add("RenderScreenspaceEffects","StormFox2.Light.MapMat",function()
|
||||
if not StormFox2.Map.GetLightRaw then return end
|
||||
if not StormFox2.Setting.SFEnabled() then return end
|
||||
-- How old is the GPU!?
|
||||
if not render.SupportsPixelShaders_2_0() then return end
|
||||
local a = 1 - StormFox2.Map.GetLightRaw() / 100
|
||||
if a <= 0 then -- Too bright
|
||||
fade = 0
|
||||
return
|
||||
end
|
||||
-- Check settings
|
||||
local scale = StormFox2.Setting.GetCache("overwrite_extra_darkness",-1)
|
||||
if scale == 0 then return end -- Force off.
|
||||
if scale < 0 then
|
||||
if not StormFox2.Setting.GetCache("extra_darkness",true) then return end
|
||||
scale = StormFox2.Setting.GetCache("extra_darkness_amount",1)
|
||||
end
|
||||
if scale <= 0 then return end
|
||||
-- Calc the "fade" between outside and inside
|
||||
local t = StormFox2.Environment.Get()
|
||||
if t.outside then
|
||||
fade = math.min(2, fade + FrameTime())
|
||||
elseif t.nearest_outside then
|
||||
-- Calc dot
|
||||
local view = StormFox2.util.GetCalcView()
|
||||
if not view then return end
|
||||
local d = view.pos:DistToSqr(t.nearest_outside)
|
||||
if d < 15000 then
|
||||
fade = math.min(2, fade + FrameTime())
|
||||
elseif d > 40000 then -- Too far away
|
||||
fade = math.max(0, fade - FrameTime())
|
||||
else
|
||||
local v1 = view.ang:Forward()
|
||||
local v2 = (t.nearest_outside - view.pos):GetNormalized()
|
||||
if v1:Dot(v2) < 0.6 then -- You're looking away
|
||||
fade = math.max(0, fade - FrameTime())
|
||||
else -- You're looking at it
|
||||
fade = math.min(2, fade + FrameTime())
|
||||
end
|
||||
end
|
||||
else
|
||||
fade = math.max(0, fade - FrameTime())
|
||||
end
|
||||
if fade <= 0 then return end
|
||||
-- Render
|
||||
UpdateStencil(exp(a * scale * math.min(1, fade)))
|
||||
render.SetMaterial(mat_screen)
|
||||
local w,h = ScrW(),ScrH()
|
||||
render.OverrideBlend( true, 0, BLEND_ONE_MINUS_SRC_COLOR, 2, BLEND_ONE, BLEND_ZERO, BLENDFUNC_ADD )
|
||||
render.DrawScreenQuadEx(0,0,w,h)
|
||||
render.OverrideBlend( false )
|
||||
end)
|
||||
end
|
||||
|
||||
--[[
|
||||
TODO:
|
||||
1) Add option to limit the angle of the shadows.
|
||||
2) Shadow color to match skies?
|
||||
]]
|
||||
155
lua/stormfox2/framework/sh_mixer.lua
Normal file
155
lua/stormfox2/framework/sh_mixer.lua
Normal file
@@ -0,0 +1,155 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
-- Weather mixed updates the variables live, unlike the Data.
|
||||
-- This can't be set tho.
|
||||
StormFox2.Mixer = {}
|
||||
|
||||
-- Local function
|
||||
local function isColor(t)
|
||||
return t.r and t.g and t.b and true or false
|
||||
end
|
||||
|
||||
---Tries to blend two variables together. Will return first variable if unable to.
|
||||
---@param nFraction number
|
||||
---@param vFrom any
|
||||
---@param vTo any
|
||||
---@return any
|
||||
---@shared
|
||||
local function Blender(nFraction, vFrom, vTo)
|
||||
-- Will it blend?
|
||||
-- Nils should be false, if one of them is a boolean
|
||||
if type(vFrom) == "nil" and type(vTo) == "boolean" then
|
||||
vFrom = false
|
||||
end
|
||||
if type(vTo) == "nil" and type(vFrom) == "boolean" then
|
||||
vTo = false
|
||||
end
|
||||
-- If the same value, then return it
|
||||
if vTo == vFrom then return vTo end
|
||||
-- In case of two diffrent variables.
|
||||
if type(vFrom) ~= type(vTo) then
|
||||
StormFox2.Warning("Mixer called with values of two different types[" .. type(vFrom) .. "," .. type(vTo) .. "]")
|
||||
debug.Trace()
|
||||
return vFrom
|
||||
elseif type(vTo) == "string" or type(vTo) == "IMaterial" or type(vTo) == "boolean" then -- String, material or bool. Return vTo.
|
||||
return vTo
|
||||
elseif type(vTo) == "number" then -- Number
|
||||
return Lerp(nFraction, vFrom, vTo)
|
||||
elseif type(vTo) == "table" then -- Objects
|
||||
local t = vTo.__MetaName and vTo.__MetaName == "CCT_Color" or false
|
||||
local f = vFrom.__MetaName and vFrom.__MetaName == "CCT_Color" or false
|
||||
if t and f then
|
||||
local v = StormFox2.util.CCTColor( Lerp( nFraction, vFrom:GetKelvin(), vTo:GetKelvin() ) )
|
||||
return v:ToRGB()
|
||||
else
|
||||
local s = f and vFrom:ToRGB() or vFrom
|
||||
local e = t and vTo:ToRGB() or vTo
|
||||
local r = Lerp( nFraction, s.r or 255, e.r )
|
||||
local g = Lerp( nFraction, s.g or 255, e.g )
|
||||
local b = Lerp( nFraction, s.b or 255, e.b )
|
||||
local a = Lerp( nFraction, s.a or 255, e.a )
|
||||
return Color( r, g, b, a )
|
||||
end
|
||||
end
|
||||
--StormFox2.Warning("ERROR: Unsupported mix value type[" .. type(vTo) .. "]. Returning original value")
|
||||
--debug.Trace()
|
||||
return vFrom
|
||||
end
|
||||
|
||||
local cache = {}
|
||||
local cStamp,nStamp,nStampFraction = 0,0,0
|
||||
local function GetVar( wWeather, sKey )
|
||||
local v1 = wWeather:Get(sKey, cStamp)
|
||||
if cStamp == nStamp or nStampFraction <= 0 then
|
||||
return v1
|
||||
end
|
||||
local v2 = wWeather:Get(sKey, nStamp)
|
||||
local v = Blender(nStampFraction, v1, v2)
|
||||
return v
|
||||
end
|
||||
|
||||
StormFox2.Mixer.Blender = Blender
|
||||
|
||||
local function vOd(a, b)
|
||||
if a == nil then return b end
|
||||
return a
|
||||
end
|
||||
|
||||
---Blends the current weather key-variables together. Will return zDefault if fail. The result will be cached, unless you set the currentP variable.
|
||||
---Mixer allows for live-precise variables.
|
||||
---@param sKey string
|
||||
---@param zDefault any
|
||||
---@param currentP? number
|
||||
---@return any
|
||||
---@shared
|
||||
function StormFox2.Mixer.Get( sKey, zDefault, currentP )
|
||||
if not currentP and cache[sKey] ~= nil then return cache[sKey] end
|
||||
if not StormFox2.Weather then return zDefault end -- Not loaded yet
|
||||
-- Get the current weather
|
||||
local cW = StormFox2.Weather.GetCurrent()
|
||||
-- In case thw weather-type is clear, no need to calculate.
|
||||
if not cW or cW.Name == "Clear" then return vOd( GetVar(cW, sKey), zDefault) end
|
||||
-- Get the percent, and check if we should cache.
|
||||
local shouldCache = not currentP
|
||||
currentP = currentP or StormFox2.Weather.GetPercent()
|
||||
if currentP >= 1 then -- No need to mix things, weather is at max.
|
||||
if shouldCache then
|
||||
cache[sKey] = GetVar(cW, sKey)
|
||||
return vOd(cache[sKey], zDefault)
|
||||
else
|
||||
return vOd(GetVar(cW, sKey), zDefault)
|
||||
end
|
||||
end
|
||||
-- Get the default weather to mix with.
|
||||
local clearW = StormFox2.Weather.Get( "Clear" )
|
||||
local var1 = GetVar(clearW, sKey)
|
||||
local var2 = GetVar(cW, sKey)
|
||||
if shouldCache then
|
||||
cache[sKey] = Blender(currentP, var1, var2)
|
||||
return vOd(cache[sKey], zDefault)
|
||||
else
|
||||
return vOd(Blender(currentP, var1, var2), zDefault)
|
||||
end
|
||||
end
|
||||
StormFox2.Mixer.Blender = Blender
|
||||
|
||||
--[[t.Function = {}
|
||||
t.Static = {}
|
||||
t.Dynamic = {}
|
||||
t.SunStamp = {}
|
||||
]]
|
||||
|
||||
-- Resets the values after a few frames. This is calculated live and should be cached.
|
||||
local max_frames = 4
|
||||
local i = 0
|
||||
local percent = 0
|
||||
hook.Add("Think", "StormFox2.mixerreset", function()
|
||||
i = i + 1
|
||||
if i < max_frames then return end
|
||||
i = 0
|
||||
cache = {}
|
||||
-- Current Stamp
|
||||
local nTime = StormFox2.Time.Get()
|
||||
local stamp, percent, next_stamp, pitch_length = StormFox2.Sky.GetStamp(nTime, nil, true) -- cpercent goes from 0 - 1
|
||||
if not pitch_length then return end
|
||||
local pitch_left = pitch_length * (1 - percent)
|
||||
local forward = 6
|
||||
if pitch_left >= 6 then -- Only look 6 degrees in the furture.
|
||||
cStamp = stamp
|
||||
nStamp = stamp
|
||||
nStampFraction = 0
|
||||
else
|
||||
cStamp = stamp
|
||||
nStamp = next_stamp
|
||||
nStampFraction = 1 - ( pitch_left / (math.min(pitch_length, 6)) )
|
||||
end
|
||||
end)
|
||||
146
lua/stormfox2/framework/sh_shadowcontrol.lua
Normal file
146
lua/stormfox2/framework/sh_shadowcontrol.lua
Normal file
@@ -0,0 +1,146 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
StormFox2.Setting.AddSV("modifyshadows",true,nil, "Effects")
|
||||
StormFox2.Setting.AddSV("modifyshadows_rate",game.IsDedicated() and 2 or 0.25,nil, "Effects", 0, 10)
|
||||
StormFox2.Setting.SetType("modifyshadows_rate", "float")
|
||||
if CLIENT then
|
||||
net.Receive(StormFox2.Net.Shadows, function()
|
||||
timer.Simple(0.2, function()
|
||||
for k, ent in ipairs(ents.GetAll()) do
|
||||
ent:MarkShadowAsDirty()
|
||||
ent:PhysWake()
|
||||
end
|
||||
end)
|
||||
end)
|
||||
end
|
||||
if CLIENT then return end
|
||||
StormFox2.Shadows = {}
|
||||
|
||||
--[[-------------------------------------------------------------------------
|
||||
Shadow controls
|
||||
---------------------------------------------------------------------------]]
|
||||
local lastP = -1
|
||||
|
||||
---Sets the shadow angles on the map using a given pitch number.
|
||||
---@param nPitch number
|
||||
---@server
|
||||
function StormFox2.Shadows.SetAngle( nPitch )
|
||||
if not StormFox2.Ent.shadow_controls then return end
|
||||
local nPitch = (nPitch + 180) % 360
|
||||
if nPitch == lastP then return end
|
||||
lastP = nPitch
|
||||
local str = nPitch .. " " .. StormFox2.Sun.GetYaw() .. " " .. 0 .. " "
|
||||
for _,ent in ipairs( StormFox2.Ent.shadow_controls ) do
|
||||
ent:Fire( "SetAngles" , str , 0 )
|
||||
end
|
||||
net.Start(StormFox2.Net.Shadows)
|
||||
net.Broadcast()
|
||||
end
|
||||
|
||||
---Sets the shadow color
|
||||
---@param sColor table
|
||||
---@server
|
||||
function StormFox2.Shadows.SetColor( sColor )
|
||||
if not StormFox2.Ent.shadow_controls then return end
|
||||
local s = sColor.r .. " " .. sColor.g .. " " .. sColor.b
|
||||
for _,ent in ipairs( StormFox2.Ent.shadow_controls ) do
|
||||
ent:SetKeyValue( "color", s )
|
||||
end
|
||||
end
|
||||
|
||||
---Sets the shadow distance
|
||||
---@param dis number
|
||||
---@server
|
||||
function StormFox2.Shadows.SetDistance( dis )
|
||||
if not StormFox2.Ent.shadow_controls then return end
|
||||
for _,ent in ipairs( StormFox2.Ent.shadow_controls ) do
|
||||
ent:SetKeyValue( "SetDistance", dis )
|
||||
end
|
||||
end
|
||||
|
||||
---Disable / Enables shadows
|
||||
---@param bool boolean
|
||||
---@server
|
||||
function StormFox2.Shadows.SetDisabled( bool )
|
||||
if not StormFox2.Ent.shadow_controls then return end
|
||||
for _,ent in ipairs( StormFox2.Ent.shadow_controls ) do
|
||||
ent:SetKeyValue( "SetShadowsDisabled", bool and 1 or 0 )
|
||||
end
|
||||
end
|
||||
|
||||
-- Simple function to set the light
|
||||
local n
|
||||
local function SetDarkness(l)
|
||||
if n and n == l then return end
|
||||
n = l
|
||||
local c = 255 - 68 * n
|
||||
StormFox2.Shadows.SetColor( Color(c,c,c) )
|
||||
end
|
||||
|
||||
local l = 0
|
||||
local function shadowTick()
|
||||
-- Limit update rate
|
||||
if l >= CurTime() then return end
|
||||
local rate = StormFox2.Setting.GetCache("modifyshadows_rate", 2)
|
||||
l = CurTime() + rate
|
||||
|
||||
local sP = StormFox2.Sun.GetAngle().p % 360
|
||||
--360 -> 180 Day
|
||||
local c = math.abs(math.AngleDifference(sP, 270)) -- 0 - 180. Above 90 is night.
|
||||
if c > 90 then -- Night
|
||||
StormFox2.Shadows.SetAngle( 270 )
|
||||
else
|
||||
StormFox2.Shadows.SetAngle( sP )
|
||||
end
|
||||
if c < 80 then
|
||||
SetDarkness(1)
|
||||
elseif c < 85 then
|
||||
SetDarkness(17 - 0.2*c)
|
||||
elseif c < 95 then
|
||||
SetDarkness(0)
|
||||
elseif c < 100 then
|
||||
SetDarkness(0.1*c-9.5)
|
||||
else
|
||||
SetDarkness(0)
|
||||
end
|
||||
end
|
||||
|
||||
local function enable()
|
||||
if not StormFox2.Ent.shadow_controls then return end
|
||||
hook.Add("Think", "StormFox2.shadow.rate", shadowTick)
|
||||
end
|
||||
local function disable()
|
||||
hook.Remove("Think", "StormFox2.shadow.rate")
|
||||
if not StormFox2.Ent.shadow_controls then return end
|
||||
local a = StormFox2.Map.FindClass('shadow_control')
|
||||
if not a or #a < 1 then
|
||||
StormFox2.Shadows.SetAngle( 270 )
|
||||
StormFox2.Shadows.SetColor( Color(187, 187, 187) )
|
||||
else
|
||||
local p = (a[1]["angles"] or Angle(90,0,0)).p + 180
|
||||
StormFox2.Shadows.SetAngle( p )
|
||||
local c = string.Explode(" ", a[1]["color"] or "187 187 187")
|
||||
StormFox2.Shadows.SetColor( Color(c[1],c[2],c[3]) )
|
||||
end
|
||||
end
|
||||
|
||||
if StormFox2.Setting.Get("modifyshadows", true) then
|
||||
enable()
|
||||
end
|
||||
StormFox2.Setting.Callback("modifyshadows",function(b)
|
||||
if b then
|
||||
enable()
|
||||
else
|
||||
disable()
|
||||
end
|
||||
end)
|
||||
|
||||
266
lua/stormfox2/framework/sh_temperature.lua
Normal file
266
lua/stormfox2/framework/sh_temperature.lua
Normal file
@@ -0,0 +1,266 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
-- Holds temperature and wind
|
||||
--[[-------------------------------------------------------------------------
|
||||
Temperature is not universal. A few contries cling on to fahrenheit,
|
||||
so we need another function to display the temperature correctly.
|
||||
|
||||
StormFox runs on celsius, but can convert the temperature to whatever you wish.
|
||||
|
||||
Clients have to use these functions:
|
||||
StormFox2.Temperature.GetDisplay() -- Returns the temperature in what their setting is set to.
|
||||
StormFox2.Temperature.GetDisplaySymbol() -- Returns the temperature symbol for their setting.
|
||||
StormFox2.Temperature.GetDisplayDefault() -- Returns the default temperature setting for their country.
|
||||
StormFox2.Temperature.GetDisplayType() -- Returns the temperature setting clients have set to.
|
||||
|
||||
Fun facts:
|
||||
At -90C, we need specialized air or our brain "forgets" to breathe.
|
||||
You'll be unconscious in an hour in 10C water. Dead in 3.
|
||||
At -180C oxygen will liquidfy.
|
||||
Coldest recorded temp on Earth is -90C
|
||||
|
||||
---------------------------------------------------------------------------]]
|
||||
StormFox2.Temperature = {}
|
||||
local convert_from,convert_to = {},{}
|
||||
local p1,p2,p3,p4,p5 = 3 / 2, 33 / 100, 4 / 5, 21 / 40,240 / 54
|
||||
convert_to["fahrenheit"] = function(nC) return nC * 1.8 + 32 end
|
||||
convert_to["kelvin"] = function(nC) return nC + 273.15 end
|
||||
convert_to["rankine"] = function(nC) return (nC + 273.15) * 1.8 end
|
||||
convert_to["delisle"] = function(nC) return (100 - nC) * p1 end
|
||||
convert_to["newton"] = function(nC) return nC * p2 end
|
||||
convert_to["réaumur"] = function(nC) return nC * p3 end
|
||||
convert_to["rømer"] = function(nC) return nC * p4 + 7.5 end
|
||||
convert_to["wedgwood"] = function(nC) return (nC - 580.8) * p5 end
|
||||
convert_to["gas_mark"] = function(nC)
|
||||
if nC >= 135 then
|
||||
return 1 + (nC - 135) / 13.9
|
||||
else
|
||||
return 1 / ((135 - nC) / 13.9 * 2)
|
||||
end
|
||||
end
|
||||
convert_to["banana"] = function(nC) -- 380 kJ of energy in an average size banana. Takes about 344,49kJ to heat up an avage room by 10c. 1 banana = 1.1c
|
||||
return 10 * (nC - 10) / 11
|
||||
end
|
||||
local p1,p2,p3,p4,p5,p6 = 5 / 9, 2 / 3, 100 / 33, 5 / 4, 40 / 21,54 / 240
|
||||
convert_from["fahrenheit"] = function(nF) return (nF - 32) / 1.8 end
|
||||
convert_from["kelvin"] = function(nK) return nK - 273.15 end
|
||||
convert_from["rankine"] = function(nR) return (nR - 491.67) * p1 end
|
||||
convert_from["delisle"] = function(nD) return 100 - nD * p2 end
|
||||
convert_from["newton"] = function(nN) return nN * p3 end
|
||||
convert_from["réaumur"] = function(nR) return nR * p4 end
|
||||
convert_from["rømer"] = function(nR) return (nR - 7.5) * p5 end
|
||||
convert_from["wedgwood"] = function(nW) return (nW * p6) + 580.8 end
|
||||
convert_from["gas_mark"] = function(nG)
|
||||
if nG >= 1 then
|
||||
return 0.1 * (139 * nG + 1211)
|
||||
else
|
||||
return 135 - 6.95 / nG
|
||||
end
|
||||
end
|
||||
convert_from["banana"] = function(nB)
|
||||
return 1.1 * nB + 10
|
||||
end
|
||||
local symbol = {
|
||||
["celsius"] = "°C",
|
||||
["fahrenheit"] = "°F",
|
||||
["rankine"] = "°R",
|
||||
["delisle"] = "°D",
|
||||
["newton"] = "°N",
|
||||
["réaumur"] = "°Ré",
|
||||
["rømer"] = "°Rø",
|
||||
["wedgwood"] = "°W",
|
||||
["gas_mark"] = "°G",
|
||||
["banana"] = "°B",
|
||||
["kelvin"] = "K"
|
||||
}
|
||||
--[[<Shared>------------------------------------------------------------------
|
||||
Returns the current temperature. Valid temperatures:
|
||||
- celsius : default
|
||||
- fahrenheit
|
||||
- kelvin
|
||||
- rankine
|
||||
- delisle
|
||||
- newton
|
||||
- réaumur
|
||||
- rømer
|
||||
---------------------------------------------------------------------------]]
|
||||
local tempOverwrite
|
||||
|
||||
---Returns the current temperature. sType can be "celsius" (default), "fahrenheit", "kelvin" .. ect
|
||||
---@param sType? string
|
||||
---@return Color
|
||||
---@shared
|
||||
function StormFox2.Temperature.Get(sType)
|
||||
local n = tempOverwrite or StormFox2.Data.Get( "Temp", 20 )
|
||||
if not sType or sType == "celsius" then return n end
|
||||
if not convert_to[sType] then
|
||||
StormFox2.Warning("Invalid temperature type [" .. tostring(sType) .. "].", true)
|
||||
end
|
||||
return convert_to[sType](n)
|
||||
end
|
||||
--[[<Shared>-----------------------------------------------------------------
|
||||
Returns the list of valid temperatures.
|
||||
- celsius : default
|
||||
- fahrenheit
|
||||
- kelvin
|
||||
- rankine
|
||||
- delisle
|
||||
- newton
|
||||
- réaumur
|
||||
- rømer
|
||||
---------------------------------------------------------------------------]]
|
||||
|
||||
---Returns all temperature units supported.
|
||||
---@return table
|
||||
---@shared
|
||||
function StormFox2.Temperature.GetTypes()
|
||||
local t = table.GetKeys(convert_to)
|
||||
table.insert(t,"celsius")
|
||||
return t
|
||||
end
|
||||
|
||||
--[[<Shared>-----------------------------------------------------------------
|
||||
Converts temperature between two types
|
||||
Valid temperatures:
|
||||
- celsius : default
|
||||
- fahrenheit
|
||||
- kelvin
|
||||
- rankine
|
||||
- delisle
|
||||
- newton
|
||||
- réaumur
|
||||
- rømer
|
||||
- wedgwood
|
||||
---------------------------------------------------------------------------]]
|
||||
|
||||
---Converts temperature from one unit to another. E.g StormFox2.Temperature.Convert("celsius","fahrenheit",0) -> 32.
|
||||
---@param sTypeFrom string
|
||||
---@param sTypeTo string
|
||||
---@param nNumber number
|
||||
---@return number
|
||||
---@shared
|
||||
function StormFox2.Temperature.Convert(sTypeFrom,sTypeTo,nNumber)
|
||||
if sTypeFrom and sTypeFrom ~= "celsius" then
|
||||
if not convert_from[sTypeFrom] then
|
||||
error("Invalid temperature type [" .. sTypeFrom .. "].")
|
||||
end
|
||||
nNumber = convert_from[sTypeFrom](nNumber)
|
||||
end
|
||||
if sTypeTo and sTypeTo ~= "celsius" then
|
||||
if not convert_to[sTypeTo] then
|
||||
error("Invalid temperature type [" .. sTypeTo .. "].")
|
||||
end
|
||||
nNumber = convert_to[sTypeTo](nNumber)
|
||||
end
|
||||
return nNumber
|
||||
end
|
||||
|
||||
if SERVER then
|
||||
---Sets the temperature in ceilsius. Second argument is the lerp time in seconds (default: 2).
|
||||
---@param nCelsius number
|
||||
---@param nLerpTime? number
|
||||
---@server
|
||||
function StormFox2.Temperature.Set(nCelsius,nLerpTime)
|
||||
if nCelsius < -273.15 then -- ( In space, there are 270.45 C )
|
||||
nCelsius = -273.15
|
||||
end
|
||||
StormFox2.Network.Set("Temp",nCelsius,nLerpTime or 2 * StormFox2.Time.GetSpeed_RAW())
|
||||
end
|
||||
else
|
||||
local country = system.GetCountry() or "UK"
|
||||
local fahrenheit_countries = {"BS","PW","BZ","KY","FM","MH","US","PR","VI","GU"}
|
||||
--[[Bahamas, Palau, Belize, the Cayman Islands, the Federated States of Micronesia, the Marshall Islands,
|
||||
and the United States and its territories such as Puerto Rico, the U.S. Virgin Islands, and Guam.
|
||||
]]
|
||||
local default_temp = table.HasValue(fahrenheit_countries, country) and "fahrenheit" or "celsius"
|
||||
local temp_type = default_temp
|
||||
--[[<Client>------------------------------------------------------------------
|
||||
Sets the display temperature. Returns true if given a valid temperature-type.
|
||||
Valid temperatures:
|
||||
- celsius : default
|
||||
- fahrenheit
|
||||
- kelvin
|
||||
- rankine
|
||||
- delisle
|
||||
- newton
|
||||
- réaumur
|
||||
- rømer
|
||||
---------------------------------------------------------------------------]]
|
||||
|
||||
---Sets the display temperature.
|
||||
---@param sType string
|
||||
---@return boolean success
|
||||
---@client
|
||||
function StormFox2.Temperature.SetDisplayType(sType)
|
||||
StormFox2.Setting.Set("display_temperature",convert_to[sType] and sType or "celsius")
|
||||
if convert_to[sType] then
|
||||
return true
|
||||
end
|
||||
return sType == "celsius"
|
||||
end
|
||||
|
||||
---Returns the current display temperature type.
|
||||
---@return string
|
||||
---@client
|
||||
function StormFox2.Temperature.GetDisplayType()
|
||||
return temp_type
|
||||
end
|
||||
|
||||
---Converts the current (or given) temperature to the clients temperature-unit. Ideal for displays.
|
||||
---@param nCelcius number
|
||||
---@return number
|
||||
---@client
|
||||
function StormFox2.Temperature.GetDisplay(nCelcius)
|
||||
if nCelcius then
|
||||
return StormFox2.Temperature.Convert(nil,temp_type,nCelcius)
|
||||
end
|
||||
return StormFox2.Temperature.Get(temp_type)
|
||||
end
|
||||
|
||||
---Returns the clients temperature-unit symbol. ("°C", "°F" ..)
|
||||
---@return string
|
||||
---@client
|
||||
function StormFox2.Temperature.GetDisplaySymbol()
|
||||
return symbol[temp_type] or "°C"
|
||||
end
|
||||
|
||||
---Returns the default temperature, based on client-country.
|
||||
---@return string
|
||||
---@client
|
||||
function StormFox2.Temperature.GetDisplayDefault()
|
||||
return default_temp
|
||||
end
|
||||
-- Load the temperature settings.
|
||||
-- Setup setting
|
||||
StormFox2.Setting.AddCL("display_temperature",default_temp)
|
||||
local t = {}
|
||||
for k, v in pairs(symbol) do
|
||||
if t[k] then continue end
|
||||
t[k] = string.upper(k[1]) .. string.sub(k, 2) .. " " .. v
|
||||
end
|
||||
StormFox2.Setting.SetType( "display_temperature", t, {"celsius", "fahrenheit", "kelvin"} )
|
||||
StormFox2.Setting.Callback("display_temperature",function(sType)
|
||||
temp_type = convert_to[sType] and sType or "celsius"
|
||||
end,"StormFox2.temp.type")
|
||||
-- Load setting
|
||||
local sType = StormFox2.Setting.Get("display_temperature",default_temp)
|
||||
temp_type = convert_to[sType] and sType or "celsius"
|
||||
|
||||
hook.Remove("stormfox2.postlib", "StormFox2.TemperatureSettings")
|
||||
|
||||
---Sets the "local" temperature. This will override the server variable until called again with 'nil'.
|
||||
---@param nCelcius? number
|
||||
---@client
|
||||
function StormFox2.Temperature.SetLocal( nCelcius )
|
||||
tempOverwrite = nCelcius
|
||||
end
|
||||
|
||||
end
|
||||
535
lua/stormfox2/framework/sh_thunder.lua
Normal file
535
lua/stormfox2/framework/sh_thunder.lua
Normal file
@@ -0,0 +1,535 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
StormFox2.Thunder = {}
|
||||
|
||||
---Returns true if it is thundering.
|
||||
---@return boolean
|
||||
---@shared
|
||||
function StormFox2.Thunder.IsThundering()
|
||||
return StormFox2.Data.Get("nThunder", 0) > 0
|
||||
end
|
||||
|
||||
---Returns the amount of posible strikes pr minute.
|
||||
---@return number
|
||||
---@shared
|
||||
function StormFox2.Thunder.GetActivity()
|
||||
return StormFox2.Data.Get("nThunder", 0)
|
||||
end
|
||||
|
||||
if SERVER then
|
||||
local THUNDER_MAKE_SKYBOX = 0
|
||||
local THUNDER_TRACE_ERROR = 1
|
||||
local THUNDER_SUCCESS = 2
|
||||
|
||||
local function ETHull(pos,pos2,size,mask)
|
||||
local t = util.TraceHull( {
|
||||
start = pos,
|
||||
endpos = pos2,
|
||||
maxs = Vector(size,size,4),
|
||||
mins = Vector(-size,-size,0),
|
||||
mask = mask
|
||||
} )
|
||||
t.HitPos = t.HitPos or pos + pos2
|
||||
return t
|
||||
end
|
||||
-- Damages an entity
|
||||
local function StrikeDamageEnt( ent )
|
||||
if not ent or not IsValid(ent) then return end
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin( ent:GetPos() )
|
||||
effectdata:SetEntity(ent)
|
||||
effectdata:SetMagnitude(2)
|
||||
effectdata:SetScale(3)
|
||||
for i = 1,100 do
|
||||
util.Effect( "TeslaHitboxes", effectdata, true, true )
|
||||
end
|
||||
local ctd = DamageInfo()
|
||||
ctd:IsDamageType(DMG_SHOCK)
|
||||
ctd:SetDamage(math.Rand(90,200))
|
||||
local vr = VectorRand()
|
||||
vr.z = math.abs(vr.z)
|
||||
ctd:SetDamageForce(vr * 1000)
|
||||
ctd:SetInflictor(game.GetWorld())
|
||||
ctd:SetAttacker(game.GetWorld())
|
||||
ent:TakeDamageInfo(ctd)
|
||||
end
|
||||
-- Damanges an area
|
||||
local function StrikeDamagePos( vPos )
|
||||
local b_InWater = bit.band( util.PointContents( vPos ), CONTENTS_WATER ) == CONTENTS_WATER
|
||||
local t = {}
|
||||
for _,ent in ipairs(ents.FindInSphere(vPos,750)) do
|
||||
-- It hit in water, and you're nearby
|
||||
if b_InWater and ent:WaterLevel() > 0 then
|
||||
StrikeDamageEnt(ent)
|
||||
table.insert(t, ent)
|
||||
elseif ent:GetPos():Distance( vPos ) < 150 then
|
||||
StrikeDamageEnt(ent)
|
||||
table.insert(t, ent)
|
||||
end
|
||||
end
|
||||
hook.Run("StormFox2.Thunder.OnStrike", vPos, t)
|
||||
end
|
||||
-- Make STrike
|
||||
local Sway = 100
|
||||
|
||||
-- Traces a lightningstrike from sky to ground.
|
||||
|
||||
local BrushZ = math.max(1, ( StormFox2.Map.MaxSize().z - StormFox2.Map.MinSize().z ) / 20000)
|
||||
|
||||
local function MakeStrikeDown( vPos, nTraceSize )
|
||||
if not nTraceSize then nTraceSize = 512 end
|
||||
-- Find the sky position at the area
|
||||
local SkyPos = StormFox2.DownFall.FindSky( vPos, vector_up, 8 )
|
||||
if not SkyPos then -- Unable to find sky above. Get the higest point
|
||||
SkyPos = Vector(vPos.x, vPos.y, StormFox2.Map.MaxSize().z)
|
||||
SkyPos = StormFox2.DownFall.FindSky( SkyPos, vector_up, 1 ) or SkyPos
|
||||
end
|
||||
--debugoverlay.Box(SkyPos, Vector(1,1,1) * -20, Vector(1,1,1) * 20, 15, Color(255,0,0))
|
||||
-- Find the strike distance (Some maps are suuuper tall)
|
||||
local tr = ETHull(SkyPos - vector_up * 10, Vector( vPos.x, vPos.y, StormFox2.Map.MinSize().z), 256, MASK_SOLID_BRUSHONLY )
|
||||
if tr.AllSolid or tr.Fraction == 0 then -- This is inside solid and should instead be done in the skybox.
|
||||
return THUNDER_MAKE_SKYBOX, SkyPos
|
||||
end
|
||||
SkyPos.z = math.min( SkyPos.z, tr.HitPos.z + 8000 )
|
||||
local line = {}
|
||||
table.insert(line,pos)
|
||||
-- Create a line down
|
||||
local olddir = Vector(0,0,-1)
|
||||
local m_dis = math.max(1, ( SkyPos.z - StormFox2.Map.MinSize().z ) / 20000)
|
||||
local pos = SkyPos - vector_up * 5
|
||||
local _n = nTraceSize / 40
|
||||
for i = 20, 1, -1 do
|
||||
-- Random sway
|
||||
local randir = Angle(math.Rand(-Sway,Sway) + 90,math.random(360),math.Rand(-Sway,Sway)):Forward() + olddir
|
||||
randir:Normalize()
|
||||
randir.z = -math.abs(randir.z)
|
||||
olddir = randir
|
||||
local pos2 = pos + randir * math.Rand(800, 1000) * m_dis
|
||||
local m_dis = math.max(1, ( StormFox2.Map.MaxSize().z - StormFox2.Map.MinSize().z ) / 20000)
|
||||
local tr = ETHull(pos, pos2, nTraceSize - i * _n )
|
||||
--debugoverlay.Line(pos, pos2, 10)
|
||||
if not tr.Hit then
|
||||
table.insert(line, pos2)
|
||||
pos = pos2
|
||||
else
|
||||
if tr.HitSky then -- We hit the side of the skybox. Go to other way
|
||||
olddir = -olddir
|
||||
else
|
||||
table.insert(line, tr.HitPos)
|
||||
return THUNDER_SUCCESS, line, tr
|
||||
end
|
||||
end
|
||||
end
|
||||
return line, tr
|
||||
end
|
||||
|
||||
-- Creates a lightniingstrike up ( Useful when forcing a lightning strike to hit something )
|
||||
local function MakeStrikeUp( vPos )
|
||||
local SkyPos = StormFox2.DownFall.FindSky( vPos, vector_up, 8 )
|
||||
if not SkyPos then -- Unable to find sky above. Get the higest point
|
||||
SkyPos = Vector(vPos.x, vPos.y, StormFox2.Map.MaxSize().z)
|
||||
SkyPos = StormFox2.DownFall.FindSky( SkyPos, vector_up, 1 ) or SkyPos
|
||||
end
|
||||
local olddir = Vector(0,0,-1)
|
||||
local pos = vPos
|
||||
local m_dis = math.max(1, ( StormFox2.Map.MaxSize().z - StormFox2.Map.MinSize().z ) / 20000)
|
||||
local list = {pos}
|
||||
for i = 1, 20 do
|
||||
local randir = Angle(math.Rand(-Sway,Sway) + 90,math.random(360),math.Rand(-Sway,Sway)):Forward() + olddir
|
||||
randir:Normalize()
|
||||
randir.z = -math.abs(randir.z)
|
||||
olddir = randir
|
||||
local pos2 = pos + -randir * math.Rand(800, 1000) * m_dis
|
||||
if pos2.z >= SkyPos.z then
|
||||
table.insert(list, Vector(pos2.x, pos2.y, SkyPos.z))
|
||||
break
|
||||
else
|
||||
pos = pos2
|
||||
table.insert(list, pos)
|
||||
end
|
||||
end
|
||||
return table.Reverse(list)
|
||||
end
|
||||
|
||||
local function LightFluff(tList, b_InSkybox )
|
||||
local n_Length = math.Rand(.4,0.7)
|
||||
local n_Light = math.random(200, 250)
|
||||
|
||||
net.Start(StormFox2.Net.Thunder)
|
||||
net.WriteBool( true )
|
||||
net.WriteUInt(#tList, 5)
|
||||
for i = 1, #tList do
|
||||
net.WriteVector(tList[i])
|
||||
end
|
||||
net.WriteBool( b_InSkybox )
|
||||
net.WriteFloat(n_Length)
|
||||
net.WriteUInt(n_Light,8)
|
||||
net.Broadcast()
|
||||
end
|
||||
|
||||
---Creates a lightningstrike at a given position. Will return a hit entity as a second argument.
|
||||
---@param pos Vector
|
||||
---@return boolean success
|
||||
---@return Entity
|
||||
---@server
|
||||
function StormFox2.Thunder.CreateAt( pos )
|
||||
local t_Var, tList, tr
|
||||
local b_InSkybox = false
|
||||
local vMapMin = StormFox2.Map.MinSize()
|
||||
local vMapMax = StormFox2.Map.MaxSize()
|
||||
if not pos then
|
||||
pos = Vector( math.Rand(vMapMin.x, vMapMax.x), math.Rand(vMapMin.y, vMapMax.y), math.Rand(vMapMax.z, vMapMin.z / 2) )
|
||||
end
|
||||
local bInside = pos.x >= vMapMin.x and pos.x <= vMapMax.x and vMapMin.y and pos.y <= vMapMax.y
|
||||
if bInside then
|
||||
t_Var, tList, tr = MakeStrikeDown( pos )
|
||||
if t_Var == THUNDER_MAKE_SKYBOX then
|
||||
bInside = false
|
||||
end
|
||||
end
|
||||
if not bInside then -- Outside the map
|
||||
tList = MakeStrikeUp( Vector(pos.x, pos.y, StormFox2.Map.MinSize().z) )
|
||||
b_InSkybox = true
|
||||
end
|
||||
if not tList then return false end -- Unable to create lightning strike here.
|
||||
local hPos = tr and tr.HitPos or tList[#tList]
|
||||
if not hPos then return end
|
||||
if tr and IsValid( tr.Entity ) then
|
||||
table.insert(tList, tr.Entity:GetPos() + tr.Entity:OBBCenter())
|
||||
hPos = tr.Entity:GetPos() + tr.Entity:OBBCenter()
|
||||
end
|
||||
StrikeDamagePos( hPos )
|
||||
LightFluff(tList, b_InSkybox )
|
||||
return true, tr and IsValid( tr.Entity ) and tr.Entity
|
||||
end
|
||||
|
||||
---Creates a lightning strike to hit the given position / entity.
|
||||
---@param zPosOrEnt Vector|Entity
|
||||
---@param bRangeDamage number
|
||||
---@return boolean success
|
||||
---@server
|
||||
function StormFox2.Thunder.Strike( zPosOrEnt, bRangeDamage )
|
||||
-- Strike the entity
|
||||
if not bRangeDamage and zPosOrEnt.Health then
|
||||
local ent = zPosOrEnt
|
||||
timer.Simple(0.4, function()
|
||||
StrikeDamageEnt( ent )
|
||||
end)
|
||||
end
|
||||
if zPosOrEnt.GetPos then
|
||||
if zPosOrEnt.OBBCenter then
|
||||
zPosOrEnt = zPosOrEnt:GetPos() + zPosOrEnt:OBBCenter()
|
||||
else
|
||||
zPosOrEnt = zPosOrEnt:GetPos()
|
||||
end
|
||||
end
|
||||
if bRangeDamage then
|
||||
timer.Simple(0.4, function() StrikeDamagePos( zPosOrEnt ) end)
|
||||
end
|
||||
local b_InSkybox = not StormFox2.Map.IsInside( zPosOrEnt )
|
||||
--if b_InSkybox then
|
||||
-- zPosOrEnt = StormFox2.Map.WorldtoSkybox( zPosOrEnt )
|
||||
--end
|
||||
|
||||
local tList = MakeStrikeUp( zPosOrEnt )
|
||||
LightFluff(tList, false )
|
||||
return true
|
||||
end
|
||||
|
||||
---Creates a rumble.
|
||||
---@param pos Vector
|
||||
---@param bLight boolean
|
||||
---@server
|
||||
function StormFox2.Thunder.Rumble( pos, bLight )
|
||||
if not pos then
|
||||
local vMapMin = StormFox2.Map.MinSize()
|
||||
local vMapMax = StormFox2.Map.MaxSize()
|
||||
pos = Vector( math.Rand(vMapMin.x, vMapMax.x), math.Rand(vMapMin.y, vMapMax.y), math.Rand(vMapMax.z, vMapMin.z / 2) )
|
||||
end
|
||||
local n_Length = bLight and math.Rand(.4,0.7) or 0
|
||||
local n_Light = bLight and math.random(150, 250) or 0
|
||||
net.Start( StormFox2.Net.Thunder )
|
||||
net.WriteBool( false )
|
||||
net.WriteVector( pos )
|
||||
net.WriteFloat(n_Length)
|
||||
net.WriteUInt(n_Light,8)
|
||||
net.Broadcast()
|
||||
end
|
||||
|
||||
-- Enables thunder and makes them spawn at random, until set off or another weather gets selected
|
||||
local b = false
|
||||
local n = math.max(StormFox2.Map.MaxSize().x, StormFox2.Map.MaxSize().y, -StormFox2.Map.MinSize().x,-StormFox2.Map.MinSize().y)
|
||||
if StormFox2.Map.Has3DSkybox() then
|
||||
n = n * 1.5
|
||||
end
|
||||
|
||||
do
|
||||
local n = 0
|
||||
---Enables / Disables thunder.
|
||||
---@param bEnable boolean
|
||||
---@param nActivityPrMinute? number
|
||||
---@param nTimeAmount? number
|
||||
---@server
|
||||
function StormFox2.Thunder.SetEnabled( bEnable, nActivityPrMinute, nTimeAmount )
|
||||
n = 0
|
||||
if bEnable then
|
||||
StormFox2.Network.Set("nThunder", nActivityPrMinute)
|
||||
if nTimeAmount then
|
||||
StormFox2.Network.Set("nThunder", 0, nTimeAmount)
|
||||
end
|
||||
else
|
||||
StormFox2.Network.Set("nThunder", 0)
|
||||
end
|
||||
end
|
||||
hook.Add("Think", "StormFox2.thunder.activity", function()
|
||||
if not StormFox2.Thunder.IsThundering() then return end
|
||||
if n >= CurTime() then return end
|
||||
local a = StormFox2.Thunder.GetActivity()
|
||||
n = CurTime() + math.random(50, 60) / a
|
||||
-- Strike or rumble
|
||||
if math.random(1,3) < 3 then
|
||||
StormFox2.Thunder.CreateAt()
|
||||
else
|
||||
StormFox2.Thunder.Rumble( nil, math.random(10) > 1 )
|
||||
end
|
||||
end)
|
||||
end
|
||||
else
|
||||
lightningStrikes = lightningStrikes or {}
|
||||
local _Light, _Stop, _Length = 0,0,0
|
||||
|
||||
---Returns light created by thunder.
|
||||
---@return number
|
||||
---@client
|
||||
function StormFox2.Thunder.GetLight()
|
||||
if _Light <= 0 then return 0 end
|
||||
if _Stop < CurTime() then
|
||||
_Light = 0
|
||||
return 0
|
||||
end
|
||||
local t = (_Stop - CurTime()) / _Length
|
||||
local c = math.abs(math.sin( t * math.pi ))
|
||||
local l = _Light * c
|
||||
return math.random(l, l * 0.5) -- Flicker a bit
|
||||
end
|
||||
|
||||
-- 0 - 2000
|
||||
local CloseStrikes = {"sound/stormfox2/amb/thunder_strike.ogg"}
|
||||
-- 2000 - 20000
|
||||
local MediumStrikes = {"sound/stormfox2/amb/thunder_strike.ogg", "sound/stormfox2/amb/thunder_strike2.ogg"}
|
||||
-- 20000 +
|
||||
local FarStrikes = {}
|
||||
|
||||
if IsMounted("csgo") or IsMounted("left4dead2") then
|
||||
table.insert(FarStrikes, "ambient/weather/thunderstorm/lightning_strike_1.wav")
|
||||
table.insert(FarStrikes, "ambient/weather/thunderstorm/lightning_strike_4.wav")
|
||||
end
|
||||
if #FarStrikes < 1 then
|
||||
table.insert(FarStrikes, "sound/stormfox2/amb/thunder_strike2.ogg")
|
||||
end
|
||||
|
||||
local snd_buffer = {}
|
||||
local function StrikeEffect( pos, n_Length )
|
||||
local dlight = DynamicLight( 1 )
|
||||
if ( dlight ) then
|
||||
dlight.pos = pos
|
||||
dlight.r = 255
|
||||
dlight.g = 255
|
||||
dlight.b = 255
|
||||
dlight.brightness = 6
|
||||
dlight.Decay = 3000 / n_Length
|
||||
dlight.Size = 256 * 8
|
||||
dlight.DieTime = CurTime() + n_Length
|
||||
end
|
||||
local effectdata = EffectData()
|
||||
local s = math.random(5, 8)
|
||||
effectdata:SetOrigin( pos + vector_up * 4 )
|
||||
effectdata:SetMagnitude( s / 2 )
|
||||
effectdata:SetNormal(vector_up)
|
||||
effectdata:SetRadius( 8 )
|
||||
util.Effect( "Sparks", effectdata, true, true )
|
||||
end
|
||||
|
||||
local function PlayStrike( vPos, nViewDis, viewPos )
|
||||
local snd = ""
|
||||
if nViewDis <= 2000 then
|
||||
snd = table.Random(CloseStrikes)
|
||||
elseif nViewDis <= 15000 then
|
||||
snd = table.Random(MediumStrikes)
|
||||
else
|
||||
snd = table.Random(FarStrikes)
|
||||
end
|
||||
if string.sub(snd, 0, 6 ) == "sound/" or string.sub(snd,-4) == ".ogg" then
|
||||
sound.PlayFile( snd, "3dnoplay", function( station, errCode, errStr )
|
||||
if ( IsValid( station ) ) then
|
||||
station:Set3DFadeDistance( 0, 10 )
|
||||
station:SetVolume( 1)
|
||||
station:SetPos(vPos)
|
||||
station:Play()
|
||||
end
|
||||
end)
|
||||
else
|
||||
surface.PlaySound( snd )
|
||||
end
|
||||
end
|
||||
--[[
|
||||
Sound moves about 343 meters pr second
|
||||
52.49 hU = 1 meter ~ 18.004 hU pr second
|
||||
]]
|
||||
local b = true
|
||||
local function SndThink()
|
||||
if #snd_buffer < 1 then
|
||||
hook.Remove("Think","StormFox2.Thunder.SndDis")
|
||||
b = false
|
||||
return
|
||||
end
|
||||
local r = {}
|
||||
local view = StormFox2.util.ViewEntity():GetPos()
|
||||
local c = CurTime() - 0.2
|
||||
for k,v in ipairs( snd_buffer ) do
|
||||
local travel = (c - v[2]) * 18004
|
||||
local vDis = view:Distance( v[1] )
|
||||
if vDis - travel < 0 then
|
||||
table.insert(r, k)
|
||||
PlayStrike( v[1], vDis, view )
|
||||
end
|
||||
end
|
||||
for i = #r, 1, -1 do
|
||||
table.remove(snd_buffer, r[i])
|
||||
end
|
||||
end
|
||||
hook.Add("Think","StormFox2.Thunder.SndDis", SndThink)
|
||||
|
||||
local function Strike( tList, b_InSkybox, n_Length, n_Light )
|
||||
table.insert(lightningStrikes, {CurTime() + n_Length, n_Length, b_InSkybox, tList, true})
|
||||
local pos = tList[#tList][1]
|
||||
sound.Play("ambient/energy/weld" .. math.random(1,2) .. ".wav", pos)
|
||||
if not b then
|
||||
hook.Add("Think","StormFox2.Thunder.SndDis", SndThink)
|
||||
end
|
||||
table.insert(snd_buffer, {pos, CurTime()})
|
||||
local c = CurTime()
|
||||
_Light = 255
|
||||
_Length = .7
|
||||
_Stop = math.max(c + _Length, _Stop)
|
||||
end
|
||||
|
||||
local function Rumble( vPos, n_Length, n_Light )
|
||||
-- Thunder is at 120dB
|
||||
local c = CurTime()
|
||||
_Light = n_Light
|
||||
_Length = n_Length
|
||||
_Stop = math.max(c + n_Length, _Stop)
|
||||
sound.Play("ambient/atmosphere/thunder" .. math.random(3,4) .. ".wav", StormFox2.util.ViewEntity():GetPos(), 150)
|
||||
|
||||
end
|
||||
local Sway = 120
|
||||
net.Receive( StormFox2.Net.Thunder, function(len)
|
||||
local b_Strike = net.ReadBool()
|
||||
if b_Strike then
|
||||
local tList = {}
|
||||
local old
|
||||
local n = net.ReadUInt(5)
|
||||
for i = 1, n do
|
||||
local randir = Angle(math.Rand(-Sway,Sway) + 90,math.random(360),math.Rand(-Sway,Sway))
|
||||
local new = net.ReadVector()
|
||||
if old then
|
||||
randir = randir:Forward() + (new - old):Angle():Forward() * 2
|
||||
else
|
||||
randir = randir:Forward()
|
||||
end
|
||||
old = new
|
||||
tList[i] = {new,math.Rand(1.2,1.5),randir,math.random(0,1)}
|
||||
--debugoverlay.Sphere(new, 15, 15, Color(255,255,255), true)
|
||||
end
|
||||
local b_InSkybox = net.ReadBool()
|
||||
Strike(tList, b_InSkybox, net.ReadFloat(), net.ReadUInt(8))
|
||||
else
|
||||
local vPos = net.ReadVector()
|
||||
Rumble(vPos, net.ReadFloat(), net.ReadUInt(8) )
|
||||
end
|
||||
end)
|
||||
|
||||
-- Render Strikes
|
||||
local tex = {(Material("stormfox2/effects/lightning"))}
|
||||
local texend = {(Material("stormfox2/effects/lightning_end")),(Material("stormfox2/effects/lightning_end2"))}
|
||||
for k, v in ipairs( texend ) do
|
||||
v:SetFloat("$nofog",1)
|
||||
end
|
||||
local t = 0
|
||||
hook.Add("PostDrawOpaqueRenderables","StormFox2.Render.Lightning",function(a,sky)
|
||||
if a or #lightningStrikes < 1 then return end
|
||||
if sky then return end -- Doesn't work yet
|
||||
local r = {}
|
||||
local c = CurTime()
|
||||
local col = Color( 255, 255, 255, 255)
|
||||
for k, v in ipairs( lightningStrikes ) do
|
||||
-- Render world or skybox
|
||||
--if v[3] ~= sky then continue end
|
||||
-- Remove if dead
|
||||
if v[1] < c then
|
||||
table.insert(r, k)
|
||||
continue
|
||||
end
|
||||
|
||||
local life = 1 - ( v[1] - c ) / v[2] -- 0 - 1
|
||||
if life < 0.6 then
|
||||
col.a = 425 * life
|
||||
else
|
||||
col.a = 637.5 * (1 - life)
|
||||
end
|
||||
local fuzzy = life < 0.6
|
||||
local i = 0.6 / #v[4]
|
||||
if v[5] and not fuzzy then
|
||||
StrikeEffect( v[4][#v[4]][1] , life )
|
||||
lightningStrikes[k][5] = false
|
||||
end
|
||||
-- Render beams
|
||||
render.SetMaterial(tex[1])
|
||||
render.StartBeam(#v[4])
|
||||
local l = math.Rand(0.4, 0.8)
|
||||
for k2, v2 in ipairs( v[4] ) do
|
||||
if life < k2 * i then break end
|
||||
local tp = 0.1
|
||||
render.AddBeam( v2[1], 400, (l * (k2 - 1)) % 1, col )
|
||||
end
|
||||
render.EndBeam()
|
||||
|
||||
-- Render strikes
|
||||
if fuzzy then
|
||||
for k2, v2 in ipairs( v[4] ) do
|
||||
if life < k2 * i or k2 + 3 >= #v[4] then break end
|
||||
local n2 = life * 2- k2 * 0.04
|
||||
local vec = v2[1]
|
||||
local tp = 1 / #v[4] * k2
|
||||
local n = k2 % #texend + 1
|
||||
render.SetMaterial(texend[n])
|
||||
local w,h = texend[n]:Width() * n2,texend[n]:Height() * n2
|
||||
render.DrawBeam( vec, vec + v2[3] * h * v2[2], w * v2[2], 1 - n2, 1, col )
|
||||
end
|
||||
else
|
||||
local v1 = v[4][1][1]
|
||||
local v2 = v[4][#v[4]][1]
|
||||
local vc = (v1 + v2) / 2
|
||||
vc.z = v2.z
|
||||
local vc2 = Vector(vc.x,vc.y,v1.z)
|
||||
local a = math.max(0, 1 - life - 0.2)
|
||||
col.a = a * 1275
|
||||
render.SetMaterial(Material("stormfox2/effects/lightning_light"))
|
||||
render.DrawBeam(vc, vc2, 24400, 0.3 , 0.7, col)
|
||||
end
|
||||
end
|
||||
for i = #r, 1, -1 do
|
||||
table.remove(lightningStrikes, r[i])
|
||||
end
|
||||
end)
|
||||
end
|
||||
779
lua/stormfox2/framework/sh_timemaster.lua
Normal file
779
lua/stormfox2/framework/sh_timemaster.lua
Normal file
@@ -0,0 +1,779 @@
|
||||
--[[
|
||||
| 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
|
||||
447
lua/stormfox2/framework/sh_weather_handle.lua
Normal file
447
lua/stormfox2/framework/sh_weather_handle.lua
Normal file
@@ -0,0 +1,447 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
-- Updates the weather for given players
|
||||
|
||||
local lastSet = 0
|
||||
local CurrentWeather
|
||||
local CurrentPercent = 1
|
||||
|
||||
local function isColor(t)
|
||||
return t.r and t.g and t.b and true or false
|
||||
end
|
||||
local function Blender(nFraction, vFrom, vTo) -- Will it blend?
|
||||
-- Nils should be false, if one of them is a boolean
|
||||
if type(vFrom) == "nil" and type(vTo) == "boolean" then
|
||||
vFrom = false
|
||||
end
|
||||
if type(vTo) == "nil" and type(vFrom) == "boolean" then
|
||||
vTo = false
|
||||
end
|
||||
-- If the same value, then return it
|
||||
if vTo == vFrom then return vTo end
|
||||
-- In case of two diffrent variables.
|
||||
if type(vFrom) ~= type(vTo) then
|
||||
StormFox2.Warning("Mixer called with values of two different types[" .. type(vFrom) .. "," .. type(vTo) .. "]")
|
||||
debug.Trace()
|
||||
return vFrom
|
||||
elseif type(vTo) == "string" or type(vTo) == "IMaterial" or type(vTo) == "boolean" then -- String, material or bool. Return vTo.
|
||||
return vTo
|
||||
elseif type(vTo) == "number" then -- Number
|
||||
return Lerp(nFraction, vFrom, vTo)
|
||||
elseif type(vTo) == "table" and isColor(vTo) then -- Color
|
||||
local r = Lerp( nFraction, vFrom.r or 255, vTo.r )
|
||||
local g = Lerp( nFraction, vFrom.g or 255, vTo.g )
|
||||
local b = Lerp( nFraction, vFrom.b or 255, vTo.b )
|
||||
local a = Lerp( nFraction, vFrom.a or 255, vTo.a )
|
||||
return Color( r, g, b, a )
|
||||
end
|
||||
--StormFox2.Warning("ERROR: Unsupported mix value type[" .. type(vTo) .. "]. Returning original value")
|
||||
--debug.Trace()
|
||||
return vFrom
|
||||
end
|
||||
|
||||
local function IsSame(sName, nPercentage, nDelta)
|
||||
if CurrentPercent ~= nPercentage then return false end
|
||||
if not CurrentWeather then return false end
|
||||
return CurrentWeather.Name == sName
|
||||
end
|
||||
|
||||
local function ApplyWeather(sName, nPercentage, nDelta)
|
||||
hook.Run("StormFox2.weather.prechange", sName ,nPercentage )
|
||||
if nDelta and nDelta <= 0 then
|
||||
nDelta = nil
|
||||
elseif nDelta then
|
||||
local sp = StormFox2.Time.GetSpeed_RAW()
|
||||
if sp > 0 then
|
||||
nDelta = nDelta / sp
|
||||
end
|
||||
end
|
||||
local bSameWeather = sName == (CurrentWeather and CurrentWeather.Name or "Clear")
|
||||
if CurrentWeather and CurrentWeather.OnChange then
|
||||
CurrentWeather:OnChange( sName, nPercentage, nDelta )
|
||||
end
|
||||
if CurrentWeather and CurrentWeather.OnRemove and not bSameWeather then
|
||||
CurrentWeather:OnRemove( sName, nPercentage, nDelta )
|
||||
end
|
||||
local clear = StormFox2.Weather.Get( "Clear" )
|
||||
CurrentWeather = StormFox2.Weather.Get( sName )
|
||||
CurrentPercent = nPercentage
|
||||
local stamp = StormFox2.Sky.GetLastStamp()
|
||||
|
||||
if sName == "Clear" then
|
||||
nPercentage = 1
|
||||
end
|
||||
if nPercentage >= 1 then
|
||||
for _,key in ipairs( StormFox2.Weather.GetKeys() ) do
|
||||
local v = CurrentWeather:Get( key, stamp )
|
||||
if type(v) == "table" and not (v.r and v.g and v.b) then
|
||||
StormFox2.Data.Set(key, v)
|
||||
else
|
||||
StormFox2.Data.Set(key, v, nDelta)
|
||||
end
|
||||
end
|
||||
elseif nPercentage <= 0 then
|
||||
for _,key in ipairs( StormFox2.Weather.GetKeys() ) do
|
||||
StormFox2.Data.Set(key, clear:Get( key, stamp ), nDelta)
|
||||
end
|
||||
else -- Mixing bin
|
||||
for _,key in ipairs( StormFox2.Weather.GetKeys() ) do
|
||||
local var2,b_nomix = CurrentWeather:Get( key, stamp )
|
||||
local d = nDelta
|
||||
if type(var2) == "table" and not (var2.r and var2.g and var2.b) then
|
||||
d = nil
|
||||
end
|
||||
if b_nomix then
|
||||
StormFox2.Data.Set(key, var2, d)
|
||||
else
|
||||
local var1 = clear:Get( key, stamp )
|
||||
if var2 and not var1 then -- This is not a default variable
|
||||
if type(var2) == "number" then
|
||||
var1 = 0
|
||||
end
|
||||
end
|
||||
if not var1 and var2 then -- THis is not a default varable
|
||||
StormFox2.Data.Set(key, var2, d)
|
||||
elseif var1 and var2 then
|
||||
StormFox2.Data.Set(key, Blender(nPercentage, var1, var2), d)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if CurrentWeather.Init and not bSameWeather then
|
||||
CurrentWeather.Init()
|
||||
end
|
||||
if CurrentWeather.Tick10 then
|
||||
CurrentWeather.Tick10()
|
||||
end
|
||||
hook.Run("StormFox2.weather.postchange", sName ,nPercentage, nDelta )
|
||||
end
|
||||
|
||||
hook.Add("StormFox2.Sky.StampChange","StormFox2.Weather.Stamp",function(_,nLerpTime)
|
||||
ApplyWeather(CurrentWeather and CurrentWeather.Name or "Clear", CurrentPercent, nLerpTime)
|
||||
end)
|
||||
|
||||
---Returns the current weather-type.
|
||||
---@return Weather
|
||||
function StormFox2.Weather.GetCurrent()
|
||||
return CurrentWeather or StormFox2.Weather.Get( "Clear" )
|
||||
end
|
||||
|
||||
---Returns the current weather percent.
|
||||
---@return number Percent
|
||||
function StormFox2.Weather.GetPercent()
|
||||
return StormFox2.Data.Get("w_Percentage",CurrentPercent)
|
||||
end
|
||||
|
||||
---Returns the weather percent we're lerping to.
|
||||
---@return number
|
||||
function StormFox2.Weather.GetFinishPercent()
|
||||
return CurrentPercent
|
||||
end
|
||||
|
||||
---Returns the current weather description. Like 'Snow', 'Storm' .. ect.
|
||||
---Second argument isn't translated.
|
||||
---@return string Description
|
||||
---@return string Description_Untranslated
|
||||
function StormFox2.Weather.GetDescription()
|
||||
local c = StormFox2.Weather.GetCurrent()
|
||||
if not c.GetName then
|
||||
return c.Name
|
||||
end
|
||||
local a,b = c:GetName(StormFox2.Time.Get(), StormFox2.Temperature.Get(), StormFox2.Wind.GetForce(), StormFox2.Thunder.IsThundering(), StormFox2.Weather.GetPercent())
|
||||
return a,b or a
|
||||
end
|
||||
|
||||
local errM = Material("error")
|
||||
|
||||
---Returns the current weather-icon.
|
||||
---@return userdata Material
|
||||
function StormFox2.Weather.GetIcon()
|
||||
local c = StormFox2.Weather.GetCurrent()
|
||||
if not c.GetIcon then
|
||||
return errM
|
||||
end
|
||||
return c.GetIcon(StormFox2.Time.Get(), StormFox2.Temperature.Get(), StormFox2.Wind.GetForce(), StormFox2.Thunder.IsThundering(), StormFox2.Weather.GetPercent())
|
||||
end
|
||||
|
||||
local SF_UPDATE_WEATHER = 0
|
||||
local SF_INIT_WEATHER = 1
|
||||
|
||||
if SERVER then
|
||||
local l_data
|
||||
|
||||
---Sets the weather.
|
||||
---@server
|
||||
---@param sName string
|
||||
---@param nPercentage number
|
||||
---@param nDelta? number
|
||||
---@return boolean success
|
||||
function StormFox2.Weather.Set( sName, nPercentage, nDelta )
|
||||
if not StormFox2.Setting.GetCache("enable", true) then return end -- Just in case
|
||||
if nDelta and l_data and nDelta == l_data then
|
||||
if IsSame(sName, nPercentage) then return false end
|
||||
end
|
||||
l_data = nDelta
|
||||
-- Default vals
|
||||
if not nDelta then
|
||||
nDelta = 4
|
||||
end
|
||||
if not nPercentage then
|
||||
nPercentage = 1
|
||||
end
|
||||
-- Unknown weathers gets replaced with 'Clear'
|
||||
if not StormFox2.Weather.Get( sName ) then
|
||||
StormFox2.Warning("Unknown weather: " .. tostring(sName))
|
||||
sName = "Clear"
|
||||
end
|
||||
-- In case we set the weather to clear, change it so it is the current weather at 0 instead
|
||||
if sName == "Clear" and CurrentWeather and nDelta > 0 then
|
||||
nPercentage = 0
|
||||
sName = CurrentWeather.Name
|
||||
elseif sName == "Clear" then
|
||||
nPercentage = 1
|
||||
end
|
||||
lastSet = CurTime()
|
||||
net.Start( StormFox2.Net.Weather )
|
||||
net.WriteBit(SF_UPDATE_WEATHER)
|
||||
net.WriteUInt( math.max(0, StormFox2.Data.GetLerpEnd( "w_Percentage" )), 32)
|
||||
net.WriteFloat(nPercentage)
|
||||
net.WriteString(sName)
|
||||
net.WriteFloat(CurTime() + nDelta)
|
||||
net.Broadcast()
|
||||
ApplyWeather(sName, nPercentage, nDelta)
|
||||
if sName == "Clear" then
|
||||
nPercentage = 0
|
||||
end
|
||||
StormFox2.Data.Set("w_Percentage",nPercentage,nDelta)
|
||||
return true
|
||||
end
|
||||
net.Receive( StormFox2.Net.Weather, function(len, ply) -- OI, what weather?
|
||||
local lerpEnd = StormFox2.Data.GetLerpEnd( "w_Percentage" )
|
||||
net.Start( StormFox2.Net.Weather )
|
||||
net.WriteBit(SF_INIT_WEATHER)
|
||||
net.WriteUInt( math.max(0, StormFox2.Data.GetLerpEnd( "w_Percentage" )), 32)
|
||||
net.WriteFloat( CurrentPercent )
|
||||
net.WriteString( StormFox2.Weather.GetCurrent().Name )
|
||||
net.WriteFloat( StormFox2.Data.Get("w_Percentage",CurrentPercent) )
|
||||
net.Send(ply)
|
||||
end)
|
||||
-- Handles the terrain logic
|
||||
timer.Create("StormFox2.terrain.updater", 4, 0, function()
|
||||
local cW = StormFox2.Weather.GetCurrent()
|
||||
local cT = StormFox2.Terrain.GetCurrent()
|
||||
|
||||
if not cW then return end -- No weather!?
|
||||
local terrain = cW:Get("Terrain")
|
||||
if not cT and not terrain then return end -- No terrain detected
|
||||
if cT and terrain and cT == terrain then return end -- Same terrain detected
|
||||
if terrain then -- Switch terraintype out. This can't be the same as the other
|
||||
StormFox2.Terrain.Set(terrain.Name)
|
||||
elseif not terrain and not cT.lock then -- This terrain doesn't have a lock. Reset terrain
|
||||
StormFox2.Terrain.Reset()
|
||||
elseif not terrain and cT.lock then -- Check the lock of cT and see if we can reset
|
||||
if cT:lock() then -- Lock tells us we can reset the terrain
|
||||
StormFox2.Terrain.Reset()
|
||||
end
|
||||
end
|
||||
end)
|
||||
local tS = CurTime()
|
||||
-- In case no weather was set
|
||||
timer.Simple(8, function()
|
||||
-- Clear up weather when it reaches 0
|
||||
timer.Create("StormFox2.weather.clear",1,0,function()
|
||||
if not CurrentWeather then return end
|
||||
if CurrentWeather.Name == "Clear" then return end
|
||||
local p = StormFox2.Weather.GetPercent()
|
||||
if p <= 0 then
|
||||
StormFox2.Weather.Set("Clear", 1, 0)
|
||||
end
|
||||
end)
|
||||
if CurrentWeather then return end
|
||||
StormFox2.Weather.Set("Clear", 1, 0)
|
||||
end)
|
||||
else
|
||||
local hasLocalWeather = false
|
||||
local svWeather
|
||||
local function SetW( sName, nPercentage, nDelta )
|
||||
-- Block same weather
|
||||
if IsSame(sName, nPercentage) then return false end
|
||||
ApplyWeather(sName, nPercentage, nDelta)
|
||||
if sName == "Clear" then
|
||||
nPercentage = 0
|
||||
end
|
||||
StormFox2.Data.Set("w_Percentage",nPercentage,nDelta)
|
||||
end
|
||||
|
||||
---Sets the weather on the client. Server-side stuff won't be set.
|
||||
---@client
|
||||
---@param sName? string
|
||||
---@param nPercentage? number
|
||||
---@param nDelta? number
|
||||
---@param nTemperature? number
|
||||
function StormFox2.Weather.SetLocal( sName, nPercentage, nDelta, nTemperature)
|
||||
-- If nil then remove the local weather
|
||||
if not sName then
|
||||
return StormFox2.Weather.RemoveLocal()
|
||||
end
|
||||
-- Unknown weathers gets replaced with 'Clear'
|
||||
if not StormFox2.Weather.Get( sName ) then
|
||||
StormFox2.Warning("Unknown weather: " .. tostring(sName))
|
||||
sName = "Clear"
|
||||
end
|
||||
if not hasLocalWeather then
|
||||
svWeather = {StormFox2.Weather.GetCurrent().Name, StormFox2.Weather.GetFinishPercent(), StormFox2.Temperature.Get()}
|
||||
end
|
||||
StormFox2.Temperature.SetLocal(nTemperature)
|
||||
-- Block same weather
|
||||
SetW(sName, nPercentage or 1, nDelta)
|
||||
hasLocalWeather = true
|
||||
end
|
||||
|
||||
---Removes the local weather.
|
||||
---@client
|
||||
function StormFox2.Weather.RemoveLocal()
|
||||
if not hasLocalWeather then return end
|
||||
SetW(svWeather[1], svWeather[2], 4)
|
||||
StormFox2.Temperature.SetLocal(nil)
|
||||
svWeather = nil
|
||||
hasLocalWeather = false
|
||||
end
|
||||
net.Receive( StormFox2.Net.Weather, function(len)
|
||||
local flag = net.ReadBit() == SF_UPDATE_WEATHER
|
||||
local wTarget = net.ReadUInt(32)
|
||||
local nPercentage = net.ReadFloat()
|
||||
local sName = net.ReadString()
|
||||
if flag then
|
||||
local nDelta = net.ReadFloat() - CurTime()
|
||||
-- Calculate the time since server set this
|
||||
if not hasLocalWeather then
|
||||
SetW(sName, nPercentage, nDelta)
|
||||
else
|
||||
svWeather[1] = sName
|
||||
svWeather[2] = nPercentage
|
||||
end
|
||||
else
|
||||
local current = net.ReadFloat()
|
||||
if not hasLocalWeather then
|
||||
local secondsLeft = wTarget - CurTime()
|
||||
if secondsLeft <= 0 then
|
||||
SetW(sName, nPercentage, 0)
|
||||
else
|
||||
SetW(sName, current, 0)
|
||||
SetW(sName, nPercentage, secondsLeft)
|
||||
end
|
||||
else
|
||||
svWeather[1] = sName
|
||||
svWeather[2] = nPercentage
|
||||
end
|
||||
end
|
||||
end)
|
||||
-- Ask the server what weather we have
|
||||
hook.Add("StormFox2.InitPostEntity", "StormFox2.terrain", function()
|
||||
net.Start( StormFox2.Net.Weather )
|
||||
net.SendToServer()
|
||||
end)
|
||||
end
|
||||
|
||||
hook.Add("Think", "StormFox2.Weather.Think", function()
|
||||
if not CurrentWeather then return end
|
||||
if not CurrentWeather.Think then return end
|
||||
if not StormFox2.Setting.SFEnabled() then return end
|
||||
CurrentWeather:Think()
|
||||
end)
|
||||
|
||||
timer.Create("StormFox2.Weather.tickslow", 1, 0, function()
|
||||
if not CurrentWeather then return end
|
||||
if not CurrentWeather.TickSlow then return end
|
||||
CurrentWeather.TickSlow()
|
||||
end)
|
||||
|
||||
hook.Add("StormFox2.weather.postchange", "StormFox2.weather.slowtickinit", function()
|
||||
if not CurrentWeather then return end
|
||||
if not CurrentWeather.TickSlow then return end
|
||||
CurrentWeather.TickSlow()
|
||||
end)
|
||||
|
||||
if CLIENT then
|
||||
local c_tab = {"PostDrawTranslucentRenderables", "PreDrawTranslucentRenderables", "HUDPaint"}
|
||||
for i,v in ipairs(c_tab) do
|
||||
hook.Add(v, "StormFox2.Weather." .. v, function(...)
|
||||
if not CurrentWeather then return end
|
||||
if not CurrentWeather[v] then return end
|
||||
CurrentWeather[v](...)
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
-- Some functions to make it easier.
|
||||
|
||||
---Returns true if it is raining, or if current weather is child of rain.
|
||||
---@return boolean
|
||||
---@shared
|
||||
function StormFox2.Weather.IsRaining()
|
||||
local wT = StormFox2.Weather.GetCurrent()
|
||||
if wT.Inherit == "Rain" then return true end
|
||||
if wT.Name ~= "Rain" then return false end
|
||||
return StormFox2.Temperature.Get() > -2 or false
|
||||
end
|
||||
|
||||
---Returns true if it is snowing.
|
||||
---@return boolean
|
||||
---@shared
|
||||
function StormFox2.Weather.IsSnowing()
|
||||
local wT = StormFox2.Weather.GetCurrent()
|
||||
if wT.Name ~= "Rain" then return false end
|
||||
return StormFox2.Temperature.Get() <= -2 or false
|
||||
end
|
||||
|
||||
---Returns the rain / snow amount. Between 0 - 1.
|
||||
---@return number
|
||||
---@shared
|
||||
function StormFox2.Weather.GetRainAmount()
|
||||
if not StormFox2.Weather.IsRaining() then return 0 end
|
||||
return StormFox2.Weather.GetPercent()
|
||||
end
|
||||
|
||||
---Returns true if the current weather is raining, snowing or inherit from rain.
|
||||
---@return boolean
|
||||
---@shared
|
||||
function StormFox2.Weather.HasDownfall()
|
||||
local wT = StormFox2.Weather.GetCurrent()
|
||||
if wT.Inherit == "Rain" then return true end
|
||||
return wT.Name == "Rain"
|
||||
end
|
||||
|
||||
-- Downfall
|
||||
|
||||
---Returns true if the entity is hit by rain or any downfall.
|
||||
---@param eEnt Entity
|
||||
---@param bDont_cache boolean
|
||||
---@return boolean
|
||||
---@shared
|
||||
function StormFox2.DownFall.IsEntityHit(eEnt, bDont_cache)
|
||||
if not StormFox2.Weather.HasDownfall() then return false end
|
||||
return (StormFox2.Wind.IsEntityInWind(eEnt,bDont_cache))
|
||||
end
|
||||
|
||||
---Checks to see if the given point is hit by rain.
|
||||
---@param vPos Vector
|
||||
---@return boolean
|
||||
---@shared
|
||||
function StormFox2.DownFall.IsPointHit(vPos)
|
||||
if not StormFox2.Weather.HasDownfall() then return false end
|
||||
local t = util.TraceLine( {
|
||||
start = vPos,
|
||||
endpos = vPos + -StormFox2.Wind.GetNorm() * 262144,
|
||||
mask = StormFox2.DownFall.Mask
|
||||
} )
|
||||
return t.HitSky
|
||||
end
|
||||
87
lua/stormfox2/framework/sv_2dskybox.lua
Normal file
87
lua/stormfox2/framework/sv_2dskybox.lua
Normal file
@@ -0,0 +1,87 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
|
||||
StormFox2.Setting.AddSV("darken_2dskybox", false, nil, "Effect")
|
||||
|
||||
local convar = GetConVar("sv_skyname")
|
||||
local mat_2dBox = "skybox/" .. convar:GetString()
|
||||
local last_f = 1
|
||||
local function OnChange( str )
|
||||
StormFox2.Map.Set2DSkyBoxDarkness( last_f )
|
||||
end
|
||||
|
||||
cvars.RemoveChangeCallback("sv_skyname", "sf_skynamehook")
|
||||
cvars.AddChangeCallback( "sv_skyname", OnChange, "sf_skynamehook" )
|
||||
|
||||
local t = {"bk", "dn", "ft", "lf", "rt", "up"}
|
||||
|
||||
---Sets the 2D skybox darkness. Mostly used for internal stuff.
|
||||
---@param f number
|
||||
---@param bRemember boolean
|
||||
---@param bDark boolean
|
||||
function StormFox2.Map.Set2DSkyBoxDarkness( f, bRemember, bDark )
|
||||
if bRemember then
|
||||
last_f = f
|
||||
end
|
||||
local sky = convar:GetString()
|
||||
if sky == "painted" then return end
|
||||
if bDark == nil then
|
||||
bDark = StormFox2.Setting.GetCache("darken_2dskybox", false)
|
||||
end
|
||||
if not StormFox2.Setting.GetCache("enable_skybox", true) or not StormFox2.Setting.SFEnabled() or not bDark then
|
||||
f = 1
|
||||
end
|
||||
mat_2dBox = "skybox/" .. sky
|
||||
local vec = Vector( f, f, f)
|
||||
|
||||
for k,v in ipairs( t ) do
|
||||
local m = Material(mat_2dBox .. v)
|
||||
if m:IsError() then continue end
|
||||
m:SetVector("$color", vec)
|
||||
m:SetInt("$nofog", 1)
|
||||
m:SetInt("$ignorez", 1)
|
||||
end
|
||||
end
|
||||
|
||||
StormFox2.Setting.Callback("darken_2dskybox", function(vVar)
|
||||
StormFox2.Map.Set2DSkyBoxDarkness( last_f, false, vVar )
|
||||
end, "darken_2dskybox")
|
||||
|
||||
local function SkyThink(b, str)
|
||||
if not StormFox2.Setting.GetCache("enable_skybox", true) or not StormFox2.Setting.SFEnabled() then return end
|
||||
if b == nil then
|
||||
b = StormFox2.Setting.GetCache("use_2dskybox", false)
|
||||
end
|
||||
if not b then
|
||||
return RunConsoleCommand("sv_skyname", "painted")
|
||||
end
|
||||
local s = str or StormFox2.Setting.GetCache("overwrite_2dskybox", "")
|
||||
if s == "" then
|
||||
local lS = 0
|
||||
if StormFox2.Sky and StormFox2.Sky.GetLastStamp then -- Something happen
|
||||
lS = StormFox2.Sky.GetLastStamp()
|
||||
end
|
||||
local sky_options = StormFox2.Weather.GetCurrent():Get("skyBox", lS)
|
||||
s = (table.Random(sky_options))
|
||||
else
|
||||
StormFox2.Map.Set2DSkyBoxDarkness( last_f )
|
||||
end
|
||||
RunConsoleCommand("sv_skyname", s)
|
||||
end
|
||||
|
||||
StormFox2.Setting.Callback("use_2dskybox",SkyThink,"2dskybox_enable")
|
||||
StormFox2.Setting.Callback("overwrite_2dskybox",function(str) SkyThink(nil, str) end,"2dskybox_enable2")
|
||||
|
||||
hook.Add("StormFox2.weather.postchange", "StormFox2.weather.set2dsky", function( _ )
|
||||
if not StormFox2.Setting.GetCache("use_2dskybox", false) then return end
|
||||
SkyThink()
|
||||
end)
|
||||
339
lua/stormfox2/framework/sv_envioment.lua
Normal file
339
lua/stormfox2/framework/sv_envioment.lua
Normal file
@@ -0,0 +1,339 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
local INVALID_VERTS = 0
|
||||
local WATER_VERTS = 1
|
||||
|
||||
StormFox2.Setting.AddSV("enable_ice",not game.IsDedicated())
|
||||
StormFox2.Setting.AddSV("enable_wateroverlay",true, nil, "Effects")
|
||||
|
||||
--[[-------------------------------------------------------------------------
|
||||
Localize
|
||||
---------------------------------------------------------------------------]]
|
||||
local round = math.Round
|
||||
local util_TraceLine = util.TraceLine
|
||||
local table_sort = table.sort
|
||||
local LocalPlayer = LocalPlayer
|
||||
--[[-------------------------------------------------------------------------
|
||||
Make a few SurfaceInfo functions.
|
||||
---------------------------------------------------------------------------]]
|
||||
local meta = FindMetaTable("SurfaceInfo")
|
||||
-- Support caching stuff
|
||||
local surf_caching = {}
|
||||
meta.__index = function(a,b)
|
||||
return meta[b] or surf_caching[a] and surf_caching[a][b]
|
||||
end
|
||||
meta.__newindex = function(a,b,c)
|
||||
if not surf_caching[a] then surf_caching[a] = {} end
|
||||
surf_caching[a][b] = c
|
||||
end
|
||||
hook.Add("EntityRemoved", "ClearSurfaceInfo", function(ent)
|
||||
for _,surf in ipairs(ent:GetBrushSurfaces() or {}) do
|
||||
surf_caching[surf] = nil
|
||||
end
|
||||
end)
|
||||
function meta:IsValid( )
|
||||
if self.b_invalid ~= nil then return self.b_invalid end
|
||||
local b = #(self:GetVertices()) > 0
|
||||
self.b_invalid = b
|
||||
return self.b_invalid
|
||||
end
|
||||
function meta:GetVerticesNoParallel( )
|
||||
if not self:IsValid() then return {} end
|
||||
if self.v_vertNP then return table.Copy(self.v_vertNP) end
|
||||
self.v_vertNP = {}
|
||||
local verts = self:GetVertices()
|
||||
for i,cv in ipairs(verts) do
|
||||
local pv,nv = verts[i - 1] or verts[#verts], verts[i + 1] or verts[1]
|
||||
local cP = ( cv - pv ):Cross( nv - pv )
|
||||
if cP.x == 0 and cP.y == 0 and cP.z == 0 then continue end -- parallel vector.
|
||||
table.insert(self.v_vertNP, cv)
|
||||
end
|
||||
return table.Copy(self.v_vertNP)
|
||||
end
|
||||
function meta:GetCenter( )
|
||||
if not self:IsValid() then return end
|
||||
if self.v_cent then return self.v_cent end
|
||||
local verts = self:GetVertices()
|
||||
if #verts < 2 then
|
||||
self.v_cent = verts[1]
|
||||
return self.v_cent
|
||||
end
|
||||
local vmax,vmin = verts[1],verts[1]
|
||||
for i = 2,#verts do
|
||||
vmax[1] = math.max(vmax[1],verts[i][1])
|
||||
vmax[2] = math.max(vmax[2],verts[i][2])
|
||||
vmax[3] = math.max(vmax[3],verts[i][3])
|
||||
vmin[1] = math.min(vmin[1],verts[i][1])
|
||||
vmin[2] = math.min(vmin[2],verts[i][2])
|
||||
vmin[3] = math.min(vmin[3],verts[i][3])
|
||||
end
|
||||
self.v_cent = vmin + (vmax - vmin) / 2
|
||||
return self.v_cent
|
||||
end
|
||||
function meta:GetNormal( )
|
||||
if not self:IsValid() then return end
|
||||
if self.v_norm then return self.v_norm end
|
||||
local p = self:GetVertices()
|
||||
if #p < 3 then return end -- Invalid brush. (Yes this happens)
|
||||
local c = p[1]
|
||||
local s = Vector(0,0,0)
|
||||
for i = 2,#p do
|
||||
s = s + ( p[i] - c ):Cross( (p[i + 1] or p[1]) - c )
|
||||
if s.x ~= 0 and s.y ~= 0 and s.z ~= 0 then -- Check if this isn't a parallel vector.
|
||||
break -- Got a valid norm
|
||||
end
|
||||
end
|
||||
self.v_norm = s:GetNormalized()
|
||||
return self.v_norm
|
||||
end
|
||||
function meta:GetAngles( )
|
||||
if not self:IsValid() then return end
|
||||
if self.a_ang then return self.a_ang end
|
||||
self.a_ang = self:GetNormal():Angle()
|
||||
return self.a_ang
|
||||
end
|
||||
function meta:GetPerimeter( )
|
||||
if not self:IsValid() then return end
|
||||
if self.n_peri then return self.n_peri end
|
||||
local p = self:GetVertices()
|
||||
local n = 0
|
||||
for i = 1,#p do
|
||||
n = n + p[i]:Distance(p[i + 1] or p[1])
|
||||
end
|
||||
self.n_peri = n
|
||||
return self.n_peri
|
||||
end
|
||||
function meta:GetArea( )
|
||||
if not self:IsValid() then return end
|
||||
if self.n_area then return self.n_area end
|
||||
local p = self:GetVertices()
|
||||
local n = #p
|
||||
if n < 3 then -- Invalid shape
|
||||
self.n_area = 0
|
||||
return 0
|
||||
--elseif n == 3 then -- Triangle, but cost more?
|
||||
-- local a,b,c = p[1]:Distance(p[2]),p[2]:Distance(p[3]),p[3]:Distance(p[1])
|
||||
-- local s = (a + b + c) / 2
|
||||
-- t_t[self] = sqrt( s * (s - a) * (s - b) * (s - c) )
|
||||
-- return t_t[self]
|
||||
else -- Any shape
|
||||
local a = Vector(0,0,0)
|
||||
for i,pc in ipairs(p) do
|
||||
local pn = p[i + 1] or p[1]
|
||||
a = a + pc:Cross(pn)
|
||||
end
|
||||
a = a / 2
|
||||
self.n_area = a:Distance(Vector(0,0,0))
|
||||
return self.n_area
|
||||
end
|
||||
end
|
||||
--[[-------------------------------------------------------------------------
|
||||
Make some adv SurfaceInfo functions.
|
||||
---------------------------------------------------------------------------]]
|
||||
function meta:GetUVVerts() -- Creates UV-data out from the shape.
|
||||
if not self:IsValid() then return end
|
||||
if self.t_uv then return table.Copy(self.t_uv) end
|
||||
local t = self:GetVerticesNoParallel()
|
||||
local a = self:GetNormal():Angle()
|
||||
local c = self:GetCenter()
|
||||
local vmin,vmax
|
||||
for i,v in ipairs(t) do
|
||||
t[i] = (t[i] - c)
|
||||
t[i]:Rotate(a)
|
||||
if not vmin then
|
||||
vmin = Vector(t[i].x,t[i].y,t[i].z)
|
||||
vmax = Vector(t[i].x,t[i].y,t[i].z)
|
||||
else
|
||||
for ii = 1,3 do
|
||||
vmin[ii] = math.min(vmin[ii],t[i][ii])
|
||||
vmax[ii] = math.max(vmax[ii],t[i][ii])
|
||||
end
|
||||
end
|
||||
end
|
||||
local y_r = vmax.z - vmin.z
|
||||
local x_r,x_r2 = vmax.x - vmin.x,vmax.y - vmin.y
|
||||
local min_x = vmin.x
|
||||
local i2 = 1
|
||||
if x_r2 > x_r then
|
||||
x_r = x_r2
|
||||
i2 = 2
|
||||
min_x = vmin.y
|
||||
end
|
||||
local new_t = {}
|
||||
for i = 1,#t do
|
||||
table.insert(new_t, {u = (t[i][i2] - min_x) / x_r,v = (t[i].z - vmin.z) / y_r})
|
||||
end
|
||||
self.t_uv = new_t
|
||||
return table.Copy(self.t_uv)
|
||||
end
|
||||
function meta:GetMesh() -- Generates a mesh-table for the surfaceinfo.
|
||||
if not self:IsValid() then return end
|
||||
if self.t_mesh then return table.Copy(self.t_mesh) end
|
||||
local verts = self:GetVerticesNoParallel()
|
||||
local n = self:GetNormal()
|
||||
-- Calc the height and width
|
||||
local h_max,h_min = verts[1].z,verts[1].z
|
||||
for i = 2,#verts do
|
||||
local h = verts[i].z
|
||||
h_max = math.max(h_max,h)
|
||||
h_min = math.min(h_min,h)
|
||||
end
|
||||
local uvt = self:GetUVVerts()
|
||||
local t = {}
|
||||
for i = 1,3 do
|
||||
table.insert(t, {pos = verts[i], u = uvt[i].u,v = uvt[i].v, normal = n})
|
||||
end
|
||||
for i = 4,#verts do
|
||||
table.insert(t, {pos = verts[1], u = uvt[1].u,v = uvt[1].v, normal = n})
|
||||
table.insert(t, {pos = verts[i - 1], u = uvt[i - 1].u,v = uvt[i - 1].v, normal = n})
|
||||
table.insert(t, {pos = verts[i], u = uvt[i].u,v = uvt[i].v, normal = n})
|
||||
end
|
||||
self.t_mesh = t
|
||||
return table.Copy(self.t_mesh)
|
||||
end
|
||||
function meta:GetMinSide()
|
||||
if not self:IsValid() then return end
|
||||
if self.n_midi then return self.n_midi end
|
||||
local mi,ma
|
||||
local p = self:GetVertices()
|
||||
for i = 1,#p do
|
||||
if not mi then
|
||||
mi = p[i]:Distance(p[i + 1] or p[1])
|
||||
ma = mi
|
||||
else
|
||||
mi = math.min(mi,p[i]:Distance(p[i + 1] or p[1]))
|
||||
ma = math.max(ma,p[i]:Distance(p[i + 1] or p[1]))
|
||||
end
|
||||
end
|
||||
self.n_midi = mi
|
||||
self.n_madi = ma
|
||||
return mi
|
||||
end
|
||||
function meta:GetMaxSide()
|
||||
if not self:IsValid() then return end
|
||||
if self.n_madi then return self.n_madi end
|
||||
self:GetMinSide()
|
||||
return self.n_madi
|
||||
end
|
||||
--[[-------------------------------------------------------------------------
|
||||
Generate meshes and env-points out from the map-data.
|
||||
---------------------------------------------------------------------------]]
|
||||
-- New surface functions
|
||||
local function SurfaceInfo_GetType( eEnt, SurfaceInfo )
|
||||
if #SurfaceInfo:GetVertices() < 3 then return INVALID_VERTS end
|
||||
if SurfaceInfo:IsWater() then -- Water
|
||||
return WATER_VERTS
|
||||
end
|
||||
return INVALID_VERTS
|
||||
end
|
||||
|
||||
|
||||
local ice = Material("stormfox2/effects/ice_water")
|
||||
local ice_size = 500
|
||||
local vec_ex = Vector(0,0,1)
|
||||
|
||||
STORMFOX_WATERMESHCOLLISON = {}
|
||||
|
||||
local scan = function() -- Locates all surfaceinfos we need.
|
||||
StormFox2.Msg("Scanning surfaces ..")
|
||||
surfaceinfos = {}
|
||||
-- Scan all brushsurfaces and grab the glass/windows, water and metal. Put them in a table with matching normal.
|
||||
for i,v in ipairs( game.GetWorld():GetBrushSurfaces() ) do
|
||||
if not v then continue end
|
||||
if not v:IsValid() then continue end
|
||||
if not v:IsWater() then continue end
|
||||
local v_type = SurfaceInfo_GetType( game.GetWorld(), v )
|
||||
if v_type == INVALID_VERTS then continue end -- Invalid or doesn't have a type.
|
||||
if not surfaceinfos[v_type] then surfaceinfos[v_type] = {} end
|
||||
table.insert(surfaceinfos[v_type], {v, v:GetCenter()} )
|
||||
end
|
||||
coroutine.yield()
|
||||
-- Generate water mesh
|
||||
if surfaceinfos[WATER_VERTS] then
|
||||
StormFox2.Msg("Generating ice-mesh [" .. #surfaceinfos[WATER_VERTS] .. "] ")
|
||||
local mesh = {}
|
||||
for i,v in ipairs(surfaceinfos[WATER_VERTS]) do
|
||||
if StormFox2.Map.IsInside( v[2] ) then
|
||||
local t = v[1]:GetVertices()
|
||||
if #t >= 3 then
|
||||
local t2 = {}
|
||||
if #t == 3 then
|
||||
for i = 1,3 do
|
||||
table.insert(t2, t[i] + vec_ex)
|
||||
table.insert(t2, t[i] - vec_ex)
|
||||
end
|
||||
table.insert(t2, t[3] + vec_ex)
|
||||
table.insert(t2, t[3] - vec_ex)
|
||||
table.insert(STORMFOX_WATERMESHCOLLISON, t2)
|
||||
elseif #t == 4 then
|
||||
for i = 1,4 do
|
||||
table.insert(t2, t[i] + vec_ex)
|
||||
table.insert(t2, t[i] - vec_ex)
|
||||
end
|
||||
table.insert(STORMFOX_WATERMESHCOLLISON, t2)
|
||||
else
|
||||
for i = 1,#t do
|
||||
table.insert(t2, t[i] + vec_ex)
|
||||
table.insert(t2, t[i] - vec_ex)
|
||||
end
|
||||
table.insert(STORMFOX_WATERMESHCOLLISON, t2)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
coroutine.yield(true)
|
||||
end
|
||||
|
||||
local cor_scan = coroutine.wrap(scan)
|
||||
local function StartGenerating()
|
||||
timer.Create("SF_ENV_SCAN", 0.2, 0, function()
|
||||
if cor_scan() then
|
||||
cor_scan = nil
|
||||
timer.Remove("SF_ENV_SCAN")
|
||||
StormFox2.Msg("Meshes completed.")
|
||||
end
|
||||
end)
|
||||
hook.Remove("StormFox2.InitPostEntity", "StormFox_ENV_SCAN")
|
||||
end
|
||||
hook.Add("StormFox2.InitPostEntity", "StormFox_ENV_SCAN", StartGenerating)
|
||||
|
||||
local bIce = false
|
||||
local function SpawnIce()
|
||||
for k,v in ipairs(ents.FindByClass("stormfox_mapice")) do
|
||||
v:Remove()
|
||||
end
|
||||
local e = ents.Create("stormfox_mapice")
|
||||
e:SetPos(Vector(0,0,0))
|
||||
e:Spawn()
|
||||
bIce = true
|
||||
end
|
||||
|
||||
local function RemoveIce()
|
||||
bIce = false
|
||||
for k,v in ipairs(ents.FindByClass("stormfox_mapice")) do
|
||||
v:Remove()
|
||||
end
|
||||
end
|
||||
|
||||
timer.Create("stormfox2.spawnice", 8, 0, function()
|
||||
if not StormFox2.Setting.GetCache("enable_ice") then
|
||||
if bIce then
|
||||
RemoveIce()
|
||||
end
|
||||
return
|
||||
end
|
||||
if bIce and StormFox2.Temperature.Get() > -1 then
|
||||
RemoveIce()
|
||||
elseif not bIce and StormFox2.Temperature.Get() <= -8 then
|
||||
SpawnIce()
|
||||
end
|
||||
end)
|
||||
114
lua/stormfox2/framework/sv_heavens.lua
Normal file
114
lua/stormfox2/framework/sv_heavens.lua
Normal file
@@ -0,0 +1,114 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
--[[-------------------------------------------------------------------------
|
||||
StormFox2.Sun.SetTimeUp(nTime) Sets how long the sun is on the sky.
|
||||
StormFox2.Sun.IsUp() Returns true if the sun is on the sky.
|
||||
|
||||
|
||||
StormFox2.Moon.SetTimeUp(nTime) Sets how long the moon is on the sky.
|
||||
|
||||
---------------------------------------------------------------------------]]
|
||||
local clamp = math.Clamp
|
||||
|
||||
StormFox2.Sun = StormFox2.Sun or {}
|
||||
StormFox2.Moon = StormFox2.Moon or {}
|
||||
StormFox2.Sky = StormFox2.Sky or {}
|
||||
|
||||
-- SunRise and SunSet
|
||||
|
||||
---Sets the time for sunrise.
|
||||
---@param nTime TimeNumber
|
||||
---@server
|
||||
function StormFox2.Sun.SetSunRise(nTime)
|
||||
StormFox2.Setting.Set("sunrise", nTime)
|
||||
end
|
||||
|
||||
---Sets the tiem for sunsets.
|
||||
---@param nTime TimeNumber
|
||||
---@server
|
||||
function StormFox2.Sun.SetSunSet(nTime)
|
||||
StormFox2.Setting.Set("sunset", nTime)
|
||||
end
|
||||
|
||||
---Sets the sunyaw. This will also affect the moon.
|
||||
---@param nYaw number
|
||||
---@server
|
||||
function StormFox2.Sun.SetYaw(nYaw)
|
||||
StormFox2.Setting.Set("sunyaw",nYaw)
|
||||
end
|
||||
|
||||
---Sets the sunsize. (Default: 30)
|
||||
---@param n number
|
||||
---@server
|
||||
function StormFox2.Sun.SetSize(n)
|
||||
StormFox2.Network.Set("sun_size",n)
|
||||
end
|
||||
|
||||
---Sets the suncolor.
|
||||
---@param cColor table
|
||||
---@deprecated
|
||||
---@server
|
||||
function StormFox2.Sun.SetColor(cColor)
|
||||
StormFox2.Network.Set("sunColor",cColor)
|
||||
end
|
||||
|
||||
-- Moon
|
||||
--[[-------------------------------------------------------------------------
|
||||
Sets the moon phase, and increases it once pr day
|
||||
---------------------------------------------------------------------------]]
|
||||
hook.Add("StormFox2.Time.NextDay","StormFox2.MoonPhase",function()
|
||||
StormFox2.Moon.SetPhase( StormFox2.Moon.GetPhase() + 1 )
|
||||
end)
|
||||
|
||||
---Sets the moon phase. A number between 0 and 7.
|
||||
---@param moon_phase number
|
||||
---@server
|
||||
function StormFox2.Moon.SetPhase( moon_phase )
|
||||
StormFox2.Network.Set("moon_phase",moon_phase % 8)
|
||||
end
|
||||
|
||||
StormFox2.Moon.SetPhase( math.random(0, 7) )
|
||||
|
||||
-- Skybox
|
||||
local function SkyTick(b)
|
||||
b = b and StormFox2.Setting.SFEnabled()
|
||||
if b then -- Reenable skybox
|
||||
local _2d = StormFox2.Setting.GetCache("use_2dskybox", false)
|
||||
if not _2d then
|
||||
RunConsoleCommand("sv_skyname", "painted")
|
||||
else
|
||||
local sky_over = StormFox2.Setting.GetCache("overwrite_2dskybox", "")
|
||||
if sky_over == "" then
|
||||
sky_over = StormFox2.Weather.GetCurrent():Get("skyBox",StormFox2.Sky.GetLastStamp()) or "skybox/sky_day02_06_hdrbk"
|
||||
if type(sky_over) == "table" then
|
||||
sky_over = table.Random(sky_over)
|
||||
end
|
||||
end
|
||||
RunConsoleCommand("sv_skyname", sky_over)
|
||||
end
|
||||
else -- Disable skybox
|
||||
local map_ent = StormFox2.Map.Entities()[1]
|
||||
if not map_ent then
|
||||
StormFox2.Warning("No map-entity?")
|
||||
RunConsoleCommand("sv_skyname", "skybox/sky_day02_06_hdrbk")
|
||||
return
|
||||
end
|
||||
local sky_name = map_ent["skyname"] or "skybox/sky_day02_06_hdrbk"
|
||||
StormFox2.Map.Set2DSkyBoxDarkness( 1 )
|
||||
RunConsoleCommand("sv_skyname", sky_name)
|
||||
end
|
||||
end
|
||||
local func = function(b)
|
||||
SkyTick(StormFox2.Setting.GetCache("enable_skybox", true))
|
||||
end
|
||||
StormFox2.Setting.Callback("enable", func, "disable_heavens")
|
||||
StormFox2.Setting.Callback("clenable", func, "disable_heavenscl")
|
||||
StormFox2.Setting.Callback("enable_skybox",SkyTick,"enable_skybox_call")
|
||||
Reference in New Issue
Block a user