mirror of
https://github.com/lifestorm/wnsrc.git
synced 2025-12-16 21:33:46 +03:00
570 lines
19 KiB
Lua
570 lines
19 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/
|
||
--]]
|
||
|
||
StormFox2.Wind = StormFox2.Wind or {}
|
||
local min,max,sqrt,abs = math.min,math.max,math.sqrt,math.abs
|
||
local function ET(pos,pos2,mask,filter)
|
||
local t = util.TraceLine( {
|
||
start = pos,
|
||
endpos = pos + pos2,
|
||
mask = mask,
|
||
filter = filter
|
||
} )
|
||
t.HitPos = t.HitPos or (pos + pos2)
|
||
return t,t.HitSky
|
||
end
|
||
|
||
-- Settings
|
||
hook.Add("stormfox2.postlib", "stormfox2.windSettings",function()
|
||
StormFox2.Setting.AddSV("windmove_players",true,nil,"Weather")
|
||
StormFox2.Setting.AddSV("windmove_foliate",true,nil,"Weather")
|
||
StormFox2.Setting.AddSV("windmove_props",false,nil,"Weather")
|
||
StormFox2.Setting.AddSV("windmove_props_break",true,nil,"Weather")
|
||
StormFox2.Setting.AddSV("windmove_props_unweld",true,nil,"Weather")
|
||
StormFox2.Setting.AddSV("windmove_props_unfreeze",true,nil,"Weather")
|
||
StormFox2.Setting.AddSV("windmove_props_max",100,nil,"Weather")
|
||
StormFox2.Setting.AddSV("windmove_props_makedebris",true,nil,"Weather")
|
||
hook.Remove("stormfox2.postlib", "stormfox2.windSettings")
|
||
end)
|
||
|
||
|
||
if SERVER then
|
||
hook.Add("stormfox2.postlib", "stormfox2.svWindInit",function()
|
||
if not StormFox2.Ent.env_winds then return end
|
||
for _,ent in ipairs( StormFox2.Ent.env_winds ) do
|
||
ent:SetKeyValue('windradius',-1) -- Make global
|
||
ent:SetKeyValue('maxgustdelay', 20)
|
||
ent:SetKeyValue('mingustdelay', 10)
|
||
ent:SetKeyValue('gustduration', 5)
|
||
end
|
||
hook.Remove("stormfox2.postlib", "stormfox2.svWindInit")
|
||
end)
|
||
---Sets the wind force. Second argument is the lerp-time.
|
||
---@param nForce number
|
||
---@param nLerpTime? number
|
||
---@server
|
||
function StormFox2.Wind.SetForce( nForce, nLerpTime )
|
||
StormFox2.Network.Set( "Wind", nForce, nLerpTime )
|
||
end
|
||
|
||
---Sets the wind yaw. Second argument is the lerp-time.
|
||
---@param nYaw number
|
||
---@param nLerpTime? number
|
||
---@server
|
||
function StormFox2.Wind.SetYaw( nYaw, nLerpTime )
|
||
StormFox2.Network.Set( "WindAngle", nYaw, nLerpTime )
|
||
end
|
||
end
|
||
|
||
---Returns the wind yaw-direction
|
||
---@return number
|
||
---@shared
|
||
function StormFox2.Wind.GetYaw()
|
||
return StormFox2.Data.Get( "WindAngle", 0 )
|
||
end
|
||
|
||
---Returns the wind force.
|
||
---@return number
|
||
---@shared
|
||
function StormFox2.Wind.GetForce()
|
||
return StormFox2.Data.Get( "Wind", 0 )
|
||
end
|
||
|
||
-- Beaufort scale and Saffir–Simpson hurricane scale
|
||
local bfs = {}
|
||
bfs[0] = "sf_winddescription.calm"
|
||
bfs[0.3] = "sf_winddescription.light_air"
|
||
bfs[1.6] = "sf_winddescription.light_breeze"
|
||
bfs[3.4] = "sf_winddescription.gentle_breeze"
|
||
bfs[5.5] = "sf_winddescription.moderate_breeze"
|
||
bfs[8] = "sf_winddescription.fresh_breeze"
|
||
bfs[10.8] = "sf_winddescription.strong_breeze"
|
||
bfs[13.9] = "sf_winddescription.near_gale"
|
||
bfs[17.2] = "sf_winddescription.gale"
|
||
bfs[20.8] = "sf_winddescription.strong_gale"
|
||
bfs[24.5] = "sf_winddescription.storm"
|
||
bfs[28.5] = "sf_winddescription.violent_storm"
|
||
bfs[32.7] = "sf_winddescription.hurricane" -- Also known as cat 1
|
||
bfs[43] = "sf_winddescription.cat2"
|
||
bfs[50] = "sf_winddescription.cat3"
|
||
bfs[58] = "sf_winddescription.cat4"
|
||
bfs[70] = "sf_winddescription.cat5"
|
||
local bfkey = table.GetKeys(bfs)
|
||
table.sort(bfkey,function(a,b) return a < b end)
|
||
|
||
---Returns the current (or given wind in m/s), in a beaufort-scale and description.
|
||
---@param ms? number
|
||
---@return number
|
||
---@return string
|
||
---@shared
|
||
function StormFox2.Wind.GetBeaufort(ms)
|
||
local n = ms or StormFox2.Wind.GetForce()
|
||
local Beaufort, Description = 0, "sf_winddescription.calm"
|
||
for k,kms in ipairs( bfkey ) do
|
||
if kms <= n then
|
||
Beaufort, Description = k - 1, bfs[ kms ]
|
||
else
|
||
break
|
||
end
|
||
end
|
||
return Beaufort, Description
|
||
end
|
||
-- Spawning env_wind won't work. Therefor we need to use the cl_tree_sway_dir on the client if it's not on the map.
|
||
if CLIENT then
|
||
local function updateWind()
|
||
if StormFox2.Map.HadClass( "env_wind" ) then return end
|
||
local nw = math.min(StormFox2.Wind.GetForce() * 0.6, 21)
|
||
local ra = math.rad( StormFox2.Data.Get( "WindAngle", 0 ) )
|
||
local wx,wy = math.cos(ra) * nw,math.sin(ra) * nw
|
||
RunConsoleCommand("cl_tree_sway_dir",wx,wy)
|
||
end
|
||
hook.Add("StormFox2.Wind.Change","StormFox2.Wind.CLFix",function(windNorm, wind)
|
||
if not StormFox2.Setting.GetCache("windmove_foliate", true) then return end
|
||
updateWind()
|
||
end)
|
||
StormFox2.Setting.Callback("windmove_foliate", function(b)
|
||
if b then
|
||
updateWind()
|
||
else
|
||
RunConsoleCommand("cl_tree_sway_dir",0,0)
|
||
end
|
||
end)
|
||
else
|
||
local function updateWind(nw, ang)
|
||
if not StormFox2.Ent.env_winds then return end
|
||
local min = nw * .6
|
||
local max = nw * .8
|
||
local gust = math.min(nw, 5.5)
|
||
for _,ent in ipairs( StormFox2.Ent.env_winds ) do
|
||
if not IsValid(ent) then continue end
|
||
--print(ent, max, min ,gust)
|
||
if ang then ent:Fire('SetWindDir', ang) end
|
||
ent:SetKeyValue('minwind', min)
|
||
ent:SetKeyValue('maxwind', max)
|
||
ent:SetKeyValue('gustdirchange', math.max(0, 21 - nw))
|
||
ent:SetKeyValue('maxgust', gust)
|
||
ent:SetKeyValue('mingust', gust * .8)
|
||
end
|
||
end
|
||
hook.Add("StormFox2.Wind.Change","StormFox2.Wind.SVFix",function(windNorm, wind)
|
||
local nw = StormFox2.Wind.GetForce() * 2
|
||
local ang = StormFox2.Data.Get( "WindAngle", 0 )
|
||
updateWind(nw, ang)
|
||
end)
|
||
StormFox2.Setting.Callback("windmove_foliate", function(b)
|
||
if not StormFox2.Ent.env_winds then return end
|
||
local ang = StormFox2.Data.Get( "WindAngle", 0 )
|
||
if not b then
|
||
updateWind(0, ang)
|
||
return
|
||
end
|
||
local nw = StormFox2.Wind.GetForce() * 2
|
||
updateWind(nw, ang)
|
||
end)
|
||
end
|
||
--[[-------------------------------------------------------------------------
|
||
Calculate and update the wind direction
|
||
---------------------------------------------------------------------------]]
|
||
local windNorm = Vector(0,0,-1)
|
||
local windVec = Vector(0,0,0)
|
||
local wind,windAng = 0,-1
|
||
local function calcfunc()
|
||
local owind = StormFox2.Data.Get("Wind",0)
|
||
local nwind = owind * 0.2
|
||
local nang = StormFox2.Data.Get("WindAngle",0)
|
||
if nwind == wind and nang == windAng then return end -- Nothing changed
|
||
wind = nwind
|
||
windAng = nang
|
||
windNorm = Angle( 90 - sqrt(wind) * 10 ,windAng,0):Forward()
|
||
windVec = windNorm * wind
|
||
windNorm:Normalize()
|
||
--[[<Shared>-----------------------------------------------------------------
|
||
Gets called when the wind changes.
|
||
---------------------------------------------------------------------------]]
|
||
hook.Run("StormFox2.Wind.Change", windNorm, owind)
|
||
end
|
||
|
||
-- If the wind-data changes, is changing or is done changing. Reclaculate the wind.
|
||
timer.Create("StormFox2.Wind.Update", 1, 0, function()
|
||
if not StormFox2.Data.IsLerping("Wind") and not StormFox2.Data.IsLerping("WindAngle") then return end
|
||
calcfunc()
|
||
end)
|
||
local function dataCheck(sKey,sVar)
|
||
if sKey ~= "Wind" and sKey ~= "WindAngle" then return end
|
||
calcfunc()
|
||
end
|
||
hook.Add("StormFox2.data.change","StormFox2.Wind.Calc",dataCheck)
|
||
hook.Add("StormFox2.data.lerpend", "StormFox2.Wind.Calcfinish", dataCheck)
|
||
|
||
---Returns the wind norm.
|
||
---@return Vector
|
||
---@shared
|
||
function StormFox2.Wind.GetNorm()
|
||
return windNorm
|
||
end
|
||
|
||
---Returns the wind vector.
|
||
---@return Vector
|
||
---@shared
|
||
function StormFox2.Wind.GetVector()
|
||
return windVec
|
||
end
|
||
--[[-------------------------------------------------------------------------
|
||
Checks if an entity is out in the wind (or rain). Caches the result for 1 second.
|
||
---------------------------------------------------------------------------]]
|
||
local function IsMaterialEmpty( t )
|
||
return t.HitTexture == "TOOLS/TOOLSINVISIBLE" or t.HitTexture == "**empty**" or t.HitTexture == "TOOLS/TOOLSNODRAW"
|
||
end
|
||
local function ET_II(pos, vec, mask, filter) -- Ignore invisble brushes 'n stuff'
|
||
local lastT
|
||
for i = 1, 5 do
|
||
local t, a = ET(pos, vec, mask, filter)
|
||
if not IsMaterialEmpty(t) and t.Hit then return t, a end
|
||
lastT = lastT or t
|
||
pos = t.HitPos
|
||
end
|
||
lastT.HitSky = true
|
||
return lastT
|
||
end
|
||
local max_dis = 32400
|
||
|
||
---Checks to see if the entity is in the wind.
|
||
---@param eEnt userdata
|
||
---@param bDont_cache? boolean
|
||
---@return boolean IsInWind
|
||
---@return Vector WindNorm
|
||
---@shared
|
||
function StormFox2.Wind.IsEntityInWind(eEnt,bDont_cache)
|
||
if not IsValid(eEnt) then return end
|
||
if not bDont_cache then
|
||
if eEnt.sf_wind_var and (eEnt.sf_wind_var[2] or 0) > CurTime() then
|
||
return eEnt.sf_wind_var[1],windNorm
|
||
else
|
||
eEnt.sf_wind_var = {}
|
||
end
|
||
end
|
||
local pos = eEnt:OBBCenter() + eEnt:GetPos()
|
||
local tr = ET_II(pos, windNorm * -640000, MASK_SHOT, eEnt)
|
||
local hitSky = tr.HitSky
|
||
local dis = tr.HitPos:DistToSqr( pos )
|
||
if not hitSky and dis >= max_dis then -- So far away. The wind would had gone around. Check if we're outside.
|
||
local tr = ET(pos,Vector(0,0,640000),MASK_SHOT,eEnt)
|
||
hitSky = tr.HitSky
|
||
end
|
||
if not bDont_cache then
|
||
eEnt.sf_wind_var[1] = hitSky
|
||
eEnt.sf_wind_var[2] = CurTime() + 1
|
||
end
|
||
return hitSky,windNorm
|
||
end
|
||
|
||
-- Wind sounds
|
||
if CLIENT then
|
||
local windSnd = -1 -- -1 = none, 0 = outside, 0+ Distance to outside
|
||
local windGusts = {}
|
||
local maxVol = 1.5
|
||
local function AddGuest( snd, vol, duration )
|
||
if windGusts[snd] then return end
|
||
if not duration then duration = SoundDuration( snd ) end
|
||
windGusts[snd] = {vol * 0.4, CurTime() + duration - 1}
|
||
end
|
||
|
||
timer.Create("StormFox2.Wind.Snd", 1, 0, function()
|
||
windSnd = -1
|
||
if StormFox2.Wind.GetForce() <= 0 then return end
|
||
local env = StormFox2.Environment.Get()
|
||
if not env or (not env.outside and not env.nearest_outside) then return end
|
||
if not env.outside and env.nearest_outside then
|
||
local view = StormFox2.util.RenderPos()
|
||
windSnd = StormFox2.util.RenderPos():Distance(env.nearest_outside)
|
||
else
|
||
windSnd = 0
|
||
end
|
||
-- Guests
|
||
local vM = (400 - windSnd) / 400
|
||
if vM <= 0 then return end
|
||
local wForce = StormFox2.Wind.GetForce()
|
||
if math.random(50) > 40 then
|
||
if wForce > 17 and math.random(1,2) > 1 then
|
||
AddGuest("ambient/wind/windgust.wav",math.Rand(0.8, 1) * vM)
|
||
elseif wForce > 14 and wForce < 30 then
|
||
AddGuest("ambient/wind/wind_med" .. math.random(1,2) .. ".wav", math.min(maxVol, wForce / 30) * vM)
|
||
end
|
||
end
|
||
if wForce > 27 and math.random(50) > 30 then
|
||
AddGuest("ambient/wind/windgust_strong.wav",math.min(maxVol, wForce / 30) * vM)
|
||
end
|
||
end)
|
||
|
||
-- Cold "empty" wind: ambience/wind1.wav
|
||
-- ambient/wind/wind1.wav
|
||
-- ambient/wind/wind_rooftop1.wav
|
||
-- ambient/wind/wind1.wav
|
||
-- StormFox2.Ambience.ForcePlay
|
||
hook.Add("StormFox2.Ambiences.OnSound", "StormFox2.Ambiences.Wind", function()
|
||
if windSnd < 0 then return end -- No wind
|
||
local wForce = StormFox2.Wind.GetForce() * 0.25
|
||
local vM = (400 - windSnd) / 400
|
||
if vM <= 0 then return end
|
||
-- Main loop
|
||
StormFox2.Ambience.ForcePlay( "ambient/wind/wind_rooftop1.wav", math.min((wForce - 1) / 35, maxVol) * vM * 0.8, math.min(1.2, 0.9 + wForce / 100) )
|
||
-- Wind gusts
|
||
for snd,data in pairs(windGusts) do
|
||
if data[2] <= CurTime() then
|
||
windGusts[snd] = nil
|
||
else
|
||
StormFox2.Ambience.ForcePlay( snd, 0.2 * data[1] + math.Rand(0, 0.1) )
|
||
end
|
||
end
|
||
end)
|
||
else
|
||
-- Flag models
|
||
local flags = {}
|
||
local flag_models = {}
|
||
flag_models["models/props_fairgrounds/fairgrounds_flagpole01.mdl"] = 90
|
||
flag_models["models/props_street/flagpole_american.mdl"] = 90
|
||
flag_models["models/props_street/flagpole_american_tattered.mdl"] = 90
|
||
flag_models["models/props_street/flagpole.mdl"] = 90
|
||
flag_models["models/mapmodels/flags.mdl"] = 0
|
||
flag_models["models/props/de_cbble/cobble_flagpole.mdl"] = 180
|
||
flag_models["models/props/de_cbble/cobble_flagpole_2.mdl"] = 225
|
||
flag_models["models/props/props_gameplay/capture_flag.mdl"] = 270
|
||
flag_models["models/props_medieval/pendant_flag/pendant_flag.mdl"] = 0
|
||
flag_models["models/props_moon/parts/moon_flag.mdl"] = 0
|
||
local function FlagInit()
|
||
-- Check if there are any flags on the map
|
||
for _,ent in pairs(ents.GetAll()) do
|
||
if not ent:CreatedByMap() then continue end
|
||
-- Check the angle
|
||
if math.abs(ent:GetAngles():Forward():Dot(Vector(0,0,1))) > 5 then continue end
|
||
if not flag_models[ent:GetModel()] then continue end
|
||
table.insert(flags,ent)
|
||
end
|
||
if #flags > 0 then -- Only add the hook if there are flags on the map.
|
||
hook.Add("StormFox2.data.change","StormFox2.flagcontroller",function(key,var)
|
||
if key == "WindAngle" then
|
||
--print("Windang", var)
|
||
for _,ent in ipairs(flags) do
|
||
if not IsValid(ent) then continue end
|
||
local y = flag_models[ent:GetModel()] or 0
|
||
ent:SetAngles(Angle(0,var + y,0))
|
||
end
|
||
elseif key == "Wind" then
|
||
--print("Wind", var)
|
||
for _,ent in ipairs(flags) do
|
||
if not IsValid(ent) then continue end
|
||
ent:SetPlaybackRate(math.Clamp(var / 7,0.5,10))
|
||
end
|
||
end
|
||
end)
|
||
end
|
||
end
|
||
hook.Add("StormFox2.PostEntityScan", "StormFox2.Wind.FlagInit", FlagInit)
|
||
end
|
||
|
||
if CLIENT then return end
|
||
-- Wind movment
|
||
local function windMove(ply, mv, cmd )
|
||
if not StormFox2.Setting.GetCache("windmove_players") then return end
|
||
if( ply:GetMoveType() != MOVETYPE_WALK ) then return end
|
||
local wF = (StormFox2.Wind.GetForce() - 15) / 11
|
||
if wF <= 0 then return end
|
||
if not StormFox2.Wind.IsEntityInWind(ply) then return end -- Not in wind
|
||
-- Calc windforce
|
||
local r = math.rad( StormFox2.Wind.GetYaw() - ply:GetAngles().y )
|
||
local fS = math.cos( r ) * wF
|
||
local sS = math.sin( r ) * wF
|
||
|
||
if mv:GetForwardSpeed() == 0 and mv:GetSideSpeed() == 0 then -- Not moving
|
||
--mv:SetSideSpeed( - sS / 10) Annoying
|
||
--mv:SetForwardSpeed( - fS / 10)
|
||
else
|
||
-- GetForwardMove() returns 10000y. We need to figure out the speed first.
|
||
local running, walking = mv:KeyDown( IN_SPEED ), mv:KeyDown( IN_WALK )
|
||
local speed = running and ply:GetRunSpeed() or walking and ply:GetSlowWalkSpeed() or ply:GetWalkSpeed()
|
||
|
||
local forward = math.Clamp(mv:GetForwardSpeed(), -speed, speed)
|
||
local side = math.Clamp(mv:GetSideSpeed(), -speed, speed)
|
||
if forward~=0 and side~=0 then
|
||
forward = forward * .7
|
||
side = side * .7
|
||
end
|
||
-- Now we modify them. We don't want to move back.
|
||
if forward > 0 and fS < 0 then
|
||
forward = math.max(0, forward / -fS)
|
||
elseif forward < 0 and fS > 0 then
|
||
forward = math.min(0, forward / fS)
|
||
end
|
||
if side > 0 and sS > 0 then
|
||
side = math.max(0, side / sS)
|
||
forward = forward + fS * 20
|
||
elseif side < 0 and sS < 0 then
|
||
side = math.min(0, side / -sS)
|
||
forward = forward + fS * 20
|
||
end
|
||
-- Apply the new speed
|
||
mv:SetForwardSpeed( forward )
|
||
cmd:SetForwardMove( forward )
|
||
mv:SetSideSpeed( side )
|
||
cmd:SetSideMove( side )
|
||
end
|
||
end
|
||
hook.Add("SetupMove", "windtest", windMove)
|
||
|
||
-- Wind proppush
|
||
local move_list = {
|
||
["rpg_missile"] = true,
|
||
["npc_grenade_frag"] = true,
|
||
["npc_grenade_bugbait"] = true, -- Doesn't work
|
||
["gmod_hands"] = false,
|
||
["gmod_tool"] = false
|
||
}
|
||
local function CanMoveClass( ent )
|
||
if( IsValid( ent:GetParent()) ) then return end
|
||
local class = ent:GetClass()
|
||
if( move_list[class] == false ) then return false end
|
||
return string.match(class,"^prop_") or string.match(class,"^gmod_") or move_list[class]
|
||
end
|
||
|
||
local function ApplyWindEffect( ent, wind, windnorm )
|
||
if ent:GetPersistent() then return end
|
||
if(wind < 5) then return end
|
||
-- Make a toggle
|
||
local vol
|
||
local phys = ent:GetPhysicsObject()
|
||
if(not phys or not IsValid(phys)) then -- No physics
|
||
return
|
||
end
|
||
vol = phys:GetVolume() or 15
|
||
-- Check Move
|
||
local windPush = windnorm * 1.37 * vol * .66
|
||
--windnorm * 5.92 * (vol / 50)
|
||
local windRequ = phys:GetInertia()
|
||
windRequ = max(windRequ.x,windRequ.y)
|
||
if max(abs(windPush.x),abs(windPush.y)) < windRequ then -- Can't move
|
||
return
|
||
end
|
||
local class = ent:GetClass()
|
||
if( class != "npc_grenade_frag") then
|
||
windPush.x = math.Clamp(windPush.x, -5500, 5500)
|
||
windPush.y = math.Clamp(windPush.y, -5500, 5500)
|
||
end
|
||
-- Unfreeze
|
||
if(wind > 20) then
|
||
if( StormFox2.Setting.GetCache("windmove_props_unfreeze", true) ) then
|
||
if not phys:IsMoveable() then
|
||
phys:EnableMotion(true)
|
||
end
|
||
end
|
||
end
|
||
-- Unweld
|
||
if(wind > 30) then
|
||
if( StormFox2.Setting.GetCache("windmove_props_unweld", true) ) then
|
||
if constraint.FindConstraint( ent, "Weld" ) and math.random(1, 15) < 2 then
|
||
ent:EmitSound("physics/wood/wood_box_break" .. math.random(1,2) .. ".wav")
|
||
constraint.RemoveConstraints( ent, "Weld" )
|
||
end
|
||
end
|
||
end
|
||
-- Move
|
||
phys:Wake()
|
||
phys:ApplyForceCenter(Vector(windPush.x, windPush.y, math.max(phys:GetVelocity().z, 0)))
|
||
-- Break
|
||
if(wind > 40) then
|
||
if( StormFox2.Setting.GetCache("windmove_props_break", true) ) then
|
||
if not ent:IsVehicle() and (ent._sfnext_dmg or 0) <= CurTime() and ent:GetClass() != "npc_grenade_frag" then
|
||
ent._sfnext_dmg = CurTime() + 0.5
|
||
ent:TakeDamage(ent:Health() / 10 + 2,game.GetWorld(),game.GetWorld())
|
||
end
|
||
end
|
||
end
|
||
end
|
||
|
||
local move_tab = {}
|
||
local current_prop = 0
|
||
local function AddEntity( ent )
|
||
if( ent._sfwindcan or 0 ) > CurTime() then return end
|
||
if( StormFox2.Setting.GetCache("windmove_props_max", 50) <= table.Count(move_tab) ) then return end -- Too many props moving atm
|
||
move_tab[ ent ] = CurTime()
|
||
--ApplyWindEffect( ent, StormFox2.Wind.GetForce(), StormFox2.Wind.GetNorm() )
|
||
end
|
||
|
||
hook.Add("OnEntityCreated","StormFox.Wind.PropMove",function(ent)
|
||
if( not StormFox2.Setting.GetCache("windmove_props", false) ) then return end
|
||
if( not IsValid(ent) ) then return end
|
||
if( not CanMoveClass( ent ) ) then return end
|
||
AddEntity( ent )
|
||
end)
|
||
|
||
local scanID = 0
|
||
local function ScanProps()
|
||
local t = ents.GetAll()
|
||
if( #t < scanID) then
|
||
scanID = 0
|
||
end
|
||
for i = scanID, math.min(#t, scanID + 30) do
|
||
local ent = t[i]
|
||
if(not IsValid( ent )) then break end
|
||
if ent:GetPersistent() then continue end
|
||
if not CanMoveClass( ent ) then continue end
|
||
if move_tab[ ent ] then continue end -- Already added
|
||
if not StormFox2.Wind.IsEntityInWind( ent ) then continue end -- Not in wind
|
||
AddEntity( ent )
|
||
end
|
||
scanID = scanID + 30
|
||
end
|
||
|
||
local next_loop = 0 -- We shouldn't run this on think if there arae too few props
|
||
hook.Add("Think","StormFox.Wind.EffectProps",function()
|
||
if( not StormFox2.Setting.GetCache("windmove_props", false) ) then return end
|
||
if( next_loop > CurTime() ) then return end
|
||
next_loop = CurTime() + (game.SinglePlayer() and 0.1 or 0.2)
|
||
-- Scan on all entities. This would be slow. But we're only looking at 30 entities at a time.
|
||
ScanProps()
|
||
|
||
local t = table.GetKeys( move_tab )
|
||
if(#t < 1) then return end
|
||
local wind = StormFox2.Wind.GetForce()
|
||
-- Check if there is wind
|
||
if( wind < 10) then
|
||
table.Empty( move_tab )
|
||
return
|
||
end
|
||
if( current_prop > #t) then
|
||
current_prop = 1
|
||
end
|
||
local wind, c_windnorm = StormFox2.Wind.GetForce(), StormFox2.Wind.GetNorm()
|
||
local windnorm = Vector(c_windnorm.x, c_windnorm.y, 0)
|
||
local c = CurTime()
|
||
for i = current_prop, math.min(#t, current_prop + 30) do
|
||
local ent = t[i]
|
||
if(not ent) then
|
||
break
|
||
end
|
||
-- Check if valid
|
||
if(not IsValid( ent ) or not StormFox2.Wind.IsEntityInWind( ent )) then
|
||
move_tab[ent] = nil
|
||
continue
|
||
end
|
||
-- Check if presistence
|
||
if ent:GetPersistent() then continue end
|
||
-- If the entity has been in the wind for over 10 seconds, try and move on and see if we can pick up something else
|
||
if(move_tab[ ent ] < c - 10) then
|
||
ent._sfwindcan = c + math.random(20, 30)
|
||
if(StormFox2.Setting.GetCache("windmove_props_makedebris", true)) then
|
||
ent:SetCollisionGroup( COLLISION_GROUP_DEBRIS )
|
||
end
|
||
move_tab[ent] = nil
|
||
continue
|
||
end
|
||
ApplyWindEffect( ent, wind, windnorm )
|
||
end
|
||
current_prop = current_prop + 30
|
||
end) |