mirror of
https://github.com/lifestorm/wnsrc.git
synced 2025-12-17 05:43:46 +03:00
Upload
This commit is contained in:
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
|
||||
Reference in New Issue
Block a user