mirror of
https://github.com/lifestorm/wnsrc.git
synced 2025-12-17 21:53:46 +03:00
Upload
This commit is contained in:
276
lua/stormfox2/functions/cl_clouds.lua
Normal file
276
lua/stormfox2/functions/cl_clouds.lua
Normal file
@@ -0,0 +1,276 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
--[[-------------------------------------------------------------------------
|
||||
Render clouds
|
||||
---------------------------------------------------------------------------]]
|
||||
local cos,sin,rad = math.cos,math.sin,math.rad
|
||||
local max,min,clamp,ceil,abs = math.max,math.min,math.Clamp,math.ceil,math.abs
|
||||
local z_level = -.8
|
||||
local eye_mult = -.0001
|
||||
|
||||
-- Generate dome mesh
|
||||
local Render_Dome = Mesh()
|
||||
local top_height = 20
|
||||
local sc = 20
|
||||
|
||||
local stage = 0
|
||||
local e_r = rad(45)
|
||||
local t_s = 1
|
||||
local function UVMulti(uv,mul)
|
||||
return (uv - 0.5) * mul + 0.5
|
||||
end
|
||||
mesh.Begin( Render_Dome, MATERIAL_TRIANGLES, 24 )
|
||||
for i = 1,8 do
|
||||
local yaw = rad(45 * i)
|
||||
-- Generate the top
|
||||
-- L
|
||||
local c,s = cos(yaw),sin(yaw)
|
||||
local L = {Vector(c * sc,s * sc,0.1 * -sc),(1 + c) / 2 * t_s,(1 + s) / 2 * t_s}
|
||||
mesh.Position(L[1])
|
||||
mesh.TexCoord( stage, L[2], L[3])
|
||||
mesh.Color(255,255,255,255)
|
||||
mesh.AdvanceVertex()
|
||||
-- R
|
||||
local c,s = cos(yaw + e_r),sin(yaw + e_r)
|
||||
local R = {Vector(c * sc,s * sc,0.1 * -sc),(1 + c) / 2 * t_s, (1 + s) / 2 * t_s}
|
||||
mesh.Position(R[1])
|
||||
mesh.TexCoord( stage, R[2],R[3] )
|
||||
mesh.Color(255,255,255,255)
|
||||
mesh.AdvanceVertex()
|
||||
-- T
|
||||
mesh.Position(Vector(0,0,0.1 * top_height))
|
||||
mesh.TexCoord( stage, 0.5 * t_s,0.5 * t_s )
|
||||
mesh.Color(255,255,255,255)
|
||||
mesh.AdvanceVertex()
|
||||
|
||||
-- Generate side1
|
||||
mesh.Position(L[1])
|
||||
mesh.TexCoord( stage, L[2], L[3])
|
||||
mesh.Color(255,255,255,255)
|
||||
mesh.AdvanceVertex()
|
||||
|
||||
local R2 = {R[1] * 1.4 - Vector(0,0,4),UVMulti(R[2],1.4),UVMulti(R[3],1.4)}
|
||||
mesh.Position(R2[1])
|
||||
mesh.TexCoord( stage, R2[2],R2[3] )
|
||||
mesh.Color(255,255,255,0)
|
||||
mesh.AdvanceVertex()
|
||||
|
||||
mesh.Position(R[1])
|
||||
mesh.TexCoord( stage, R[2],R[3] )
|
||||
mesh.Color(255,255,255,255)
|
||||
mesh.AdvanceVertex()
|
||||
|
||||
-- Generate side 2
|
||||
mesh.Position(L[1])
|
||||
mesh.TexCoord( stage, L[2], L[3])
|
||||
mesh.Color(255,255,255,255)
|
||||
mesh.AdvanceVertex()
|
||||
|
||||
mesh.Position(L[1] * 1.4 - Vector(0,0,4))
|
||||
mesh.TexCoord( stage, UVMulti(L[2], 1.4), UVMulti(L[3],1.4))
|
||||
mesh.Color(255,255,255,0)
|
||||
mesh.AdvanceVertex()
|
||||
|
||||
mesh.Position(R2[1])
|
||||
mesh.TexCoord( stage, R2[2],R2[3] )
|
||||
mesh.Color(255,255,255,0)
|
||||
mesh.AdvanceVertex()
|
||||
end
|
||||
mesh.End()
|
||||
-- Local functions
|
||||
local matrix = Matrix()
|
||||
local function RenderDome(pos,mat,alpha)
|
||||
matrix:Identity()
|
||||
matrix:Translate( vector_origin + pos )
|
||||
--mat:SetAlpha(alpha)
|
||||
cam.PushModelMatrix(matrix)
|
||||
render.SetBlend(alpha / 255)
|
||||
render.SetMaterial(mat)
|
||||
Render_Dome:Draw()
|
||||
render.SetBlend(1)
|
||||
cam.PopModelMatrix()
|
||||
end
|
||||
local lastRT
|
||||
local function RTRender(RT,blend)
|
||||
lastRT = RT
|
||||
render.PushRenderTarget( RT )
|
||||
render.ClearDepth()
|
||||
render.Clear( 0, 0, 0, 0 )
|
||||
cam.Start2D()
|
||||
if not blend then return end
|
||||
render.OverrideAlphaWriteEnable( true, true )
|
||||
end
|
||||
local function RTMask(srcBlend,destBlend,srcBlendAlpha,destBlendAlpha)
|
||||
local srcBlend = srcBlend or BLEND_ZERO
|
||||
local destBlend = destBlend or BLEND_SRC_ALPHA --
|
||||
local blendFunc = 0 -- The blend mode used for drawing the color layer
|
||||
local srcBlendAlpha = srcBlendAlpha or BLEND_DST_ALPHA -- Determines how a rendered texture's final alpha should be calculated.
|
||||
local destBlendAlpha = destBlendAlpha or BLEND_ZERO --
|
||||
local blendFuncAlpha = 0 --
|
||||
render.OverrideBlend( true, srcBlend, destBlend, blendFunc, srcBlendAlpha, destBlendAlpha, blendFuncAlpha)
|
||||
end
|
||||
local function RTEnd(Mat_Output)
|
||||
render.OverrideBlend( false )
|
||||
render.OverrideAlphaWriteEnable( false )
|
||||
cam.End2D()
|
||||
render.PopRenderTarget()
|
||||
-- Apply changes
|
||||
Mat_Output:SetTexture("$basetexture",lastRT)
|
||||
end
|
||||
local function DrawTextureRectWindow(w,h,o_x,o_y) -- Render function that supports fractions (surface libary is whole numbers only)
|
||||
if o_x < 0 then o_x = o_x + w end
|
||||
if o_y < 0 then o_y = o_y + h end
|
||||
o_x = o_x % w
|
||||
o_y = o_y % h
|
||||
local m = Matrix()
|
||||
m:Identity()
|
||||
m:Translate(Vector(o_x % w,o_y % h))
|
||||
cam.PushModelMatrix(m)
|
||||
surface.DrawTexturedRect(0,0,w,h)
|
||||
surface.DrawTexturedRect(-w,0,w,h)
|
||||
surface.DrawTexturedRect(0,-h,w,h)
|
||||
surface.DrawTexturedRect(-w,-h,w,h)
|
||||
cam.PopModelMatrix()
|
||||
end
|
||||
-- Load materials
|
||||
-- Side clouds
|
||||
local side_clouds = {}
|
||||
for _,fil in ipairs(file.Find("materials/stormfox2/effects/clouds/side_cloud*.png","GAME")) do
|
||||
local png = Material("stormfox2/effects/clouds/" .. fil,"nocull noclamp alphatest")
|
||||
png:SetInt("$flags",2099250)
|
||||
table.insert(side_clouds,{png,png:GetInt("$realwidth") / png:GetInt("$realheight")})
|
||||
end
|
||||
-- Top clouds
|
||||
local layers = 4
|
||||
local sky_mats = {}
|
||||
local offset = {}
|
||||
local params = {}
|
||||
params[ "$basetexture" ] = ""
|
||||
params[ "$translucent" ] = 0
|
||||
params[ "$vertexalpha" ] = 1
|
||||
params[ "$vertexcolor" ] = 1
|
||||
params[ "$nofog" ] = 1
|
||||
params[ "$nolod" ] = 1
|
||||
params[ "$nomip" ] = 1
|
||||
params["$additive"] = 0
|
||||
for i = 1,layers do
|
||||
sky_mats[i] = CreateMaterial("StormFox_RTSKY" .. i,"UnlitGeneric",params)
|
||||
end
|
||||
local cloudbig = Material("stormfox2/effects/clouds/clouds_big.png","nocull noclamp smooth")
|
||||
-- 8240
|
||||
cloudbig:SetInt("$flags",2099250)
|
||||
cloudbig:SetFloat("$nocull",1)
|
||||
cloudbig:SetFloat("$nocull",1)
|
||||
cloudbig:SetFloat("$additive",0)
|
||||
local sky_rts = {}
|
||||
local texscale = 512
|
||||
for i = 1,layers do
|
||||
sky_rts[i] = GetRenderTargetEx( "StormFox_Sky" .. i, texscale, texscale, 1, MATERIAL_RT_DEPTH_NONE, 2, CREATERENDERTARGETFLAGS_UNFILTERABLE_OK, IMAGE_FORMAT_RGBA8888)
|
||||
offset[i] = {i * 99,i * 33}
|
||||
end
|
||||
local function safeCall(...)
|
||||
hook.Run("StormFox2.2DSkybox.CloudLayerRender", ...)
|
||||
end
|
||||
local function UpdateCloudMaterial(layer,cloud_alpha)
|
||||
local blend = true
|
||||
local d_seed = layer * 33
|
||||
render.PushFilterMag( TEXFILTER.ANISOTROPIC )
|
||||
render.PushFilterMin( TEXFILTER.ANISOTROPIC )
|
||||
-- Start RT render
|
||||
RTRender(sky_rts[layer],blend)
|
||||
-- Render RT texture
|
||||
surface.SetMaterial(cloudbig)
|
||||
surface.SetDrawColor(Color(255,255,255,cloud_alpha))
|
||||
--surface.DrawTexturedRect(0,0,texscale,texscale)
|
||||
DrawTextureRectWindow(texscale,texscale,offset[layer][1] + d_seed,offset[layer][2] + d_seed)
|
||||
-- If we error in here, gmod will crash.
|
||||
local b, reason = pcall(safeCall, texscale, texscale, layer)
|
||||
if not b then ErrorNoHalt(reason) end
|
||||
-- Mask RT tex
|
||||
-- RTMask()
|
||||
-- surface.SetDrawColor(Color(255,255,255,255 - cloud_alpha))
|
||||
-- surface.SetMaterial(cloudbig)
|
||||
-- DrawTextureRectWindow(texscale,texscale,offset[layer][1] + d_seed,offset[layer][2] + d_seed)
|
||||
|
||||
-- End RT tex
|
||||
RTEnd(sky_mats[layer])
|
||||
render.PopFilterMag()
|
||||
render.PopFilterMin()
|
||||
end
|
||||
local col = Color(255,255,255,175)
|
||||
local v = Vector(0,0,-20)
|
||||
local function RenderCloud(mat_id,yaw,s_size,alpha, pos)
|
||||
local mat = side_clouds[mat_id]
|
||||
if not mat then return end
|
||||
render.SetMaterial(mat[1])
|
||||
local pitch = 0.11 * s_size
|
||||
local n = Angle(pitch,yaw,0):Forward()
|
||||
col.a = math.max(175 * alpha, 255)
|
||||
render.DrawQuadEasy( n * -200 + pos + v, n, s_size * mat[2] , s_size, col, 180 )
|
||||
end
|
||||
local function LerpColor(f, col1, col2)
|
||||
return Color( Lerp(f, col1.r, col2.r), Lerp(f, col1.g, col2.g), Lerp(f, col1.b, col2.b) )
|
||||
end
|
||||
-- Cloud movement
|
||||
hook.Add("PreRender","StormFox2.Client.CloudMove",function()
|
||||
local w_ang = rad(StormFox2.Wind.GetYaw())
|
||||
local w_force = max(StormFox2.Wind.GetForce(),0.1) * 0.08 * RealFrameTime()
|
||||
local x_w,y_w = cos(w_ang) * w_force,sin(w_ang) * w_force
|
||||
for i = 1,layers do
|
||||
local ri = (layers - i + 1)
|
||||
local x,y = offset[i][1],offset[i][2]
|
||||
offset[i] = {x + x_w * ri ,y + y_w * ri}
|
||||
end
|
||||
end)
|
||||
|
||||
hook.Add("StormFox2.2DSkybox.CloudLayer","StormFox2.Client.Clouds",function(eye)
|
||||
if not StormFox2 then return end
|
||||
if not StormFox2.Mixer then return end
|
||||
local cl_amd = StormFox2.Mixer.Get("clouds",0)
|
||||
--if cl_amd <= 0 then return end
|
||||
-- Update material-color
|
||||
local c = StormFox2.Mixer.Get("bottomColor") or Color(204, 255, 255)
|
||||
-- Render sideclouds
|
||||
local vec = Vector(c.r,c.g,c.b) / 255
|
||||
for k,v in ipairs(side_clouds) do
|
||||
v[1]:SetVector("$color",vec)
|
||||
end
|
||||
local cloud_speed = StormFox2.Time.GetSpeed_RAW() * 0.1
|
||||
local sideclouds = 10 * cl_amd
|
||||
for i = 1,sideclouds do
|
||||
local a = 1
|
||||
if i < sideclouds and i == math.floor(sideclouds) then
|
||||
a = sideclouds - math.floor(sideclouds)
|
||||
end
|
||||
local row = math.floor(i / 3)
|
||||
local m_id = i % #side_clouds + 1
|
||||
local y_start = (i % 3) * 120 + row * 33
|
||||
local size = (3 + i % 5) * 24
|
||||
RenderCloud(m_id,y_start + i + SysTime() * cloud_speed, size, a, eye * eye_mult * 10 * i / 10 )
|
||||
end
|
||||
-- Render top clouds
|
||||
local up = Vector(0,0,1)
|
||||
local n = max(0,min(math.ceil(layers * cl_amd),layers))
|
||||
local thunder = 0
|
||||
if StormFox2.Thunder then
|
||||
thunder = min(255,StormFox2.Thunder.GetLight() or 0) / 25
|
||||
end
|
||||
for i = 1,n do
|
||||
local ri = n - i + layers
|
||||
local cloud_amplifier = 1 + .4 * (1 - (i / n))
|
||||
if i == 1 then
|
||||
cloud_amplifier = cloud_amplifier + thunder
|
||||
end
|
||||
UpdateCloudMaterial(i,255)
|
||||
sky_mats[i]:SetVector("$color",Vector(min(c.r * cloud_amplifier,255),min(c.g * cloud_amplifier,255),min(c.b * cloud_amplifier,255)) / 255 )
|
||||
RenderDome(up * (z_level + 0.4 * ri) + eye * eye_mult,sky_mats[i],255)
|
||||
end
|
||||
end)
|
||||
129
lua/stormfox2/functions/cl_contextmenu.lua
Normal file
129
lua/stormfox2/functions/cl_contextmenu.lua
Normal file
@@ -0,0 +1,129 @@
|
||||
--[[
|
||||
| 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 function niceName(sName)
|
||||
if sName[1] == "#" then
|
||||
sName = sName:sub(2)
|
||||
end
|
||||
sName = string.Replace(sName, "_", " ")
|
||||
local str = ""
|
||||
for s in string.gmatch(sName, "[^%s]+") do
|
||||
str = str .. string.upper(s[1]) .. string.sub(s, 2) .. " "
|
||||
end
|
||||
return string.TrimRight(str, " ")
|
||||
end
|
||||
|
||||
-- SF Settings
|
||||
local SWin
|
||||
hook.Add("ContextMenuClosed", "Stormfox2.ContextMC", function()
|
||||
if not SWin or not IsValid(SWin) then return end
|
||||
SWin:Remove()
|
||||
SWin = nil
|
||||
end)
|
||||
local setc = Color(55,55,65,255)
|
||||
local setc2 = Color(255,255,255,55)
|
||||
local matc = Material("gui/workshop_rocket.png")
|
||||
|
||||
local function CreateWindow( icon, window, bAccess )
|
||||
window:SetTitle("")
|
||||
window:DockPadding(0, 0, 8, 0)
|
||||
window:ShowCloseButton(false)
|
||||
window.c_Time = CurTime() + 0.5
|
||||
window.c = 0.5
|
||||
function window:Paint(w,h)
|
||||
if window.c < 0.99 then
|
||||
window.c = Lerp( FrameTime() * 10, window.c, 1 )
|
||||
elseif window.c < 1 then
|
||||
window.c = 1
|
||||
end
|
||||
local f = window.c
|
||||
surface.SetDrawColor(setc)
|
||||
surface.SetMaterial(matc)
|
||||
DisableClipping(true)
|
||||
surface.DrawTexturedRectUV(-16, 0, 16, h + 2, 0, 0.23, 0.3,0.77)
|
||||
surface.DrawTexturedRectUV(0, 0,w * f,h + 2, 0.3,0.23, 0.7,0.77)
|
||||
surface.DrawTexturedRectUV(w * f, 0, 16, h + 2, 0.7,0.23, 1, 0.77)
|
||||
DisableClipping(false)
|
||||
end
|
||||
local cl = vgui.Create("DButton", window)
|
||||
cl:SetText("")
|
||||
cl:SetSize(80,82)
|
||||
cl.Paint = function() end
|
||||
local cli = vgui.Create("DImage", cl)
|
||||
cli:SetPos(8,0)
|
||||
cli:SetSize(64,64)
|
||||
cli:SetImage("stormfox2/hud/settings.png")
|
||||
local label = vgui.Create("DLabel", cl )
|
||||
label:Dock( BOTTOM )
|
||||
label:SetText( niceName(language.GetPhrase("#client") .. " " .. language.GetPhrase("#superdof_pp.settings")))
|
||||
label:SetContentAlignment( 5 )
|
||||
label:SetTextColor( color_white )
|
||||
label:SetExpensiveShadow( 1, Color( 0, 0, 0, 200 ) )
|
||||
label:SizeToContentsX()
|
||||
local sv = vgui.Create("DButton", window)
|
||||
sv:SetText("")
|
||||
sv:SetPos(80,0)
|
||||
sv:SetSize(80,82)
|
||||
sv.Paint = function() end
|
||||
local svi = vgui.Create("DImage", sv)
|
||||
svi:SetPos(8,0)
|
||||
svi:SetSize(64,64)
|
||||
svi:SetImage("stormfox2/hud/controller.png")
|
||||
local label = vgui.Create("DLabel", sv )
|
||||
label:Dock( BOTTOM )
|
||||
label:SetText( niceName(language.GetPhrase("#spawnmenu.utilities.server_settings")))
|
||||
label:SetContentAlignment( 5 )
|
||||
label:SetTextColor( color_white )
|
||||
label:SetExpensiveShadow( 1, Color( 0, 0, 0, 200 ) )
|
||||
label:SizeToContentsX()
|
||||
sv.DoClick = function()
|
||||
surface.PlaySound("buttons/button14.wav")
|
||||
window:Remove()
|
||||
StormFox2.Menu.OpenSV()
|
||||
end
|
||||
cl.DoClick = function()
|
||||
surface.PlaySound("buttons/button14.wav")
|
||||
window:Remove()
|
||||
StormFox2.Menu.Open()
|
||||
end
|
||||
local w,h = icon:LocalToScreen(0,0)
|
||||
window:SetPos(w,h)
|
||||
SWin = window
|
||||
function window:Think()
|
||||
if self.c_Time > CurTime() then return end
|
||||
local x,y = self:CursorPos()
|
||||
if x > 0 and x < self:GetWide() and y > 0 and y < self:GetTall() then return end
|
||||
self:Remove()
|
||||
end
|
||||
if not bAccess then
|
||||
sv:SetCursor( "no" )
|
||||
sv:SetDisabled( true )
|
||||
svi:SetDisabled( true )
|
||||
label:SetTextColor( Color( 255,255,255, 105) )
|
||||
sv:SetToolTip(niceName(language.GetPhrase("#administrator_applications")))
|
||||
end
|
||||
surface.PlaySound("garrysmod/ui_click.wav")
|
||||
end
|
||||
|
||||
local function OpenWindow(icon, window)
|
||||
-- We can't check for IsListenServerHost, so lets hope the addminmod does that.
|
||||
CAMI.PlayerHasAccess(LocalPlayer(), "StormFox Settings",function(bAccess)
|
||||
CreateWindow( icon, window, bAccess )
|
||||
end)
|
||||
end
|
||||
|
||||
list.Set( "DesktopWindows", "StormFoxSetting", {
|
||||
title = "SF " .. niceName(language.GetPhrase("#spawnmenu.utilities.settings")),
|
||||
icon = "stormfox2/hud/settings.png",
|
||||
width = 80 * 2,
|
||||
height = 84,
|
||||
onewindow = true,
|
||||
init = OpenWindow
|
||||
} )
|
||||
204
lua/stormfox2/functions/cl_effects.lua
Normal file
204
lua/stormfox2/functions/cl_effects.lua
Normal file
@@ -0,0 +1,204 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
-- Breath Efect
|
||||
do
|
||||
local threshold = 2 -- IRL it is 7.2C, but i think the community would like to tie it closer to snow.
|
||||
StormFox2.Setting.AddCL("enable_breath", true)
|
||||
local m_mats = {(Material("particle/smokesprites_0001")),(Material("particle/smokesprites_0002")),(Material("particle/smokesprites_0003"))}
|
||||
local function GetMouth( ply )
|
||||
local att = ply:LookupAttachment("mouth")
|
||||
if att <= 0 then return end -- No mouth?
|
||||
return ply:GetAttachment(att)
|
||||
end
|
||||
|
||||
local function DoEffect(ply, size)
|
||||
if not _STORMFOX_PEM then return end -- Just in case
|
||||
local pos, ang
|
||||
local e = 1
|
||||
if ply ~= StormFox2.util.ViewEntity() then -- "Someone else"
|
||||
local att = GetMouth( ply )
|
||||
if not att then return end
|
||||
pos = att.Pos
|
||||
ang = att.Ang
|
||||
else -- Our viewpoint
|
||||
-- Check the view
|
||||
local view = StormFox2.util.GetCalcView()
|
||||
if view.drawviewer then -- Third person
|
||||
local att = GetMouth( ply )
|
||||
if not att then return end
|
||||
pos = att.Pos
|
||||
ang = att.Ang
|
||||
else
|
||||
e = 2
|
||||
ang = Angle(-view.ang.p,view.ang.y,0)
|
||||
pos = view.pos + ang:Forward() * 3 + ang:Up() * -2
|
||||
end
|
||||
end
|
||||
local l = StormFox2.Map.GetLight() / 100
|
||||
local p = _STORMFOX_PEM["2D"]:Add(table.Random(m_mats),pos)
|
||||
p:SetStartSize(1)
|
||||
p:SetEndSize(size)
|
||||
p:SetStartAlpha(math.min(255, 15 + math.random(55,135) * l * e))
|
||||
p:SetEndAlpha(0)
|
||||
p:SetLifeTime(0)
|
||||
p:SetGravity(Vector(0,0,4))
|
||||
p:SetDieTime(1)
|
||||
p:SetLighting(false)
|
||||
p:SetRoll(math.random(360))
|
||||
p:SetRollDelta(math.Rand(-0.5,0.5))
|
||||
p:SetVelocity(ang:Forward() * 2 + ply:GetVelocity() / 5)
|
||||
end
|
||||
-- Runs the effect on the player and returns next time it should be called.
|
||||
local function CheckEffect(ply)
|
||||
if not IsValid( ply) then return end
|
||||
if not ply:Alive() then return end
|
||||
if ply:WaterLevel() >= 3 then return end
|
||||
if ply:InVehicle() then
|
||||
local e = ply:GetVehicle()
|
||||
if not IsValid( e ) then return end
|
||||
if e:GetClass() ~= "prop_vehicle_jeep" then return end -- An open vehicle
|
||||
end
|
||||
if not StormFox2.Wind.IsEntityInWind(ply) then return end
|
||||
local len = ply:GetVelocity():Length()
|
||||
local t = math.Clamp(1.5 - (len / 100),0.2,1.5)
|
||||
DoEffect(ply,5 + (len / 100))
|
||||
return math.Rand(t,t * 2)
|
||||
end
|
||||
-- The most optiomal way is to check within the renderhook.
|
||||
local function RunEffect(ply)
|
||||
if not StormFox2.Setting.GetCache("enable_breath") then return end
|
||||
if not StormFox2.Setting.SFEnabled() then return end
|
||||
if StormFox2.Temperature.Get() > threshold then return end -- Breaht is visible at 7.2C or below
|
||||
if (ply._sfbreath or 0) >= CurTime() then return end
|
||||
local cE = CheckEffect( ply )
|
||||
if not cE then
|
||||
ply._sfbreath = CurTime() + 1
|
||||
return
|
||||
end
|
||||
ply._sfbreath = CurTime() + cE
|
||||
end
|
||||
hook.Add("PostPlayerDraw", "StormFox2.Effect.Breath", RunEffect)
|
||||
-- We also need to check when the player is in first person.
|
||||
timer.Create("StormFox2.Effect.BreathT", 1, 0, function()
|
||||
local LP = LocalPlayer( )
|
||||
if not IsValid( LP ) then return end
|
||||
RunEffect( LP )
|
||||
end)
|
||||
end
|
||||
|
||||
-- Depth Filter
|
||||
local W,H = ScrW(), ScrH()
|
||||
local depth_r = GetRenderTarget("SF_DepthFilter", W,H, true)
|
||||
local depthLayer = Material( "stormfox2/shader/depth_layer" )
|
||||
local a = 0
|
||||
local l
|
||||
|
||||
-- Patch: Some people out there don't update the resources when updating the mod.
|
||||
if depthLayer:GetKeyValues()["$detail"] then
|
||||
StormFox2.Warning("stormfox2/shader/depth_layer.vmt is outdated! Hotpatching, but be sure to update the resources!")
|
||||
depthLayer:SetUndefined("$detail")
|
||||
depthLayer:SetUndefined("$detailtexturetransform")
|
||||
depthLayer:SetUndefined("$detailblendmode")
|
||||
depthLayer:SetUndefined("$detailscale")
|
||||
depthLayer:SetUndefined("$additive")
|
||||
end
|
||||
|
||||
hook.Add("StormFox2.weather.postchange", "StormFox2.DepthFilter.Reset", function(b)
|
||||
if l and l == b then return end
|
||||
l = b
|
||||
a = 0
|
||||
end)
|
||||
|
||||
|
||||
local depthLayer = Material( "stormfox2/shader/depth_layer" )
|
||||
local function updateDepthTexture(fFunc, a)
|
||||
render.PushRenderTarget(depth_r)
|
||||
cam.Start2D()
|
||||
render.Clear(0,0,0,0,true, false)
|
||||
fFunc(W,H, a)
|
||||
cam.End2D()
|
||||
render.PopRenderTarget()
|
||||
depthLayer:SetTexture("$basetexture", depth_r)
|
||||
return depthLayer
|
||||
end
|
||||
local invis_col = Color(255,0,0,0)
|
||||
local function RenderDepthFilter()
|
||||
-- Reset everything to known good fpr stencils
|
||||
render.SetStencilWriteMask( 0xFF )
|
||||
render.SetStencilTestMask( 0xFF )
|
||||
render.SetStencilReferenceValue( 0 )
|
||||
render.SetStencilCompareFunction( STENCIL_ALWAYS )
|
||||
render.SetStencilPassOperation( STENCIL_REPLACE )
|
||||
render.SetStencilFailOperation( STENCIL_ZERO )
|
||||
render.SetStencilZFailOperation( STENCIL_ZERO )
|
||||
render.ClearStencil()
|
||||
|
||||
-- Enable stencil
|
||||
render.SetStencilEnable( true )
|
||||
render.SetStencilReferenceValue( 1 )
|
||||
render.SetStencilCompareFunction( STENCIL_ALWAYS )
|
||||
-- Render Mask
|
||||
local eA = EyeAngles()
|
||||
cam.Start3D( EyePos(), eA )
|
||||
render.SetColorMaterial()
|
||||
local f_D = StormFox2.Fog.GetEnd()
|
||||
if f_D > 2000 then
|
||||
render.DrawSphere(EyePos(), -2000, 30, 30, invis_col)
|
||||
else
|
||||
--[[
|
||||
Stencils look bad for heavy effects, since there is a clear pixel-line.
|
||||
I've tried smoothing it, but it would require rendering the world twice within an RT.
|
||||
|
||||
So instead we make it a plain with the fog-distance.
|
||||
Its bad in some cases, yes, but only solution I know for now.
|
||||
]]
|
||||
render.DrawQuadEasy(EyePos() + eA:Forward() * f_D, -eA:Forward(), ScrW() * 5, ScrH() * 5, invis_col, 0)
|
||||
end
|
||||
cam.End3D()
|
||||
-- Now, only draw things that have their pixels set to 1. This is the hidden parts of the stencil tests.
|
||||
render.SetStencilCompareFunction( STENCIL_EQUAL )
|
||||
-- Render Depth-filter
|
||||
cam.Start2D()
|
||||
render.SetMaterial(depthLayer)
|
||||
render.DrawScreenQuad()
|
||||
cam.End2D()
|
||||
-- Let everything render normally again
|
||||
render.SetStencilEnable( false )
|
||||
--render.PopRenderTarget()
|
||||
end
|
||||
|
||||
hook.Add("RenderScreenspaceEffects", "StormFox2.Downfall.DepthRender", function()
|
||||
if render.GetDXLevel() < 95 then return end
|
||||
if not render.SupportsPixelShaders_2_0() then return end
|
||||
if LocalPlayer():WaterLevel() >= 3 then return end -- Don't render SF effects under wanter.
|
||||
local obj = StormFox2.Setting.GetObject("depthfilter")
|
||||
if not obj then return end
|
||||
if not obj:GetValue() then return end
|
||||
|
||||
-- Check if weather has depth. If not reset alpha
|
||||
local dFr = StormFox2.Weather.GetCurrent().DepthFilter
|
||||
if not dFr then a = 0 return end
|
||||
-- Calc alpha
|
||||
if StormFox2.Environment.Get().outside then
|
||||
a = math.Approach(a, 1, FrameTime() * .8)
|
||||
else
|
||||
a = math.Approach(a, 0, FrameTime() * 5) -- Quick fadeaway
|
||||
end
|
||||
if a <= 0 then return end -- If alpha is 0 or below, don't render.
|
||||
-- Update RT
|
||||
updateDepthTexture(dFr, a)
|
||||
-- Update screenspace effect
|
||||
render.UpdateScreenEffectTexture()
|
||||
render.UpdateFullScreenDepthTexture()
|
||||
-- Render the depthfilter
|
||||
RenderDepthFilter()
|
||||
end)
|
||||
269
lua/stormfox2/functions/cl_localization.lua
Normal file
269
lua/stormfox2/functions/cl_localization.lua
Normal file
@@ -0,0 +1,269 @@
|
||||
--[[
|
||||
| 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 is a localization backup, in case the file didn't transferre.
|
||||
if not file.Exists("resource/localization/en/stormfox.properties", "GAME") then return end
|
||||
local str = [[
|
||||
#StormFox2.weather = weather
|
||||
# https://github.com/Facepunch/garrysmod/blob/master/garrysmod/resource/localization/en/community.properties Check this first
|
||||
# weather, day, night, sun, lightning, snow, cloud
|
||||
|
||||
#Misc
|
||||
sf_auto=Auto
|
||||
sf_customization=Customization
|
||||
sf_window_effects=Window Effects
|
||||
footprints=footprints
|
||||
temperature=temperature
|
||||
fog=Fog
|
||||
|
||||
#Weather
|
||||
sf_weather.clear=Clear
|
||||
sf_weather.clear.windy=Windy
|
||||
sf_weather.cloud=Cloudy
|
||||
sf_weather.cloud.thunder=Thunder
|
||||
sf_weather.cloud.storm=Storm
|
||||
sf_weather.rain=Raining
|
||||
sf_weather.rain.sleet=Sleet
|
||||
sf_weather.rain.snow=Snowing
|
||||
sf_weather.rain.thunder=Thunder
|
||||
sf_weather.rain.storm=Storm
|
||||
sf_weather.fog.low=Haze
|
||||
sf_weather.fog.medium=Fog
|
||||
sf_weather.fog.high=Thick Fog
|
||||
sf_weather.lava=Lava
|
||||
sf_weather.fallout=Nuclear Fallout
|
||||
|
||||
#Tool
|
||||
sf_tool.name=StormFox2 Tool
|
||||
sf_tool.desc=Allows you to edit StormFox2 map settings.
|
||||
sf_tool.surface_editor=Surface Editor
|
||||
sf_tool.surface_editor.desc=Allows you to edit surface-types.
|
||||
sf_tool.surface_editor.entertext=Write the texture path and click add.
|
||||
sf_tool.light_editor=Light Editor
|
||||
sf_tool.light_editor.desc=Allows you to add/remove sf-lights.
|
||||
sf_enable_breath=Enables breath
|
||||
sf_enable_breath.desc=Makes players breath visible in cold.
|
||||
|
||||
#Settings
|
||||
sf_enable=Enable StormFox
|
||||
sf_enable.desc=Enable / Disable StormFox 2
|
||||
sf_clenable=Enable StormFox
|
||||
sf_clenable.desc=Enable / Disable StormFox 2. Requires sf_allow_csenable.
|
||||
sf_allow_csenable=Allow Clients to disable StormFox 2
|
||||
sf_allow_csenable.desc=Enabling this will allow clients to disable StormFox 2.
|
||||
|
||||
sf_mthreadwarning=These settings can boost your FPS:\n%s\nWarning\: This Might crash on some older AMD CPUs!
|
||||
sf_holdc=Hold C
|
||||
sf_weatherpercent=Weather Amount
|
||||
sf_setang=Set Angle
|
||||
sf_setang.desc=Sets the wind-angle to your view.
|
||||
sf_setwind=Sets the windspeed in m/s
|
||||
sf_wcontoller=SF Controller
|
||||
sf_map.light_environment.check=This map support fast lightchanges.
|
||||
sf_map.light_environment.problem=This map will cause lagspikes for clients, when the light changes.
|
||||
sf_map.env_wind.none=This map doesn't support windgusts.
|
||||
sf_map.logic_relay.check=This map has custom day/night relays.
|
||||
sf_map.logic_relay.none=This map doens't have custom day/night relays.
|
||||
sf_windmove_players=Affect players
|
||||
sf_windmove_players.desc=Affect player movment in strong wind.
|
||||
sf_windmove_foliate=Affect Foliate
|
||||
sf_windmove_foliate.desc=Foliate moves with the wind.
|
||||
sf_windmove_props=Affect Props
|
||||
sf_windmove_props.desc=Props will move with the wind. This can cause lag!
|
||||
sf_windmove_props_break=Damage Props
|
||||
sf_windmove_props_break.desc=Props will take damage in the wind.
|
||||
sf_windmove_props_makedebris=Change CollisionGroup
|
||||
sf_windmove_props_makedebris.desc=Will make props change collisiongroup, reducing lag.
|
||||
sf_windmove_props_unfreeze=Unfreeze props.
|
||||
sf_windmove_props_unfreeze.desc=Unfreeze props being moved by the wind.
|
||||
sf_windmove_props_unweld=Unweld props.
|
||||
sf_windmove_props_unweld.desc=Unweld props being moved by the wind.
|
||||
sf_windmove_props_max=Max props being moved.
|
||||
sf_windmove_props_max.desc=Max amount of props moving. This can cause lag!
|
||||
|
||||
sf_enable_fogz=Overwrite farZ fog
|
||||
sf_enable_fogz.desc=Overwrites the maps farZ fog. This might look bad on some maps.
|
||||
sf_enable_ice=Enable ice
|
||||
sf_enable_ice.desc=Creates ice over water.
|
||||
sf_overwrite_fogdistance=Default fog-distance.
|
||||
sf_overwrite_fogdistance.desc=Overwrites the default fog-distance.
|
||||
sf_hide_forecast=Hide Forecast
|
||||
sf_hide_forecast.desc=Stops clients from updating the forecast.
|
||||
sf_allow_weather_lightchange=Allow weather maplight
|
||||
sf_allow_weather_lightchange.desc=Allows the weather to modify the maplight.
|
||||
sf_addnight_temp=Add Night Temperature
|
||||
sf_addnight_temp.desc=The amount the temperature drops doing night.
|
||||
sf_apply_settings=Apply settings.
|
||||
sf_reset_settings=Reset settings.
|
||||
sf_enable_skybox=Enable Skybox
|
||||
sf_enable_skybox.desc=Allows StormFox to use the skybox.
|
||||
sf_use_2dskybox=Use 2D Skybox
|
||||
sf_use_2dskybox.desc=Makes StormFox use 2D skyboxes instead.
|
||||
sf_overwrite_2dskybox=Overwrite 2D skybox
|
||||
sf_overwrite_2dskybox.desc=Overwrites the 2D skybox with another.
|
||||
sf_darken_2dskybox=Darken 2D Skybox
|
||||
sf_darken_2dskybox.desc=Match the skybox brightness with the map.
|
||||
sf_random_round_weather=Random weather each round.
|
||||
sf_random_round_weather.desc=Gamemodes like TTT will have random weathers between each round.
|
||||
sf_quickselect=Quick Select.
|
||||
sf_quickselect.desc=Quick select time settings.
|
||||
sf_depthfilter=Depth Filter
|
||||
sf_depthfilter.desc=Render 2D weather-effects on clients screen.
|
||||
sf_enable_sunbeams=Enable Sunbeams
|
||||
sf_enable_sunbeams.desc=Enable sunbeams when the sun is low.
|
||||
sf_edit_cubemaps=Edit Cubemaps
|
||||
sf_edit_cubemaps.desc=Change cubemap tint of map-materials.
|
||||
|
||||
#Details
|
||||
sf_quality_target=FPS Target
|
||||
sf_quality_target.desc=Adjusts the quality to reach targeted FPS.
|
||||
sf_quality_ultra=Ultra Quality
|
||||
sf_quality_ultra.desc=Allows for more effects.
|
||||
sf_12h_display=Time Display
|
||||
sf_12h_display.disc=Choose 12-hour or 24-hour clock.
|
||||
sf_display_temperature=Temperature Units
|
||||
sf_display_temperature.desc=Choose a temperature unit.
|
||||
sf_use_monthday=Date Display
|
||||
sf_use_monthday.disc=Choose MM/DD or DD/MM.
|
||||
|
||||
#Wind
|
||||
sf_wind=Wind
|
||||
sf_winddescription.calm=Calm
|
||||
sf_winddescription.light_air=Light Air
|
||||
sf_winddescription.light_breeze=Light Breeze
|
||||
sf_winddescription.gentle_breeze=Gentle Breeze
|
||||
sf_winddescription.moderate_breeze=Moderate Breeze
|
||||
sf_winddescription.fresh_breeze=Fresh Breeze
|
||||
sf_winddescription.strong_breeze=Strong Breeze
|
||||
sf_winddescription.near_gale=Near Gale
|
||||
sf_winddescription.gale=Gale
|
||||
sf_winddescription.strong_gale=Strong Gale
|
||||
sf_winddescription.storm=Storm
|
||||
sf_winddescription.violent_storm=Violent Storm
|
||||
#Hurricane is also known as Category 1
|
||||
sf_winddescription.hurricane=Hurricane
|
||||
sf_winddescription.cat2=Category 2
|
||||
sf_winddescription.cat3=Category 3
|
||||
sf_winddescription.cat4=Category 4
|
||||
sf_winddescription.cat5=Category 5
|
||||
|
||||
#Time
|
||||
sf_continue_time=Continuous Time
|
||||
sf_continue_time.desc=Continue time from last time.
|
||||
sf_real_time=Real time
|
||||
sf_real_time.desc=Use the servers OS Time.
|
||||
sf_start_time=Start time
|
||||
sf_start_time.desc=Sets the start time.
|
||||
sf_random_time=Random time
|
||||
sf_random_time.desc=Sets the time randomly on server-launch.
|
||||
sf_day_length=Day Length
|
||||
sf_day_length.desc=How long the day is in minutes.
|
||||
sf_night_length=Night Length
|
||||
sf_night_length.desc=How long the night is in minutes.
|
||||
|
||||
#Sun
|
||||
sf_sunrise=SunRise
|
||||
sf_sunrise.desc=Sets the time the sun rises.
|
||||
sf_sunset=SunSet
|
||||
sf_sunset.desc=Sets the time the sun sets.
|
||||
sf_sunyaw=SunYaw
|
||||
sf_sunyaw.desc=Sets the yaw for the sun.
|
||||
#Moon
|
||||
sf_moonsize=Moon Size
|
||||
sf_moonsize.desc=The default moon size.
|
||||
sf_moonphase=Moon Phases
|
||||
sf_moonphase.desc=Enable Moon Phases.
|
||||
sf_moonlock=Moon Lock
|
||||
sf_moonlock.desc=Locks the moon to the sun's rotation.
|
||||
|
||||
|
||||
|
||||
#'Maplight
|
||||
sf_maplight_max=Max Maplight
|
||||
sf_maplight_max.desc=The max lightlevel. You can adjust this if the map is too bright/dark.
|
||||
sf_maplight_min=Min Maplight
|
||||
sf_maplight_min.desc=The min lightlevel. You can adjust this if the map is too bright/dark.
|
||||
|
||||
sf_maplight_smooth=Maplight Lerp.
|
||||
sf_maplight_smooth.desc=Enables smooth light transitions.
|
||||
sf_maplight_updaterate=Maplight UpdateRate
|
||||
sf_maplight_updaterate.desc=The max amount of times StormFox will update the maplight doing transitions. Will cause lag on large maps!
|
||||
|
||||
sf_maplight_auto.desc=Select the best/fastes option for the map.
|
||||
sf_maplight_lightenv.desc=Enable light_environment.
|
||||
sf_maplight_colormod.desc=Enable colormod.
|
||||
sf_maplight_dynamic.desc=Enable dynamic light/shadows.
|
||||
sf_maplight_lightstyle.desc=Enable lightstyle.
|
||||
|
||||
sf_modifyshadows=Modify shadows
|
||||
sf_modifyshadows.desc=Modify default shadows to follow the sun.
|
||||
sf_modifyshadows_rate=Modify shadow rate
|
||||
sf_modifyshadows_rate.desc=The seconds between each shadow-update.
|
||||
|
||||
sf_extra_lightsupport=Extra Lightsupport
|
||||
sf_extra_lightsupport.desc=Utilize engine.LightStyle to change the map-light. This can cause lag-spikes, but required on certain maps.
|
||||
|
||||
#Effects
|
||||
sf_enable_fog=Enable Fog
|
||||
sf_enable_fog.desc=Allow StormFox to edit the fog.
|
||||
sf_allow_fog_change=Allow clients to toggle fog.
|
||||
sf_allow_fog_change.desc=Enabling this will allow clients to toggle fog.
|
||||
sf_footprint_enabled=Enable Footprints
|
||||
sf_footprint_enabled.desc=Enable footprint effects.
|
||||
sf_footprint_playeronly=Player Footprints Only.
|
||||
sf_footprint_playeronly.desc=Only players make footprints.
|
||||
sf_footprint_distance=Footprint Render Distance
|
||||
sf_footprint_distance.desc=Max render distance for footprints.
|
||||
sf_footprint_max=Max Footprints
|
||||
sf_footprint_max.desc=Max amount of footprints
|
||||
|
||||
sf_edit_tonemap=Enable tonemap
|
||||
sf_edit_tonemap.desc=Allow StormFox to edit the tonemap.
|
||||
sf_enable_wateroverlay=Render water overlay
|
||||
sf_enable_wateroverlay.desc=Enables water-overlay for weather-types.
|
||||
|
||||
sf_extra_darkness=Extra Darkness
|
||||
sf_extra_darkness.desc=Adds a darkness-filter to make bright maps darker.
|
||||
sf_extra_darkness_amount=Extra Darkness Amount
|
||||
sf_extra_darkness_amount.desc=Scales the darkness-filter.
|
||||
|
||||
sf_overwrite_extra_darkness=Overwrite Extra Darkness
|
||||
sf_overwrite_extra_darkness.desc=Overwrites the players sf_extra_darkness.
|
||||
sf_footprint_enablelogic=Enables Serverside Footprints
|
||||
sf_footprint_enablelogic.desc=Enables server-side footprints.
|
||||
|
||||
sf_window_enable=Enable window effects
|
||||
sf_window_enable.desc=Enables window weather effects.
|
||||
sf_window_distance=Window Render Distance
|
||||
sf_window_distance.desc=The render distance for breakable windows.
|
||||
sf_override_foliagesway=Override Foliagesway
|
||||
sf_override_foliagesway.desc=Overrides and applies foliagesway to most foliage on launch.
|
||||
|
||||
#Weather
|
||||
sf_auto_weather=Auto weather
|
||||
sf_auto_weather.desc=Automatically change weather over time.
|
||||
sf_max_weathers_prweek=Max Weathers Pr Week
|
||||
sf_max_weathers_prweek.desc=Max amount of weathers pr week.
|
||||
sf_temp_range=Temperature range
|
||||
sf_temp_range.desc=The min and max temperature.
|
||||
sf_temp_acc=Temperature change.
|
||||
sf_temp_acc.desc=The max temperature changes pr day.
|
||||
sf_weather_damage=Weather Damage
|
||||
sf_weather_damage.desc=Allow weather to cause damage
|
||||
sf_max_wind=Maximum wind
|
||||
sf_max_wind.desc=The maximum generated wind in m/s.
|
||||
]]
|
||||
|
||||
for k, v in ipairs( string.Explode("\n", str)) do
|
||||
if string.match(v, "%s-#") then continue end
|
||||
local a,b = string.match(v, "%s*(.+)=(.+)")
|
||||
if not a or not b then continue end
|
||||
language.Add(a, b)
|
||||
end
|
||||
334
lua/stormfox2/functions/cl_menu.lua
Normal file
334
lua/stormfox2/functions/cl_menu.lua
Normal file
@@ -0,0 +1,334 @@
|
||||
--[[
|
||||
| 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.Menu = StormFox2.Menu or {}
|
||||
|
||||
local function niceName(sName)
|
||||
if sName[1] == "#" then
|
||||
sName = sName:sub(2)
|
||||
end
|
||||
sName = string.Replace(sName, "_", " ")
|
||||
local str = ""
|
||||
for s in string.gmatch(sName, "[^%s]+") do
|
||||
str = str .. string.upper(s[1]) .. string.sub(s, 2) .. " "
|
||||
end
|
||||
return string.TrimRight(str, " ")
|
||||
end
|
||||
|
||||
local function wrapText(sText, wide)
|
||||
wide = wide - 10
|
||||
local tw,th = surface.GetTextSize(language.GetPhrase(sText))
|
||||
local lines,b = 1, false
|
||||
local s = ""
|
||||
for w in string.gmatch(sText, "[^%s,]+") do
|
||||
local tt = s .. (b and " " or "") .. w
|
||||
if surface.GetTextSize(tt) >= wide then
|
||||
s = s .. "\n" .. w
|
||||
lines = lines + 1
|
||||
else
|
||||
s = tt
|
||||
end
|
||||
b = true
|
||||
end
|
||||
return s, lines
|
||||
end
|
||||
|
||||
local m = Material("gui/gradient")
|
||||
local function paintKnob(self,x, y) -- Skin doesn't have x or y pos
|
||||
local skin = self:GetSkin()
|
||||
if ( self:GetDisabled() ) then return skin.tex.Input.Slider.H.Disabled( x, y, 15, 15 ) end
|
||||
if ( self.Depressed ) then
|
||||
return skin.tex.Input.Slider.H.Down( x, y, 15, 15 )
|
||||
end
|
||||
if ( self.Hovered ) then
|
||||
return skin.tex.Input.Slider.H.Hover( x, y, 15, 15 )
|
||||
end
|
||||
skin.tex.Input.Slider.H.Normal( x, y, 15, 15 )
|
||||
end
|
||||
local notchesColor = Color(0,0,0,100)
|
||||
|
||||
-- Tips
|
||||
local function AddTip( self, text )
|
||||
if IsValid( self.tTip ) then return end
|
||||
self.tTip = vgui.Create("DTooltip")
|
||||
self.tTip:SetText( text )
|
||||
self.tTip.TargetPanel = self
|
||||
self.tTip:PositionTooltip()
|
||||
end
|
||||
local function RemoveTip( self )
|
||||
if IsValid( self.tTip ) then
|
||||
self.tTip:Remove()
|
||||
end
|
||||
self.tTip = nil
|
||||
end
|
||||
|
||||
local tabs = {
|
||||
[1] = {"Start","#start",(Material("stormfox2/hud/menu/dashboard.png")),function(board)
|
||||
board:AddTitle("#information")
|
||||
local dash = vgui.Create("DPanel", board)
|
||||
dash.Paint = empty
|
||||
dash:Dock(TOP)
|
||||
dash:SetTall(80)
|
||||
|
||||
local fps, qu, sup, mth
|
||||
-- FPS
|
||||
local p = vgui.Create("SF_Setting_Ring", dash)
|
||||
p:SetText(string.upper(language.GetPhrase("#fps")) .. ": ")
|
||||
p:SetSize(74, 74)
|
||||
p:SetPos(24,10)
|
||||
function p:Think()
|
||||
if (self.u_t or 0) > SysTime() then return end
|
||||
if not system.HasFocus() then return end
|
||||
self.u_t = SysTime() + 1
|
||||
local t = StormFox2.Setting.GetCache("quality_target",144)
|
||||
local _, avgFPS = StormFox2.Client.GetQualityNumber()
|
||||
self:SetValue( avgFPS / t)
|
||||
p:SetText(string.upper(language.GetPhrase("#fps")) .. ": " .. math.floor(avgFPS))
|
||||
end
|
||||
fps = p
|
||||
-- Quality
|
||||
local p = vgui.Create("SF_Setting_Ring", dash)
|
||||
p:SetText(language.GetPhrase("#effects"))
|
||||
p:SetSize(74, 74)
|
||||
p:SetPos(106,10)
|
||||
function p:Think()
|
||||
if (self.u_t or 0) > SysTime() then return end
|
||||
if not system.HasFocus() then return end
|
||||
self.u_t = SysTime() + 1
|
||||
local max_q = StormFox2.Setting.GetCache("quality_ultra",false) and 20 or 7
|
||||
local q, _ = StormFox2.Client.GetQualityNumber()
|
||||
local f = q / max_q
|
||||
self:SetValue( f )
|
||||
p:SetText(language.GetPhrase("#effects") .. "\n" .. math.floor(f * 100) .. "%")
|
||||
end
|
||||
qu = p
|
||||
-- Support GPU
|
||||
local p = vgui.Create("SF_Setting_Ring", dash)
|
||||
p:SetText(niceName(language.GetPhrase("#support")))
|
||||
p:SetSize(74, 74)
|
||||
p:SetPos(188,10)
|
||||
--p:SetColor(255,0,0)
|
||||
local t = {render.SupportsPixelShaders_1_4(),render.SupportsVertexShaders_2_0(), render.SupportsPixelShaders_2_0(), render.SupportsHDR()}
|
||||
local v = 0
|
||||
local s ="#problems.no_problems"
|
||||
for k,v2 in ipairs(t) do
|
||||
if not v2 then
|
||||
if k == 1 then
|
||||
s = "#problem.no_ps14"
|
||||
elseif k == 2 then
|
||||
s = "#problem.no_vs20"
|
||||
elseif k == 3 then
|
||||
s = "#problem.no_ps20"
|
||||
else
|
||||
s = "#problem.no_hdr"
|
||||
end
|
||||
break
|
||||
end
|
||||
v = v + 1
|
||||
end
|
||||
p:SetTooltip(s)
|
||||
local f = v / #t
|
||||
p:SetValue(f)
|
||||
local c = HSLToColor(120 * f, 1, 0.5 * f)
|
||||
--p:SetColor(c.r,c.g,c.b)
|
||||
p:SetText(niceName(language.GetPhrase("#support")) .. "\n" .. v .. "/" .. #t)
|
||||
sup = p
|
||||
-- MThread
|
||||
local p = vgui.Create("SF_Setting_Ring", dash)
|
||||
p:SetText(niceName(language.GetPhrase("#MThread")))
|
||||
p:SetSize(74, 74)
|
||||
p:SetPos(188,10)
|
||||
--p:SetColor(255,0,0)
|
||||
local t = {["cl_threaded_bone_setup"] = 1,
|
||||
["cl_threaded_client_leaf_system"] = 1,
|
||||
["r_threaded_client_shadow_manager"] = 1,
|
||||
["r_threaded_particles"] = 1,
|
||||
["r_threaded_renderables"] = 1,
|
||||
["r_queued_ropes"] = 1,
|
||||
["studio_queue_mode"] = 1,
|
||||
["gmod_mcore_test"] = 1,
|
||||
["mat_queue_mode"] = 2}
|
||||
local v = 0
|
||||
local s = "\n"
|
||||
for k,v2 in pairs(t) do
|
||||
if GetConVar(k):GetInt() ~= v2 then
|
||||
s = s .. k .. " " .. v2 .. "\n"
|
||||
continue
|
||||
end
|
||||
v = v + 1
|
||||
end
|
||||
local f = v / table.Count(t)
|
||||
p:SetValue(f)
|
||||
local c = HSLToColor(120 * f, 1, 0.5 * f)
|
||||
--p:SetColor(c.r,c.g,c.b)
|
||||
p:SetText(niceName(language.GetPhrase("#MThread")) .. "\n" .. v .. "/" .. table.Count(t))
|
||||
if f < 1 then
|
||||
p:SetTooltip(string.format(language.GetPhrase("#sf_mthreadwarning"), s))
|
||||
else
|
||||
p:SetTooltip(language.GetPhrase("#problems.no_problems"))
|
||||
end
|
||||
mth = p
|
||||
function dash:PerformLayout(w, h)
|
||||
local a = w / 5
|
||||
local x = -fps:GetTall() / 2
|
||||
fps:SetPos(x + a, h - fps:GetTall())
|
||||
qu:SetPos(x + a*2, h - qu:GetTall())
|
||||
sup:SetPos(x + a*3, h - sup:GetTall())
|
||||
mth:SetPos(x + a*4, h - sup:GetTall())
|
||||
end
|
||||
-- Fps Slider
|
||||
local FPSTarget = vgui.Create("SF_Setting", board)
|
||||
FPSTarget:SetSetting("quality_target")
|
||||
board:MarkUsed("quality_target")
|
||||
do
|
||||
local obj = StormFox2.Setting.GetObject("quality_target")
|
||||
local slider = vgui.Create("DButton", FPSTarget)
|
||||
local text = vgui.Create("DTextEntry", FPSTarget)
|
||||
FPSTarget:MoveDescription(340)
|
||||
slider:SetPos(5,15)
|
||||
slider:SetSize( 300, 25 )
|
||||
slider:SetText("")
|
||||
text:SetPos( 304, 19)
|
||||
text:SetSize( 40,20 )
|
||||
local hot = Color(255,0,0,205)
|
||||
-- Text set
|
||||
function text:OnEnter( str )
|
||||
str = str:lower()
|
||||
if str == language.GetPhrase("#all"):lower() or str == "all" then
|
||||
str = 0
|
||||
else
|
||||
str = tonumber( str ) or 0
|
||||
end
|
||||
obj:SetValue(str)
|
||||
end
|
||||
-- Slider skin functions
|
||||
function slider:GetNotchColor()
|
||||
return notchesColor
|
||||
end
|
||||
function slider:GetNotches()
|
||||
return math.floor(self:GetWide() / 21)
|
||||
end
|
||||
-- Slider paint
|
||||
function slider:Paint( w, h )
|
||||
local var = self._OvR or StormFox2.Setting.GetCache("quality_target", 144)
|
||||
local cV = 300 - var
|
||||
local skin = self:GetSkin()
|
||||
skin:PaintNumSlider(self,w,h)
|
||||
-- "warm"
|
||||
surface.SetMaterial(m)
|
||||
surface.SetDrawColor(hot)
|
||||
local wi = w / 300 * 260
|
||||
surface.DrawTexturedRectUV(wi - 7, 4, w - wi, h - 6, 1,0,0,1)
|
||||
paintKnob(self, 1 + (w - 16) / 300 * cV,-0.5)
|
||||
end
|
||||
function slider:UpdateText( var )
|
||||
if var > 0 then
|
||||
text:SetText(var)
|
||||
else
|
||||
text:SetText(niceName(language.GetPhrase("#all")))
|
||||
end
|
||||
end
|
||||
-- Slider think
|
||||
function slider:Think()
|
||||
if self:IsDown() then
|
||||
self._down = true
|
||||
self._OvR = math.Clamp(1 - (self:LocalCursorPos() - 6) / (self:GetWide() - 12), 0, 1) * 300
|
||||
if self._OvR < 40 then
|
||||
AddTip(self, "#frame_blend_pp.desc2")
|
||||
else
|
||||
RemoveTip( self )
|
||||
end
|
||||
self:UpdateText( math.Round(self._OvR, 0) )
|
||||
else
|
||||
if not text:IsEditing() then
|
||||
self:UpdateText( math.Round(obj:GetValue(), 0) )
|
||||
end
|
||||
self._OvR = nil
|
||||
RemoveTip( self )
|
||||
if self._down then
|
||||
self._down = nil
|
||||
local var = math.Clamp(1 - (self:LocalCursorPos() - 6) / (self:GetWide() - 12), 0, 1) * 300
|
||||
obj:SetValue( math.Round(var, 0) )
|
||||
end
|
||||
end
|
||||
end
|
||||
slider:UpdateText(math.Round(obj:GetValue(), 0))
|
||||
end
|
||||
FPSTarget:Dock(TOP)
|
||||
-- EnableDisable
|
||||
local p = board:AddSetting("clenable")
|
||||
--local qs = board:AddSetting("quality_target")
|
||||
board:AddSetting("quality_ultra")
|
||||
board:AddTitle("#sf_customization")
|
||||
local l = vgui.Create("DPanel", board)
|
||||
l:DockMargin(10,0,0,0)
|
||||
l:SetTall(24)
|
||||
l:Dock(TOP)
|
||||
function l:Paint(w,h)
|
||||
local md = StormFox2.Setting.GetCache("use_monthday",false) and os.date( "%m/%d/%Y" ) or os.date( "%d/%m/%Y" )
|
||||
local dt = StormFox2.Setting.GetCache("display_temperature")
|
||||
local hs = string.Explode(":", os.date( "%H:%M") or "17:23")
|
||||
local n = hs[1] * 60 + hs[2]
|
||||
local str = niceName(language.GetPhrase("#time")) .. ": " .. StormFox2.Time.GetDisplay(n) .. " " .. md
|
||||
str = str .. " " .. niceName(language.GetPhrase("#temperature")) .. ": " .. math.Round(StormFox2.Temperature.Convert(nil,dt,22), 1) .. StormFox2.Temperature.GetDisplaySymbol()
|
||||
draw.DrawText(str, "DermaDefaultBold", 5, 0, color_black, TEXT_ALIGN_LEFT)
|
||||
end
|
||||
board:AddSetting("12h_display")
|
||||
board:AddSetting("use_monthday")
|
||||
board:AddSetting("display_temperature")
|
||||
end},
|
||||
[2] = {"Effects","#effects",(Material("stormfox2/hud/menu/settings.png")),function(board)
|
||||
board:AddTitle(language.GetPhrase("#effects"))
|
||||
local fog = board:AddSetting("enable_fog")
|
||||
board:AddSetting("extra_darkness")
|
||||
board:AddSetting("extra_darkness_amount")
|
||||
board:AddSetting("enable_breath")
|
||||
board:AddSetting("enable_sunbeams")
|
||||
board:AddSetting("edit_cubemaps")
|
||||
|
||||
board:AddTitle(language.GetPhrase("#footprints"))
|
||||
board:AddSetting("footprint_enabled")
|
||||
board:AddSetting("footprint_playeronly")
|
||||
board:AddSetting("footprint_distance")
|
||||
board:AddSetting("footprint_max")
|
||||
board:AddTitle(language.GetPhrase("#sf_window_effects"))
|
||||
board:AddSetting("window_enable")
|
||||
board:AddSetting("window_distance")
|
||||
|
||||
fog:SetDisabled(not StormFox2.Setting.GetCache("allow_fog_change"))
|
||||
StormFox2.Setting.Callback("allow_fog_change",function(vVar,_,_, self)
|
||||
fog:SetDisabled(not vVar)
|
||||
end,fog)
|
||||
end},
|
||||
[3] = {"Misc","#misc",(Material("stormfox2/hud/menu/other.png")),function(board)
|
||||
board:AddTitle("SF2 " .. language.GetPhrase("spawnmenu.utilities.settings"))
|
||||
local panel = board:AddSetting("mapfile_cl")
|
||||
panel:SetTitle("#makepersistent")
|
||||
panel:SetDescription(language.GetPhrase("#persistent_mode") .. " data\\stormfox2\\cl_settings\\" .. game.GetMap() .. ".json")
|
||||
end},
|
||||
[4] = {"DLC","DLC",(Material("stormfox2/hud/menu/dlc.png")), function(board)
|
||||
hook.Run("stormfox2.menu.dlc", board)
|
||||
end}
|
||||
}
|
||||
|
||||
---Opens the client-settings.
|
||||
---@client
|
||||
function StormFox2.Menu.Open()
|
||||
if _SFMENU and IsValid(_SFMENU) then
|
||||
_SFMENU:Remove()
|
||||
_SFMENU = nil
|
||||
end
|
||||
local p = vgui.Create("SF_Menu")
|
||||
_SFMENU = p
|
||||
p:SetTitle("StormFox " .. niceName(language.GetPhrase("#client")) .. " ".. language.GetPhrase("#spawnmenu.utilities.settings"))
|
||||
p:CreateLayout(tabs, StormFox2.Setting.GetAllClient())
|
||||
p:SetCookie("sf2_lastmenucl")
|
||||
_SFMENU:MakePopup()
|
||||
end
|
||||
1220
lua/stormfox2/functions/cl_menu_sv.lua
Normal file
1220
lua/stormfox2/functions/cl_menu_sv.lua
Normal file
File diff suppressed because it is too large
Load Diff
171
lua/stormfox2/functions/cl_sky.lua
Normal file
171
lua/stormfox2/functions/cl_sky.lua
Normal file
@@ -0,0 +1,171 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
--[[<Ignore All>-------------------------------------------------------------------------
|
||||
We overwrite the sky variables. Its much better to handle it clientside.
|
||||
---------------------------------------------------------------------------]]
|
||||
-- Override skypaint- Since its set by each tick.
|
||||
local g_SkyPaint_tab = {}
|
||||
function g_SkyPaint_tab.IsValid() return true end
|
||||
|
||||
local g_datacache = {}
|
||||
function g_SkyPaint_tab:GetNetworkVars()
|
||||
return g_datacache
|
||||
end
|
||||
-- Setup data
|
||||
local function AddDataCache(name,defaultdata)
|
||||
g_datacache[name] = defaultdata
|
||||
g_SkyPaint_tab["Get" .. name] = function()
|
||||
return g_datacache[name]
|
||||
end
|
||||
g_SkyPaint_tab["Set" .. name] = function(self,var)
|
||||
g_datacache[name] = var or defaultdata
|
||||
end
|
||||
return g_SkyPaint_tab["Set" .. name]
|
||||
end
|
||||
_STORMFOX_TOPCOLOROR = AddDataCache("TopColor", Vector( 0.2, 0.5, 1.0 ) )
|
||||
AddDataCache("BottomColor", Vector( 0.8, 1.0, 1.0 ) )
|
||||
AddDataCache("FadeBias", 1 )
|
||||
|
||||
AddDataCache("SunNormal", Vector( 0.4, 0.0, 0.01 ) )
|
||||
AddDataCache("SunColor", Vector( 0.2, 0.1, 0.0 ) )
|
||||
AddDataCache("SunSize", 2.0 )
|
||||
|
||||
AddDataCache("DuskColor", Vector( 1.0, 0.2, 0.0 ) )
|
||||
AddDataCache("DuskScale", 1 )
|
||||
AddDataCache("DuskIntensity", 1 )
|
||||
|
||||
AddDataCache("DrawStars", true )
|
||||
AddDataCache("StarLayers", 1 )
|
||||
AddDataCache("StarSpeed", 0.01 )
|
||||
AddDataCache("StarScale", 0.5 )
|
||||
AddDataCache("StarFade", 1.5 )
|
||||
AddDataCache("StarTexture", "skybox/starfield" )
|
||||
|
||||
AddDataCache("HDRScale", 0.66 )
|
||||
|
||||
-- Override the skypaint directly
|
||||
local SkyPaintEnt
|
||||
local c = false
|
||||
if #ents.FindByClass("env_skypaint") > 0 then
|
||||
SkyPaintEnt = ents.FindByClass("env_skypaint")[1]
|
||||
end
|
||||
hook.Add("Think","StormFox2.sky.paintFix",function()
|
||||
if not IsValid(g_SkyPaint) then return end
|
||||
-- Disable skybox and reset entity
|
||||
if not StormFox2.Setting.GetCache("enable_skybox", true) or not StormFox2.Setting.SFEnabled() then
|
||||
if SkyPaintEnt and type(g_SkyPaint) ~= "Entity" then
|
||||
g_SkyPaint = SkyPaintEnt
|
||||
c = false
|
||||
end
|
||||
return
|
||||
end
|
||||
if type(g_SkyPaint) ~= "Entity" then
|
||||
return
|
||||
end
|
||||
if g_SkyPaint:GetClass() == "env_skypaint" then
|
||||
-- We'll hande it from here
|
||||
SkyPaintEnt = g_SkyPaint
|
||||
g_SkyPaint = g_SkyPaint_tab
|
||||
c = true
|
||||
end
|
||||
end)
|
||||
-- Local functions
|
||||
local min,max,abs,app = math.min,math.max,math.abs,math.Approach
|
||||
local function ColVec(col,div)
|
||||
if not div then
|
||||
return Vector(col.r,col.g,col.b)
|
||||
end
|
||||
return Vector(col.r / div,col.g / div,col.b / div)
|
||||
end
|
||||
-- Read and set the skydata
|
||||
hook.Add("Think","StormFox2.sky.think",function()
|
||||
if not IsValid(g_SkyPaint) then return end
|
||||
if not StormFox2.Time then return end
|
||||
if not StormFox2.Mixer then return end
|
||||
if not StormFox2.Setting.SFEnabled() then return end
|
||||
if not StormFox2.Setting.GetCache("enable_skybox", true) then return end
|
||||
if StormFox2.Setting.GetCache("use_2dskybox",false,nil, "Effects") then return end
|
||||
if not c then return end -- Make sure we use the table, and not the entity.
|
||||
-- Top color + Thunder
|
||||
local fogAm
|
||||
if StormFox2.Fog then
|
||||
fogAm = StormFox2.Fog.GetAmount()
|
||||
end
|
||||
local thunder = 0
|
||||
if StormFox2.Thunder then
|
||||
local cl_amd = StormFox2.Mixer.Get("clouds",0) or 0
|
||||
thunder = min(255,StormFox2.Thunder.GetLight() or 0) * 0.1 + (cl_amd * .9)
|
||||
end
|
||||
local t_data = StormFox2.Mixer.Get("topColor") or Color( 51, 127.5, 255 )
|
||||
local t_color = Color(max(thunder,t_data.r),max(thunder,t_data.g),max(thunder,t_data.b))
|
||||
local b_color = StormFox2.Mixer.Get("bottomColor") or Color(204, 255, 255)
|
||||
if fogAm and fogAm > 0.75 then
|
||||
t_color = StormFox2.Mixer.Blender((fogAm - .75) * 3, t_color, StormFox2.Fog.GetColor())
|
||||
end
|
||||
g_SkyPaint:SetTopColor(ColVec(t_color,255))
|
||||
g_SkyPaint:SetBottomColor(ColVec(b_color,255))
|
||||
g_SkyPaint:SetFadeBias(StormFox2.Mixer.Get("fadeBias",0.2))
|
||||
g_SkyPaint:SetDuskColor(ColVec(StormFox2.Mixer.Get("duskColor",color_white) or color_white,255))
|
||||
g_SkyPaint:SetDuskIntensity(StormFox2.Mixer.Get("duskIntensity",1.94))
|
||||
g_SkyPaint:SetDuskScale(StormFox2.Mixer.Get("duskScale",0.29))
|
||||
|
||||
-- Stars
|
||||
local n = StormFox2.Mixer.Get("starFade",100) * 0.015
|
||||
if n <= 0 then
|
||||
g_SkyPaint:SetDrawStars(false)
|
||||
g_SkyPaint:SetStarFade(0)
|
||||
else
|
||||
g_SkyPaint:SetDrawStars(true)
|
||||
g_SkyPaint:SetStarSpeed((StormFox2.Mixer.Get("starSpeed") or 0.001) * StormFox2.Time.GetSpeed_RAW())
|
||||
g_SkyPaint:SetStarFade(n)
|
||||
g_SkyPaint:SetStarScale(StormFox2.Mixer.Get("starScale") or 0.5)
|
||||
g_SkyPaint:SetStarTexture(StormFox2.Mixer.Get("starTexture","skybox/starfield"))
|
||||
end
|
||||
-- SunSize
|
||||
local s_size = StormFox2.Mixer.Get("sunSize",2) * (StormFox2.Mixer.Get("skyVisibility",100) / 100)
|
||||
g_SkyPaint:SetSunSize(s_size / 10)
|
||||
|
||||
if StormFox2.Sun and StormFox2.Sun.GetAngle then
|
||||
g_SkyPaint:SetSunNormal(StormFox2.Sun.GetAngle():Forward())
|
||||
local sF = StormFox2.Mixer.Get("sunFade", 1)
|
||||
g_SkyPaint:SetSunColor(ColVec(StormFox2.Mixer.Get("sunColor"), 1550 / sF))
|
||||
end
|
||||
g_SkyPaint:SetHDRScale(StormFox2.Mixer.Get("HDRScale",0.7))
|
||||
end)
|
||||
|
||||
-- Debug
|
||||
if true then return end
|
||||
local x = 0
|
||||
local x2 = 0
|
||||
local function drawVal(text, val)
|
||||
if type(val) == "table" then
|
||||
val = val.r .. " " .. val.g .. " " .. val.b
|
||||
end
|
||||
draw.DrawText(text .. ": " .. tostring(val), "DermaDefault", x2, x * 20, color_white, TEXT_ALIGN_LEFT)
|
||||
x = x + 1
|
||||
end
|
||||
hook.Add("HUDPaint", "SF_DEBUG.Sky", function()
|
||||
local t_color = StormFox2.Mixer.Get("topColor") or Color( 51, 127.5, 255 )
|
||||
local b_color = StormFox2.Mixer.Get("bottomColor") or Color(204, 255, 255)
|
||||
x = 1
|
||||
x2 = 10
|
||||
drawVal("StormFox2 Debug","")
|
||||
x2 = 20
|
||||
drawVal("TopColor",t_color)
|
||||
drawVal("BottomColor",t_color)
|
||||
drawVal("fadeBias",StormFox2.Mixer.Get("fadeBias",0.2))
|
||||
drawVal("duskIntensity",StormFox2.Mixer.Get("duskIntensity",1.94))
|
||||
drawVal("duskScale",StormFox2.Mixer.Get("duskScale",0.29))
|
||||
drawVal("starFade",StormFox2.Mixer.Get("starFade",100))
|
||||
drawVal("starScale",StormFox2.Mixer.Get("starScale",0.5))
|
||||
drawVal("starSpeed",StormFox2.Mixer.Get("starSpeed",0.001))
|
||||
drawVal("starTexture",StormFox2.Mixer.Get("starTexture","skybox/starfield"))
|
||||
end)
|
||||
33
lua/stormfox2/functions/cl_spook.lua
Normal file
33
lua/stormfox2/functions/cl_spook.lua
Normal file
@@ -0,0 +1,33 @@
|
||||
--[[
|
||||
| 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 s = string.Explode("-", os.date("%m-%d"))
|
||||
if s[1] ~= "10" then return end
|
||||
if tonumber(s[2]) < 20 then return end
|
||||
|
||||
-- Layers are large by design. (Kinda like a fish lense). Center is "large".
|
||||
local mat = Material("hud/killicons/default")
|
||||
local c = Color(255,255,255,0)
|
||||
local dist = 80 -- 80 to 60
|
||||
local size = 32 -- 64 to 32
|
||||
hook.Add("StormFox2.2DSkybox.CloudLayerRender", "StormFox2.IAmNotHere", function(w, h, layer)
|
||||
local d = StormFox2.Date.GetYearDay()
|
||||
if d % 2 == 1 then return end
|
||||
if layer ~= 1 then return end
|
||||
local rotate = d * 33 % 360
|
||||
local p = StormFox2.Weather.GetPercent()
|
||||
c.a = math.min(105, (p - 0.1) * 1000)
|
||||
if c.a <= 0 then return end
|
||||
local x, y, ang = math.cos(math.rad(rotate)) * dist, math.sin(math.rad(rotate)) * dist, t
|
||||
surface.SetDrawColor(c)
|
||||
surface.SetMaterial(mat)
|
||||
surface.DrawTexturedRectRotated(w / 2 + x,h / 2 + y, size,size, 90 - rotate)
|
||||
end)
|
||||
499
lua/stormfox2/functions/cl_weather_gen.lua
Normal file
499
lua/stormfox2/functions/cl_weather_gen.lua
Normal file
@@ -0,0 +1,499 @@
|
||||
--[[
|
||||
| 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.WeatherGen = StormFox2.WeatherGen or {}
|
||||
-- Settings
|
||||
local autoWeather = StormFox2.Setting.AddSV("auto_weather",true,nil, "Weather")
|
||||
local hideForecast = StormFox2.Setting.AddSV("hide_forecast",false,nil, "Weather")
|
||||
|
||||
-- OpenWeatherMap
|
||||
--[[
|
||||
Some of these settings are fake, allow the client to set the settings, but never retrive the secured ones.
|
||||
So you can't see the correct location or api_key and variables won't be networked to the clients.
|
||||
]]
|
||||
|
||||
StormFox2.Setting.AddSV("openweathermap_key", "", nil,"Weather") -- Fake'ish setting
|
||||
StormFox2.Setting.AddSV("openweathermap_location", "", nil,"Weather") -- Fake'ish setting
|
||||
StormFox2.Setting.AddSV("openweathermap_city","",nil,"Weather") -- Fake'ish setting
|
||||
|
||||
local OWEnabled = StormFox2.Setting.AddSV("openweathermap_enabled",false,nil,"Weather")
|
||||
StormFox2.Setting.AddSV("openweathermap_lat",52,nil,"Weather",-180,180) -- Unpercise setting
|
||||
StormFox2.Setting.AddSV("openweathermap_lon",-2,nil,"Weather",-180,180) -- Unpercise setting
|
||||
|
||||
-- Generator
|
||||
StormFox2.Setting.AddSV("min_temp",-10,nil,"Weather")
|
||||
StormFox2.Setting.AddSV("max_temp",20,nil, "Weather")
|
||||
StormFox2.Setting.AddSV("max_wind",50,nil, "Weather")
|
||||
StormFox2.Setting.AddSV("addnight_temp",-7,nil, "Weather")
|
||||
|
||||
local function toStr( num )
|
||||
local c = tostring( num )
|
||||
return string.rep("0", 4 - #c) .. c
|
||||
end
|
||||
local default
|
||||
local function SplitSetting( str )
|
||||
if #str< 20 then return default end -- Invalid, use default
|
||||
local tab = {}
|
||||
local min = math.min(100, string.byte(str, 1,1) - 33 ) / 100
|
||||
local max = math.min(100, string.byte(str, 2,2) - 33 ) / 100
|
||||
tab.amount_min = math.min(min, max)
|
||||
tab.amount_max = math.max(min, max)
|
||||
|
||||
local min = math.min(1440,tonumber( string.sub(str, 3, 6) ) or 0)
|
||||
local max = math.min(1440,tonumber( string.sub(str, 7, 10) ) or 0)
|
||||
tab.start_min = math.min(min, max)
|
||||
tab.start_max = math.max(min, max)
|
||||
|
||||
local min = tonumber( string.sub(str, 11, 14) ) or 0
|
||||
local max = tonumber( string.sub(str, 15, 18) ) or 0
|
||||
|
||||
tab.length_min = math.min(min, max)
|
||||
tab.length_max = math.max(min, max)
|
||||
|
||||
tab.thunder = string.sub(str, 19, 19) == "1"
|
||||
tab.pr_week = tonumber( string.sub(str, 20) ) or 0
|
||||
return tab
|
||||
end
|
||||
local function CombineSetting( tab )
|
||||
local c =string.char( 33 + (tab.amount_min or 0) * 100 )
|
||||
c = c .. string.char( 33 + (tab.amount_max or 0) * 100 )
|
||||
|
||||
c = c .. toStr(math.Clamp( math.Round( tab.start_min or 0), 0, 1440 ) )
|
||||
c = c .. toStr(math.Clamp( math.Round( tab.start_max or 0), 0, 1440 ) )
|
||||
|
||||
c = c .. toStr(math.Clamp( math.Round( tab.length_min or 360 ), 180, 9999) )
|
||||
c = c .. toStr(math.Clamp( math.Round( tab.length_max or 360 ), 180, 9999) )
|
||||
|
||||
c = c .. (tab.thunder and "1" or "0")
|
||||
|
||||
c = c .. tostring( tab.pr_week or 2 )
|
||||
return c
|
||||
end
|
||||
local default_setting = {}
|
||||
default_setting["Rain"] = CombineSetting({
|
||||
["amount_min"] = 0.4,
|
||||
["amount_max"] = 0.9,
|
||||
["start_min"] = 300,
|
||||
["start_max"] = 1200,
|
||||
["length_min"] = 360,
|
||||
["length_max"] = 1200,
|
||||
["pr_week"] = 3
|
||||
})
|
||||
default_setting["Cloud"] = CombineSetting({
|
||||
["amount_min"] = 0.2,
|
||||
["amount_max"] = 0.7,
|
||||
["start_min"] = 300,
|
||||
["start_max"] = 1200,
|
||||
["length_min"] = 360,
|
||||
["length_max"] = 1200,
|
||||
["pr_week"] = 3
|
||||
})
|
||||
default_setting["Clear"] = CombineSetting({
|
||||
["amount_min"] = 1,
|
||||
["amount_max"] = 1,
|
||||
["start_min"] = 0,
|
||||
["start_max"] = 1440,
|
||||
["length_min"] = 360,
|
||||
["length_max"] = 1440,
|
||||
["pr_week"] = 7
|
||||
})
|
||||
-- Morning fog
|
||||
default_setting["Fog"] = CombineSetting({
|
||||
["amount_min"] = 0.15,
|
||||
["amount_max"] = 0.30,
|
||||
["start_min"] = 360,
|
||||
["start_max"] = 560,
|
||||
["length_min"] = 160,
|
||||
["length_max"] = 360,
|
||||
["pr_week"] = 1
|
||||
})
|
||||
default = CombineSetting({
|
||||
["amount_min"] = 0.4,
|
||||
["amount_max"] = 0.9,
|
||||
["start_min"] = 300,
|
||||
["start_max"] = 1200,
|
||||
["length_min"] = 300,
|
||||
["length_max"] = 1200,
|
||||
["pr_week"] = 0
|
||||
})
|
||||
StormFox2.WeatherGen.ConvertSettingToTab = SplitSetting
|
||||
StormFox2.WeatherGen.ConvertTabToSetting = CombineSetting
|
||||
|
||||
if StormFox2.Weather and StormFox2.Weather.Loaded then
|
||||
for _, sName in ipairs( StormFox2.Weather.GetAll() ) do
|
||||
local str = default_setting[sName] or default
|
||||
StormFox2.Setting.AddSV("wgen_" .. sName,str,nil,"Weather")
|
||||
end
|
||||
else
|
||||
hook.Add("stormfox2.postloadweather", "StormFox2.WeatherGen.Load", function()
|
||||
for _, sName in ipairs( StormFox2.Weather.GetAll() ) do
|
||||
local str = default_setting[sName] or default
|
||||
StormFox2.Setting.AddSV("wgen_" .. sName,str,nil,"Weather")
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
-- API
|
||||
|
||||
local days = 2
|
||||
local days_length = days * 1440
|
||||
local hours_8 = 60 * 8
|
||||
|
||||
forecast = forecast or {}
|
||||
local nul_icon = Material("gui/noicon.png")
|
||||
-- Is it rain or inherits from rain?
|
||||
local function isWTRain(wT)
|
||||
if wT.Name == "Rain" then return true end
|
||||
if wT.Inherit == "Rain" then return true end
|
||||
return false
|
||||
end
|
||||
|
||||
local function fkey( x, a, b )
|
||||
return (x - a) / (b - a)
|
||||
end
|
||||
|
||||
-- The tables are already in order.
|
||||
local function findNext( tab, time ) -- First one is time
|
||||
for i, tab in ipairs( tab ) do
|
||||
if time > tab[1] then continue end
|
||||
return i
|
||||
end
|
||||
return 0
|
||||
end
|
||||
|
||||
local function calcPoint( tab, time )
|
||||
local i = findNext( tab, time )
|
||||
local _next = tab[i]
|
||||
local _first = tab[i - 1]
|
||||
local _procent = 1
|
||||
if not _first then
|
||||
_first = _next
|
||||
else
|
||||
_procent = fkey(time, _first[1], _next[1])
|
||||
end
|
||||
return _procent, _first, _next
|
||||
end
|
||||
|
||||
net.Receive("StormFox2.weekweather", function(len)
|
||||
forecast = {}
|
||||
forecast.unix_time = net.ReadBool()
|
||||
forecast.temperature = net.ReadTable()
|
||||
forecast.weather = net.ReadTable()
|
||||
forecast.wind = net.ReadTable()
|
||||
forecast.windyaw = net.ReadTable()
|
||||
for _, v in pairs( forecast.temperature ) do
|
||||
if not forecast._minTemp then
|
||||
forecast._minTemp = v[2]
|
||||
else
|
||||
forecast._minTemp = math.min(forecast._minTemp, v[2])
|
||||
end
|
||||
if not forecast._maxTemp then
|
||||
forecast._maxTemp = v[2]
|
||||
else
|
||||
forecast._maxTemp = math.max(forecast._maxTemp, v[2])
|
||||
end
|
||||
end
|
||||
if not forecast._minTemp then return end -- Invalid forecast
|
||||
-- Make sure there is at least 10C between
|
||||
local f = 10 - math.abs(forecast._minTemp - forecast._maxTemp)
|
||||
if f > 0 then
|
||||
forecast._minTemp = forecast._minTemp - f / 2
|
||||
forecast._maxTemp = forecast._maxTemp + f / 2
|
||||
end
|
||||
-- Calculate / make a table for each 4 hours
|
||||
forecast._ticks = {}
|
||||
local lastW
|
||||
for i = 0, days_length + 1440, hours_8 do
|
||||
local _first = findNext( forecast.weather, i - hours_8 / 2 )
|
||||
local _last = findNext( forecast.weather, i + hours_8 / 2 ) or _first
|
||||
if not _first then continue end --????
|
||||
local m = 0
|
||||
local w_type = {
|
||||
["fAmount"] = 0,
|
||||
["sName"] = "Clear"
|
||||
}
|
||||
for i = _first, _last do
|
||||
local w_data = forecast.weather[i]
|
||||
if not w_data then continue end
|
||||
if w_data[2].fAmount == 0 or w_data[2].fAmount < m then continue end
|
||||
m = w_data[2].fAmount
|
||||
w_type = w_data[2]
|
||||
end
|
||||
local _tempP, _tempFirst, _tempNext = calcPoint( forecast.temperature, i )
|
||||
if _tempNext then
|
||||
--local _tempP = fkey( i, )
|
||||
forecast._ticks[i] = {
|
||||
["fAmount"] = w_type.fAmount,
|
||||
["sName"] = w_type.sName,
|
||||
["nTemp"] = Lerp(_tempP, _tempFirst[2], _tempNext[2]),
|
||||
["bThunder"] = w_type.bThunder or nil
|
||||
}
|
||||
end
|
||||
end
|
||||
--PrintTable(forecast)
|
||||
hook.Run("StormFox2.WeatherGen.ForcastUpdate")
|
||||
end)
|
||||
|
||||
---Returns the forecast data.
|
||||
---@return table
|
||||
---@client
|
||||
function StormFox2.WeatherGen.GetForecast()
|
||||
return forecast
|
||||
end
|
||||
|
||||
---Returns true if we're using unix time for the forecast.
|
||||
---@return boolean
|
||||
---@client
|
||||
function StormFox2.WeatherGen.IsUnixTime()
|
||||
return forecast.unix_time or false
|
||||
end
|
||||
|
||||
|
||||
-- Render forcast
|
||||
|
||||
local bg = Color(26,41,72, 255)
|
||||
local rc = Color(155,155,155,4)
|
||||
local ca = Color(255,255,255,12)
|
||||
local tempBG = Color(255,255,255,15)
|
||||
local sorter = function(a,b) return a[1] < b[1] end
|
||||
|
||||
local m_box = Material("vgui/arrow")
|
||||
local m_c = Material("gui/gradient_up")
|
||||
local function DrawTemperature( x, y, w, h, t_list, min_temp, max_temp, bExpensive, offX, offY )
|
||||
surface.SetDrawColor(rc)
|
||||
surface.DrawRect(x, y, w, h)
|
||||
surface.SetDrawColor(ca)
|
||||
surface.DrawLine(x, y + h, x + w, y + h)
|
||||
render.SetScissorRect( x + offX , y - 25 + offY, x + w + offX, y + h + offY, true )
|
||||
local unix = StormFox2.WeatherGen.IsUnixTime()
|
||||
|
||||
local temp_p = fkey(0, max_temp, min_temp)
|
||||
local tempdiff = max_temp - min_temp
|
||||
|
||||
local yT = h / tempdiff
|
||||
local div = 10
|
||||
if tempdiff < 25 then
|
||||
div = 10
|
||||
elseif tempdiff < 75 then
|
||||
div = 20
|
||||
elseif tempdiff < 150 then
|
||||
div = 100
|
||||
elseif tempdiff < 300 then
|
||||
div = 200
|
||||
elseif tempdiff < 500 then
|
||||
div = 300
|
||||
else
|
||||
div = 1000
|
||||
end
|
||||
local s = math.ceil(min_temp / div) * div
|
||||
local counts = (max_temp - s) / div
|
||||
for temp = s, max_temp, div do
|
||||
local tOff = temp - min_temp
|
||||
local ly = y + h - (tOff * yT)
|
||||
if temp == 0 then
|
||||
surface.SetDrawColor(color_white)
|
||||
surface.SetMaterial(m_box)
|
||||
surface.DrawTexturedRectUV(x, ly, w, 1, 0, 0.5, w / 1 * 0.3, 0.6)
|
||||
else
|
||||
surface.SetDrawColor(ca)
|
||||
surface.DrawLine(x, ly, x + w, ly)
|
||||
end
|
||||
end
|
||||
|
||||
local curTim = unix and os.time() or StormFox2.Time.Get()
|
||||
local oldX, oldY, oldP
|
||||
surface.SetTextColor(color_white)
|
||||
surface.SetFont("SF_Display_H3")
|
||||
for i, data in ipairs( t_list ) do
|
||||
if not data then break end
|
||||
local time_p
|
||||
if unix then
|
||||
time_p = (data[1] - curTim) / (1440 * 60 * 1.5)
|
||||
else
|
||||
time_p = (data[1] - curTim) / days_length
|
||||
end
|
||||
local temp_p = data[2]
|
||||
local pointx = time_p * w + x
|
||||
local pointy = y + h - (temp_p * h)
|
||||
if oldX then
|
||||
if oldX > x + w then break end
|
||||
surface.SetDrawColor(color_white)
|
||||
surface.DrawLine(pointx, pointy, oldX, oldY)
|
||||
if bExpensive then
|
||||
local triangle = {
|
||||
{ x = oldX , y = oldY , u = 0,v = oldP},
|
||||
{ x = pointx, y = pointy, u = 1,v = temp_p},
|
||||
{ x = pointx, y = y + h , u = 1,v = 0},
|
||||
{ x = oldX , y = y + h , u = 0,v = 0},
|
||||
}
|
||||
surface.SetMaterial(m_c)
|
||||
surface.SetDrawColor(tempBG)
|
||||
surface.DrawPoly( triangle )
|
||||
end
|
||||
surface.SetTextPos(pointx - 5, pointy - 14)
|
||||
local temp = min_temp + temp_p * tempdiff
|
||||
temp = math.Round(StormFox2.Temperature.GetDisplay(temp), 1) .. StormFox2.Temperature.GetDisplaySymbol()
|
||||
surface.DrawText(temp)
|
||||
end
|
||||
oldX = pointx
|
||||
oldY = pointy
|
||||
oldP = temp_p
|
||||
end
|
||||
render.SetScissorRect(0,0,0,0,false)
|
||||
--PrintTable(t_list)
|
||||
end
|
||||
|
||||
local lM = Material("vgui/loading-rotate")
|
||||
local lL = Material("stormfox2/logo.png")
|
||||
local function DrawDisabled( str, w, h )
|
||||
draw.DrawText(str, "SF_Display_H", w / 2, h / 4, color_white, TEXT_ALIGN_CENTER)
|
||||
surface.SetDrawColor(color_white)
|
||||
surface.SetMaterial(lL)
|
||||
surface.DrawTexturedRectRotated(w / 2, h / 3 * 2, 64, 64, 0)
|
||||
surface.SetMaterial(lM)
|
||||
surface.DrawTexturedRectRotated(w / 2, h / 3 * 2, 128, 128, (CurTime() * 100)% 360)
|
||||
end
|
||||
|
||||
---Renders the forecast.
|
||||
---@param w number
|
||||
---@param h number
|
||||
---@param bExpensive boolean
|
||||
---@param offX? number
|
||||
---@param offY? number
|
||||
function StormFox2.WeatherGen.DrawForecast(w,h,bExpensive, offX, offY)
|
||||
offX = offX or 0
|
||||
offY = offY or 0
|
||||
local y = 0
|
||||
surface.SetDrawColor(bg)
|
||||
surface.DrawRect(0,0,w,h)
|
||||
-- Check if enabled, else render disable message
|
||||
if not autoWeather:GetValue() then
|
||||
local s = language.GetPhrase("sf_auto_weather") or "sf_auto_weather"
|
||||
local d = language.GetPhrase("#addons.preset_disabled") or "Disabled"
|
||||
s = s.. ": " .. string.match(d, "%w+")
|
||||
DrawDisabled( s, w, h )
|
||||
return
|
||||
end
|
||||
if hideForecast:GetValue() then
|
||||
local s = language.GetPhrase("sf_hide_forecast") or "sf_hide_forecast"
|
||||
local d = language.GetPhrase("#addons.preset_enabled") or "Enabled"
|
||||
s = s.. ": " .. string.match(d, "%w+")
|
||||
DrawDisabled( s, w, h )
|
||||
return
|
||||
end
|
||||
if not forecast or not forecast._minTemp then
|
||||
local c = string.rep(".", CurTime() % 3 + 1)
|
||||
DrawDisabled( "No data yet" .. c, w, h )
|
||||
return
|
||||
end
|
||||
local unix = StormFox2.WeatherGen.IsUnixTime()
|
||||
local curTim = unix and os.time() or StormFox2.Time.Get()
|
||||
-- Draw Temperature
|
||||
-- Convert it into a list of temperature w procent
|
||||
local c_temp = StormFox2.Temperature.Get()
|
||||
local min_temp = math.min(c_temp, forecast._minTemp)
|
||||
local max_temp = math.max(c_temp, forecast._maxTemp)
|
||||
local abs = math.abs(max_temp - min_temp) * 0.1
|
||||
min_temp = min_temp - abs
|
||||
max_temp = max_temp + abs
|
||||
|
||||
local t = {}
|
||||
t[1] = { curTim, fkey( c_temp, min_temp, max_temp ) }
|
||||
for i, data in ipairs( forecast.temperature ) do
|
||||
local time = data[1]
|
||||
if time <= curTim then continue end -- Ignore anything before
|
||||
table.insert(t, {time, fkey( data[2], min_temp, max_temp ) } )
|
||||
end
|
||||
DrawTemperature( w * 0.05, h * 0.5 ,w * 0.9, h * 0.4,t, min_temp, max_temp, bExpensive, offX, offY)
|
||||
-- Draw current weahter
|
||||
surface.SetDrawColor(color_white)
|
||||
surface.SetMaterial(StormFox2.Weather.GetIcon())
|
||||
surface.SetFont("SF_Display_H")
|
||||
local tex = StormFox2.Weather.GetDescription()
|
||||
local tw, th = surface.GetTextSize(tex)
|
||||
local wide = tw + 48
|
||||
surface.DrawTexturedRect(w / 2 - 48,h * 0.05, 40,40)
|
||||
draw.DrawText(tex, "SF_Display_H", w / 2 , h * 0.07, color_white, TEXT_ALIGN_LEFT)
|
||||
-- Draw DayIcons
|
||||
surface.SetDrawColor(color_white)
|
||||
local s = w / 12
|
||||
if not unix then
|
||||
local c = math.ceil(curTim / hours_8) * hours_8
|
||||
for i = c, days_length + c - 420, hours_8 do
|
||||
-- Render Time
|
||||
local t_stamp = StormFox2.Time.GetDisplay( i % 1440 )
|
||||
local delt = i - curTim
|
||||
local x = math.ceil(w * 0.9 / days_length * delt)
|
||||
draw.DrawText(t_stamp, "SF_Display_H3", x , h * 0.9, color_white)
|
||||
-- Render icon
|
||||
local day = forecast._ticks[i]
|
||||
if day then
|
||||
local w_type = StormFox2.Weather.Get(day.sName)
|
||||
if not w_type then
|
||||
surface.SetMaterial(nul_icon)
|
||||
else
|
||||
surface.SetMaterial(w_type.GetIcon( i % 1440, day.nTemp, day.nWind or 0, day.bThunder or false, day.fAmount or 0) )
|
||||
surface.DrawTexturedRect(x, h * 0.25, s, s)
|
||||
local name = w_type:GetName(i % 1440, day.nTemp, day.nWind or 0, day.bThunder or false, day.fAmount or 0)
|
||||
draw.DrawText(name, "SF_Display_H2", x + s / 2, h * 0.25 + s, color_white, TEXT_ALIGN_CENTER)
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
--(1440 * 60 * 1.5)
|
||||
local wP = ( w * 0.9 ) / (1440 * 60 * 1.5)
|
||||
local _12 = StormFox2.Setting.Get("12h_display", false)
|
||||
local z = 0
|
||||
for i, data in pairs( forecast.weather ) do
|
||||
local unixT = data[1] or 0
|
||||
if unixT < curTim then continue end
|
||||
z = z + 1
|
||||
if z > 6 then continue end
|
||||
local delta = unixT - curTim
|
||||
local t_stamp
|
||||
local fakeTime = os.date( "%H:%M", unixT )
|
||||
if _12 then
|
||||
t_stamp = os.date( "%I:%M %p", unixT )
|
||||
else
|
||||
t_stamp = fakeTime
|
||||
end
|
||||
local x = math.ceil(wP * delta)
|
||||
draw.DrawText("[" .. t_stamp .. "]", "SF_Display_H3", x , h * 0.9, color_white)
|
||||
local day = data[2]
|
||||
if day then
|
||||
local n = string.Explode(":", fakeTime)
|
||||
local f = n[1] * 60 + n[2]
|
||||
local w_type = StormFox2.Weather.Get(day.sName)
|
||||
local l_temp = 0
|
||||
for id, tD in ipairs( forecast.temperature ) do
|
||||
if tD[1] > unixT then break end
|
||||
l_temp = tD[2]
|
||||
end
|
||||
|
||||
local l_wind = 0
|
||||
for id, tD in ipairs( forecast.wind ) do
|
||||
if tD[1] > unixT then break end
|
||||
l_wind = tD[2]
|
||||
end
|
||||
|
||||
if not w_type then
|
||||
surface.SetMaterial(nul_icon)
|
||||
surface.DrawTexturedRect(x, h * 0.25, s, s)
|
||||
else
|
||||
surface.SetMaterial(w_type.GetIcon( f, l_temp, l_wind, day.bThunder or false, day.fAmount or 0) )
|
||||
surface.DrawTexturedRect(x, h * 0.25, s, s)
|
||||
local name = w_type:GetName(i % 1440, l_temp, l_wind, day.bThunder or false, day.fAmount or 0)
|
||||
draw.DrawText(name, "SF_Display_H2", x + s / 2, h * 0.25 + s, color_white, TEXT_ALIGN_CENTER)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
189
lua/stormfox2/functions/sh_concommands.lua
Normal file
189
lua/stormfox2/functions/sh_concommands.lua
Normal file
@@ -0,0 +1,189 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
-- All concommands for stormfox 2
|
||||
|
||||
local function SendMsg( ply, message )
|
||||
message = "[SF2]: " .. message
|
||||
if not ply then print( message ) return end
|
||||
ply:PrintMessage(HUD_PRINTTALK, message)
|
||||
end
|
||||
|
||||
-- Menu commands
|
||||
if CLIENT then
|
||||
-- Server menu
|
||||
concommand.Add('stormfox2_svmenu', StormFox2.Menu.OpenSV, nil, "Opens SF serverside menu")
|
||||
|
||||
-- Client menu
|
||||
concommand.Add('stormfox2_menu', StormFox2.Menu.Open, nil, "Opens SF clientside menu")
|
||||
|
||||
-- Controller
|
||||
concommand.Add('stormfox2_controller', StormFox2.Menu.OpenController, nil, "Opens SF controller menu")
|
||||
else -- Console only
|
||||
concommand.Add("stormfox2_settings_reset", function( ply, cmd, args, argStr )
|
||||
if ply and IsValid(ply) and not ply:IsListenServerHost() then return end -- Nope, console only
|
||||
StormFox2.Setting.Reset()
|
||||
end)
|
||||
end
|
||||
|
||||
-- Weather
|
||||
concommand.Add("stormfox2_setweather", function(ply, _, arg, _)
|
||||
if CLIENT then return end
|
||||
-- Check if valid weather
|
||||
if #arg < 1 then
|
||||
SendMsg(ply, "Weather can't be nil")
|
||||
return
|
||||
end
|
||||
local s = string.upper(string.sub(arg[1],0,1)) .. string.lower(string.sub(arg[1], 2))
|
||||
if not StormFox2.Weather.Get(s) then
|
||||
SendMsg(ply, "Invalid weather [" .. s .. "]")
|
||||
return
|
||||
end
|
||||
StormFox2.Permission.EditAccess(ply,"StormFox WeatherEdit", function()
|
||||
StormFox2.Weather.Set( s, tonumber( arg[2] or "1" ) or 1)
|
||||
end)
|
||||
end)
|
||||
|
||||
concommand.Add("stormfox2_setthunder", function(ply, _, _, argS)
|
||||
if CLIENT then return end
|
||||
StormFox2.Permission.EditAccess(ply,"StormFox WeatherEdit", function()
|
||||
local n = tonumber(argS) or (StormFox2.Thunder.IsThundering() and 6 or 0)
|
||||
StormFox2.Thunder.SetEnabled( n > 0, n )
|
||||
end)
|
||||
end)
|
||||
|
||||
-- Time and Date
|
||||
concommand.Add("stormfox2_settime", function(ply, _, _, argS)
|
||||
if CLIENT then return end
|
||||
-- Check if valid
|
||||
if not argS or string.len(argS) < 1 then
|
||||
SendMsg(ply, "You need to type an input! Use formats like 'stormfox2_settime 19:00' or 'stormfox2_settime 7:00 PM'")
|
||||
return
|
||||
end
|
||||
local tN = StormFox2.Time.StringToTime(argS)
|
||||
if not tN then
|
||||
SendMsg(ply, "Invalid input! Use formats like '19:00' or '7:00 PM'")
|
||||
return
|
||||
end
|
||||
StormFox2.Permission.EditAccess(ply,"StormFox WeatherEdit", function()
|
||||
StormFox2.Time.Set( argS )
|
||||
end)
|
||||
end)
|
||||
|
||||
concommand.Add("stormfox2_setyearday", function(ply, _, _, argStr)
|
||||
if CLIENT then return end
|
||||
StormFox2.Permission.EditAccess(ply,"StormFox WeatherEdit", function()
|
||||
StormFox2.Date.SetYearDay( tonumber(argStr) or 0 )
|
||||
end)
|
||||
end)
|
||||
|
||||
concommand.Add("stormfox2_setwind", function(ply, _, _, argStr)
|
||||
if CLIENT then return end
|
||||
StormFox2.Permission.EditAccess(ply,"StormFox WeatherEdit", function()
|
||||
StormFox2.Wind.SetForce( tonumber(argStr) or 0 )
|
||||
end)
|
||||
end)
|
||||
|
||||
concommand.Add("stormfox2_setwindangle", function(ply, _, _, argStr)
|
||||
if CLIENT then return end
|
||||
StormFox2.Permission.EditAccess(ply,"StormFox WeatherEdit", function()
|
||||
StormFox2.Wind.SetYaw( tonumber(argStr) or 0 )
|
||||
end)
|
||||
end)
|
||||
|
||||
concommand.Add("stormfox2_settemperature", function(ply, _, _, argStr)
|
||||
if CLIENT then return end
|
||||
local temp = tonumber( string.match(argStr, "-?[%d]+") or "0" ) or 0
|
||||
if string.match(argStr, "[fF]") then
|
||||
temp = StormFox2.Temperature.Convert("fahrenheit","celsius",temp) or temp
|
||||
end
|
||||
StormFox2.Permission.EditAccess(ply,"StormFox WeatherEdit", function()
|
||||
StormFox2.Temperature.Set( temp )
|
||||
end)
|
||||
end)
|
||||
|
||||
local function SetSetting( arg, arg2, ply )
|
||||
if not arg or arg == "" then
|
||||
SendMsg( ply, "You need to indecate a setting: stormfox2_setting [Setting] [Value]")
|
||||
return
|
||||
end
|
||||
local obj = StormFox2.Setting.GetObject(arg)
|
||||
if not obj then
|
||||
SendMsg( ply, "Invalid setting: \"" .. tostring( arg ) .. "\"!")
|
||||
return
|
||||
end
|
||||
if not arg2 then
|
||||
SendMsg( ply, "You need a value for the setting!")
|
||||
return
|
||||
end
|
||||
obj:SetValue( arg2 )
|
||||
SendMsg( ply, tostring( arg ) .. " = " .. tostring( arg2 ))
|
||||
end
|
||||
|
||||
local function AutoComplete(cmd, args)
|
||||
args = string.TrimLeft(args)
|
||||
local a = string.Explode(" ", args or "")
|
||||
if #a < 2 then
|
||||
local options = {}
|
||||
for _, sName in pairs( StormFox2.Setting.GetAllServer() ) do
|
||||
if string.find(string.lower(sName),string.lower(a[1]), nil, true) then
|
||||
table.insert(options, "stormfox2_setting " .. sName)
|
||||
end
|
||||
end
|
||||
if #options < 1 then
|
||||
return {"stormfox2_setting [No Setting Found!]"}
|
||||
elseif #options < 2 and "stormfox2_setting " .. args == options[1] then
|
||||
local obj = StormFox2.Setting.GetObject(a[1])
|
||||
if not obj then
|
||||
return {"stormfox2_setting [Invalid Setting!]"}
|
||||
end
|
||||
return {"stormfox2_setting " .. a[1] .. " [" .. obj.type .. "]"}
|
||||
end
|
||||
return options
|
||||
elseif not a[1] or string.TrimLeft(a[1]) == "" then
|
||||
return {"stormfox2_setting [Setting] [Value]"}
|
||||
else
|
||||
local obj = StormFox2.Setting.GetObject(a[1])
|
||||
if not obj then
|
||||
return {"stormfox2_setting [Invalid Setting!]"}
|
||||
else
|
||||
return {"stormfox2_setting " .. a[1] .. " [" .. obj.type .. "]"}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
concommand.Add("stormfox2_setting", function(ply, _, _, argStr)
|
||||
if CLIENT then return end
|
||||
StormFox2.Permission.EditAccess(ply,"StormFox Settings", function()
|
||||
local a = string.Explode(" ", argStr, false)
|
||||
SetSetting(a[1],a[2])
|
||||
end)
|
||||
end, AutoComplete)
|
||||
|
||||
-- Forces the settings to save.
|
||||
concommand.Add("stormfox2_settings_save", function(ply, _, _, _)
|
||||
if CLIENT then return end
|
||||
StormFox2.Permission.EditAccess(ply,"StormFox Settings", function()
|
||||
SendMsg( ply, "Force saved settings to data/" .. StormFox2.Setting.GetSaveFile())
|
||||
StormFox2.Setting.ForceSave()
|
||||
end)
|
||||
end)
|
||||
|
||||
-- Debug commands
|
||||
if true then return end
|
||||
concommand.Add("stormfox2_debug_spawnice", function(ply)
|
||||
if ply and not ply:IsListenServerHost() then return end
|
||||
SpawnIce()
|
||||
end, nil, nil)
|
||||
|
||||
concommand.Add("stormfox2_debug_removeice", function(ply)
|
||||
if ply and not ply:IsListenServerHost() then return end
|
||||
RemoveIce()
|
||||
end, nil, nil)
|
||||
685
lua/stormfox2/functions/sh_controller.lua
Normal file
685
lua/stormfox2/functions/sh_controller.lua
Normal file
@@ -0,0 +1,685 @@
|
||||
--[[
|
||||
| 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 functions
|
||||
StormFox2.Menu = StormFox2.Menu or {}
|
||||
local SF_SETWEATHER = 0
|
||||
local SF_SETTEMP = 1
|
||||
local SF_SETWIND_A = 2
|
||||
local SF_SETWIND_F = 3
|
||||
local SF_SETTIME = 4
|
||||
local SF_SETTIME_S = 5
|
||||
local SF_THUNDER = 6
|
||||
local SF_YEARDAY = 7
|
||||
|
||||
if SERVER then
|
||||
-- Gets called from sh_permission.lua
|
||||
|
||||
---Internally used by permissions to relay settings.
|
||||
---@param ply Player
|
||||
---@param uID number
|
||||
---@param var any
|
||||
---@deprecated
|
||||
---@server
|
||||
function StormFox2.Menu.SetWeatherData(ply, uID, var)
|
||||
if uID == SF_SETWEATHER and type(var) == "table" then
|
||||
if type(var[1]) ~= "string" or type(var[2])~= "number" then return end
|
||||
StormFox2.Weather.Set( var[1], var[2] )
|
||||
elseif uID == SF_SETTEMP and type(var) == "number" then
|
||||
StormFox2.Temperature.Set( var )
|
||||
elseif uID == SF_SETWIND_F and type(var) == "number" then
|
||||
StormFox2.Wind.SetForce( var, 3 )
|
||||
elseif uID == SF_SETWIND_A and type(var) == "number" then
|
||||
StormFox2.Wind.SetYaw( var, 3 )
|
||||
elseif uID == SF_SETTIME and type(var) == "number" then
|
||||
StormFox2.Time.Set( var )
|
||||
elseif uID == SF_SETTIME_S and type(var) == "number" then
|
||||
if not StormFox2.Time.IsPaused() then
|
||||
StormFox2.Time.Pause()
|
||||
else
|
||||
StormFox2.Time.Resume()
|
||||
end
|
||||
elseif uID == SF_THUNDER and type(var) == "boolean" then
|
||||
StormFox2.Thunder.SetEnabled(var, 6)
|
||||
elseif uID == SF_YEARDAY and type(var) == "number" then
|
||||
StormFox2.Date.SetYearDay( var )
|
||||
end
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
-- Send a request to change the weather
|
||||
local function SetWeather( uID, var )
|
||||
net.Start( StormFox2.Net.Permission )
|
||||
net.WriteUInt(1, 1) -- SF_SERVEREDIT
|
||||
net.WriteUInt(uID, 4)
|
||||
net.WriteType(var)
|
||||
net.SendToServer()
|
||||
end
|
||||
|
||||
-- Menu
|
||||
local t_col = Color(67,73,83)
|
||||
local h_col = Color(84,90,103)
|
||||
local b_col = Color(51,56,62)
|
||||
local n = 0.7
|
||||
local p_col = Color(51 * n,56 * n,62 * n)
|
||||
local rad,cos,sin = math.rad, math.cos, math.sin
|
||||
|
||||
local grad = Material("gui/gradient_down")
|
||||
local function DrawButton(self,w,h)
|
||||
local hov = self:IsHovered()
|
||||
local down = self:IsDown() or self._DEPRESSED
|
||||
surface.SetDrawColor(b_col)
|
||||
surface.DrawRect(0,0,w,h)
|
||||
if self._DISABLED then
|
||||
elseif down then
|
||||
surface.SetDrawColor(p_col)
|
||||
elseif hov then
|
||||
surface.SetDrawColor(h_col)
|
||||
else
|
||||
surface.SetDrawColor(t_col)
|
||||
end
|
||||
surface.SetMaterial(grad)
|
||||
surface.DrawTexturedRect(0,0,w,h)
|
||||
surface.SetDrawColor(p_col)
|
||||
surface.DrawOutlinedRect(0,0,w,h)
|
||||
end
|
||||
|
||||
local bg_color = Color(27,27,27)
|
||||
local side_color = Color(44,48,54)
|
||||
|
||||
local function OpenMenu( self )
|
||||
local menu = vgui.Create("DNumberWang")
|
||||
menu.m_numMin = nil
|
||||
function menu:SetDraggable() end
|
||||
local sx = 50 - self:GetWide()
|
||||
local sy = 24 - self:GetTall()
|
||||
menu:MakePopup()
|
||||
menu:SetDraggable(true)
|
||||
local x, y = self:LocalToScreen(-sx / 2,-sy / 2)
|
||||
menu:SetPos( x,y )
|
||||
menu:RequestFocus()
|
||||
menu:SetSize(50,24)
|
||||
menu.m_bIsMenuComponent = true
|
||||
RegisterDermaMenuForClose( menu )
|
||||
function menu:GetDeleteSelf() return true end
|
||||
menu:SetValue( self:GetVal() )
|
||||
menu.b = self
|
||||
function menu:OnEnter( str )
|
||||
CloseDermaMenus()
|
||||
if not str then return end
|
||||
self.b.p:OnMenu( tonumber( str ) )
|
||||
end
|
||||
end
|
||||
|
||||
local color_gray = Color(155,155,155)
|
||||
local function SliderNumber(self)
|
||||
local p = vgui.Create("DPanel", self)
|
||||
p:SetTall(18)
|
||||
p._ta = 30
|
||||
function p:Paint() end
|
||||
function p:SetVal(n) self.val = n end
|
||||
function p:GetVal() return self.val or 0 end
|
||||
p._aimval = nil
|
||||
AccessorFunc(p, "_min", "Min", FORCE_NUMBER)
|
||||
AccessorFunc(p, "_max", "Max", FORCE_NUMBER)
|
||||
p:SetMax(1)
|
||||
p:SetMin(0)
|
||||
function p:GetAP()
|
||||
return (self._aimval - self:GetMin() ) / ( self:GetMax() - self:GetMin() )
|
||||
end
|
||||
function p:GetP()
|
||||
return (self:GetVal() - self:GetMin() ) / ( self:GetMax() - self:GetMin() )
|
||||
end
|
||||
function p:SetP(f)
|
||||
p:SetVal( -f * self:GetMin() + f * self:GetMax() + self:GetMin() )
|
||||
end
|
||||
local slider = vgui.Create("DButton", p)
|
||||
local button = vgui.Create("DButton", p)
|
||||
button:SetText("")
|
||||
button.p = p
|
||||
slider:SetText("")
|
||||
function button:SetVal( n ) p:SetVal(n) end
|
||||
function button:GetVal() return p:GetVal() end
|
||||
function button:DoClick()
|
||||
OpenMenu(self)
|
||||
end
|
||||
function p:OnMenu( val )
|
||||
if not val then return end
|
||||
self:SetVal( val )
|
||||
self:OnVal( val )
|
||||
end
|
||||
function p:DrawText( num ) return num end
|
||||
function button:Paint(w,h)
|
||||
if not self:IsEnabled() then return end
|
||||
surface.SetDrawColor(0, 0, 0, 155)
|
||||
surface.DrawRect(0, 0, w, h)
|
||||
local s = p:DrawText( p:GetVal() )
|
||||
draw.DrawText(s, "DermaDefault", w / 2, 2, color_white, TEXT_ALIGN_CENTER)
|
||||
end
|
||||
function slider:Paint(w,h)
|
||||
local v = math.Clamp(p:GetP(), 0, 1)
|
||||
local a = p._aimval and math.Clamp(p:GetAP(), 0, 1)
|
||||
local pos = w * v
|
||||
-- Background
|
||||
draw.RoundedBox(30, 0, h / 2 - 3, w, 4, color_black)
|
||||
-- White
|
||||
draw.RoundedBox(30, 0, h / 2 - 3, pos, 4, color_white)
|
||||
if a and v ~= a then
|
||||
local pos2= w * a
|
||||
local mi = math.min(pos, pos2)
|
||||
draw.RoundedBox(30, mi, h / 2 - 3, math.abs(pos - pos2),4, color_gray)
|
||||
draw.RoundedBox(30, pos2 - 1, 0, 3, h, color_gray)
|
||||
end
|
||||
draw.RoundedBox(30, pos - 1, 0, 3, h, color_white)
|
||||
end
|
||||
function p:PerformLayout(w, h)
|
||||
button:SetPos(w - self._ta,0)
|
||||
button:SetSize(self._ta, h)
|
||||
if self._ta > 0 then
|
||||
slider:SetSize(w - self._ta - 5,18)
|
||||
else
|
||||
slider:SetSize(w,18)
|
||||
end
|
||||
slider:SetPos(0, h / 2 - 9)
|
||||
end
|
||||
function slider:OnDepressed()
|
||||
self._update = true
|
||||
end
|
||||
function slider:OnReleased()
|
||||
self._update = false
|
||||
local x,y = self:LocalCursorPos()
|
||||
local f = math.Round(math.Clamp(x / self:GetWide(), 0, 1), 2)
|
||||
p:SetP( f )
|
||||
p:OnVal( p:GetVal() )
|
||||
end
|
||||
function slider:Think()
|
||||
if p.Think2 then
|
||||
p:Think2()
|
||||
end
|
||||
if not self._update then return end
|
||||
local x,y = self:LocalCursorPos()
|
||||
local f = math.Round(math.Clamp(x / self:GetWide(), 0, 1), 2)
|
||||
p:SetP( f )
|
||||
end
|
||||
function p:SetTextSize( num)
|
||||
self._ta = num
|
||||
if num <= 0 then
|
||||
button:SetEnabled(false)
|
||||
else
|
||||
button:SetEnabled(true)
|
||||
end
|
||||
self:InvalidateLayout()
|
||||
end
|
||||
function p:OnVal( val ) end
|
||||
p:SetVal(0.6)
|
||||
return p
|
||||
end
|
||||
|
||||
local bottom_size = 24
|
||||
local col_ba = Color(0,0,0,155)
|
||||
local col_dis = Color(125,125,125,125)
|
||||
local m_cir = Material("stormfox2/hud/hudring2.png")
|
||||
local m_thunder = Material("stormfox2/hud/w_cloudy_thunder.png")
|
||||
local padding = 15
|
||||
local padding_y = 5
|
||||
|
||||
local function addW( w_select, v, p )
|
||||
local b = vgui.Create("DButton",w_select)
|
||||
b:SetSize(32,32)
|
||||
b:SetText("")
|
||||
b:DockMargin(0,0,0,0)
|
||||
w_select:AddPanel(b)
|
||||
b.weather = v
|
||||
b:SetToolTip(v)
|
||||
function b:OnCursorEntered()
|
||||
local w = StormFox2.Weather.Get(self.weather)
|
||||
if not IsValid(w) then return end -- Something bad happen
|
||||
b:SetToolTip(w:GetName(StormFox2.Time.Get(), StormFox2.Temperature.Get(), StormFox2.Wind.GetForce(), StormFox2.Thunder.IsThundering(), p:GetVal() / 100))
|
||||
end
|
||||
function b:Paint(w,h)
|
||||
DrawButton(self,w,h)
|
||||
local weather = StormFox2.Weather.Get(b.weather)
|
||||
local mat = weather.GetSymbol and weather.GetSymbol(_,StormFox2.Temperature.Get())
|
||||
if mat then
|
||||
surface.SetDrawColor(255,255,255)
|
||||
surface.SetMaterial(mat)
|
||||
surface.DrawTexturedRect(5,5,w - 10,h - 10)
|
||||
end
|
||||
end
|
||||
function b:DoClick()
|
||||
SetWeather(SF_SETWEATHER, {self.weather, p:GetVal() / 100})
|
||||
end
|
||||
end
|
||||
|
||||
local function versionGet()
|
||||
if not StormFox2.Version then return "?" end
|
||||
return string.format("%.2f", StormFox2.Version)
|
||||
end
|
||||
|
||||
local function Init(self)
|
||||
self:SetSize(180,432)
|
||||
self:SetPos(math.min(ScrW() * 0.8, ScrW() - 180), ScrH() / 2 - 200)
|
||||
self:SetTitle("")
|
||||
self.btnMaxim:SetVisible( false )
|
||||
self.btnMinim:SetVisible( false )
|
||||
function self:Paint(w,h)
|
||||
surface.SetDrawColor(side_color)
|
||||
surface.DrawRect(0,0,w,h)
|
||||
-- Top
|
||||
local t = "StormFox " .. versionGet()
|
||||
surface.SetDrawColor(p_col)
|
||||
surface.DrawRect(0,0,w,24)
|
||||
|
||||
surface.SetFont("SF2.W_Button")
|
||||
local tw,th = surface.GetTextSize(t)
|
||||
surface.SetTextColor(color_white)
|
||||
surface.SetTextPos(10,th / 2 - 2)
|
||||
surface.DrawText(t)
|
||||
end
|
||||
self:DockMargin(0,24,0,0)
|
||||
self:DockPadding(0,24,0,0)
|
||||
-- Weather
|
||||
local m_weather = vgui.Create("DPanel", self)
|
||||
m_weather:SetTall(70)
|
||||
m_weather:Dock(TOP)
|
||||
m_weather.Paint = function() end
|
||||
self.weather = m_weather
|
||||
local w_button = vgui.Create("DLabel", m_weather)
|
||||
w_button:SetText("")
|
||||
w_button:SetTall(28)
|
||||
function w_button:Paint(w,h)
|
||||
local t = "Set Weather"
|
||||
surface.SetTextColor(color_white)
|
||||
surface.SetFont("SF2.W_Button")
|
||||
local tw,th = surface.GetTextSize(t)
|
||||
surface.SetTextPos(w / 2 - tw / 2, h / 2 - th / 2)
|
||||
surface.DrawText(t)
|
||||
end
|
||||
local w_select = vgui.Create("DHorizontalScroller", m_weather)
|
||||
w_select:SetOverlap( -4 )
|
||||
w_select.num = 0
|
||||
-- Percent & W
|
||||
local p = SliderNumber( self )
|
||||
p:SetToolTip('#sf_weatherpercent')
|
||||
p:SetTextSize(40)
|
||||
if StormFox2.Weather.GetCurrent() == StormFox2.Weather.Get('Clear') then
|
||||
p:SetVal(85)
|
||||
else
|
||||
p:SetVal(math.Round(math.Clamp(StormFox2.Weather.GetPercent() * 100, 0, 100), 2))
|
||||
end
|
||||
function p:OnVal(x)
|
||||
SetWeather(SF_SETWEATHER, {StormFox2.Weather.GetCurrent().Name, x / 100})
|
||||
end
|
||||
function m_weather:PerformLayout(w, h)
|
||||
w_button:SetWide(w * 0.7)
|
||||
w_button:SetPos(w * 0.15,5)
|
||||
-- Calc the wide
|
||||
local wide = w_select.num * (32 - w_select.m_iOverlap)
|
||||
-- If weathers won't fit, make it default size and pos
|
||||
if wide >= w * 0.9 then
|
||||
w_select:SetSize(w * 0.9,32)
|
||||
w_select:SetPos(w * 0.05, 32)
|
||||
else -- Calc calculate the middle
|
||||
w_select:SetSize(wide,32)
|
||||
w_select:SetPos(w * 0.05 + (w * 0.9 - wide) / 2 , 32)
|
||||
end
|
||||
end
|
||||
local t = StormFox2.Weather.GetAll()
|
||||
addW(w_select, "Clear", p) -- Always add clear
|
||||
if table.HasValue(t, "Cloud") then
|
||||
addW(w_select, "Cloud", p)
|
||||
w_select.num = w_select.num + 1
|
||||
end
|
||||
if table.HasValue(t, "Rain") then
|
||||
addW(w_select, "Rain", p)
|
||||
w_select.num = w_select.num + 1
|
||||
end
|
||||
if table.HasValue(t, "Fog") then
|
||||
addW(w_select, "Fog", p)
|
||||
w_select.num = w_select.num + 1
|
||||
end
|
||||
for k,v in ipairs(t) do
|
||||
if v == "Clear" or v == "Cloud" or v == "Rain" or v == "Fog" then continue end -- Ignore
|
||||
addW(w_select, v, p)
|
||||
w_select.num = w_select.num + 1
|
||||
end
|
||||
p:SetMin(1)
|
||||
p:SetMax(100)
|
||||
p:Dock(TOP)
|
||||
p:DockMargin(padding,0,padding,padding_y)
|
||||
function p:DrawText( s )
|
||||
return s .. "%"
|
||||
end
|
||||
-- Thunder
|
||||
local tP = vgui.Create("DPanel", self)
|
||||
tP:Dock(TOP)
|
||||
tP:SetTall(32)
|
||||
tP.Paint = empty
|
||||
local thunder = vgui.Create("DButton", tP)
|
||||
thunder:NoClipping( true )
|
||||
thunder:SetSize(33, 32)
|
||||
thunder:SetText('')
|
||||
function tP:PerformLayout(w, h)
|
||||
thunder:SetPos(w / 2 - 16,0)
|
||||
end
|
||||
function thunder:Paint(w,h)
|
||||
local cW = StormFox2.Weather.GetCurrent()
|
||||
local hasThunder = cW.Name ~= "Clear"
|
||||
self._DEPRESSED = StormFox2.Thunder.IsThundering()
|
||||
self._DISABLED = not hasThunder and not self._DEPRESSED
|
||||
DrawButton(self,w,h)
|
||||
if not self._DISABLED then
|
||||
surface.SetDrawColor(color_white)
|
||||
else
|
||||
surface.SetDrawColor(col_dis)
|
||||
end
|
||||
surface.SetMaterial(m_thunder)
|
||||
surface.DrawTexturedRect(5,5,w - 10,h - 10)
|
||||
end
|
||||
function thunder:DoClick()
|
||||
local cW = StormFox2.Weather.GetCurrent()
|
||||
local hasThunder = cW.Name ~= "Clear"
|
||||
local isth = StormFox2.Thunder.IsThundering()
|
||||
if not isth and not hasThunder then
|
||||
return
|
||||
end
|
||||
SetWeather(SF_THUNDER, not isth)
|
||||
end
|
||||
-- Temperature
|
||||
local t = vgui.Create("DPanel", self)
|
||||
t:SetTall(30)
|
||||
t:Dock(TOP)
|
||||
t:DockMargin(padding,padding_y,padding,0)
|
||||
local text = language.GetPhrase("#temperature")
|
||||
t.text = string.upper(text[1]) .. string.sub(text, 2)
|
||||
function t:Paint(w,h)
|
||||
surface.SetFont("SF2.W_Button")
|
||||
local tw,th = surface.GetTextSize(self.text)
|
||||
surface.SetTextColor(color_white)
|
||||
surface.SetTextPos(w / 2 - tw / 2,th / 2 - 2)
|
||||
surface.DrawText(self.text)
|
||||
end
|
||||
local tempslider = SliderNumber(self)
|
||||
local function Conv( n ) return math.Round(StormFox2.Temperature.Convert(nil,StormFox2.Temperature.GetDisplayType(),n), 1) end
|
||||
tempslider:DockMargin(padding,0,padding,padding_y)
|
||||
tempslider:Dock(TOP)
|
||||
tempslider:SetMin(Conv(-20))
|
||||
tempslider:SetMax(Conv(40))
|
||||
tempslider:SetTextSize(40)
|
||||
function tempslider:OnVal( num )
|
||||
num = math.Round(StormFox2.Temperature.Convert(StormFox2.Temperature.GetDisplayType(),nil,num), 1)
|
||||
SetWeather(SF_SETTEMP, num)
|
||||
end
|
||||
function tempslider:DrawText( n )
|
||||
return n .. StormFox2.Temperature.GetDisplaySymbol()
|
||||
end
|
||||
tempslider:SetVal( math.Round(StormFox2.Temperature.GetDisplay(),1) )
|
||||
function tempslider:Think()
|
||||
tempslider._aimval = math.Round(StormFox2.Temperature.GetDisplay(StormFox2.Data.GetFinal( "Temp", 20 )),1)
|
||||
tempslider:SetVal( math.Round(StormFox2.Temperature.GetDisplay(),1) )
|
||||
end
|
||||
-- Wind Ang
|
||||
local t = vgui.Create("DPanel", self)
|
||||
t:DockMargin(padding,padding_y,padding,0)
|
||||
t:SetTall(30)
|
||||
t:Dock(TOP)
|
||||
local text = language.GetPhrase("#sf_wind")
|
||||
t.text = string.upper(text[1]) .. string.sub(text, 2)
|
||||
function t:Paint(w,h)
|
||||
surface.SetFont("SF2.W_Button")
|
||||
local tw,th = surface.GetTextSize(self.text)
|
||||
surface.SetTextColor(color_white)
|
||||
surface.SetTextPos(w / 2 - tw / 2,th / 2 - 2)
|
||||
surface.DrawText(self.text)
|
||||
end
|
||||
local b = vgui.Create("DPanel", self)
|
||||
function b:Paint() end
|
||||
b:SetSize(80,80)
|
||||
b:Dock(TOP)
|
||||
local w_ang = vgui.Create("DButton", b)
|
||||
w_ang:SetToolTip('#sf_setang.desc')
|
||||
w_ang:SetText("")
|
||||
function b:PerformLayout(w, h)
|
||||
w_ang:SetSize(h,h)
|
||||
w_ang:SetPos(w / 2 - h / 2)
|
||||
end
|
||||
function w_ang:Paint( w, h )
|
||||
render.PushFilterMag(TEXFILTER.ANISOTROPIC)
|
||||
render.PushFilterMin(TEXFILTER.ANISOTROPIC)
|
||||
surface.SetDrawColor(col_ba)
|
||||
surface.SetMaterial(m_cir)
|
||||
surface.DrawTexturedRect(0,0,w,h)
|
||||
|
||||
local windang = EyeAngles().y - (StormFox2.Wind.GetYaw() or 0)
|
||||
local wind = StormFox2.Wind.GetForce() or 0
|
||||
local t = {{x = w / 2,y = h / 2, u=0.5,v=0.5}}
|
||||
local l = math.Clamp(wind,0,70) / 3
|
||||
if l < 1 then
|
||||
surface.SetDrawColor(155,255,155)
|
||||
l = 2
|
||||
else
|
||||
surface.SetDrawColor(155,155,255)
|
||||
end
|
||||
local nn = 90 - l * 5
|
||||
for i = 0,l - 1 do
|
||||
local c,s = cos(rad(i * 10 + windang + nn)),sin(rad(i * 10 + windang + nn))
|
||||
local x = c * w / 2 + w / 2
|
||||
local y = s * h / 2 + h / 2
|
||||
table.insert(t,{x = x,y = y, u = (c + 1) / 2, v = (s + 1) / 2})
|
||||
end
|
||||
local c,s = cos(rad(l * 10 + windang + nn)),sin(rad(l * 10 + windang + nn))
|
||||
local x = c * w / 2 + w / 2
|
||||
local y = s * h / 2 + h / 2
|
||||
table.insert(t,{x = x,y = y, u=(c + 1) / 2,v = (s + 1) / 2})
|
||||
--draw.NoTexture()
|
||||
surface.DrawPoly(t)
|
||||
surface.SetFont("DermaDefault")
|
||||
local t = language.GetPhrase("#sf_setang")
|
||||
local tw,th = surface.GetTextSize(t)
|
||||
surface.SetTextPos(w / 2 - tw / 2, h / 2 - th / 2)
|
||||
surface.DrawText(t)
|
||||
render.PopFilterMag()
|
||||
render.PopFilterMin()
|
||||
end
|
||||
function w_ang:DoClick()
|
||||
SetWeather(SF_SETWIND_A, (EyeAngles().y + 180) % 360)
|
||||
end
|
||||
-- Wind
|
||||
local p = vgui.Create("DPanel", self)
|
||||
p:SetTall(22)
|
||||
p:Dock(TOP)
|
||||
p:DockMargin(padding,padding_y,padding,0)
|
||||
function p:Paint(w,h)
|
||||
local f = math.Round(StormFox2.Wind.GetForce() or 0, 1)
|
||||
local bf,desc = StormFox2.Wind.GetBeaufort(f)
|
||||
local text = f .."m/s : " .. language.GetPhrase(desc)
|
||||
surface.SetFont("DermaDefault")
|
||||
surface.SetTextColor(color_white)
|
||||
local tw,th = surface.GetTextSize(text)
|
||||
surface.SetTextPos(w / 2 - tw / 2, h / 2 - th / 2)
|
||||
surface.DrawText(text)
|
||||
end
|
||||
local windslide = SliderNumber(self)
|
||||
windslide:SetToolTip('#sf_setwind')
|
||||
windslide:Dock(TOP)
|
||||
windslide:DockMargin(padding,0,padding,0)
|
||||
windslide:SetMin(0)
|
||||
windslide:SetMax(70)
|
||||
windslide:SetTextSize(0)
|
||||
windslide:SetVal( StormFox2.Wind.GetForce() or 0 )
|
||||
function windslide:OnVal( num )
|
||||
SetWeather(SF_SETWIND_F, num)
|
||||
end
|
||||
function windslide:Think2()
|
||||
windslide._aimval = StormFox2.Data.GetFinal( "Wind", 0 )
|
||||
windslide:SetVal( StormFox2.Wind.GetForce() or 0 )
|
||||
end
|
||||
-- Time
|
||||
local p = vgui.Create("DPanel", self)
|
||||
p:SetTall(40)
|
||||
p.Paint = function() end
|
||||
local t = vgui.Create("SF_TIME", p)
|
||||
function t:Think()
|
||||
self:SetValue( StormFox2.Time.Get() )
|
||||
end
|
||||
function t:OnNewValue( var )
|
||||
SetWeather( SF_SETTIME, var )
|
||||
end
|
||||
p:Dock(TOP)
|
||||
local pause = vgui.Create("DButton", p)
|
||||
pause.state = 1
|
||||
pause:SetSize(30, 30)
|
||||
function p:PerformLayout(w, h)
|
||||
pause:SetPos(10,10)
|
||||
t:SetPos( 42 ,10)
|
||||
t:SetWide( w - 20 - 27 )
|
||||
end
|
||||
local a = StormFox2.Setting.GetObject("day_length")
|
||||
local b = StormFox2.Setting.GetObject("night_length")
|
||||
|
||||
local r = Material("gui/point.png")
|
||||
local z = Material("gui/workshop_rocket.png")
|
||||
function pause:Think()
|
||||
if StormFox2.Time.IsPaused() then
|
||||
self.state = 0 -- pause
|
||||
else
|
||||
self.state = 1 -- running
|
||||
end
|
||||
end
|
||||
pause:SetText("")
|
||||
--pause.Paint = DrawButton
|
||||
--t.bg.Paint = DrawButton
|
||||
--
|
||||
--t.ampm.Paint = DrawButton
|
||||
--function t.ampm:UpdateColours()
|
||||
-- self:SetTextStyleColor( color_white )
|
||||
--end
|
||||
--t.hour.color = color_white
|
||||
--t.min.color = color_white
|
||||
|
||||
local c = Color(0,0,0,225)
|
||||
function pause:PaintOver(w,h)
|
||||
local s = 15
|
||||
if self.state == 0 then
|
||||
surface.SetMaterial(r)
|
||||
surface.SetDrawColor(c)
|
||||
surface.DrawTexturedRectRotated(w / 2 + 2,h / 2,w - s,h - s, 90)
|
||||
else
|
||||
surface.SetMaterial(z)
|
||||
surface.SetDrawColor(c)
|
||||
surface.DrawTexturedRectRotated(w / 2 - 5,h / 2,w - s * 1.1,h, 0)
|
||||
surface.DrawTexturedRectRotated(w / 2 + 5,h / 2,w - s * 1.1,h, 0)
|
||||
end
|
||||
end
|
||||
function pause:DoClick()
|
||||
SetWeather(SF_SETTIME_S, 0)
|
||||
end
|
||||
pause:SetPos(20 ,10)
|
||||
end
|
||||
|
||||
-- Caht status
|
||||
local openChat = false
|
||||
hook.Add("StartChat","StormFox2.Controller.Disable",function()
|
||||
openChat = true
|
||||
end)
|
||||
hook.Add("FinishChat","StormFox2.Controller.Enable",function()
|
||||
openChat = false
|
||||
end)
|
||||
|
||||
local mat = Material("gui/workshop_rocket.png")
|
||||
local c = Color(55,55,55)
|
||||
|
||||
---Builds the controller
|
||||
---@deprecated
|
||||
---@return userdata panel
|
||||
---@client
|
||||
function StormFox2.Menu._OpenController()
|
||||
if _SF_CONTROLLER then
|
||||
_SF_CONTROLLER:Remove()
|
||||
end
|
||||
if spawnmenu and spawnmenu.SetActiveControlPanel then
|
||||
spawnmenu.SetActiveControlPanel(nil)
|
||||
end
|
||||
local p = vgui.Create("DFrame")
|
||||
|
||||
if not p then return end
|
||||
_SF_CONTROLLER = p
|
||||
Init(p)
|
||||
local settings = vgui.Create("DButton", p)
|
||||
settings:SetSize(31, 24)
|
||||
settings:SetPos(p:GetWide() - 31 * 2 - 4)
|
||||
settings:SetIcon('icon16/cog_edit.png')
|
||||
settings:SetText("")
|
||||
settings:SetToolTip("#spawnmenu.utilities.server_settings")
|
||||
function settings:DoClick()
|
||||
surface.PlaySound("buttons/button14.wav")
|
||||
RunConsoleCommand("stormfox2_svmenu")
|
||||
end
|
||||
function settings:Paint() end
|
||||
function p:PaintOver(w,h)
|
||||
if self.enabled then return end
|
||||
local x,y = 0, h / 2
|
||||
surface.SetMaterial(mat)
|
||||
surface.SetDrawColor(HSLToColor(240, 0.3,0.5 + sin(CurTime() * 1.5) / 10))
|
||||
surface.DrawTexturedRectUV(0,h * 0.4,w,h * 0.2,0.2,-0.2,0.8,1)
|
||||
draw.DrawText("#sf_holdc", "SF2.W_Button", w / 2, h / 2, color_white, TEXT_ALIGN_CENTER)
|
||||
end
|
||||
function p:Think()
|
||||
local x,y = self:LocalCursorPos(0,0)
|
||||
local inside = x > 0 and x < self:GetWide() and y > 0 and y < self:GetTall()
|
||||
if not self.enabled and input.IsKeyDown(KEY_C) and not openChat and not gui.IsConsoleVisible() then
|
||||
self.enabled = true
|
||||
self.btnClose:SetDisabled( false )
|
||||
self:MakePopup()
|
||||
self:SetSelected()
|
||||
elseif self.enabled then
|
||||
if input.IsKeyDown(KEY_C) then return end -- If KEY is down, don't disable
|
||||
if self:HasHierarchicalFocus() and not self:HasFocus() then return end -- Typing in something. Don't disable.
|
||||
if inside then return end -- Mouse is inside controller. Don't disable yet.
|
||||
self.enabled = false
|
||||
self.btnClose:SetDisabled( true )
|
||||
self:SetMouseInputEnabled(false)
|
||||
self:SetKeyboardInputEnabled(false)
|
||||
end
|
||||
end
|
||||
return _SF_CONTROLLER
|
||||
end
|
||||
|
||||
---Opens the controller
|
||||
---@client
|
||||
function StormFox2.Menu.OpenController()
|
||||
net.Start("StormFox2.menu")
|
||||
net.WriteBool(false)
|
||||
net.SendToServer()
|
||||
end
|
||||
|
||||
---Closes the controller
|
||||
---@client
|
||||
function StormFox2.Menu.CloseController()
|
||||
if _SF_CONTROLLER then
|
||||
_SF_CONTROLLER:Remove()
|
||||
end
|
||||
end
|
||||
-- Controller
|
||||
list.Set( "DesktopWindows", "StormFoxController", {
|
||||
title = "#sf_wcontoller",
|
||||
icon = "stormfox2/hud/controller.png",
|
||||
width = 960,
|
||||
height = 700,
|
||||
onewindow = true,
|
||||
init = function( icon, window )
|
||||
window:Remove()
|
||||
surface.PlaySound("buttons/button14.wav")
|
||||
StormFox2.Menu.OpenController()
|
||||
end
|
||||
} )
|
||||
concommand.Add('stormfox2_controller', StormFox2.Menu.OpenController, nil, "Opens SF controller menu")
|
||||
288
lua/stormfox2/functions/sh_fog.lua
Normal file
288
lua/stormfox2/functions/sh_fog.lua
Normal file
@@ -0,0 +1,288 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
--[[-------------------------------------------------------------------------
|
||||
Use the map-data to set a minimum and maximum fogdistance
|
||||
---------------------------------------------------------------------------]]
|
||||
StormFox2.Setting.AddSV("enable_svfog",true,nil, "Effects")
|
||||
if CLIENT then StormFox2.Setting.AddCL("enable_fog",true, "sf_enable_fog") end
|
||||
StormFox2.Setting.AddSV("enable_fogz",false,nil, "Effects")
|
||||
StormFox2.Setting.AddSV("overwrite_fogdistance",-1,nil, "Effects", -1, 800000)
|
||||
StormFox2.Setting.SetType("overwrite_fogdistance","special_float")
|
||||
StormFox2.Setting.AddSV("allow_fog_change",engine.ActiveGamemode() == "sandbox",nil, "Effects")
|
||||
|
||||
StormFox2.Fog = {}
|
||||
-- Local functions
|
||||
local function fogEnabledCheck()
|
||||
if not StormFox2.Setting.SFEnabled() then return false end
|
||||
if not StormFox2.Setting.GetCache("enable_svfog", true) then return false end
|
||||
if not StormFox2.Setting.GetCache("allow_fog_change", false) then return true end
|
||||
return StormFox2.Setting.GetCache("enable_fog", true)
|
||||
end
|
||||
local _fS, _fE, _fD = 0,400000,1
|
||||
local function fogStart( f )
|
||||
_fS = f
|
||||
end
|
||||
local function fogEnd( f )
|
||||
_fE = f
|
||||
end
|
||||
local function fogDensity( f )
|
||||
_fD = f
|
||||
end
|
||||
local function getFogFill()
|
||||
if _fS >= 0 then return 0 end
|
||||
return -_fS / (_fE - _fS) * _fD * 0.1
|
||||
end
|
||||
-- Makes it so fog isn't linear
|
||||
local e = 2.71828
|
||||
local function fogCalc(b, a, p)
|
||||
if a == b then return a end
|
||||
p = e^(-8.40871*p)
|
||||
local d = b - a
|
||||
return a + d * p
|
||||
end
|
||||
|
||||
---Returns the start of the fog.
|
||||
---@return number
|
||||
---@shared
|
||||
function StormFox2.Fog.GetStart()
|
||||
return math.max(0, _fS)
|
||||
end
|
||||
|
||||
---Returns the end of fog.
|
||||
---@return number
|
||||
---@shared
|
||||
function StormFox2.Fog.GetEnd()
|
||||
return _fE
|
||||
end
|
||||
-- Locate / Calculate the default fog-data
|
||||
local map_distance, map_farZ = -1, -1
|
||||
local tab = StormFox2.Map.FindClass("env_fog_controller")
|
||||
if #tab < 1 then
|
||||
map_distance = 400000
|
||||
else
|
||||
-- Set a minimum
|
||||
map_distance = 6000
|
||||
for _, data in ipairs(tab) do
|
||||
map_farZ = math.max(map_farZ, data.farz)
|
||||
-- Calculate fog-brightness. We can use this to scale the map-distance up to match the fog.
|
||||
local col_brightness = 1
|
||||
local density = (tonumber( data.fogmaxdensity or "" ) or 1)
|
||||
if data.fogcolor then
|
||||
local fcol = string.Explode(" ", data.fogcolor)
|
||||
col_brightness = (0.2126 * fcol[1] + 0.7152 * fcol[2] + 0.0722 * fcol[3]) / 255
|
||||
end
|
||||
density = density * col_brightness
|
||||
map_distance = math.max(((data.fogend or 6000) / density), map_distance)
|
||||
end
|
||||
-- It is important we don't overshoot farZ
|
||||
if map_farZ > 0 then
|
||||
map_distance = math.min(map_distance, map_farZ)
|
||||
end
|
||||
end
|
||||
|
||||
---Returns the fog-amount. 0 - 1
|
||||
---@return number
|
||||
---@shared
|
||||
function StormFox2.Fog.GetAmount()
|
||||
return 1 - _fE / map_distance
|
||||
end
|
||||
|
||||
---Returns the fog-distance ( Same as StormFox2.Fog.GetEnd(), but uses the map as a fallback )
|
||||
---@return number
|
||||
---@shared
|
||||
function StormFox2.Fog.GetDistance()
|
||||
return _fE or map_distance
|
||||
end
|
||||
|
||||
-- Returns the default fog-distance for clear weather.
|
||||
local function getDefaultDistance()
|
||||
local ov = StormFox2.Setting.GetCache("overwrite_fogdistance",-1)
|
||||
if ov > -1 then
|
||||
return ov
|
||||
end
|
||||
return map_distance
|
||||
end
|
||||
-- Returns the fog-distance.
|
||||
local function getAimDistance(bFinal)
|
||||
local cW = StormFox2.Weather.GetCurrent()
|
||||
local ov = getDefaultDistance()
|
||||
if cW.Name == "Clear" then return ov end
|
||||
local perc = bFinal and StormFox2.Weather.GetFinishPercent() or StormFox2.Weather.GetPercent()
|
||||
local a = math.min(cW:Get('fogDistance'), ov)
|
||||
if a == ov then return ov end -- This weathertype doesn't change the fog .. or is higer than default
|
||||
if not a or perc <= 0 then return ov end -- If weather percent is 0 or under. Return the "clear" distance.
|
||||
if perc >= 1 then return a end -- If weather is higer or equal to 1, return the base value.
|
||||
return fogCalc(ov, a, perc)
|
||||
end
|
||||
|
||||
if SERVER then
|
||||
local loaded, data, f_FogZ = true
|
||||
|
||||
---Sets the fogZ distance. Seems buggy atm, use at own rist.
|
||||
---@param num number
|
||||
---@param nTimer number
|
||||
---@server
|
||||
function StormFox2.Fog.SetZ(num, nTimer)
|
||||
timer.Remove( "sf_fog_timer" )
|
||||
if nTimer then
|
||||
timer.Create("sf_fog_timer", nTimer, 1, function()
|
||||
StormFox2.Fog.SetZ(num)
|
||||
end)
|
||||
return
|
||||
end
|
||||
f_FogZ = num
|
||||
if not loaded then
|
||||
data = num
|
||||
return
|
||||
end
|
||||
if not num then num = map_farZ end
|
||||
for k,v in ipairs( StormFox2.Ent.env_fog_controllers or {} ) do
|
||||
if not IsValid(v) then continue end
|
||||
v:SetKeyValue("farz", num)
|
||||
end
|
||||
end
|
||||
|
||||
---Returns the fogz distance.
|
||||
---@return number
|
||||
---@server
|
||||
function StormFox2.Fog.GetZ()
|
||||
if not StormFox2.Setting.Get("enable_fogz", false) then return map_farZ end
|
||||
return f_FogZ or (StormFox2.Fog.GetDistance() + 100)
|
||||
end
|
||||
hook.Add("StormFox2.PostEntityScan", "StormFox2.Fog.Initz", function()
|
||||
loaded = true
|
||||
if data then
|
||||
StormFox2.Fog.SetZ(data)
|
||||
data = nil
|
||||
end
|
||||
end)
|
||||
hook.Add("StormFox2.weather.postchange", "StormFox2.Fog.Updater", function( sName ,nPercentage, nDelta )
|
||||
local old_fE = _fE or map_distance
|
||||
_fE = getAimDistance(true)
|
||||
if _fE > 3000 then
|
||||
_fS = 0
|
||||
else
|
||||
_fS = _fE - 3000
|
||||
end
|
||||
-- Check fogZ distance
|
||||
if not StormFox2.Setting.Get("enable_fogz", false) then return end
|
||||
if old_fE > _fE then -- The fog shriks
|
||||
StormFox2.Fog.SetZ(_fE * 2 + 100, nDelta)
|
||||
elseif old_fE < _fE then -- The fog grows
|
||||
StormFox2.Fog.SetZ(_fE * 2 + 100)
|
||||
end
|
||||
end)
|
||||
timer.Create("StormFox2.Fog.SVUpdate", 2, 0, function()
|
||||
local cWD = StormFox2.Weather.GetCurrent().Dynamic or {}
|
||||
if cWD.fogDistance then return end
|
||||
_fE = getAimDistance(true)
|
||||
end)
|
||||
|
||||
---Returns the fog-color.
|
||||
---@return Color
|
||||
---@server
|
||||
function StormFox2.Fog.GetColor()
|
||||
return StormFox2.Mixer.Get("fogColor", StormFox2.Mixer.Get("bottomColor",color_white) ) or color_white
|
||||
end
|
||||
return
|
||||
end
|
||||
----- Fog render and clientside -----
|
||||
-- Fog logic and default render
|
||||
-- Returns the "distance" to outside
|
||||
local f_outside = 0
|
||||
local f_indoor = -1
|
||||
local f_lastDist = map_distance
|
||||
|
||||
local function outSideVar()
|
||||
local env = StormFox2.Environment.Get()
|
||||
if env.outside then
|
||||
return f_outside
|
||||
end
|
||||
if not env.nearest_outside then
|
||||
return f_indoor
|
||||
end
|
||||
local dis = StormFox2.util.RenderPos():Distance(env.nearest_outside) / 300
|
||||
if dis > 1 then
|
||||
return f_indoor
|
||||
end
|
||||
return dis
|
||||
end
|
||||
hook.Add("Think", "StormFox2.Fog.Updater", function()
|
||||
-- Figure out the fogdistance we should have
|
||||
local f_envfar = outSideVar()
|
||||
local fog_dis = getAimDistance()
|
||||
local fog_indoor = StormFox2.Mixer.Get("fogIndoorDistance",3000)
|
||||
if f_envfar == f_indoor then -- Indoors
|
||||
fog_dis = math.max(fog_dis, fog_indoor)
|
||||
elseif f_envfar ~= f_outside then
|
||||
fog_dis = Lerp(f_envfar + 0.1, fog_dis, fog_indoor)
|
||||
end
|
||||
_fE = math.Approach(_fE, fog_dis, math.max(10, _fE) * FrameTime())
|
||||
if _fE > 3000 then
|
||||
_fS = 0
|
||||
else
|
||||
_fS = _fE - 3000
|
||||
end
|
||||
end)
|
||||
|
||||
local f_Col = color_white
|
||||
local SkyFog = function(scale)
|
||||
if _fD <= 0 then return end
|
||||
if not scale then scale = 1 end
|
||||
if not fogEnabledCheck() then return end
|
||||
f_Col = StormFox2.Mixer.Get("fogColor", StormFox2.Mixer.Get("bottomColor") ) or color_white
|
||||
-- Apply fog
|
||||
local tD = StormFox2.Thunder.GetLight() / 2055
|
||||
render.FogMode( 1 )
|
||||
render.FogStart( StormFox2.Fog.GetStart() * scale )
|
||||
render.FogEnd( StormFox2.Fog.GetEnd() * scale )
|
||||
render.FogMaxDensity( (_fD - tD) * 0.999 )
|
||||
render.FogColor( f_Col.r,f_Col.g,f_Col.b )
|
||||
return true
|
||||
end
|
||||
hook.Add("SetupSkyboxFog","StormFox2.Sky.Fog",SkyFog)
|
||||
hook.Add("SetupWorldFog","StormFox2.Sky.WorldFog",SkyFog)
|
||||
-- Returns the fog-color.
|
||||
function StormFox2.Fog.GetColor()
|
||||
return f_Col or color_white
|
||||
end
|
||||
|
||||
-- Additional Fog render
|
||||
local m_fog = Material('stormfox2/effects/fog_sphere')
|
||||
local l_fogz = 0
|
||||
hook.Add("StormFox2.2DSkybox.FogLayer", "StormFox2.Fog.RSky", function( viewPos )
|
||||
if not fogEnabledCheck() then return end
|
||||
local v = Vector(math.cos( viewPos.y ), math.sin( viewPos.y ), 0)
|
||||
m_fog:SetVector("$color", Vector(f_Col.r,f_Col.g,f_Col.b) / 255)
|
||||
m_fog:SetFloat("$alpha", math.Clamp(5000 / _fE, 0, 1))
|
||||
render.SetMaterial( m_fog )
|
||||
local tH = math.min(StormFox2.Environment.GetZHeight(), 2100)
|
||||
if tH ~= l_fogz then
|
||||
local delta = math.abs(l_fogz, tH) / 2
|
||||
l_fogz = math.Approach( l_fogz, tH, math.max(delta, 10) * 5 * FrameTime() )
|
||||
end
|
||||
local h = 2000 + 6000 * StormFox2.Fog.GetAmount()
|
||||
render.DrawSphere( Vector(0,0,h - l_fogz * 4) , -30000, 30, 30, color_white)
|
||||
end)
|
||||
|
||||
local mat = Material("color")
|
||||
local v1 = Vector(1,1,1)
|
||||
hook.Add("PostDrawOpaqueRenderables", "StormFox2.Sky.FogPDE", function()
|
||||
if _fS >= 0 or _fD <= 0 then return end
|
||||
if not fogEnabledCheck() then return end
|
||||
local a = getFogFill()
|
||||
mat:SetVector("$color",Vector(f_Col.r / 255,f_Col.g / 255,f_Col.b / 255))
|
||||
mat:SetFloat("$alpha",a)
|
||||
render.SetMaterial(mat)
|
||||
render.DrawScreenQuad()
|
||||
mat:SetVector("$color",v1)
|
||||
mat:SetFloat("$alpha",1)
|
||||
end)
|
||||
298
lua/stormfox2/functions/sh_footprints.lua
Normal file
298
lua/stormfox2/functions/sh_footprints.lua
Normal file
@@ -0,0 +1,298 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
--[[-------------------------------------------------------------------------
|
||||
Footsteps and logic.
|
||||
- Overrides default footstepsounds with terrain-sounds
|
||||
---------------------------------------------------------------------------]]
|
||||
local NetL = {"npc_zombie", "npc_poisonzombie", "npc_vortigaunt", "npc_antlion", "npc_fastzombie"} -- These entites only play sounds serverside and needs to be networked.
|
||||
local BL = {"npc_hunter"} -- Tehse entities should not get their sound replaced
|
||||
local find = string.find
|
||||
local bAlwaysFootstep = false -- This is set to true on cold maps
|
||||
local defaultSnowName = "snow.step"
|
||||
local defaultSnowSnd = {
|
||||
"stormfox/footstep/footstep_snow0.ogg",
|
||||
"stormfox/footstep/footstep_snow1.ogg",
|
||||
"stormfox/footstep/footstep_snow2.ogg",
|
||||
"stormfox/footstep/footstep_snow3.ogg",
|
||||
"stormfox/footstep/footstep_snow4.ogg",
|
||||
"stormfox/footstep/footstep_snow5.ogg",
|
||||
"stormfox/footstep/footstep_snow6.ogg",
|
||||
"stormfox/footstep/footstep_snow7.ogg",
|
||||
"stormfox/footstep/footstep_snow8.ogg",
|
||||
"stormfox/footstep/footstep_snow9.ogg"
|
||||
}
|
||||
|
||||
if SERVER then
|
||||
util.AddNetworkString("StormFox2.feetfix")
|
||||
end
|
||||
|
||||
-- We use this to cache the last foot for the players.
|
||||
local lastFoot = {}
|
||||
hook.Add("PlayerFootstep", "StormFox2.lastfootprint", function(ply, pos, foot, sound, volume, filter, ...)
|
||||
lastFoot[ply] = foot
|
||||
end)
|
||||
-- Local functions
|
||||
--local noSpam = {}
|
||||
local cache = {}
|
||||
-- Returns the foot from sounddata
|
||||
local function GetFootstep(tab)
|
||||
local ent = tab.Entity
|
||||
if not ent or not IsValid(ent) then return end
|
||||
if not ent:IsPlayer() and not ent:IsNPC() and not ent:IsNextBot() then return end
|
||||
--if (noSpam[ent] or 0) > CurTime() then return end
|
||||
-- Check to see if it is a footstep
|
||||
local OriginalSnd = tab.OriginalSoundName:lower()
|
||||
local foot = -1
|
||||
if cache[OriginalSnd] then
|
||||
foot = cache[OriginalSnd]
|
||||
elseif string.match(OriginalSnd, "npc_antlionguard.farstep") or string.match(OriginalSnd, "npc_antlionguard.nearstep") then
|
||||
foot = lastFoot[ent] or -1
|
||||
elseif find(OriginalSnd, "stepleft",1,true) or find(OriginalSnd, "gallopleft",1,true) then
|
||||
foot = 0
|
||||
cache[OriginalSnd] = 0
|
||||
elseif find(OriginalSnd, "stepright",1,true) or find(OriginalSnd, "gallopright",1,true) then
|
||||
foot = 1
|
||||
cache[OriginalSnd] = 1
|
||||
elseif find(OriginalSnd, ".footstep",1,true) or find(tab.SoundName:lower(),"^player/footsteps",1) then
|
||||
foot = lastFoot[ent] or -1
|
||||
else -- Invalid
|
||||
return
|
||||
end
|
||||
-- No footstep spam
|
||||
--noSpam[ent] = CurTime() + 0.01
|
||||
return foot
|
||||
end
|
||||
-- TraceHull for the given entity
|
||||
local function EntTraceTexture(ent,pos) -- Returns the texture the entity is "on"
|
||||
local mt = ent:GetMoveType()
|
||||
if mt < 2 or mt > 3 then return end -- Not walking.
|
||||
local filter = ent
|
||||
if ent.GetViewEntity then
|
||||
filter = ent:GetViewEntity()
|
||||
end
|
||||
local t = util.TraceHull( {
|
||||
start = pos + Vector(0,0,30),
|
||||
endpos = pos + Vector(0,0,-60),
|
||||
maxs = ent:OBBMaxs(),
|
||||
mins = ent:OBBMins(),
|
||||
collisiongroup = ent:GetCollisionGroup(),
|
||||
filter = filter
|
||||
} )
|
||||
if not t.Hit then return end -- flying
|
||||
if t.Entity and IsValid(t.Entity) and t.HitNonWorld and t.HitTexture == "**studio**" then
|
||||
return
|
||||
end
|
||||
return t.HitTexture
|
||||
end
|
||||
-- Returns true if the entity is on replaced texture.
|
||||
local function IsOnReplacedTex(ent,snd,pos)
|
||||
if ent._sf2ns and ent._sf2ns > CurTime() then return false, ent._sf2nt or "nil" end
|
||||
ent._sf2ns = CurTime() + 0.1
|
||||
local sTexture = EntTraceTexture(ent,pos)
|
||||
ent._sf2nt = sTexture
|
||||
if not sTexture then return false,"nil" end
|
||||
local mat = Material(sTexture)
|
||||
if not mat then return false, sTexture end
|
||||
if mat:IsError() and (ent:IsNPC() or string.find(snd,"grass") or string.find(snd,"dirt")) then -- Used by maps
|
||||
return true, sTexture
|
||||
end
|
||||
if StormFox2.Terrain.HasMaterialChanged(mat) then return true, sTexture end
|
||||
return false,sTexture
|
||||
end
|
||||
-- Footstep overwrite and logic
|
||||
hook.Add("EntityEmitSound", "StormFox2.footstep.detecter", function(data)
|
||||
if not StormFox2.Terrain then return end
|
||||
local cT = StormFox2.Terrain.GetCurrent()
|
||||
if not cT then return end
|
||||
-- Only enable if we edit or need footsteps.
|
||||
if not (bAlwaysFootstep or (cT and cT.footstepLisen)) then return end
|
||||
-- Check if the server has disabled the footprint logic on their side.
|
||||
if SERVER and not game.SinglePlayer() and not StormFox2.Setting.GetCache("footprint_enablelogic",true) then return end
|
||||
-- Check if it is a footstep sound of some sort.
|
||||
local foot = GetFootstep(data) -- Returns [-1 = invalid, 0 = left, 1 = right]
|
||||
if not foot then return end
|
||||
-- Checks to see if the texturem the entity stands on, have been replaced.
|
||||
local bReplace, sTex = IsOnReplacedTex(data.Entity,data.SoundName:lower(),data.Pos or data.Entity:GetPos())
|
||||
-- Overwrite the sound if needed.
|
||||
local changed
|
||||
if bReplace and cT.footprintSnds then
|
||||
if cT.footprintSnds[2] then
|
||||
data.OriginalSoundName = cT.footprintSnds[2] .. (foot == 0 and "left" or "right")
|
||||
end
|
||||
if not cT.footprintSnds[1] then
|
||||
data.SoundName = "ambient/_period.wav"
|
||||
else
|
||||
data.SoundName = table.Random(cT.footprintSnds[1])
|
||||
data.OriginalSoundName = data.SoundName
|
||||
end
|
||||
changed = true
|
||||
end
|
||||
-- Call footstep hook
|
||||
hook.Run("StormFox2.terrain.footstep", data.Entity, foot, data.SoundName, sTex, bReplace )
|
||||
-- Singleplayer and server-sounds fix
|
||||
if SERVER and (game.SinglePlayer() or table.HasValue(NetL, data.Entity:GetClass())) then
|
||||
net.Start("StormFox2.feetfix",true)
|
||||
net.WriteEntity(data.Entity)
|
||||
net.WriteInt(foot or 1,2)
|
||||
net.WriteString(data.SoundName)
|
||||
net.WriteString(sTex)
|
||||
net.WriteBool(bReplace)
|
||||
net.Broadcast()
|
||||
end
|
||||
-- Call terrain function
|
||||
if cT.footstepFunc then
|
||||
cT.footstepFunc(data.Entity, foot, data.SoundName, sTex, bReplace)
|
||||
end
|
||||
return changed
|
||||
end)
|
||||
-- Singleplayer and entity fix
|
||||
if CLIENT then
|
||||
net.Receive("StormFox2.feetfix",function()
|
||||
local cT = StormFox2.Terrain.GetCurrent()
|
||||
if not cT then return end
|
||||
local ent = net.ReadEntity()
|
||||
if not IsValid(ent) then return end
|
||||
local foot = net.ReadInt(2)
|
||||
local sndName = net.ReadString()
|
||||
local sTex = net.ReadString()
|
||||
local bReplace = net.ReadBool()
|
||||
if cT.footstepFunc then
|
||||
cT.footstepFunc(ent, foot, sndName, sTex, bReplace)
|
||||
end
|
||||
hook.Run("StormFox2.terrain.footstep", ent, foot, sndName, sTex, bReplace)
|
||||
end)
|
||||
end
|
||||
--[[-------------------------------------------------------------------------
|
||||
Footprint render
|
||||
---------------------------------------------------------------------------]]
|
||||
if CLIENT then
|
||||
local sin,cos,rad,clamp,ceil,min = math.sin,math.cos,math.rad,math.Clamp,math.ceil,math.min
|
||||
local prints = {}
|
||||
local footstep_maxlife = 30
|
||||
local function ET(pos,pos2,mask,filter)
|
||||
local t = util.TraceLine( {
|
||||
start = pos,
|
||||
endpos = pos + pos2,
|
||||
mask = mask,
|
||||
filter = filter
|
||||
} )
|
||||
if not t then -- tracer failed, this should not happen. Create a fake result.
|
||||
local t = {}
|
||||
t.HitPos = pos + pos2
|
||||
return t
|
||||
end
|
||||
t.HitPos = t.HitPos or (pos + pos2)
|
||||
return t
|
||||
end
|
||||
local function AddPrint(ent,foot)
|
||||
-- Foot calc
|
||||
local velspeed = ent:GetVelocity():Length()
|
||||
local y = rad(ent:GetAngles().y)
|
||||
local fy = y + rad((foot * 2 - 1) * -90)
|
||||
local l = 5 * ent:GetModelScale()
|
||||
local ex = Vector(cos(fy) * l + cos(y) * l,sin(fy) * l + sin(y) * l,0)
|
||||
local pos = ent:GetPos() + ex
|
||||
-- Find impact
|
||||
local tr = ET(pos + Vector(0,0,20),Vector(0,0,-40),MASK_SOLID_BRUSHONLY,ent)
|
||||
if not tr.Hit then return end -- In space?
|
||||
-- If no bone_angle then angle math
|
||||
local normal = -tr.HitNormal
|
||||
-- CalcAng
|
||||
local yawoff
|
||||
if ent:IsPlayer() then
|
||||
yawoff = normal:Angle().y - ent:EyeAngles().y + 180
|
||||
else
|
||||
yawoff = normal:Angle().y - ent:GetAngles().y + 180
|
||||
end
|
||||
table.insert(prints,{tr.HitPos, normal,foot,ent:GetModelScale() or 1,CurTime() + footstep_maxlife,clamp(velspeed / 300,1,2),yawoff})
|
||||
-- pos, normal,foot,scale, life, lengh, yawoff
|
||||
end
|
||||
-- Footprint logic
|
||||
local BL = {"npc_hunter","monster_bigmomma","npc_vortigaunt","npc_dog","npc_fastzombie","npc_stalker"} -- Blacklist footprints
|
||||
local function CanPrint(ent)
|
||||
local c = ent:GetClass()
|
||||
for i,v in ipairs(BL) do
|
||||
if find(c, v,1,true) then return false end
|
||||
end
|
||||
if find(ent:GetModel(),"_torso",1,true) then return false end
|
||||
return true
|
||||
end
|
||||
hook.Add("StormFox2.terrain.footstep", "StormFox2.terrain.makefootprint", function(ent, foot, sSnd, sTexture, bReplace )
|
||||
if foot < 0 then return end -- Invalid foot
|
||||
if not bReplace and bAlwaysFootstep then -- This is a cold map, check for snow
|
||||
if not find(sTexture:lower(),"snow",1,true) then return end
|
||||
elseif bReplace then -- This is terrain
|
||||
local cT = StormFox2.Terrain.GetCurrent()
|
||||
if not cT then return end
|
||||
if not cT.footprints then return end
|
||||
else -- Invalid
|
||||
return
|
||||
end
|
||||
if not CanPrint(ent) then return end
|
||||
if not StormFox2.Setting.GetCache("footprint_enabled",true) then return end
|
||||
if StormFox2.Setting.GetCache("footprint_playeronly",false) and not ent:IsPlayer() then return end
|
||||
local n_max = StormFox2.Setting.GetCache("footprint_max",200)
|
||||
if #prints > n_max then
|
||||
table.remove(prints, 1)
|
||||
end
|
||||
AddPrint(ent,foot)
|
||||
end)
|
||||
-- Footprint render
|
||||
local mat = {Material("stormfox2/effects/foot_hq.png"),Material("stormfox2/effects/foot_hql.png"),Material("stormfox2/effects/foot_m.png"),Material("stormfox2/effects/foot_s.png")}
|
||||
local function getMat(q,foot)
|
||||
if q == 1 then
|
||||
if foot == 0 then
|
||||
return mat[2]
|
||||
else
|
||||
return mat[1]
|
||||
end
|
||||
end
|
||||
return mat[q + 1]
|
||||
end
|
||||
local DrawQuadEasy = render.DrawQuadEasy
|
||||
local bC = Color(0,0,0,255)
|
||||
hook.Add("PreDrawOpaqueRenderables","StormFox2.Terrain.Footprints",function()
|
||||
if not StormFox2.Setting.GetCache("footprint_enabled",true) then return end
|
||||
if #prints < 1 then return end
|
||||
local lp = StormFox2.util.RenderPos()
|
||||
local del = {}
|
||||
local footstep_dis = StormFox2.Setting.GetCache("footprint_distance",2000,"The renderdistance for footprints") ^ 2
|
||||
for k,v in pairs(prints) do
|
||||
local pos,normal,foot,scale,life,lengh,yawoff = v[1],v[2],v[3],v[4],v[5],v[6],v[7]
|
||||
local blend = life - CurTime()
|
||||
if blend <= 0 then
|
||||
table.insert(del,k)
|
||||
else
|
||||
local q = min(ceil(lp:DistToSqr(pos) / footstep_dis),4)
|
||||
if q >= 4 then continue end
|
||||
render.SetMaterial(getMat(q,foot))
|
||||
if foot == 0 and q > 1 then
|
||||
DrawQuadEasy( pos + Vector(0,0,q / 3 + 1), normal, 6 * scale, 10 * scale * lengh, bC, yawoff )
|
||||
else
|
||||
DrawQuadEasy( pos + Vector(0,0,q / 3), normal, -6 * scale, 10 * scale * lengh, bC, yawoff )
|
||||
end
|
||||
end
|
||||
end
|
||||
for i = #del,1,-1 do
|
||||
table.remove(prints,del[i])
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
-- If the map is cold or has snow, always check for footsteps.
|
||||
bAlwaysFootstep = StormFox2.Map.IsCold() or StormFox2.Map.HasSnow() -- This is a cold map.
|
||||
if CLIENT then
|
||||
StormFox2.Setting.AddCL("footprint_enabled",true) -- Add footprint setting
|
||||
StormFox2.Setting.AddCL("footprint_max",200) -- Add footprint setting
|
||||
StormFox2.Setting.AddCL("footprint_distance",2000) -- Add footprint setting
|
||||
StormFox2.Setting.AddCL("footprint_playeronly",false) -- Add footprint setting
|
||||
end
|
||||
StormFox2.Setting.AddSV("footprint_enablelogic",true)
|
||||
122
lua/stormfox2/functions/sh_tonemapcontroller.lua
Normal file
122
lua/stormfox2/functions/sh_tonemapcontroller.lua
Normal file
@@ -0,0 +1,122 @@
|
||||
--[[
|
||||
| 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("edit_tonemap", false, nil, "Effects")
|
||||
|
||||
if CLIENT then return end
|
||||
StormFox2.ToneMap = {}
|
||||
--SetBloomScale
|
||||
-- On load data
|
||||
local function LoadSettings()
|
||||
-- Locate tonemap
|
||||
local t = StormFox2.Map.FindClass("env_tonemap_controller")
|
||||
if #t < 1 then return end -- Unable to locate tonemap within BSP
|
||||
local targetname = t[1].targetname
|
||||
if not targetname then return end -- This tonemap can't have any settings
|
||||
-- Search for logic_auto
|
||||
local tab = {}
|
||||
for k, v in ipairs( StormFox2.Map.FindClass("logic_auto") ) do
|
||||
if not v.onmapspawn then continue end -- No setting?
|
||||
if not string.match(v.onmapspawn, "^" .. targetname .. ",") then continue end -- This targets tonemap.
|
||||
for s in string.gmatch(v.raw, '"OnMapSpawn"%s?"' .. targetname .. ',(.-)"') do
|
||||
local t = string.Explode(",", s)
|
||||
tab[t[1]] = t[2]
|
||||
end
|
||||
end
|
||||
return tab
|
||||
end
|
||||
|
||||
local DefaultSettings = LoadSettings()
|
||||
local ent
|
||||
local changed = false
|
||||
hook.Add("StormFox2.PostEntityScan", "StormFox2.ToneMapFind", function()
|
||||
ent = StormFox2.Ent.env_tonemap_controller and StormFox2.Ent.env_tonemap_controller[1]
|
||||
end)
|
||||
|
||||
do
|
||||
local last = 1
|
||||
|
||||
---Sets the tonemaps bloomscale. Use at own rist ask it looks like Soure engine doesn't like it.
|
||||
---@param num number
|
||||
---@server
|
||||
function StormFox2.ToneMap.SetBloomScale( num )
|
||||
if not ent or not DefaultSettings or not DefaultSettings.SetBloomScale then return end
|
||||
if last == num then return end
|
||||
ent:Fire("SetBloomScale",DefaultSettings.SetBloomScale * num)
|
||||
changed = true
|
||||
last = num
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local last = 1
|
||||
|
||||
---Sets the tonemaps exposure scale. Use at own rist ask it looks like Soure engine doesn't like it.
|
||||
---@param num number
|
||||
---@server
|
||||
function StormFox2.ToneMap.SetExposureScale( num )
|
||||
if not ent or not DefaultSettings then return end
|
||||
if last == num then return end
|
||||
ent:Fire("SetAutoExposureMax",(DefaultSettings.SetAutoExposureMax or 1) * num)
|
||||
ent:Fire("SetAutoExposureMin",(DefaultSettings.SetAutoExposureMin or 0) * num)
|
||||
changed = true
|
||||
last = num
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local last = 1
|
||||
|
||||
---Sets the tonemaps rate-scale. Use at own rist ask it looks like Soure engine doesn't like it.
|
||||
---@param num number
|
||||
---@server
|
||||
function StormFox2.ToneMap.SetTonemapRateScale( num )
|
||||
if not ent or not DefaultSettings then return end
|
||||
if last == num then return end
|
||||
ent:Fire("SetTonemapRate",(DefaultSettings.SetTonemapRate or 0.1) * num)
|
||||
changed = true
|
||||
last = num
|
||||
end
|
||||
end
|
||||
|
||||
---Resets the tonemap settings applied.
|
||||
---@server
|
||||
function StormFox2.ToneMap.Reset()
|
||||
if not changed or not ent then return end
|
||||
changed = false
|
||||
StormFox2.ToneMap.SetBloomScale( 1 )
|
||||
StormFox2.ToneMap.SetExposureScale( 1 )
|
||||
StormFox2.ToneMap.SetTonemapRateScale( 1 )
|
||||
end
|
||||
|
||||
local function getMaxLight()
|
||||
local c = StormFox2.Weather.Get("Clear")
|
||||
return c:Get("mapDayLight",80)
|
||||
end
|
||||
|
||||
local function ToneMapUpdate( lightlvlraw )
|
||||
if not StormFox2.Setting.SFEnabled() or not StormFox2.Setting.GetCache("edit_tonemap", true) then
|
||||
StormFox2.ToneMap.Reset()
|
||||
else
|
||||
StormFox2.ToneMap.SetExposureScale( lightlvlraw / 100 )
|
||||
end
|
||||
end
|
||||
|
||||
local last_Raw = 100
|
||||
-- Toggle tonemap with setting
|
||||
StormFox2.Setting.Callback("edit_tonemap",function()
|
||||
ToneMapUpdate(last_Raw)
|
||||
end,"sf_edit_tonemap")
|
||||
-- Save the last raw-lightlvl and update the tonemap
|
||||
hook.Add("StormFox2.lightsystem.new", "StormFox2.ToneMap-Controller", function(lightlvl, lightlvl_raw)
|
||||
last_Raw = lightlvl_raw
|
||||
ToneMapUpdate(lightlvl_raw)
|
||||
end)
|
||||
205
lua/stormfox2/functions/sh_tweaks.lua
Normal file
205
lua/stormfox2/functions/sh_tweaks.lua
Normal file
@@ -0,0 +1,205 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
-- Delete old skybox brushes
|
||||
if SERVER then
|
||||
hook.Add( "InitPostEntity", "DeleteBrushNEntity", function()
|
||||
for i, ent in ipairs( ents.GetAll() ) do
|
||||
if not IsValid(ent) then continue end
|
||||
if ent:GetClass() == "func_brush" and (ent:GetName() or "") == "daynight_brush" then
|
||||
SafeRemoveEntity(ent)
|
||||
elseif ent:CreatedByMap() and (ent:GetModel() or "") == "models/props/de_port/clouds.mdl" then
|
||||
ent:SetNoDraw( true )
|
||||
end
|
||||
end
|
||||
end )
|
||||
end
|
||||
|
||||
-- Foliage overwrite
|
||||
StormFox2.Setting.AddSV("override_foliagesway",true,nil, "Effects")
|
||||
if StormFox2.Setting.Get("override_foliagesway", true) and CLIENT then
|
||||
--[[
|
||||
Foliage_type:
|
||||
-2 - No treesway
|
||||
-1 - Tree trunk
|
||||
0 - Tree / w branches andor leaves
|
||||
1 - Branches / Leaves
|
||||
2 - Ground Plant
|
||||
Bendyness multiplier:
|
||||
1 - default
|
||||
mat_height:
|
||||
0 - height
|
||||
WaveBonus_speed:
|
||||
<number>
|
||||
]]
|
||||
|
||||
local default_foliage = {}
|
||||
default_foliage["models/msc/e_leaves"] = {1}
|
||||
default_foliage["models/msc/e_leaves2"] = {1}
|
||||
default_foliage["models/msc/e_bark3"] = {-1}
|
||||
|
||||
default_foliage["models/trees/japanese_tree_bark_02"] = {-1, 0.5}
|
||||
default_foliage["models/trees/japanese_tree_round_02"] = {1}
|
||||
default_foliage["models/trees/japanese_tree_round_03"] = {1}
|
||||
default_foliage["models/trees/japanese_tree_round_05"] = {1}
|
||||
|
||||
default_foliage["models/props_foliage/tree_deciduous_01a_leaves2"] = {1}
|
||||
default_foliage["models/msc/e_bigbush3"] = {2,4}
|
||||
default_foliage["models/props_coalmine/foliage1"] = {2}
|
||||
default_foliage["models/props_foliage/mall_trees_branches03"] = {2}
|
||||
default_foliage["models/props_foliage/tree_deciduous_01a_branches"] = {2}
|
||||
default_foliage["models/props_foliage/bramble01a"] = {2,0.4}
|
||||
default_foliage["models/props_foliage/leaves_bushes"] = {2}
|
||||
default_foliage["models/props_foliage/leaves"] = {2}
|
||||
default_foliage["models/props_foliage/cane_field01"] = {2,nil,0.3}
|
||||
--default_foliage["models/props_foliage/cattails"] = {2} Not working
|
||||
--default_foliage["models/props_foliage/trees_farm01"] = {-1,0.8,0.02,1.5} Doesn't look good on some trees
|
||||
default_foliage["models/props_foliage/cedar01_mip0"] = {0,0.4,0.02,3}
|
||||
default_foliage["models/props_foliage/coldstream_cedar_bark"] = {-1}
|
||||
default_foliage["models/props_foliage/coldstream_cedar_branches"] = {0}
|
||||
default_foliage["models/props_foliage/urban_trees_branches03"] = {0}
|
||||
default_foliage["models/props_foliage/bush"] = {2}
|
||||
default_foliage["models/props_foliage/corn_plant01"] = {1,3.4}
|
||||
default_foliage["models/props_foliage/detail_clusters"] = {2}
|
||||
default_foliage["models/cliffs/ferns01"] = {0,2,nil,2}
|
||||
default_foliage["models/props_foliage/rocks_vegetation"] = {0,4,nil,1,2}
|
||||
default_foliage["models/props_foliage/flower_barrel"] = {0,3,0.07,2}
|
||||
default_foliage["models/props_foliage/flower_barrel_dead"] = {0,1,0.07,2}
|
||||
default_foliage["models/props_foliage/flower_barrel_dead"] = {0,1,0.07,2}
|
||||
default_foliage["models/props/de_inferno/flower_barrel"] = {0,3,0.02,2}
|
||||
default_foliage["models/props_foliage/grass_01"] = {2,0.5}
|
||||
default_foliage["models/props_foliage/grass_02"] = {2,0.5}
|
||||
default_foliage["models/props_foliage/grass_clusters"] = {2}
|
||||
default_foliage["models/props_foliage/urban_trees_branches02_mip0"] = {-1}
|
||||
default_foliage["models/props_foliage/hedge_128"] = {2,0.8}
|
||||
default_foliage["models/props_foliage/foliage1"] = {2}
|
||||
default_foliage["models/props_foliage/hr_f/hr_medium_tree_color"] = {-1}
|
||||
default_foliage["models/props_foliage/ivy01"] = {2,0.1}
|
||||
default_foliage["models/props_foliage/mall_trees_branches01"] = {0,1,nil,2}
|
||||
default_foliage["models/props_foliage/mall_trees_barks01"] = {-1,1,nil,4}
|
||||
default_foliage["models/props_foliage/mall_trees_branches02"] = {-1,1,nil,4}
|
||||
--default_foliage["models/props_foliage/oak_tree01"] = {}
|
||||
default_foliage["models/props_foliage/potted_plants"] = {0,4,0.055}
|
||||
default_foliage["models/props_foliage/shrub_03"] = {2}
|
||||
default_foliage["models/props_foliage/shrub_03_skin2"] = {2}
|
||||
default_foliage["models/props_foliage/swamp_vegetation01"] = {-1,0.005,0.2}
|
||||
default_foliage["models/props_foliage/swamp_branches"] = {0,0.005,0.2,10}
|
||||
default_foliage["models/props_foliage/swamp_trees_branches01_large"] = {0,0.005,0.2,10}
|
||||
default_foliage["models/props_foliage/swamp_trees_barks_large"] = {0,0.005,0.2,10}
|
||||
default_foliage["models/props_foliage/swamp_trees_barks"] = {0,0.005,0.2,10}
|
||||
default_foliage["models/props_foliage/swamp_trees_branches01"] = {0,0.005,0.2,10}
|
||||
default_foliage["models/props_foliage/swamp_trees_barks_still"] = {0,0.005,0.2,10}
|
||||
default_foliage["models/props_foliage/swamp_trees_barks_generic"] = {0,0.005,0.2,10}
|
||||
default_foliage["models/props_foliage/swamp_shrubwall01"] = {2}
|
||||
default_foliage["models/props_foliage/swamp_trees_branches01_alphatest"] = {0,0.05}
|
||||
default_foliage["models/props_foliage/swamp_trees_branches01_still"] = {0,0.05}
|
||||
default_foliage["models/props_foliage/branch_city"] = {-1}
|
||||
default_foliage["models/props_foliage/arbre01"] = {-1,0.4,0.04,2}
|
||||
default_foliage["models/props_foliage/arbre01_b"] = {-1,0.05,nil,2}
|
||||
default_foliage["models/props_foliage/tree_deciduous_01a-lod.mdl"] = {}
|
||||
default_foliage["models/props_foliage/tree_deciduous_01a_lod"] = {-1}
|
||||
default_foliage["models/props_foliage/tree_pine_01_branches"] = {-2} -- Looks bad. Remove.
|
||||
default_foliage["models/props_foliage/pine_tree_large"] = {-1,0.8}
|
||||
default_foliage["models/props_foliage/pine_tree_large_snow"] = {-1,0.8}
|
||||
default_foliage["models/props_foliage/branches_farm01"] = {-1,0.2,0.8}
|
||||
default_foliage["models/props_foliage/urban_trees_branches03_small"] = {2,0.8}
|
||||
default_foliage["models/props_foliage/urban_trees_barks01_medium"] = {-1}
|
||||
default_foliage["models/props_foliage/urban_trees_branches03_medium"] = {0,2}
|
||||
default_foliage["models/props_foliage/urban_trees_barks01_medium"] = {-1,2,0.2}
|
||||
default_foliage["models/props_foliage/urban_trees_branches02_small"] = {2}
|
||||
default_foliage["models/props_foliage/urban_trees_barks01_clusters"] = {-1,0.2,0.2}
|
||||
default_foliage["models/props_foliage/urban_trees_branches01_clusters"] = {0,0.2,0.2}
|
||||
default_foliage["models/props_foliage/urban_trees_barks01"] = {-1,0.2}
|
||||
default_foliage["models/props_foliage/urban_trees_barks01_dry"] = {2,nil,10}
|
||||
default_foliage["models/props_foliage/leaves_large_vines"] = {0}
|
||||
default_foliage["models/props_foliage/vines01"] = {2,0.3}
|
||||
default_foliage["models/map_detail/foliage/foliage_01"] = {2,0.5}
|
||||
default_foliage["models/map_detail/foliage/detailsprites_01"] = {2}
|
||||
default_foliage["models/nita/ph_resortmadness/pg_jungle_plant"] = {0,1.2}
|
||||
default_foliage["models/nita/ph_resortmadness/plant_03"] = {-1,0.3}
|
||||
default_foliage["models/nita/ph_resortmadness/leaf_8"] = {0,2}
|
||||
default_foliage["models/nita/ph_resortmadness/fern_2"] = {0,2}
|
||||
default_foliage["models/nita/ph_resortmadness/tx_plant_02"] = {0,4,nil,4}
|
||||
default_foliage["models/nita/ph_resortmadness/tx_plant_04"] = {0,4,nil,4}
|
||||
default_foliage["models/nita/ph_resortmadness/orchid"] = {0,4,nil,4}
|
||||
default_foliage["models/props_foliage/ah_foliage_sheet001"] = {2,0.4}
|
||||
default_foliage["models/props_foliage/ah_apple_bark001"] = {2,0.4}
|
||||
|
||||
default_foliage["statua/nature/furcard1"] = {2,0.1}
|
||||
default_foliage["models/statua/shared/furcard1"] = {2,0.1}
|
||||
local max = math.max
|
||||
local function SetFoliageData(texture,foliage_type,bendyness,mat_height,wave_speed)
|
||||
if not texture then return end
|
||||
if not wave_speed then wave_speed = 0 end
|
||||
if not bendyness then bendyness = 1 end
|
||||
if not mat_height then mat_height = 0 end
|
||||
local mat = Material(texture)
|
||||
|
||||
if mat:IsError() then return end -- This client don't know what the material this is
|
||||
-- Enable / Disable the material
|
||||
if foliage_type < -1 then
|
||||
mat:SetInt("$treeSway",0)
|
||||
return
|
||||
end
|
||||
mat:SetInt("$treeSway",1) -- 0 is no sway, 1 is classic tree sway, 2 is an alternate, radial tree sway effect.
|
||||
-- 'Default' settings
|
||||
mat:SetFloat("$treeswayspeed",2) -- The treesway speed
|
||||
mat:SetFloat("$treeswayspeedlerpstart",1000) -- Sway starttime
|
||||
-- Default varables I don't know what do or doesn't have much to do with cl_tree_sway_dir
|
||||
mat:SetFloat("$treeswayscrumblefalloffexp",3)
|
||||
mat:SetFloat("$treeswayspeedhighwindmultiplier",0.2)
|
||||
mat:SetFloat("$treeswaystartradius",0)
|
||||
mat:SetFloat("$treeswayscrumblefrequency",6.6)
|
||||
mat:SetFloat("$treeswayspeedlerpend",2500 * bendyness)
|
||||
-- Special varables
|
||||
if foliage_type == -1 then --Trunk
|
||||
mat:SetFloat("$treeSwayStartHeight",mat_height) -- When it starts to sway
|
||||
mat:SetFloat("$treeswayheight",max(700 - bendyness * 100,0)) -- << How far up before XY starts to matter
|
||||
mat:SetFloat("$treeswayradius",max(110 - bendyness * 10,0)) -- ?
|
||||
mat:SetFloat("$treeswayscrumblespeed",3 + (wave_speed or 0)) -- ?
|
||||
mat:SetFloat("$treeswayscrumblestrength",0.1 * bendyness) -- "Strechyness"
|
||||
mat:SetFloat("$treeswaystrength",0) -- "Strechyness"
|
||||
elseif foliage_type == 0 then -- Trees
|
||||
mat:SetFloat("$treeSwayStartHeight",mat_height) -- When it starts to sway
|
||||
mat:SetFloat("$treeswayheight",max(700 - bendyness * 100,0)) -- << How far up before XY starts to matter
|
||||
mat:SetFloat("$treeswayradius",max(110 - bendyness * 10,0)) -- ?
|
||||
mat:SetFloat("$treeswayscrumblespeed",3 + (wave_speed or 0) ) -- ?
|
||||
mat:SetFloat("$treeswayscrumblestrength",0.1 * bendyness) -- "Strechyness"
|
||||
mat:SetFloat("$treeswaystrength",0) -- ?
|
||||
elseif foliage_type == 1 then -- Leaves
|
||||
mat:SetFloat("$treeSwayStartHeight",0.5 + mat_height / 2)
|
||||
mat:SetFloat("$treeswayheight",8)
|
||||
mat:SetFloat("$treeswayradius",1)
|
||||
mat:SetFloat("$treeswayscrumblespeed",1 + (wave_speed or 0))
|
||||
mat:SetFloat("$treeswayscrumblestrength",0.1)
|
||||
mat:SetFloat("$treeswaystrength",0.06 * bendyness)
|
||||
else
|
||||
mat:SetFloat("$treeSwayStartHeight",0.1 + mat_height / 10)
|
||||
mat:SetFloat("$treeswayheight",8)
|
||||
mat:SetFloat("$treeswayradius",1)
|
||||
mat:SetFloat("$treeswayscrumblespeed",wave_speed or 0)
|
||||
mat:SetFloat("$treeswayscrumblestrength",0)
|
||||
mat:SetFloat("$treeswaystrength",0.05 * bendyness)
|
||||
end
|
||||
mat:SetFloat("treeswaystatic", 0)
|
||||
end
|
||||
|
||||
hook.Add("stormfox2.postinit", "stormfox2.treeswayinit", function()
|
||||
for texture,data in pairs(default_foliage) do
|
||||
if not data or #data < 1 then continue end
|
||||
if data[1] < -1 then
|
||||
SetFoliageData(texture,-2)
|
||||
else
|
||||
SetFoliageData(texture,unpack(data))
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
40
lua/stormfox2/functions/sh_vfire.lua
Normal file
40
lua/stormfox2/functions/sh_vfire.lua
Normal file
@@ -0,0 +1,40 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
--[[-------------------------------------------------------------------------
|
||||
vFire support :D
|
||||
---------------------------------------------------------------------------]]
|
||||
|
||||
local vFireList = {}
|
||||
hook.Add("vFireOnCalculateWind","vFire - StormFox Handshake",function(vFireEnt)
|
||||
local outside = StormFox2.Wind.IsEntityInWind(vFireEnt)
|
||||
if outside then
|
||||
vFireList[vFireEnt] = true
|
||||
return StormFox2.Wind.GetVector() / 20
|
||||
end
|
||||
end)
|
||||
if CLIENT then return end
|
||||
local ran = math.random
|
||||
timer.Create("vFire - StormFox Rain",2,0,function()
|
||||
local r = StormFox2.Weather.GetRainAmount()
|
||||
if r <= 0 then table.Empty(vFireList) return end
|
||||
for ent,_ in pairs(vFireList) do
|
||||
if IsValid(ent) then
|
||||
ent:SoftExtinguish(r * ran(130,160))
|
||||
end
|
||||
end
|
||||
table.Empty(vFireList)
|
||||
end)
|
||||
|
||||
timer.Simple(2,function()
|
||||
if not vFireInstalled then return end
|
||||
StormFox2.Msg("Gee, vFire, what do you want to do tonight?")
|
||||
hook.Call("vFire - StormFox Handeshake")
|
||||
end)
|
||||
223
lua/stormfox2/functions/sv_mapio.lua
Normal file
223
lua/stormfox2/functions/sv_mapio.lua
Normal file
@@ -0,0 +1,223 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
--[[-------------------------------------------------------------------------
|
||||
Light entities: ( env_projectedtexture , light_dynamic, light, light_spot )
|
||||
Requirements:
|
||||
- Named "night" or "1" or "day".
|
||||
- Not have the name "indoor".
|
||||
|
||||
logic_relays support and map lights.
|
||||
dusk / night_events
|
||||
dawn / day_events
|
||||
weather_<type> Called when a weathertype gets applied
|
||||
weather_onchange Called when a weathertype changes
|
||||
weather_<type>_off Called when a weathertype gets removed
|
||||
|
||||
---------------------------------------------------------------------------]]
|
||||
|
||||
-- Special Relays
|
||||
local special_relays = {}
|
||||
special_relays.day_relays = {}
|
||||
special_relays.daytime_relays = {}
|
||||
special_relays.night_relays = {}
|
||||
special_relays.nighttime_relays = {}
|
||||
special_relays.weather_on = {}
|
||||
special_relays.weather_off = {}
|
||||
|
||||
local scanned = false
|
||||
local startingQ = {}
|
||||
hook.Add("StormFox2.InitPostEntity", "StormFox2.MapInteractions.SRelays", function()
|
||||
for _, ent in ipairs( ents.GetAll() ) do
|
||||
if not ent:IsValid() then continue end
|
||||
local class = ent:GetClass()
|
||||
if class == "logic_day_relay" then
|
||||
if ent:GetTriggerType() == 0 then -- Light change
|
||||
table.insert(special_relays.day_relays, ent)
|
||||
else
|
||||
table.insert(special_relays.daytime_relays, ent)
|
||||
end
|
||||
elseif class == "logic_night_relay" then
|
||||
if ent:GetTriggerType() == 0 then -- Light change
|
||||
table.insert(special_relays.night_relays, ent)
|
||||
else
|
||||
table.insert(special_relays.nighttime_relays, ent)
|
||||
end
|
||||
elseif class == "logic_weather_relay" then
|
||||
table.insert(special_relays.weather_on, ent)
|
||||
elseif class == "logic_weather_off_relay" then
|
||||
table.insert(special_relays.weather_off, ent)
|
||||
end
|
||||
end
|
||||
scanned = true
|
||||
for k, ent in ipairs( startingQ ) do
|
||||
if not ent:IsValid() then continue end
|
||||
ent:Trigger()
|
||||
end
|
||||
startingQ = {}
|
||||
end)
|
||||
local function triggerAll(tab)
|
||||
if not scanned then -- Wait until all entities are loaded
|
||||
for _, ent in ipairs(tab) do
|
||||
if not ent:IsValid() then continue end
|
||||
table.insert(startingQ, ent)
|
||||
end
|
||||
return
|
||||
end
|
||||
for _, ent in ipairs(tab) do
|
||||
if not ent:IsValid() then continue end
|
||||
ent:Trigger()
|
||||
end
|
||||
end
|
||||
|
||||
local night_lights = {{}, {}, {}, {}, {}, {}}
|
||||
local relays = {}
|
||||
local switch
|
||||
-- local functions
|
||||
local function setELight( ent, bTurnOn )
|
||||
local sOnOff = bTurnOn and "TurnOn" or "TurnOff"
|
||||
ent:Fire( sOnOff )
|
||||
end
|
||||
local function setLights( bTurnOn )
|
||||
if timer.Exists("StormFox2.mi.lights") then
|
||||
timer.Remove("StormFox2.mi.lights")
|
||||
end
|
||||
local i = 1
|
||||
timer.Create("StormFox2.mi.lights", 0.5, 6, function()
|
||||
for _,ent in ipairs(night_lights[i] or {}) do
|
||||
if not IsValid(ent) then continue end
|
||||
setELight(ent, bTurnOn)
|
||||
end
|
||||
i = i + 1
|
||||
end)
|
||||
end
|
||||
local function SetRelay(fMapLight)
|
||||
local lights_on = fMapLight < 20
|
||||
if switch ~= nil and lights_on == switch then return end -- Nothing changed
|
||||
if lights_on then
|
||||
StormFox2.Map.CallLogicRelay("night_events")
|
||||
triggerAll(special_relays.night_relays)
|
||||
setLights( true )
|
||||
else
|
||||
StormFox2.Map.CallLogicRelay("day_events")
|
||||
triggerAll(special_relays.day_relays)
|
||||
setLights( false )
|
||||
end
|
||||
switch = lights_on
|
||||
end
|
||||
|
||||
local includeNames = {
|
||||
["1"] = true,
|
||||
["streetlight"] = true,
|
||||
["streetlights"] = true
|
||||
}
|
||||
|
||||
local includeSearch = {
|
||||
["night"] = true,
|
||||
["day"] = true,
|
||||
-- ["lake"] = true, Used indoors .. for some reason
|
||||
["outdoor"] = true
|
||||
}
|
||||
|
||||
local excludeSearch = {
|
||||
["indoor"] = true,
|
||||
["ind_"] = true,
|
||||
["apt_"] = true
|
||||
}
|
||||
|
||||
local function Search(name, tab)
|
||||
for _, str in ipairs( tab ) do
|
||||
if string.format(name, str) then return true end
|
||||
end
|
||||
return false
|
||||
end
|
||||
local t = {"env_projectedtexture", "light_dynamic", "light", "light_spot"}
|
||||
hook.Add("StormFox2.InitPostEntity", "StormFox2.lightioinit", function()
|
||||
-- Locate lights on the map
|
||||
for i,ent in ipairs( ents.GetAll() ) do
|
||||
local c = ent:GetClass()
|
||||
if not table.HasValue(t, c) then continue end
|
||||
local name = ent:GetName()
|
||||
-- Unnamed entities
|
||||
if not name then
|
||||
if c == "light_spot" then
|
||||
table.insert(night_lights[ 1 + i % 6 ],ent)
|
||||
end
|
||||
continue
|
||||
end
|
||||
name = name:lower()
|
||||
-- Check for include
|
||||
if includeNames[name] then
|
||||
table.insert(night_lights[ 1 + i % 6 ],ent)
|
||||
continue
|
||||
end
|
||||
-- Check exclude
|
||||
if Search(name, excludeSearch) then
|
||||
continue
|
||||
end
|
||||
-- Check include
|
||||
if not Search(name, includeSearch) then
|
||||
continue
|
||||
end
|
||||
table.insert(night_lights[ 1 + i % 6 ],ent)
|
||||
end
|
||||
-- Update on launch
|
||||
timer.Simple(5, function()
|
||||
SetRelay(StormFox2.Map.GetLight())
|
||||
end)
|
||||
end)
|
||||
-- Call day and night relays
|
||||
hook.Add("StormFox2.lightsystem.new", "StormFox2.mapinteractions.light", SetRelay)
|
||||
|
||||
-- Call day andn ight time-related relays
|
||||
hook.Add("StormFox2.Time.OnDay", "StormFox2.mapinteractions.day", function()
|
||||
triggerAll( special_relays.daytime_relays )
|
||||
end)
|
||||
hook.Add("StormFox2.Time.OnNight", "StormFox2.mapinteractions.night", function()
|
||||
triggerAll( special_relays.nighttime_relays )
|
||||
end)
|
||||
|
||||
local function getRelayName( )
|
||||
local c_weather = StormFox2.Weather.GetCurrent()
|
||||
local relay = c_weather.Name
|
||||
if c_weather.LogicRelay then
|
||||
relay = c_weather.LogicRelay() or relay
|
||||
end
|
||||
return relay
|
||||
end
|
||||
|
||||
-- StormFox2.Map.w_CallLogicRelay( name )
|
||||
local lastWeather
|
||||
local function checkWRelay()
|
||||
local relay = getRelayName()
|
||||
relay = string.lower(relay)
|
||||
if lastWeather and lastWeather == relay then return end -- Nothing changed
|
||||
StormFox2.Map.w_CallLogicRelay( relay )
|
||||
local wP = StormFox2.Data.GetFinal("w_Percentage") or 0
|
||||
for k,ent in ipairs(special_relays.weather_on) do
|
||||
if ent:GetRequiredWeather() ~= relay then continue end
|
||||
if not ent:HasRequredAmount() then continue end
|
||||
ent:Trigger()
|
||||
end
|
||||
for k,ent in ipairs(special_relays.weather_off) do
|
||||
if ent:GetRequiredWeather() ~= lastWeather then continue end
|
||||
ent:Trigger()
|
||||
end
|
||||
lastWeather = relay
|
||||
end
|
||||
|
||||
hook.Add("StormFox2.weather.postchange", "StormFox2.mapinteractions" , function( sName ,nPercentage )
|
||||
timer.Simple(1, checkWRelay)
|
||||
end)
|
||||
|
||||
hook.Add("StormFox2.data.change", "StormFox2.mapinteractions.w_logic", function(sKey, nDay)
|
||||
if sKey ~= "Temp" then return end
|
||||
timer.Simple(1, checkWRelay)
|
||||
end)
|
||||
17
lua/stormfox2/functions/sv_menu.lua
Normal file
17
lua/stormfox2/functions/sv_menu.lua
Normal file
@@ -0,0 +1,17 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
|
||||
net.Receive(StormFox2.Net.Texture, function(len, ply)
|
||||
StormFox2.Permission.EditAccess(ply,"StormFox Settings", function()
|
||||
StormFox2.Map.ModifyMaterialType( net.ReadString(), net.ReadInt( 3 ))
|
||||
end)
|
||||
end)
|
||||
901
lua/stormfox2/functions/sv_weather_gen.lua
Normal file
901
lua/stormfox2/functions/sv_weather_gen.lua
Normal file
@@ -0,0 +1,901 @@
|
||||
--[[
|
||||
| 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.WeatherGen = StormFox2.WeatherGen or {}
|
||||
-- Settings
|
||||
local auto_weather = StormFox2.Setting.AddSV("auto_weather",true,nil, "Weather")
|
||||
local hide_forecast = StormFox2.Setting.AddSV("hide_forecast",false,nil, "Weather")
|
||||
util.AddNetworkString( "StormFox2.weekweather" )
|
||||
|
||||
local forecast = {} -- The forecast table
|
||||
local function SetForecast( tab, unix_time )
|
||||
forecast = tab
|
||||
forecast.unix_time = unix_time
|
||||
if not hide_forecast then return end
|
||||
net.Start("StormFox2.weekweather")
|
||||
net.WriteBool( unix_time )
|
||||
net.WriteTable( tab.temperature or {} )
|
||||
net.WriteTable( tab.weather or {} )
|
||||
net.WriteTable( tab.wind or {} )
|
||||
net.WriteTable( tab.windyaw or {} )
|
||||
net.Broadcast()
|
||||
end
|
||||
|
||||
---Returns the forecast data
|
||||
---@return table
|
||||
---@server
|
||||
function StormFox2.WeatherGen.GetForecast()
|
||||
return forecast
|
||||
end
|
||||
|
||||
---Returns true if we're using unix time for the forecast.
|
||||
---@return boolean
|
||||
---@server
|
||||
function StormFox2.WeatherGen.IsUnixTime()
|
||||
return forecast.unix_time or false
|
||||
end
|
||||
|
||||
-- Open Weather API Settings
|
||||
local api_MaxCalls = 59
|
||||
|
||||
local KEY_INVALID = 0
|
||||
local KEY_UNKNOWN = 1
|
||||
local KEY_VALID = 2
|
||||
|
||||
local KEY_STATUS = KEY_UNKNOWN
|
||||
|
||||
local API_ENABLE = StormFox2.Setting.AddSV("openweathermap_enabled",false,nil,"Weather")
|
||||
StormFox2.Setting.AddSV("openweathermap_lat",52,nil,"Weather",-180,180) -- Fake setting
|
||||
StormFox2.Setting.AddSV("openweathermap_lon",-2,nil,"Weather",-180,180) -- Fake setting
|
||||
|
||||
if SERVER then
|
||||
CreateConVar("sf_openweathermap_key", "", {FCVAR_ARCHIVE, FCVAR_PROTECTED}, "Sets the API key")
|
||||
CreateConVar("sf_openweathermap_real_lat","52.613909" , {FCVAR_ARCHIVE, FCVAR_PROTECTED}, "The real LAT for the API")
|
||||
CreateConVar("sf_openweathermap_real_lon","-2.005960" , {FCVAR_ARCHIVE, FCVAR_PROTECTED}, "The real LON for the API")
|
||||
end
|
||||
local key = StormFox2.Setting.AddSV("openweathermap_key", "", nil,"Weather")
|
||||
local location = StormFox2.Setting.AddSV("openweathermap_location", "", nil,"Weather") -- Fake setting
|
||||
local city = StormFox2.Setting.AddSV("openweathermap_city","",nil,"Weather") -- Fake setting
|
||||
|
||||
-- Keep them secret and never network them.
|
||||
key.isSecret = true
|
||||
location.isSecret = true
|
||||
city.isSecret = true
|
||||
local function onSuccessF( body, len, head, code )
|
||||
KEY_STATUS = KEY_VALID
|
||||
if not auto_weather:GetValue() then return end
|
||||
-- Most likly an invalid API-Key.
|
||||
local t = util.JSONToTable(body) or {}
|
||||
if code == 401 then
|
||||
KEY_STATUS = KEY_INVALID
|
||||
StormFox2.Warning(t.message or "API returned 401! Check your OpenWeatherMap account.")
|
||||
StormFox2.Setting.Set("openweathermap_enabled", false)
|
||||
return
|
||||
end
|
||||
if t.cod == "404" then return end -- Not found
|
||||
local timeZone = t.timezone and tonumber(t.timezone) or 0
|
||||
-- We can set the sunrise and sunset
|
||||
if t.sys and t.sys.sunrise and t.sys.sunset then
|
||||
local sunrise = os.date("!%H:%M",t.sys.sunrise + timeZone)
|
||||
local sunset = os.date("!%H:%M",t.sys.sunset + timeZone)
|
||||
StormFox2.Setting.Set("sunrise",StormFox2.Time.StringToTime(sunrise))
|
||||
StormFox2.Setting.Set("sunset",StormFox2.Time.StringToTime(sunset))
|
||||
end
|
||||
if t.main then
|
||||
-- Temperature
|
||||
local temp = StormFox2.Temperature.Convert("kelvin",nil,tonumber( t.main.temp or t.main.temp_min or t.main.temp_max ))
|
||||
StormFox2.Temperature.Set( temp, 1 )
|
||||
-- Weather
|
||||
local cloudyness = ( t.clouds and t.clouds.all or 0 ) / 110
|
||||
local rain = 0
|
||||
if t.rain then
|
||||
rain = math.max( t.rain["1h"] or 0, t.rain["3h"] or 0, 2) / 8
|
||||
elseif t.snow then
|
||||
rain = math.max( t.snow["1h"] or 0, t.snow["3h"] or 0, 2) / 8
|
||||
end
|
||||
if rain > 0 then
|
||||
StormFox2.Weather.Set("Rain", math.Round(rain * .7 + 0.2,2))
|
||||
elseif cloudyness >= 0.1 then
|
||||
StormFox2.Weather.Set("Cloud", math.Round(cloudyness, 2))
|
||||
else
|
||||
StormFox2.Weather.Set("Clear", 1)
|
||||
end
|
||||
-- Thunder
|
||||
local b_thunder = false
|
||||
if t.weather and t.weather[1] and t.weather[1].id and (rain > 0 or cloudyness >= 0.3) then
|
||||
local id = t.weather[1].id
|
||||
b_thunder = ( id >= 200 and id <= 202 ) or ( id >= 210 and id <= 212 ) or ( id >= 230 and id <= 232 ) or id == 212
|
||||
end
|
||||
StormFox2.Thunder.SetEnabled(b_thunder, id == 212 and 12 or 6) -- 212 is heavy thunderstorm
|
||||
-- Wind
|
||||
StormFox2.Wind.SetForce( t.wind and t.wind.speed or 0 )
|
||||
StormFox2.Wind.SetYaw( t.wind and t.wind.deg or 0 )
|
||||
end
|
||||
end
|
||||
local n_NextAllowedCall = 0
|
||||
local b_BlockNextW = false
|
||||
local function UpdateLiveWeather( api_key )
|
||||
if b_BlockNextW then return end
|
||||
if KEY_STATUS == KEY_INVALID then return end
|
||||
if n_NextAllowedCall >= CurTime() then
|
||||
return StormFox2.Warning("API can't be called that often!")
|
||||
end
|
||||
n_NextAllowedCall = CurTime() + (60 / api_MaxCalls)
|
||||
local lat = GetConVar("sf_openweathermap_real_lat"):GetString()
|
||||
local lon = GetConVar("sf_openweathermap_real_lon"):GetString()
|
||||
local api_key = api_key or GetConVar("sf_openweathermap_key"):GetString()
|
||||
http.Fetch("http://api.openweathermap.org/data/2.5/weather?lat=" .. lat .. "&lon=" .. lon .. "&appid=" .. api_key, onSuccessF)
|
||||
end
|
||||
|
||||
local function onSuccessForecast( body, len, head, code )
|
||||
if KEY_STATUS == KEY_INVALID then return end
|
||||
local t = util.JSONToTable(body) or {}
|
||||
if code == 401 then
|
||||
KEY_STATUS = KEY_INVALID
|
||||
StormFox2.Warning(t.message or "API returned 401! Check your OpenWeatherMap account.")
|
||||
StormFox2.Setting.Set("openweathermap_enabled", false)
|
||||
return
|
||||
end
|
||||
if t.cod == "404" then return end -- Not found
|
||||
if not t.list then return end -- ??
|
||||
local forecast = {}
|
||||
forecast.temperature= {}
|
||||
forecast.weather = {}
|
||||
forecast.wind = {}
|
||||
forecast.windyaw = {}
|
||||
|
||||
local last_time = -1
|
||||
local ex_time = 0
|
||||
for k, v in ipairs( t.list ) do
|
||||
if not v.main then continue end -- ERR
|
||||
--local timestr = string.match(v.dt_txt, "(%d+:%d+:%d)")
|
||||
--local c = string.Explode(":", timestr)
|
||||
--local h, m, s = c[1] or "0", c[2] or "0", c[3] or "0"
|
||||
--local time = ( tonumber( h ) or 0 ) * 60 + (tonumber( m ) or 0) + (tonumber( s ) or 0) / 60
|
||||
--if time < last_time then -- New day
|
||||
-- ex_time = ex_time + 1440
|
||||
-- last_time = time
|
||||
--else
|
||||
-- last_time = time
|
||||
--end
|
||||
-- New time: time + ex_time
|
||||
--local timeStamp = time + ex_time
|
||||
local timeStamp = v.dt
|
||||
if timeStamp > 1440 then
|
||||
if k%2 == 1 then
|
||||
continue
|
||||
end
|
||||
elseif timeStamp > 2440 then
|
||||
continue
|
||||
end
|
||||
|
||||
local temp = StormFox2.Temperature.Convert("kelvin",nil,tonumber( v.main.temp or v.main.temp_min or v.main.temp_max ))
|
||||
|
||||
local cloudyness = ( t.clouds and t.clouds.all or 0 ) / 110
|
||||
local rain = 0
|
||||
local w_type = "Clear"
|
||||
local w_procent = 0
|
||||
if v.rain then
|
||||
rain = math.max( v.rain["1h"] or 0, v.rain["3h"] or 0, 2) / 8
|
||||
elseif v.snow then
|
||||
rain = math.max( v.snow["1h"] or 0, v.snow["3h"] or 0, 2) / 8
|
||||
end
|
||||
if rain > 0 then
|
||||
w_procent = math.Round(rain * .7 + 0.2,2)
|
||||
w_type = "Rain"
|
||||
elseif cloudyness > 0.1 then
|
||||
w_procent = math.Round(cloudyness, 2)
|
||||
w_type = "Cloud"
|
||||
end
|
||||
local b_thunder = false
|
||||
if v.weather and v.weather[1] and v.weather[1].id and (rain > 0 or cloudyness >= 0.3) then
|
||||
local id = v.weather[1].id
|
||||
b_thunder = ( id >= 200 and id <= 202 ) or ( id >= 210 and id <= 212 ) or ( id >= 230 and id <= 232 ) or id == 212
|
||||
end
|
||||
local wind = v.wind and v.wind.speed or 0
|
||||
local windyaw = v.wind and v.wind.deg or 0
|
||||
|
||||
table.insert(forecast.temperature, {timeStamp, temp})
|
||||
table.insert(forecast.weather, {timeStamp, {
|
||||
["sName"] = w_type,
|
||||
["fAmount"] = w_procent
|
||||
}})
|
||||
table.insert(forecast.wind, {timeStamp, wind})
|
||||
table.insert(forecast.windyaw, {timeStamp, windyaw})
|
||||
end
|
||||
SetForecast( forecast, true )
|
||||
end
|
||||
|
||||
local function UpdateLiveFeed( api_key )
|
||||
if KEY_STATUS == KEY_INVALID then return end
|
||||
local lat = GetConVar("sf_openweathermap_real_lat"):GetString()
|
||||
local lon = GetConVar("sf_openweathermap_real_lon"):GetString()
|
||||
local api_key = api_key or GetConVar("sf_openweathermap_key"):GetString()
|
||||
http.Fetch("http://api.openweathermap.org/data/2.5/forecast?lat=" .. lat .. "&lon=" .. lon .. "&appid=" .. api_key, onSuccessForecast)
|
||||
end
|
||||
|
||||
local function SetCity( sCityName, callBack )
|
||||
if KEY_STATUS == KEY_INVALID then return end
|
||||
if n_NextAllowedCall >= CurTime() then
|
||||
return StormFox2.Warning("API can't be called that often!")
|
||||
end
|
||||
n_NextAllowedCall = CurTime() + (60 / api_MaxCalls)
|
||||
http.Fetch("http://api.openweathermap.org/data/2.5/weather?q=" .. sCityName .. "&appid=" .. GetConVar("sf_openweathermap_key"):GetString(), function( body, len, head, code )
|
||||
-- Most likly an invalid API-Key.
|
||||
local t = util.JSONToTable(body) or {}
|
||||
if code == 401 then
|
||||
KEY_STATUS = KEY_INVALID
|
||||
StormFox2.Warning(t.message or "API returned 401")
|
||||
StormFox2.Setting.Set("openweathermap_enabled", false)
|
||||
return
|
||||
end
|
||||
if t.cod == 404 or not t.coord then -- City not found
|
||||
if callBack then callBack( false ) end
|
||||
return
|
||||
end
|
||||
b_BlockNextW = true -- Stop the setting from updating the weather again
|
||||
local lat = tonumber( t.coord.lat )
|
||||
RunConsoleCommand( "sf_openweathermap_real_lat", lat )
|
||||
StormFox2.Setting.Set("openweathermap_lat",math.Round(lat)) -- Fake settings
|
||||
|
||||
local lon = tonumber( t.coord.lon )
|
||||
RunConsoleCommand( "sf_openweathermap_real_lon", lon )
|
||||
StormFox2.Setting.Set("openweathermap_lon",math.Round(lon)) -- Fake settings
|
||||
b_BlockNextW = false
|
||||
onSuccessF( body, len, head, code )
|
||||
|
||||
-- We found a city. Make the forecast
|
||||
timer.Simple(1, UpdateLiveFeed)
|
||||
if callBack then callBack( true ) end
|
||||
end)
|
||||
end
|
||||
--- Update Value
|
||||
key:AddCallback( function( sString )
|
||||
RunConsoleCommand( "sf_openweathermap_key", sString )
|
||||
key.value = "" -- Silent set it again
|
||||
KEY_STATUS = KEY_UNKNOWN
|
||||
UpdateLiveWeather( sString ) -- Try and set the weather
|
||||
end)
|
||||
location:AddCallback( function( sString )
|
||||
local num = tonumber( string.match(sString, "[-%d]+") or "0" ) or 0
|
||||
if sString:sub(0, 1) == "a" then
|
||||
RunConsoleCommand( "sf_openweathermap_real_lat", num )
|
||||
StormFox2.Setting.Set("openweathermap_lat",math.Round(num)) -- Fake settings
|
||||
else
|
||||
RunConsoleCommand( "sf_openweathermap_real_lon", num )
|
||||
StormFox2.Setting.Set("openweathermap_lon",math.Round(num)) -- Fake settings
|
||||
end
|
||||
location.value = "" -- Silent set it again
|
||||
UpdateLiveWeather() -- Set the weather to the given location
|
||||
timer.Simple(1, UpdateLiveFeed)
|
||||
end)
|
||||
city:AddCallback( function( cityName )
|
||||
if cityName == "" then return end
|
||||
SetCity( cityName )
|
||||
city.value = "" -- Silent set it again
|
||||
end)
|
||||
|
||||
-- Enable and disable API
|
||||
local status = false
|
||||
local function EnableAPI()
|
||||
if status then return end
|
||||
timer.Create("SF_WGEN_API", 5 * 60, 0, function()
|
||||
if not auto_weather:GetValue() then return end
|
||||
if not status then return end
|
||||
UpdateLiveWeather()
|
||||
end)
|
||||
timer.Simple(1, UpdateLiveFeed)
|
||||
end
|
||||
local function DisableAPI()
|
||||
if not status then return end
|
||||
timer.Destroy("SF_WGEN_API")
|
||||
end
|
||||
local function IsUsingAPI()
|
||||
return status
|
||||
end
|
||||
|
||||
-- Weather Gen Settings
|
||||
local max_days_generate = 7
|
||||
local min_temp = StormFox2.Setting.AddSV("min_temp",-10,nil,"Weather",-273.15)
|
||||
local max_temp = StormFox2.Setting.AddSV("max_temp",20,nil, "Weather")
|
||||
local max_wind = StormFox2.Setting.AddSV("max_wind",50,nil, "Weather")
|
||||
local night_temp= StormFox2.Setting.AddSV("addnight_temp",-7,nil, "Weather")
|
||||
local function toStr( num )
|
||||
local c = tostring( num )
|
||||
return string.rep("0", 4 - #c) .. c
|
||||
end
|
||||
local default
|
||||
local function SplitSetting( str )
|
||||
if #str< 20 then return default end -- Invalid, use default
|
||||
local tab = {}
|
||||
local min = math.min(100, string.byte(str, 1,1) - 33 ) / 100
|
||||
local max = math.min(100, string.byte(str, 2,2) - 33 ) / 100
|
||||
tab.amount_min = math.min(min, max)
|
||||
tab.amount_max = math.max(min, max)
|
||||
|
||||
local min = math.min(1440,tonumber( string.sub(str, 3, 6) ) or 0)
|
||||
local max = math.min(1440,tonumber( string.sub(str, 7, 10) ) or 0)
|
||||
tab.start_min = math.min(min, max)
|
||||
tab.start_max = math.max(min, max)
|
||||
|
||||
local min = tonumber( string.sub(str, 11, 14) ) or 0
|
||||
local max = tonumber( string.sub(str, 15, 18) ) or 0
|
||||
|
||||
tab.length_min = math.min(min, max)
|
||||
tab.length_max = math.max(min, max)
|
||||
|
||||
tab.thunder = string.sub(str, 19, 19) == "1"
|
||||
tab.pr_week = tonumber( string.sub(str, 20) ) or 0
|
||||
return tab
|
||||
end
|
||||
local function CombineSetting( tab )
|
||||
local c =string.char( 33 + (tab.amount_min or 0) * 100 )
|
||||
c = c .. string.char( 33 + (tab.amount_max or 0) * 100 )
|
||||
|
||||
c = c .. toStr(math.Clamp( math.Round( tab.start_min or 0), 0, 1440 ) )
|
||||
c = c .. toStr(math.Clamp( math.Round( tab.start_max or 0), 0, 1440 ) )
|
||||
|
||||
c = c .. toStr(math.Clamp( math.Round( tab.length_min or 360 ), 180, 9999) )
|
||||
c = c .. toStr(math.Clamp( math.Round( tab.length_max or 360 ), 180, 9999) )
|
||||
|
||||
c = c .. (tab.thunder and "1" or "0")
|
||||
|
||||
c = c .. tostring( tab.pr_week or 2 )
|
||||
return c
|
||||
end
|
||||
local default_setting = {}
|
||||
default_setting["Rain"] = CombineSetting({
|
||||
["amount_min"] = 0.4,
|
||||
["amount_max"] = 0.9,
|
||||
["start_min"] = 300,
|
||||
["start_max"] = 1200,
|
||||
["length_min"] = 360,
|
||||
["length_max"] = 1200,
|
||||
["thunder"] = true,
|
||||
["pr_week"] = 3
|
||||
})
|
||||
default_setting["Cloud"] = CombineSetting({
|
||||
["amount_min"] = 0.2,
|
||||
["amount_max"] = 0.7,
|
||||
["start_min"] = 300,
|
||||
["start_max"] = 1200,
|
||||
["length_min"] = 360,
|
||||
["length_max"] = 1200,
|
||||
["pr_week"] = 3
|
||||
})
|
||||
default_setting["Clear"] = CombineSetting({
|
||||
["amount_min"] = 1,
|
||||
["amount_max"] = 1,
|
||||
["start_min"] = 0,
|
||||
["start_max"] = 1440,
|
||||
["length_min"] = 360,
|
||||
["length_max"] = 1440,
|
||||
["pr_week"] = 7
|
||||
})
|
||||
-- Morning fog
|
||||
default_setting["Fog"] = CombineSetting({
|
||||
["amount_min"] = 0.15,
|
||||
["amount_max"] = 0.30,
|
||||
["start_min"] = 360,
|
||||
["start_max"] = 560,
|
||||
["length_min"] = 160,
|
||||
["length_max"] = 360,
|
||||
["pr_week"] = 1
|
||||
})
|
||||
default = CombineSetting({
|
||||
["amount_min"] = 0.4,
|
||||
["amount_max"] = 0.9,
|
||||
["start_min"] = 300,
|
||||
["start_max"] = 1200,
|
||||
["length_min"] = 300,
|
||||
["length_max"] = 1200,
|
||||
["pr_week"] = 0
|
||||
})
|
||||
-- Create settings for weather-types.
|
||||
local weather_setting = {}
|
||||
local OnWeatherSettingChange
|
||||
local function call( newVar, oldVar, sName )
|
||||
sName = string.match(sName, "wgen_(.+)") or sName
|
||||
weather_setting[sName] = SplitSetting( newVar )
|
||||
OnWeatherSettingChange()
|
||||
end
|
||||
hook.Add("stormfox2.postloadweather", "StormFox2.WeatherGen.Load", function()
|
||||
for _, sName in ipairs( StormFox2.Weather.GetAll() ) do
|
||||
local str = default_setting[sName] or default
|
||||
local obj = StormFox2.Setting.AddSV("wgen_" .. sName,str,nil,"Weather")
|
||||
obj:AddCallback( call )
|
||||
weather_setting[sName] = SplitSetting( obj:GetValue() )
|
||||
end
|
||||
end)
|
||||
for _, sName in ipairs( StormFox2.Weather.GetAll() ) do
|
||||
local str = default_setting[sName] or default
|
||||
local obj = StormFox2.Setting.AddSV("wgen_" .. sName,str,nil,"Weather")
|
||||
obj:AddCallback( call, "updateWSetting" )
|
||||
weather_setting[sName] = SplitSetting( obj:GetValue() )
|
||||
end
|
||||
local function SetWeatherSetting(sName, tab)
|
||||
if CLIENT then return end
|
||||
StormFox2.Setting.SetValue("wgen_" .. sName, CombineSetting(tab))
|
||||
end
|
||||
-- Returns the lowest key that is higer than the inputed key.
|
||||
-- Second return is the higest key that is lower than the inputed key.
|
||||
local function getClosestKey( tab, key)
|
||||
local s, ls
|
||||
for k, v in ipairs( table.GetKeys(tab) ) do
|
||||
if v < key then
|
||||
if not ls or ls < v then
|
||||
ls = v
|
||||
end
|
||||
else
|
||||
if not s or s > v then
|
||||
s = v
|
||||
end
|
||||
end
|
||||
end
|
||||
return s, ls or 0
|
||||
end
|
||||
local generator = {} -- Holds all the days
|
||||
local day = {}
|
||||
day.__index = day
|
||||
local function CreateDay()
|
||||
local t = {}
|
||||
t._temperature = {}
|
||||
t._wind = {}
|
||||
t._windyaw = {}
|
||||
t._weather = {}
|
||||
setmetatable(t, day)
|
||||
table.insert(generator, t)
|
||||
if #generator > max_days_generate then
|
||||
table.remove(generator, 1)
|
||||
end
|
||||
return t
|
||||
end
|
||||
local lastTemp
|
||||
function day:SetTemperature( nTime, nCelcius )
|
||||
-- I got no clue why it tries to set values outside, but clamp it here just in case.
|
||||
nCelcius = math.Clamp(nCelcius, min_temp:GetValue(), max_temp:GetValue())
|
||||
self._temperature[nTime] = nCelcius
|
||||
lastTemp = nCelcius
|
||||
return self
|
||||
end
|
||||
function day:GetTemperature( nTime )
|
||||
return self._temperature[nTime]
|
||||
end
|
||||
local lastWind, lastWindYaw
|
||||
local lastLastWind
|
||||
function day:SetWind( nTime, nWind, nWindYaw )
|
||||
self._wind[nTime] = nWind
|
||||
self._windyaw[nTime] = nWindYaw
|
||||
lastLastWind = lastWind
|
||||
lastWind = nWind
|
||||
lastWindYaw = nWindYaw
|
||||
return self
|
||||
end
|
||||
function day:GetWind( nTime )
|
||||
return self._wind[nTime], self._windyaw[nTime]
|
||||
end
|
||||
function day:SetWeather( sName, nStart, nDuration, nAmount, nThunder )
|
||||
self._weather[nStart] = {
|
||||
["sName"] = sName,
|
||||
["nStart"] = nStart,
|
||||
["nDuration"] = nDuration,
|
||||
["fAmount"] = nAmount,
|
||||
["nThunder"] = nThunder }
|
||||
self._last = math.max(self._last or 0, nStart + nDuration)
|
||||
end
|
||||
function day:GetWeather( nTime )
|
||||
return self._weather[nTime]
|
||||
end
|
||||
function day:GetWeathers()
|
||||
return self._weather
|
||||
end
|
||||
function day:GetLastWeather()
|
||||
return self._weather[self._last]
|
||||
end
|
||||
local function GetLastDay()
|
||||
return generator[#generator]
|
||||
end
|
||||
local weatherWeekCount = {}
|
||||
local function CanGenerateWeather( sName )
|
||||
local count = weatherWeekCount[ sName ] or 0
|
||||
local setting = weather_setting[ sName ]
|
||||
if not setting then return false end -- Invalid weahter? Ignore this.
|
||||
local pr_week = setting.pr_week or 0
|
||||
if pr_week <= 0 then return false end -- Disabled
|
||||
if pr_week < 1 then -- Floats between 0 and 1 is random.
|
||||
pr_week = math.random(0, 1 / pr_week) <= 1 and 1 or 0
|
||||
end
|
||||
if count >= pr_week then return false end -- This weahter is reached max for this week
|
||||
return true
|
||||
end
|
||||
local function SortList()
|
||||
local t = {}
|
||||
for _, sName in pairs(StormFox2.Weather.GetAll()) do
|
||||
t[sName] = weatherWeekCount[sName] or 0
|
||||
end
|
||||
return table.SortByKey(t, true)
|
||||
end
|
||||
local function UpdateWeekCount()
|
||||
weatherWeekCount = {}
|
||||
for k, day in ipairs( generator ) do
|
||||
for nTime, weather in pairs( day:GetWeathers() ) do
|
||||
local sName = weather.sName
|
||||
weatherWeekCount[sName] = (weatherWeekCount[sName] or 0) + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
local atemp = math.random(-4, 4)
|
||||
local nextWeatherOverflow = 0
|
||||
local function GenerateDay()
|
||||
local newDay = CreateDay()
|
||||
UpdateWeekCount()
|
||||
-- Handle temperature
|
||||
do
|
||||
local mi, ma = min_temp:GetValue(), max_temp:GetValue()
|
||||
local ltemp = lastTemp or math.random(mi, ma)
|
||||
local aftemp = -math.min(ltemp - mi, 12) -- The closer the temperature is to minimum, the lower min
|
||||
local ahtemp = math.min(ma - ltemp, 12) -- The closer the temperature is to maximum, the lower max
|
||||
atemp = atemp + math.Rand(-4, 4) -- How much the temperature goes up or down
|
||||
atemp = math.Clamp(atemp, aftemp, ahtemp)
|
||||
-- UnZero
|
||||
local tempBoost = 7 - math.abs( ltemp + atemp )
|
||||
if tempBoost > 0 then
|
||||
if atemp >= 0 then
|
||||
atemp = math.max(atemp + tempBoost, tempBoost)
|
||||
else
|
||||
atemp = math.min(atemp - tempBoost, -tempBoost)
|
||||
end
|
||||
end
|
||||
-- Spikes
|
||||
if math.random(10) > 8 then
|
||||
-- Create a spike
|
||||
if ltemp + atemp >= 0 then
|
||||
atemp = mi / 2
|
||||
else
|
||||
atemp = ma / 2
|
||||
end
|
||||
end
|
||||
-- New temp
|
||||
local newMidTemp = math.Round(math.Clamp(ltemp + atemp, mi + 4, ma), 1)
|
||||
-- Make the new temperature
|
||||
|
||||
local h = StormFox2.Sun.GetSunRise()
|
||||
local n_temp = night_temp:GetValue() or -7
|
||||
local sunDown = StormFox2.Sun.GetSunSet() + math.random(-180, 180) - 180
|
||||
newDay:SetTemperature( sunDown, newMidTemp )
|
||||
newDay:SetTemperature( h - 180, math.max(newMidTemp + math.random(n_temp / 2, n_temp), mi) )
|
||||
lastTemp = newMidTemp -- To make sure night-temp, don't effect the overall temp
|
||||
end
|
||||
-- Handle wind
|
||||
local newWind
|
||||
do
|
||||
--lastWind, lastWindYaw
|
||||
if not lastWind then
|
||||
lastWind = math.random(5)
|
||||
lastWindYaw = math.random(360)
|
||||
end
|
||||
local buff = math.abs(atemp) - 4 -- Wind tent to increase the more temp changes. Also add a small negative modifier
|
||||
if math.random(1, 50) >= 49 and buff > 4 then -- Sudden Storm
|
||||
buff = buff + 10
|
||||
end
|
||||
local addforce = math.random(buff / 2, buff - math.abs(lastLastWind or 0))
|
||||
newWind = math.min(max_wind:GetValue(), math.max(0, lastWind + addforce))
|
||||
local yawChange = math.min(40, lastWind + addforce * 15)
|
||||
newDay:SetWind( math.random(180, 1080), newWind, ( lastWindYaw + math.random(-yawChange, yawChange) ) % 360 )
|
||||
end
|
||||
-- Handle weather
|
||||
local i = 3 -- Only generates 2 types of weathers pr day at max
|
||||
local _last = nextWeatherOverflow -- The next empty-time of the day
|
||||
for _, sName in ipairs( SortList() ) do
|
||||
if _last >= 1440 then continue end -- This day is full of weathers. Ignore.
|
||||
if sName == "Clear" and math.random(0, newWind) < newWind * 0.8 then -- Roll a dice between 0 and windForce. If dice is below 80%, try and find another weahter instead.
|
||||
if atemp > 0 then -- Warm weather tent to clear up the weather
|
||||
break
|
||||
elseif atemp < 0 then -- Colder weather will form weather
|
||||
continue
|
||||
end
|
||||
end
|
||||
-- Check if weather is enabled, and we haven't reached max.
|
||||
if not CanGenerateWeather( sName ) then continue end
|
||||
local setting = weather_setting[sName]
|
||||
local minS, maxS = setting.start_min, setting.start_max
|
||||
local minL, maxL = setting.length_min, setting.length_max
|
||||
if _last >= maxS then continue end -- This weather can't be generated this late.
|
||||
i = i - 1
|
||||
if i <= 0 then break end
|
||||
local start_time = math.random(math.max(minS, _last), maxS)
|
||||
local length_time = math.random(minL, maxL)
|
||||
local amount = math.Rand(setting.amount_min, setting.amount_max)
|
||||
local nThunder
|
||||
if setting.thunder and amount > 0.5 and math.random(0, 10) > 7 then
|
||||
nThunder = math.random(4,8)
|
||||
end
|
||||
newDay:SetWeather( sName, start_time, length_time, amount, nThunder )
|
||||
_last = start_time + length_time
|
||||
end
|
||||
nextWeatherOverflow = math.max(0, _last - 1440)
|
||||
end
|
||||
local function GenerateWeek()
|
||||
for i = 1, max_days_generate do
|
||||
GenerateDay()
|
||||
end
|
||||
end
|
||||
local enable = false
|
||||
local function IsUsingWeatherGen()
|
||||
return enable
|
||||
end
|
||||
local function TimeToIndex( tab )
|
||||
local c = table.GetKeys( tab )
|
||||
local a = {}
|
||||
table.sort(c)
|
||||
for i = 1, #c do
|
||||
a[i] = {c[i], tab[c[i]]}
|
||||
end
|
||||
return a
|
||||
end
|
||||
local wGenList = {}
|
||||
local function PushDayToList() -- Merges the 7 days into one long line. Its more stable this way
|
||||
-- empty forecast
|
||||
wGenList = {}
|
||||
wGenList._temperature = {}
|
||||
wGenList._wind = {}
|
||||
wGenList._windyaw = {}
|
||||
wGenList._weather = {}
|
||||
local lastWType = "Clear"
|
||||
local lastWTime = -100
|
||||
for i = 1, 4 do
|
||||
local f = {}
|
||||
local day = generator[i]
|
||||
for nTime, var in pairs( day._temperature ) do
|
||||
wGenList._temperature[ nTime + (i - 1) * 1440 ] = var
|
||||
end
|
||||
for nTime, var in pairs( day._wind ) do
|
||||
local nn = nTime + (i - 1) * 1440
|
||||
wGenList._wind[ nn ] = var
|
||||
wGenList._windyaw[ nn ] = day._windyaw[ nTime ]
|
||||
end
|
||||
for nTime, var in pairs( day._weather ) do
|
||||
if var.sName == "Clear" then -- Ignore clear weathers. They're default.
|
||||
lastWType = "Clear"
|
||||
continue
|
||||
end
|
||||
local nTimeStart = nTime + (i - 1) * 1440
|
||||
local nTimeMax = nTimeStart + math.Round(math.random(var.nDuration / 4, var.nDuration / 2), 1)
|
||||
local nTimeMaxEnd = nTimeStart + var.nDuration * 0.75
|
||||
local nTimeEnd = nTimeStart + var.nDuration
|
||||
|
||||
local wObj = StormFox2.Weather.Get(var.sName)
|
||||
local t = {
|
||||
["sName"] = var.sName,
|
||||
["fAmount"] = math.Round(var.fAmount, 2),
|
||||
["bThunder"] = var.nThunder
|
||||
}
|
||||
local useCloud = wObj.Inherit == "Cloud" and math.random(1, 10) >= 5
|
||||
local startWType = useCloud and "Cloud" or var.sName
|
||||
if lastWType == var.sName and lastWTime == nTimeStart then -- In case we had the same weather type before, remove the "fading out" part
|
||||
wGenList._weather[ lastWTime ] = nil
|
||||
startWType = var.sName
|
||||
else
|
||||
wGenList._weather[ nTimeStart ] = {
|
||||
["sName"] = startWType,
|
||||
["fAmount"] = 0
|
||||
}
|
||||
end
|
||||
wGenList._weather[ nTimeMax ] = {
|
||||
["sName"] = startWType,
|
||||
["fAmount"] = math.Round(var.fAmount, 2)
|
||||
}
|
||||
wGenList._weather[ nTimeMaxEnd ] = t
|
||||
wGenList._weather[ nTimeEnd ] = {
|
||||
["sName"] = var.sName,
|
||||
["fAmount"] = 0
|
||||
}
|
||||
lastWType = var.sName
|
||||
lastWTime = var.nTimeEnd
|
||||
end
|
||||
end
|
||||
-- Push it into an index
|
||||
wGenList.weather = TimeToIndex( wGenList._weather )
|
||||
wGenList.temperature = TimeToIndex( wGenList._temperature )
|
||||
wGenList.wind = TimeToIndex( wGenList._wind )
|
||||
wGenList.windyaw = TimeToIndex( wGenList._windyaw )
|
||||
if not IsUsingWeatherGen() then return end -- Don't update the forecast. But keep the weather in mind in case it gets enabled.
|
||||
SetForecast( wGenList )
|
||||
end
|
||||
-- In case settings change, update weekweather
|
||||
local function ClearAndRedo()
|
||||
timer.Simple(1, function()
|
||||
weatherWeekCount = {}
|
||||
generator = {}
|
||||
weather_index = 0
|
||||
wind_index = 0
|
||||
temp_index = 0
|
||||
-- Generate new Day
|
||||
GenerateWeek()
|
||||
-- Make WGen
|
||||
PushDayToList()
|
||||
end)
|
||||
end
|
||||
min_temp:AddCallback( ClearAndRedo, "weekWeather" )
|
||||
max_temp:AddCallback( ClearAndRedo, "weekWeather" )
|
||||
max_wind:AddCallback( ClearAndRedo, "weekWeather" )
|
||||
night_temp:AddCallback( ClearAndRedo, "weekWeather" )
|
||||
OnWeatherSettingChange = ClearAndRedo
|
||||
|
||||
local lastWeather, lastWind, lastTemp = -1, -1 , -1
|
||||
|
||||
local function fkey( x, a, b )
|
||||
return (x - a) / (b - a)
|
||||
end
|
||||
|
||||
local function findNext( tab, time ) -- First one is time
|
||||
for i, v in ipairs( tab ) do
|
||||
if time > v[1] then continue end
|
||||
return i
|
||||
end
|
||||
return 0
|
||||
end
|
||||
|
||||
local weather_index = 0
|
||||
local wind_index = 0
|
||||
local temp_index = 0
|
||||
|
||||
local function EnableWGenerator(forceCall)
|
||||
if enable and not forceCall then return end
|
||||
enable = true
|
||||
GenerateWeek() -- Generate a week
|
||||
PushDayToList() -- Push said list to w-table.
|
||||
-- We need to set the start-weather
|
||||
-- Set the start temperature
|
||||
local curTime = math.ceil(StormFox2.Time.Get())
|
||||
local t_index = findNext( wGenList.temperature, curTime )
|
||||
if t_index > 0 then
|
||||
local procentStart = 1
|
||||
local _start = wGenList.temperature[t_index - 1]
|
||||
local _end = wGenList.temperature[t_index]
|
||||
if _start then
|
||||
procentStart = fkey( curTime, _start[1], _end[1] )
|
||||
end
|
||||
local temp = Lerp( procentStart, (_start or _end)[2], _end[2] )
|
||||
StormFox2.Temperature.Set( math.Round(temp, 2), 0 )
|
||||
end
|
||||
|
||||
-- Set the start wind
|
||||
local wind_index = findNext( wGenList.wind, curTime )
|
||||
if wind_index > 0 then
|
||||
local procentStart = 1
|
||||
local _start = wGenList.wind[t_index - 1]
|
||||
local _end = wGenList.wind[t_index]
|
||||
if _start then
|
||||
procentStart = fkey( curTime, _start[1], _end[1] )
|
||||
end
|
||||
local wind = Lerp( procentStart, (_start or _end)[2], _end[2] )
|
||||
StormFox2.Wind.SetForce( math.Round(wind, 2), 0 )
|
||||
|
||||
local _start = wGenList.windyaw[t_index - 1]
|
||||
local _end = wGenList.windyaw[t_index]
|
||||
local windyaw = Lerp( procentStart, (_start or _end)[2], _end[2] )
|
||||
StormFox2.Wind.SetYaw( math.Round(windyaw, 2), 0 )
|
||||
end
|
||||
|
||||
-- Set the start weather
|
||||
local weather_index = findNext( wGenList.weather, curTime )
|
||||
if weather_index > 0 then
|
||||
local procentStart = 1
|
||||
local _start = wGenList.weather[weather_index - 1]
|
||||
local _end = wGenList.weather[weather_index]
|
||||
if _start then
|
||||
procentStart = fkey( curTime, _start[1], _end[1] )
|
||||
else
|
||||
_start = _end
|
||||
end
|
||||
local isClear = _end[2].sName == "Clear" or _end[2].fAmount == 0
|
||||
local w_type = ( isClear and _start[2] or _end[2] ).sName
|
||||
local w_procent = ( isClear and _start[2] or _end[2] ).fAmount
|
||||
StormFox2.Weather.Set( w_type, w_procent * procentStart )
|
||||
if _end[2].bThunder then
|
||||
StormFox2.Thunder.SetEnabled(true, _end[2].bThunder)
|
||||
else
|
||||
StormFox2.Thunder.SetEnabled(false, 0)
|
||||
end
|
||||
end
|
||||
-- Create a timer to modify the weather, checks every 1.5 seconds
|
||||
timer.Create("SF_WGEN_DEF", 0.5, 0, function()
|
||||
local cT = StormFox2.Time.Get()
|
||||
local e_index = findNext( wGenList.weather, cT )
|
||||
local i_index = findNext( wGenList.wind, cT )
|
||||
local t_index = findNext( wGenList.temperature, cT )
|
||||
if weather_index~= e_index then
|
||||
weather_index = e_index
|
||||
local w_data = wGenList.weather[e_index]
|
||||
if w_data then
|
||||
local delta = StormFox2.Time.SecondsUntil(w_data[1])
|
||||
StormFox2.Weather.Set(w_data[2].sName, w_data[2].fAmount, delta )
|
||||
if w_data[2].bThunder then
|
||||
StormFox2.Thunder.SetEnabled(true, w_data[2].bThunder)
|
||||
else
|
||||
StormFox2.Thunder.SetEnabled(false, 0)
|
||||
end
|
||||
end
|
||||
end
|
||||
if wind_index~= i_index then
|
||||
wind_index = i_index
|
||||
local i_data = wGenList.wind[i_index]
|
||||
local y_data = wGenList.windyaw[i_index]
|
||||
|
||||
if i_data then
|
||||
local secs = StormFox2.Time.SecondsUntil(i_data[1])
|
||||
StormFox2.Wind.SetForce(i_data[2], secs)
|
||||
if y_data then
|
||||
StormFox2.Wind.SetYaw( y_data[2], secs)
|
||||
end
|
||||
end
|
||||
end
|
||||
if temp_index~= t_index then
|
||||
temp_index = t_index
|
||||
local t_data = wGenList.temperature[t_index]
|
||||
if t_data then
|
||||
local delta = StormFox2.Time.SecondsUntil(t_data[1])
|
||||
StormFox2.Temperature.Set(t_data[2], delta )
|
||||
end
|
||||
end
|
||||
|
||||
end)
|
||||
end
|
||||
local function DisableWGenerator()
|
||||
if not enable then return end
|
||||
enable = false
|
||||
timer.Destroy("SF_WGEN_DEF")
|
||||
end
|
||||
hook.Add("StormFox2.Time.NextDay", "StormFox2.WGen.ND", function()
|
||||
if not enable then return end
|
||||
-- Generate new Day
|
||||
GenerateDay()
|
||||
-- Make WGen
|
||||
PushDayToList()
|
||||
weather_index = 0
|
||||
wind_index = 0
|
||||
temp_index = 0
|
||||
end)
|
||||
-- Logic
|
||||
local function NewWGenSetting()
|
||||
if not auto_weather:GetValue() then -- Auto weather is off. Make sure API is off too
|
||||
DisableAPI()
|
||||
DisableWGenerator()
|
||||
return
|
||||
end
|
||||
if API_ENABLE:GetValue() == true then
|
||||
EnableAPI()
|
||||
DisableWGenerator()
|
||||
StormFox2.Msg("Using OpenWeatherMap API")
|
||||
else
|
||||
DisableAPI()
|
||||
EnableWGenerator()
|
||||
StormFox2.Msg("Using WeatherGen")
|
||||
end
|
||||
end
|
||||
API_ENABLE:AddCallback( NewWGenSetting, "API_Enable")
|
||||
auto_weather:AddCallback( NewWGenSetting, "WGEN_Enable")
|
||||
hook.Add("stormfox2.postinit", "WGenInit", NewWGenSetting)
|
||||
|
||||
|
||||
NewWGenSetting()
|
||||
hook.Add("StormFox2.data.initspawn", "StormFox2.Weather.SendForcast",function( ply )
|
||||
if not hide_forecast then return end
|
||||
if not forecast then return end -- ?
|
||||
net.Start("StormFox2.weekweather")
|
||||
net.WriteBool( forecast.unix_time )
|
||||
net.WriteTable( forecast.temperature or {} )
|
||||
net.WriteTable( forecast.weather or {} )
|
||||
net.WriteTable( forecast.wind or {} )
|
||||
net.WriteTable( forecast.windyaw or {} )
|
||||
net.Broadcast()
|
||||
end)
|
||||
Reference in New Issue
Block a user