mirror of
https://github.com/lifestorm/wnsrc.git
synced 2025-12-16 21:33:46 +03:00
447 lines
14 KiB
Lua
447 lines
14 KiB
Lua
--[[
|
|
| This file was obtained through the combined efforts
|
|
| of Madbluntz & Plymouth Antiquarian Society.
|
|
|
|
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
|
| Maloy, DrPepper10 @ RIP, Atle!
|
|
|
|
|
| Visit for more: https://plymouth.thetwilightzone.ru/
|
|
--]]
|
|
|
|
-- Updates the weather for given players
|
|
|
|
local lastSet = 0
|
|
local CurrentWeather
|
|
local CurrentPercent = 1
|
|
|
|
local function isColor(t)
|
|
return t.r and t.g and t.b and true or false
|
|
end
|
|
local function Blender(nFraction, vFrom, vTo) -- Will it blend?
|
|
-- Nils should be false, if one of them is a boolean
|
|
if type(vFrom) == "nil" and type(vTo) == "boolean" then
|
|
vFrom = false
|
|
end
|
|
if type(vTo) == "nil" and type(vFrom) == "boolean" then
|
|
vTo = false
|
|
end
|
|
-- If the same value, then return it
|
|
if vTo == vFrom then return vTo end
|
|
-- In case of two diffrent variables.
|
|
if type(vFrom) ~= type(vTo) then
|
|
StormFox2.Warning("Mixer called with values of two different types[" .. type(vFrom) .. "," .. type(vTo) .. "]")
|
|
debug.Trace()
|
|
return vFrom
|
|
elseif type(vTo) == "string" or type(vTo) == "IMaterial" or type(vTo) == "boolean" then -- String, material or bool. Return vTo.
|
|
return vTo
|
|
elseif type(vTo) == "number" then -- Number
|
|
return Lerp(nFraction, vFrom, vTo)
|
|
elseif type(vTo) == "table" and isColor(vTo) then -- Color
|
|
local r = Lerp( nFraction, vFrom.r or 255, vTo.r )
|
|
local g = Lerp( nFraction, vFrom.g or 255, vTo.g )
|
|
local b = Lerp( nFraction, vFrom.b or 255, vTo.b )
|
|
local a = Lerp( nFraction, vFrom.a or 255, vTo.a )
|
|
return Color( r, g, b, a )
|
|
end
|
|
--StormFox2.Warning("ERROR: Unsupported mix value type[" .. type(vTo) .. "]. Returning original value")
|
|
--debug.Trace()
|
|
return vFrom
|
|
end
|
|
|
|
local function IsSame(sName, nPercentage, nDelta)
|
|
if CurrentPercent ~= nPercentage then return false end
|
|
if not CurrentWeather then return false end
|
|
return CurrentWeather.Name == sName
|
|
end
|
|
|
|
local function ApplyWeather(sName, nPercentage, nDelta)
|
|
hook.Run("StormFox2.weather.prechange", sName ,nPercentage )
|
|
if nDelta and nDelta <= 0 then
|
|
nDelta = nil
|
|
elseif nDelta then
|
|
local sp = StormFox2.Time.GetSpeed_RAW()
|
|
if sp > 0 then
|
|
nDelta = nDelta / sp
|
|
end
|
|
end
|
|
local bSameWeather = sName == (CurrentWeather and CurrentWeather.Name or "Clear")
|
|
if CurrentWeather and CurrentWeather.OnChange then
|
|
CurrentWeather:OnChange( sName, nPercentage, nDelta )
|
|
end
|
|
if CurrentWeather and CurrentWeather.OnRemove and not bSameWeather then
|
|
CurrentWeather:OnRemove( sName, nPercentage, nDelta )
|
|
end
|
|
local clear = StormFox2.Weather.Get( "Clear" )
|
|
CurrentWeather = StormFox2.Weather.Get( sName )
|
|
CurrentPercent = nPercentage
|
|
local stamp = StormFox2.Sky.GetLastStamp()
|
|
|
|
if sName == "Clear" then
|
|
nPercentage = 1
|
|
end
|
|
if nPercentage >= 1 then
|
|
for _,key in ipairs( StormFox2.Weather.GetKeys() ) do
|
|
local v = CurrentWeather:Get( key, stamp )
|
|
if type(v) == "table" and not (v.r and v.g and v.b) then
|
|
StormFox2.Data.Set(key, v)
|
|
else
|
|
StormFox2.Data.Set(key, v, nDelta)
|
|
end
|
|
end
|
|
elseif nPercentage <= 0 then
|
|
for _,key in ipairs( StormFox2.Weather.GetKeys() ) do
|
|
StormFox2.Data.Set(key, clear:Get( key, stamp ), nDelta)
|
|
end
|
|
else -- Mixing bin
|
|
for _,key in ipairs( StormFox2.Weather.GetKeys() ) do
|
|
local var2,b_nomix = CurrentWeather:Get( key, stamp )
|
|
local d = nDelta
|
|
if type(var2) == "table" and not (var2.r and var2.g and var2.b) then
|
|
d = nil
|
|
end
|
|
if b_nomix then
|
|
StormFox2.Data.Set(key, var2, d)
|
|
else
|
|
local var1 = clear:Get( key, stamp )
|
|
if var2 and not var1 then -- This is not a default variable
|
|
if type(var2) == "number" then
|
|
var1 = 0
|
|
end
|
|
end
|
|
if not var1 and var2 then -- THis is not a default varable
|
|
StormFox2.Data.Set(key, var2, d)
|
|
elseif var1 and var2 then
|
|
StormFox2.Data.Set(key, Blender(nPercentage, var1, var2), d)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
if CurrentWeather.Init and not bSameWeather then
|
|
CurrentWeather.Init()
|
|
end
|
|
if CurrentWeather.Tick10 then
|
|
CurrentWeather.Tick10()
|
|
end
|
|
hook.Run("StormFox2.weather.postchange", sName ,nPercentage, nDelta )
|
|
end
|
|
|
|
hook.Add("StormFox2.Sky.StampChange","StormFox2.Weather.Stamp",function(_,nLerpTime)
|
|
ApplyWeather(CurrentWeather and CurrentWeather.Name or "Clear", CurrentPercent, nLerpTime)
|
|
end)
|
|
|
|
---Returns the current weather-type.
|
|
---@return Weather
|
|
function StormFox2.Weather.GetCurrent()
|
|
return CurrentWeather or StormFox2.Weather.Get( "Clear" )
|
|
end
|
|
|
|
---Returns the current weather percent.
|
|
---@return number Percent
|
|
function StormFox2.Weather.GetPercent()
|
|
return StormFox2.Data.Get("w_Percentage",CurrentPercent)
|
|
end
|
|
|
|
---Returns the weather percent we're lerping to.
|
|
---@return number
|
|
function StormFox2.Weather.GetFinishPercent()
|
|
return CurrentPercent
|
|
end
|
|
|
|
---Returns the current weather description. Like 'Snow', 'Storm' .. ect.
|
|
---Second argument isn't translated.
|
|
---@return string Description
|
|
---@return string Description_Untranslated
|
|
function StormFox2.Weather.GetDescription()
|
|
local c = StormFox2.Weather.GetCurrent()
|
|
if not c.GetName then
|
|
return c.Name
|
|
end
|
|
local a,b = c:GetName(StormFox2.Time.Get(), StormFox2.Temperature.Get(), StormFox2.Wind.GetForce(), StormFox2.Thunder.IsThundering(), StormFox2.Weather.GetPercent())
|
|
return a,b or a
|
|
end
|
|
|
|
local errM = Material("error")
|
|
|
|
---Returns the current weather-icon.
|
|
---@return userdata Material
|
|
function StormFox2.Weather.GetIcon()
|
|
local c = StormFox2.Weather.GetCurrent()
|
|
if not c.GetIcon then
|
|
return errM
|
|
end
|
|
return c.GetIcon(StormFox2.Time.Get(), StormFox2.Temperature.Get(), StormFox2.Wind.GetForce(), StormFox2.Thunder.IsThundering(), StormFox2.Weather.GetPercent())
|
|
end
|
|
|
|
local SF_UPDATE_WEATHER = 0
|
|
local SF_INIT_WEATHER = 1
|
|
|
|
if SERVER then
|
|
local l_data
|
|
|
|
---Sets the weather.
|
|
---@server
|
|
---@param sName string
|
|
---@param nPercentage number
|
|
---@param nDelta? number
|
|
---@return boolean success
|
|
function StormFox2.Weather.Set( sName, nPercentage, nDelta )
|
|
if not StormFox2.Setting.GetCache("enable", true) then return end -- Just in case
|
|
if nDelta and l_data and nDelta == l_data then
|
|
if IsSame(sName, nPercentage) then return false end
|
|
end
|
|
l_data = nDelta
|
|
-- Default vals
|
|
if not nDelta then
|
|
nDelta = 4
|
|
end
|
|
if not nPercentage then
|
|
nPercentage = 1
|
|
end
|
|
-- Unknown weathers gets replaced with 'Clear'
|
|
if not StormFox2.Weather.Get( sName ) then
|
|
StormFox2.Warning("Unknown weather: " .. tostring(sName))
|
|
sName = "Clear"
|
|
end
|
|
-- In case we set the weather to clear, change it so it is the current weather at 0 instead
|
|
if sName == "Clear" and CurrentWeather and nDelta > 0 then
|
|
nPercentage = 0
|
|
sName = CurrentWeather.Name
|
|
elseif sName == "Clear" then
|
|
nPercentage = 1
|
|
end
|
|
lastSet = CurTime()
|
|
net.Start( StormFox2.Net.Weather )
|
|
net.WriteBit(SF_UPDATE_WEATHER)
|
|
net.WriteUInt( math.max(0, StormFox2.Data.GetLerpEnd( "w_Percentage" )), 32)
|
|
net.WriteFloat(nPercentage)
|
|
net.WriteString(sName)
|
|
net.WriteFloat(CurTime() + nDelta)
|
|
net.Broadcast()
|
|
ApplyWeather(sName, nPercentage, nDelta)
|
|
if sName == "Clear" then
|
|
nPercentage = 0
|
|
end
|
|
StormFox2.Data.Set("w_Percentage",nPercentage,nDelta)
|
|
return true
|
|
end
|
|
net.Receive( StormFox2.Net.Weather, function(len, ply) -- OI, what weather?
|
|
local lerpEnd = StormFox2.Data.GetLerpEnd( "w_Percentage" )
|
|
net.Start( StormFox2.Net.Weather )
|
|
net.WriteBit(SF_INIT_WEATHER)
|
|
net.WriteUInt( math.max(0, StormFox2.Data.GetLerpEnd( "w_Percentage" )), 32)
|
|
net.WriteFloat( CurrentPercent )
|
|
net.WriteString( StormFox2.Weather.GetCurrent().Name )
|
|
net.WriteFloat( StormFox2.Data.Get("w_Percentage",CurrentPercent) )
|
|
net.Send(ply)
|
|
end)
|
|
-- Handles the terrain logic
|
|
timer.Create("StormFox2.terrain.updater", 4, 0, function()
|
|
local cW = StormFox2.Weather.GetCurrent()
|
|
local cT = StormFox2.Terrain.GetCurrent()
|
|
|
|
if not cW then return end -- No weather!?
|
|
local terrain = cW:Get("Terrain")
|
|
if not cT and not terrain then return end -- No terrain detected
|
|
if cT and terrain and cT == terrain then return end -- Same terrain detected
|
|
if terrain then -- Switch terraintype out. This can't be the same as the other
|
|
StormFox2.Terrain.Set(terrain.Name)
|
|
elseif not terrain and not cT.lock then -- This terrain doesn't have a lock. Reset terrain
|
|
StormFox2.Terrain.Reset()
|
|
elseif not terrain and cT.lock then -- Check the lock of cT and see if we can reset
|
|
if cT:lock() then -- Lock tells us we can reset the terrain
|
|
StormFox2.Terrain.Reset()
|
|
end
|
|
end
|
|
end)
|
|
local tS = CurTime()
|
|
-- In case no weather was set
|
|
timer.Simple(8, function()
|
|
-- Clear up weather when it reaches 0
|
|
timer.Create("StormFox2.weather.clear",1,0,function()
|
|
if not CurrentWeather then return end
|
|
if CurrentWeather.Name == "Clear" then return end
|
|
local p = StormFox2.Weather.GetPercent()
|
|
if p <= 0 then
|
|
StormFox2.Weather.Set("Clear", 1, 0)
|
|
end
|
|
end)
|
|
if CurrentWeather then return end
|
|
StormFox2.Weather.Set("Clear", 1, 0)
|
|
end)
|
|
else
|
|
local hasLocalWeather = false
|
|
local svWeather
|
|
local function SetW( sName, nPercentage, nDelta )
|
|
-- Block same weather
|
|
if IsSame(sName, nPercentage) then return false end
|
|
ApplyWeather(sName, nPercentage, nDelta)
|
|
if sName == "Clear" then
|
|
nPercentage = 0
|
|
end
|
|
StormFox2.Data.Set("w_Percentage",nPercentage,nDelta)
|
|
end
|
|
|
|
---Sets the weather on the client. Server-side stuff won't be set.
|
|
---@client
|
|
---@param sName? string
|
|
---@param nPercentage? number
|
|
---@param nDelta? number
|
|
---@param nTemperature? number
|
|
function StormFox2.Weather.SetLocal( sName, nPercentage, nDelta, nTemperature)
|
|
-- If nil then remove the local weather
|
|
if not sName then
|
|
return StormFox2.Weather.RemoveLocal()
|
|
end
|
|
-- Unknown weathers gets replaced with 'Clear'
|
|
if not StormFox2.Weather.Get( sName ) then
|
|
StormFox2.Warning("Unknown weather: " .. tostring(sName))
|
|
sName = "Clear"
|
|
end
|
|
if not hasLocalWeather then
|
|
svWeather = {StormFox2.Weather.GetCurrent().Name, StormFox2.Weather.GetFinishPercent(), StormFox2.Temperature.Get()}
|
|
end
|
|
StormFox2.Temperature.SetLocal(nTemperature)
|
|
-- Block same weather
|
|
SetW(sName, nPercentage or 1, nDelta)
|
|
hasLocalWeather = true
|
|
end
|
|
|
|
---Removes the local weather.
|
|
---@client
|
|
function StormFox2.Weather.RemoveLocal()
|
|
if not hasLocalWeather then return end
|
|
SetW(svWeather[1], svWeather[2], 4)
|
|
StormFox2.Temperature.SetLocal(nil)
|
|
svWeather = nil
|
|
hasLocalWeather = false
|
|
end
|
|
net.Receive( StormFox2.Net.Weather, function(len)
|
|
local flag = net.ReadBit() == SF_UPDATE_WEATHER
|
|
local wTarget = net.ReadUInt(32)
|
|
local nPercentage = net.ReadFloat()
|
|
local sName = net.ReadString()
|
|
if flag then
|
|
local nDelta = net.ReadFloat() - CurTime()
|
|
-- Calculate the time since server set this
|
|
if not hasLocalWeather then
|
|
SetW(sName, nPercentage, nDelta)
|
|
else
|
|
svWeather[1] = sName
|
|
svWeather[2] = nPercentage
|
|
end
|
|
else
|
|
local current = net.ReadFloat()
|
|
if not hasLocalWeather then
|
|
local secondsLeft = wTarget - CurTime()
|
|
if secondsLeft <= 0 then
|
|
SetW(sName, nPercentage, 0)
|
|
else
|
|
SetW(sName, current, 0)
|
|
SetW(sName, nPercentage, secondsLeft)
|
|
end
|
|
else
|
|
svWeather[1] = sName
|
|
svWeather[2] = nPercentage
|
|
end
|
|
end
|
|
end)
|
|
-- Ask the server what weather we have
|
|
hook.Add("StormFox2.InitPostEntity", "StormFox2.terrain", function()
|
|
net.Start( StormFox2.Net.Weather )
|
|
net.SendToServer()
|
|
end)
|
|
end
|
|
|
|
hook.Add("Think", "StormFox2.Weather.Think", function()
|
|
if not CurrentWeather then return end
|
|
if not CurrentWeather.Think then return end
|
|
if not StormFox2.Setting.SFEnabled() then return end
|
|
CurrentWeather:Think()
|
|
end)
|
|
|
|
timer.Create("StormFox2.Weather.tickslow", 1, 0, function()
|
|
if not CurrentWeather then return end
|
|
if not CurrentWeather.TickSlow then return end
|
|
CurrentWeather.TickSlow()
|
|
end)
|
|
|
|
hook.Add("StormFox2.weather.postchange", "StormFox2.weather.slowtickinit", function()
|
|
if not CurrentWeather then return end
|
|
if not CurrentWeather.TickSlow then return end
|
|
CurrentWeather.TickSlow()
|
|
end)
|
|
|
|
if CLIENT then
|
|
local c_tab = {"PostDrawTranslucentRenderables", "PreDrawTranslucentRenderables", "HUDPaint"}
|
|
for i,v in ipairs(c_tab) do
|
|
hook.Add(v, "StormFox2.Weather." .. v, function(...)
|
|
if not CurrentWeather then return end
|
|
if not CurrentWeather[v] then return end
|
|
CurrentWeather[v](...)
|
|
end)
|
|
end
|
|
end
|
|
|
|
-- Some functions to make it easier.
|
|
|
|
---Returns true if it is raining, or if current weather is child of rain.
|
|
---@return boolean
|
|
---@shared
|
|
function StormFox2.Weather.IsRaining()
|
|
local wT = StormFox2.Weather.GetCurrent()
|
|
if wT.Inherit == "Rain" then return true end
|
|
if wT.Name ~= "Rain" then return false end
|
|
return StormFox2.Temperature.Get() > -2 or false
|
|
end
|
|
|
|
---Returns true if it is snowing.
|
|
---@return boolean
|
|
---@shared
|
|
function StormFox2.Weather.IsSnowing()
|
|
local wT = StormFox2.Weather.GetCurrent()
|
|
if wT.Name ~= "Rain" then return false end
|
|
return StormFox2.Temperature.Get() <= -2 or false
|
|
end
|
|
|
|
---Returns the rain / snow amount. Between 0 - 1.
|
|
---@return number
|
|
---@shared
|
|
function StormFox2.Weather.GetRainAmount()
|
|
if not StormFox2.Weather.IsRaining() then return 0 end
|
|
return StormFox2.Weather.GetPercent()
|
|
end
|
|
|
|
---Returns true if the current weather is raining, snowing or inherit from rain.
|
|
---@return boolean
|
|
---@shared
|
|
function StormFox2.Weather.HasDownfall()
|
|
local wT = StormFox2.Weather.GetCurrent()
|
|
if wT.Inherit == "Rain" then return true end
|
|
return wT.Name == "Rain"
|
|
end
|
|
|
|
-- Downfall
|
|
|
|
---Returns true if the entity is hit by rain or any downfall.
|
|
---@param eEnt Entity
|
|
---@param bDont_cache boolean
|
|
---@return boolean
|
|
---@shared
|
|
function StormFox2.DownFall.IsEntityHit(eEnt, bDont_cache)
|
|
if not StormFox2.Weather.HasDownfall() then return false end
|
|
return (StormFox2.Wind.IsEntityInWind(eEnt,bDont_cache))
|
|
end
|
|
|
|
---Checks to see if the given point is hit by rain.
|
|
---@param vPos Vector
|
|
---@return boolean
|
|
---@shared
|
|
function StormFox2.DownFall.IsPointHit(vPos)
|
|
if not StormFox2.Weather.HasDownfall() then return false end
|
|
local t = util.TraceLine( {
|
|
start = vPos,
|
|
endpos = vPos + -StormFox2.Wind.GetNorm() * 262144,
|
|
mask = StormFox2.DownFall.Mask
|
|
} )
|
|
return t.HitSky
|
|
end |