From 2736f498f30220b858fc6fac23e7ddc4a597df6d Mon Sep 17 00:00:00 2001 From: Alexander Pickering Date: Mon, 30 May 2016 14:42:09 -0400 Subject: Inital commit --- gamemode/weather.lua | 703 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 703 insertions(+) create mode 100644 gamemode/weather.lua (limited to 'gamemode/weather.lua') diff --git a/gamemode/weather.lua b/gamemode/weather.lua new file mode 100644 index 0000000..762ebd5 --- /dev/null +++ b/gamemode/weather.lua @@ -0,0 +1,703 @@ + +GM.Weather = {} +GM.Weather.Rain = 0 +GM.Weather.Thunder = 0 +GM.Weather.Lightning = 0 +GM.Weather.Wind = 0 +GM.Weather.TransitionTime = 60 // 1 minute for weather transitions + +GM.Weather.New = {} +GM.Weather.New.Rain = 0 +GM.Weather.New.Thunder = 0 +GM.Weather.New.Lightning = 0 +GM.Weather.New.Wind = 0 + +function GM:EntityKeyValue( ent, key, val ) + + if ent:GetClass() == "worldspawn" and key == "skyname" then + + SetGlobalString( "SkyName", val ) + + end + +end + +function GM:WeatherInit() + + if CLIENT then + + RainEmitter = ParticleEmitter( Vector(0,0,0) ) + + end + +end + +function GM:PlayerIndoors( ply ) + + if SERVER then + + return ply:IsIndoors() + + else + + local tr = util.TraceLine( util.GetPlayerTrace( LocalPlayer(), Vector(0,0,1) ) ) + + if tr.HitWorld and not tr.HitSky then + + GAMEMODE.PlayerIsIndoors = true + + return true + + end + + end + + GAMEMODE.PlayerIsIndoors = false + + return false + +end + +function GM:RandomizeWeather( force ) + + GAMEMODE.Weather.New.Rain = 0 + GAMEMODE.Weather.New.Thunder = 0 + GAMEMODE.Weather.New.Lightning = 0 + GAMEMODE.Weather.New.Wind = 0 + + if math.random(1,5) == 1 and not force then + + GAMEMODE:SynchWeather() + + return {0,0,0,0} + + end + + for k,v in pairs( GAMEMODE.Weather.New ) do + + if math.random(1,5) > 1 then + + GAMEMODE.Weather.New[k] = math.Rand(0,1) + + if math.random(1,3) == 1 then + + GAMEMODE.Weather.New[k] = 1 + + end + + end + + end + + local count = 0 + + for k,v in pairs( GAMEMODE.Weather.New ) do + + if v == 0 then + + count = count + 1 + + end + + end + + if count == 4 or math.random(1,10) == 1 then + + GAMEMODE.Weather.New.Rain = 1 + GAMEMODE.Weather.New.Thunder = 1 + GAMEMODE.Weather.New.Lightning = 1 + GAMEMODE.Weather.New.Wind = 1 + + end + + GAMEMODE:SynchWeather() + + return { GAMEMODE.Weather.New.Rain, GAMEMODE.Weather.New.Thunder, GAMEMODE.Weather.New.Lightning, GAMEMODE.Weather.New.Wind } + +end + +function GM:ManualWeather( rain, thunder, lightning, wind ) + + GAMEMODE.Weather.New.Rain = rain + GAMEMODE.Weather.New.Thunder = thunder + GAMEMODE.Weather.New.Lightning = lightning + GAMEMODE.Weather.New.Wind = wind + + GAMEMODE.Weather.NextShift = CurTime() + math.random( 240, 480 ) + + GAMEMODE:SynchWeather() + +end + +function GM:ShiftWeather() + + for k,v in pairs( GAMEMODE.Weather.New ) do + + if v < 0.2 and math.random(1,2) == 1 then + + GAMEMODE.Weather.New[k] = 0 + + else + + GAMEMODE.Weather.New[k] = math.Clamp( v + math.Rand( -0.2, math.Rand( 0.2, 0.3 ) ), 0, 1 ) + + end + + end + + GAMEMODE:SynchWeather() + +end + +function GM:WeatherThink() + + if not GAMEMODE.Weather.NextShift then + + GAMEMODE.Weather.NextShift = CurTime() + math.random( 120, 600 ) + + elseif GAMEMODE.Weather.NextShift < CurTime() then + + GAMEMODE.Weather.NextShift = nil + + GAMEMODE:ShiftWeather() + + end + +end + +function GM:SynchWeather() + + net.Start( "WeatherSynch" ) + + net.WriteTable( GAMEMODE.Weather.New ) + + net.Broadcast() + +end + +if SERVER then return end + +net.Receive( "WeatherSynch", function( len ) + + GAMEMODE.Weather.New = net.ReadTable() + GAMEMODE.Weather.Transition = true + GAMEMODE.Weather.Inc = 0 + + //PrintTable( GAMEMODE.Weather.New ) + +end ) + +function GM:ProcessWeather() + + GAMEMODE:RainThink() + GAMEMODE:ThunderThink() + GAMEMODE:LightningThink() + GAMEMODE:WindThink() + + if GAMEMODE.Weather.Transition then + + //local scale = 1 - ( ( GAMEMODE.Weather.Transition - CurTime() ) / GAMEMODE.Weather.TransitionTime ) + + if GAMEMODE.Weather.Inc <= CurTime() then + + GAMEMODE.Weather.Inc = CurTime() + 1 + local count = 0 + + for k,v in pairs( GAMEMODE.Weather.New ) do + + local diff = math.abs( GAMEMODE.Weather[k] - GAMEMODE.Weather.New[k] ) + local inc = diff / GAMEMODE.Weather.TransitionTime + + GAMEMODE.Weather[k] = math.Approach( GAMEMODE.Weather[k], GAMEMODE.Weather.New[k], inc ) + + if GAMEMODE.Weather[k] == GAMEMODE.Weather.New[k] then + + count = count + 1 + + end + + end + + if count == 4 then + + GAMEMODE.Weather.Transition = false + + end + + end + + end + +end + +RainMat = surface.GetTextureID( "effects/rain_warp" ) + +function GM:PaintWeather() + + if GAMEMODE.Weather.Rain > 0 and render.GetDXLevel() >= 90 then + + for k,v in pairs( GAMEMODE.RainDrops ) do + + local scale = math.Clamp( ( v.Time - CurTime() ) / v.Life, 0, 1 ) + + surface.SetDrawColor( 200, 200, 220, 255 * scale ) + surface.SetTexture( RainMat ) + surface.DrawTexturedRect( v.X, v.Y - v.Movement * scale, v.Size, v.Size ) + + end + + end + +end + +function GM:GetSky() + + local tr = util.TraceLine( util.GetPlayerTrace( LocalPlayer(), Vector(0,0,1) ) ) + + if tr.HitSky then + + GAMEMODE.LastSkyPos = tr.HitPos + GAMEMODE.PlayerIsIndoors = false + + GAMEMODE:ComputeSkyBounds() + + return tr.HitPos + + elseif GAMEMODE.LastSkyPos then + + GAMEMODE.PlayerIsIndoors = true + + return GAMEMODE.LastSkyPos + + else + + return LocalPlayer():GetPos() + + end + +end + +GM.RainDist = 1000 +GM.RainDrops = {} + +function GM:ComputeSkyBounds() + + local trace = {} + trace.start = GAMEMODE.LastSkyPos + trace.endpos = trace.start + Vector( GAMEMODE.RainDist, 0, 0 ) + + local tr = util.TraceLine( trace ) + + trace = {} + trace.start = tr.HitPos + trace.endpos = trace.start + Vector( 0, GAMEMODE.RainDist, 0 ) + + tr = util.TraceLine( trace ) + + GAMEMODE.RightSkyBound = tr.HitPos + + trace = {} + trace.start = GAMEMODE.LastSkyPos + trace.endpos = trace.start + Vector( GAMEMODE.RainDist * -1, 0, 0 ) + + tr = util.TraceLine( trace ) + + trace = {} + trace.start = tr.HitPos + trace.endpos = trace.start + Vector( 0, GAMEMODE.RainDist * -1, 0 ) + + tr = util.TraceLine( trace ) + + GAMEMODE.LeftSkyBound = tr.HitPos + +end + +function GM:GetClosestSkyPos() + + local skypos = GAMEMODE:GetSky() + local pos = LocalPlayer():GetPos() + + local trace = {} + trace.start = skypos + trace.endpos = Vector( pos.x, pos.y, skypos.z ) + + local tr = util.TraceLine( trace ) + + GAMEMODE.LastSkyPos = tr.HitPos + + GAMEMODE:ComputeSkyBounds() + + return tr.HitPos + +end + +GM.RainSound = Sound( "ambient/weather/rumble_rain_nowind.wav" ) + +function GM:RainThink() + + for k,v in pairs( GAMEMODE.RainDrops ) do + + if v.Time < CurTime() then + + table.remove( GAMEMODE.RainDrops, k ) + + break + + end + + end + + if GAMEMODE.Weather.Rain > 0 and ( GAMEMODE.NextRainDrop or 0 ) < CurTime() and not GAMEMODE.PlayerIsIndoors then + + GAMEMODE.NextRainDrop = CurTime() + math.Rand( 1 - GAMEMODE.Weather.Rain, ( 1.2 - GAMEMODE.Weather.Rain ) * 3 ) + + for i=1, math.random( 1, math.floor( GAMEMODE.Weather.Rain * 4 ) ) do + + local tbl = {} + + tbl.Size = math.random( 40, 80 ) + math.random( 0, GAMEMODE.Weather.Rain * 20 ) + tbl.X = math.random( 0, ScrW() - tbl.Size ) + tbl.Y = math.random( 0, ScrH() - tbl.Size ) + tbl.Movement = math.random( 20, 80 ) + tbl.Life = math.Rand( 1.0, 5.0 ) + tbl.Time = CurTime() + tbl.Life + + if math.random(1,5) == 1 then + + tbl.Movement = 10 + + end + + table.insert( GAMEMODE.RainDrops, tbl ) + + end + + end + + if ( GAMEMODE.NextRain or 0 ) < CurTime() then + + GAMEMODE.NextRain = CurTime() + 0.2 + + local amt = math.floor( GAMEMODE.Weather.Rain * 175 * CV_Density:GetFloat() ) + + GAMEMODE:SpawnRain( amt ) + + if not GAMEMODE.RainNoise then + + GAMEMODE.RainNoise = CreateSound( LocalPlayer(), GAMEMODE.RainSound ) + GAMEMODE.RainNoise:PlayEx( GAMEMODE.Weather.Rain * 0.3, 100 ) + GAMEMODE.RainVolume = GAMEMODE.Weather.Rain * 0.4 + + else + + if GAMEMODE.PlayerIsIndoors then + + GAMEMODE.RainVolume = math.Approach( ( GAMEMODE.RainVolume or 0 ), math.max( GAMEMODE.Weather.Rain * 0.05, 0.02 ), 0.01 ) + + elseif GAMEMODE.Weather.Rain == 0 then + + GAMEMODE.RainVolume = math.Approach( ( GAMEMODE.RainVolume or 0 ), 0, 0.002 ) + + else + + GAMEMODE.RainVolume = math.Approach( ( GAMEMODE.RainVolume or 0 ), math.max( GAMEMODE.Weather.Rain * 0.4, 0.02 ), 0.002 ) + + end + + GAMEMODE.RainNoise:ChangeVolume( GAMEMODE.RainVolume, GAMEMODE.RainVolume ) + + end + + end + +end + +function GM:SpawnRain( amt ) + + if amt == 0 and not GetGlobalBool( "Radiation", false ) then return end + + local function RainCollision( particle, pos, norm ) + + particle:SetDieTime( 0 ) + + if math.random(1,6) == 1 then + + local particle = RainEmitter:Add( "effects/blood", pos ) + particle:SetVelocity( Vector(0,0,0) ) + particle:SetLifeTime( 0 ) + particle:SetDieTime( 0.25 ) + particle:SetStartAlpha( 100 ) + particle:SetEndAlpha( 0 ) + particle:SetStartSize( 1 ) + particle:SetEndSize( math.Rand( 3, 10 + GAMEMODE.Weather.Rain * 5 ) ) + particle:SetRoll( math.Rand( -360, 360 ) ) + particle:SetAirResistance( 0 ) + particle:SetCollide( false ) + //particle:SetColor( Color( 200, 200, 250 ) ) + + end + + end + + local function CloudCollision( particle, pos, norm ) + + particle:SetDieTime( 0 ) + + end + + local function RadCollision( particle, pos, norm ) + + particle:SetDieTime( math.Rand( 1.0, 3.0 ) ) + + end + + local pos = GAMEMODE:GetClosestSkyPos() + + if not pos then return end + + if GetGlobalBool( "Radiation", false ) then + + for i=1, 10 do + + local vec = Vector( math.random( GAMEMODE.LeftSkyBound.x, GAMEMODE.RightSkyBound.x ), math.random( GAMEMODE.LeftSkyBound.y, GAMEMODE.RightSkyBound.y ), pos.z ) + + local particle = RainEmitter:Add( "effects/rain_cloud", vec ) + particle:SetVelocity( Vector( 0, 0, math.random( -1000, -800 ) ) + WindVector * math.Rand( 0, 2.0 ) ) + particle:SetLifeTime( 0 ) + particle:SetDieTime( 10 ) + particle:SetStartAlpha( math.random( 5, 10 ) ) + particle:SetEndAlpha( 5 ) + particle:SetStartSize( math.random( 150, 250 ) ) + particle:SetEndSize( 250 ) + particle:SetAirResistance( 0 ) + particle:SetCollide( true ) + particle:SetBounce( 0 ) + particle:SetColor( Color( 100, 250, 50 ) ) + particle:SetCollideCallback( CloudCollision ) + + if i < 3 then + + local particle = RainEmitter:Add( "effects/rain_cloud", vec ) + particle:SetVelocity( Vector( 0, 0, math.random( -1000, -800 ) ) + WindVector * math.Rand( 0, 2.0 ) ) + particle:SetLifeTime( 0 ) + particle:SetDieTime( 10 ) + particle:SetStartAlpha( 255 ) + particle:SetEndAlpha( 0 ) + particle:SetStartSize( math.random( 1, 3 ) ) + particle:SetEndSize( 0 ) + particle:SetRoll( math.random( -180, 180 ) ) + particle:SetColor( 100, 200, 0 ) + particle:SetGravity( Vector( 0, 0, -300 ) + WindVector * ( math.sin( CurTime() * 0.01 ) * 20 ) ) + particle:SetCollide( true ) + particle:SetCollideCallback( RadCollision ) + particle:SetBounce( math.Rand( 0, 0.1 ) ) + + end + + end + + end + + if amt == 0 then return end + + for i=1, amt do + + local vec = Vector( math.random( GAMEMODE.LeftSkyBound.x, GAMEMODE.RightSkyBound.x ), math.random( GAMEMODE.LeftSkyBound.y, GAMEMODE.RightSkyBound.y ), pos.z ) + local len = math.random( 40, 80 ) + + local particle = RainEmitter:Add( "particle/Water/WaterDrop_001a", vec ) + particle:SetVelocity( Vector( 0, 0, math.random( -1000, -800 ) ) ) + particle:SetLifeTime( 0 ) + particle:SetDieTime( 10 ) + particle:SetStartAlpha( math.random( 5, 20 ) ) + particle:SetEndAlpha( 20 ) + particle:SetStartSize( 2.0 ) + particle:SetEndSize( math.Rand( 3.0, 4.0 + GAMEMODE.Weather.Rain ) ) + particle:SetStartLength( len ) + particle:SetEndLength( len + 5 ) + particle:SetAirResistance( 0 ) + particle:SetCollide( true ) + particle:SetBounce( 0 ) + //particle:SetColor( Color( 200, 200, 250 ) ) + particle:SetCollideCallback( RainCollision ) + + end + + amt = math.floor( amt * 0.05 ) + 1 + + for i=1, amt do + + local vec = Vector( math.random( GAMEMODE.LeftSkyBound.x, GAMEMODE.RightSkyBound.x ), math.random( GAMEMODE.LeftSkyBound.y, GAMEMODE.RightSkyBound.y ), pos.z ) + + local particle = RainEmitter:Add( "effects/rain_cloud", vec ) + particle:SetVelocity( Vector( 0, 0, math.random( -1000, -800 ) ) + WindVector * math.Rand( 0, 2.0 ) ) + particle:SetLifeTime( 0 ) + particle:SetDieTime( 10 ) + particle:SetStartAlpha( 3 + math.Rand( 0, GAMEMODE.Weather.Rain * 5 ) ) + particle:SetEndAlpha( 5 ) + particle:SetStartSize( math.random( 100, 200 ) ) + particle:SetEndSize( 200 ) + particle:SetAirResistance( 0 ) + particle:SetCollide( true ) + particle:SetBounce( 0 ) + particle:SetColor( Color( 200, 200, 250 ) ) + particle:SetCollideCallback( CloudCollision ) + + end + +end + +function GM:LightningThink() + + if GAMEMODE.Weather.Lightning == 0 then + + if GAMEMODE.NextLightning and GAMEMODE.NextLightning > CurTime() then + + GAMEMODE:LightUpSky( false ) + GAMEMODE.NextLightning = 0 + + end + + return + + end + + local skyname = GetGlobalString( "SkyName" ) + + if skyname and not GAMEMODE.SkyMat then + + GAMEMODE.SkyMat = {} + GAMEMODE.SkyMat[1] = Material("skybox/" .. skyname .. "up") + GAMEMODE.SkyMat[2] = Material("skybox/" .. skyname .. "dn") + GAMEMODE.SkyMat[3] = Material("skybox/" .. skyname .. "lf") + GAMEMODE.SkyMat[4] = Material("skybox/" .. skyname .. "rt") + GAMEMODE.SkyMat[5] = Material("skybox/" .. skyname .. "bk") + GAMEMODE.SkyMat[6] = Material("skybox/" .. skyname .. "ft") + + GAMEMODE.OldSky = {} + GAMEMODE.LitUp = {} + + skyname = "sky_day01_01" + + GAMEMODE.NewSky = {} + GAMEMODE.NewSky[1] = Material("skybox/" .. skyname .. "up") + GAMEMODE.NewSky[2] = Material("skybox/" .. skyname .. "dn") + GAMEMODE.NewSky[3] = Material("skybox/" .. skyname .. "lf") + GAMEMODE.NewSky[4] = Material("skybox/" .. skyname .. "rt") + GAMEMODE.NewSky[5] = Material("skybox/" .. skyname .. "bk") + GAMEMODE.NewSky[6] = Material("skybox/" .. skyname .. "ft") + + end + + if ( GAMEMODE.NextLightning or 0 ) < CurTime() then + + if not GAMEMODE.FlashInterval then + + GAMEMODE.FlashInterval = CurTime() + math.Rand( 1.0, 2.5 ) + GAMEMODE.FlashTime = CurTime() + math.Rand( 0, 0.2 ) + GAMEMODE.FlashToggle = CurTime() + math.Rand( 0, 0.8 ) + + sound.Play( table.Random( GAMEMODE.Thunder ), LocalPlayer():GetShootPos(), 150, math.random( 80, 110 ), 0.2 ) + + end + + GAMEMODE:LightUpSky( GAMEMODE.FlashTime >= CurTime() ) + + if GAMEMODE.FlashToggle < CurTime() then + + GAMEMODE.FlashTime = CurTime() + math.Rand( 0, 0.2 ) + GAMEMODE.FlashToggle = CurTime() + math.Rand( 0, 0.8 ) + + end + + if GAMEMODE.FlashInterval < CurTime() then + + GAMEMODE.FlashInterval = nil + GAMEMODE.NextLightning = CurTime() + math.random( 4, 8 + ( 1.0 - GAMEMODE.Weather.Lightning ) * 50 ) + GAMEMODE:LightUpSky( false ) + + end + + end + +end + +function GM:LightUpSky( bool ) + + if bool then + + for k,v in pairs( GAMEMODE.SkyMat ) do + + if not GAMEMODE.LitUp[k] then + + GAMEMODE.OldSky[k] = v:GetTexture( "$basetexture" ) + GAMEMODE.LitUp[k] = true + + v:SetTexture( "$basetexture", GAMEMODE.NewSky[k]:GetTexture( "$basetexture" ) ) + + end + + end + + else + + for k,v in pairs( GAMEMODE.SkyMat ) do + + if GAMEMODE.LitUp and GAMEMODE.LitUp[k] then + + GAMEMODE.LitUp[k] = false + + v:SetTexture( "$basetexture", GAMEMODE.OldSky[k] ) + + end + + end + + end + +end + +function GM:WindThink() + + if GAMEMODE.Weather.Wind == 0 then return end + + if ( GAMEMODE.NextWind or 0 ) < CurTime() then + + local vol = math.max( GAMEMODE.Weather.Wind, 0.2 ) + local snd = table.Random( GAMEMODE.Wind ) + + if GAMEMODE.PlayerIsIndoors then + + vol = 0.1 + + end + + sound.Play( snd, LocalPlayer():GetShootPos(), 150, math.random( 80, 110 ), vol ) + + GAMEMODE.NextWind = CurTime() + math.random( 1, SoundDuration( snd ) + ( 1.0 - GAMEMODE.Weather.Wind ) * 30 + math.Rand( -2, 2 ) ) + + end + +end + +function GM:ThunderThink() + + if GAMEMODE.Weather.Thunder == 0 then return end + + if ( GAMEMODE.NextThunder or 0 ) < CurTime() then + + GAMEMODE.NextThunder = CurTime() + math.random( 4, 8 + ( 1.0 - GAMEMODE.Weather.Thunder ) * 50 ) + + local vol = math.max( GAMEMODE.Weather.Thunder, 0.2 ) + + if GAMEMODE.PlayerIsIndoors then + + vol = 0.1 + + end + + sound.Play( table.Random( GAMEMODE.Thunder ), LocalPlayer():GetShootPos(), 150, math.random( 80, 110 ), vol ) + + end + +end \ No newline at end of file -- cgit v1.2.3-70-g09d2