mirror of
https://github.com/lifestorm/wnsrc.git
synced 2025-12-17 13:53:45 +03:00
374 lines
11 KiB
Lua
374 lines
11 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/
|
|
--]]
|
|
|
|
SWEP.Flashlights = {} -- tracks projectedlights
|
|
-- {{att = int, light = ProjectedTexture}}
|
|
SWEP.CheapFlashlights = {} -- tracks cheap flashlight models + lights
|
|
-- {{att = int, dlight = DynamicLight, vlight = ClientsideModel}}
|
|
|
|
function SWEP:GetHasFlashlights()
|
|
for i, k in pairs(self.Attachments) do
|
|
if !k.Installed then continue end
|
|
if self:GetBuff_Stat("Flashlight", i) != nil then return true end
|
|
end
|
|
|
|
return false
|
|
end
|
|
|
|
function SWEP:CreateFlashlightsVM()
|
|
self:KillFlashlights()
|
|
self.Flashlights = {}
|
|
|
|
local total_lights = 0
|
|
|
|
for i, k in pairs(self.Attachments) do
|
|
if !k.Installed then continue end
|
|
if self:GetBuff_Stat("Flashlight", i) then
|
|
local newlight = {
|
|
att = i,
|
|
light = ProjectedTexture(),
|
|
bone = self:GetBuff_Stat("FlashlightBone", i) or "laser",
|
|
col = self:GetBuff_Stat("FlashlightColor", i) or Color(255, 255, 255),
|
|
br = self:GetBuff_Stat("FlashlightBrightness", i) or 2
|
|
}
|
|
total_lights = total_lights + 1
|
|
|
|
local l = newlight.light
|
|
if !IsValid(l) then continue end
|
|
|
|
table.insert(self.Flashlights, newlight)
|
|
|
|
l:SetFOV(self:GetBuff_Stat("FlashlightFOV", i) or 50)
|
|
|
|
if self:GetBuff_Stat("FlashlightHFOV", i) then
|
|
l:SetHorizontalFOV(self:GetBuff_Stat("FlashlightHFOV", i))
|
|
end
|
|
|
|
if self:GetBuff_Stat("FlashlightVFOV", i) then
|
|
l:SetVerticalFOV(self:GetBuff_Stat("FlashlightVFOV", i))
|
|
end
|
|
|
|
l:SetFarZ(self:GetBuff_Stat("FlashlightFarZ", i) or 512)
|
|
l:SetNearZ(self:GetBuff_Stat("FlashlightNearZ", i) or 4)
|
|
|
|
local atten = self:GetBuff_Stat("FlashlightAttenuationType", i) or ArcCW.FLASH_ATT_LINEAR
|
|
|
|
l:SetLinearAttenuation(0)
|
|
l:SetConstantAttenuation(0)
|
|
l:SetQuadraticAttenuation(0)
|
|
|
|
if atten == ArcCW.FLASH_ATT_CONSTANT then
|
|
l:SetConstantAttenuation(100)
|
|
elseif atten == ArcCW.FLASH_ATT_QUADRATIC then
|
|
l:SetQuadraticAttenuation(100)
|
|
else
|
|
l:SetLinearAttenuation(100)
|
|
end
|
|
|
|
l:SetColor(self:GetBuff_Stat("FlashlightColor", i) or Color(255, 255, 255))
|
|
l:SetTexture(self:GetBuff_Stat("FlashlightTexture", i))
|
|
l:SetBrightness(self:GetBuff_Stat("FlashlightBrightness", i))
|
|
l:SetEnableShadows(true)
|
|
l:Update()
|
|
|
|
local g_light = {
|
|
Weapon = self,
|
|
ProjectedTexture = l
|
|
}
|
|
|
|
table.insert(ArcCW.FlashlightPile, g_light)
|
|
end
|
|
end
|
|
|
|
if total_lights > 2 then -- you are a madman
|
|
for i, k in pairs(self.Flashlights) do
|
|
if k.light:IsValid() then k.light:SetEnableShadows(false) end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- for world model flashlights we will use a cheap solution similar to what HL2 uses
|
|
-- throw up a volumetric light model
|
|
-- function SWEP:CreateFlashlightsWM()
|
|
-- self:KillFlashlights()
|
|
-- self.CheapFlashlights = {}
|
|
-- for i, k in pairs(self.Attachments) do
|
|
-- if !k.Installed then continue end
|
|
-- local atttbl = ArcCW.AttachmentTable[k.Installed]
|
|
|
|
-- if atttbl.Flashlight then
|
|
-- local newlight = {
|
|
-- att = i,
|
|
-- vlight = ClientsideModel(ArcCW.VolumetricLightModel),
|
|
-- scale_x = 1,
|
|
-- scale_y = 1,
|
|
-- maxz = atttbl.FlashlightFarZ or 512,
|
|
-- bone = atttbl.FlashlightBone or "laser",
|
|
-- col = Color(255, 255, 255)
|
|
-- }
|
|
|
|
-- local vl = newlight.vlight
|
|
|
|
-- if !IsValid(vl) then continue end
|
|
|
|
-- table.insert(self.CheapFlashlights, newlight)
|
|
|
|
-- local xfov = atttbl.FlashlightHFOV or atttbl.FlashlightFOV or 50
|
|
-- local yfov = atttbl.FlashlightVFOV or atttbl.FlashlightFOV or 50
|
|
|
|
-- local target_x = 128 * (xfov / 90)
|
|
-- local target_y = 128 * (yfov / 90)
|
|
|
|
-- local scale_x = target_x / ArcCW.VolumetricLightX
|
|
-- local scale_y = target_y / ArcCW.VolumetricLightY
|
|
|
|
-- newlight.scale_x = scale_x
|
|
-- newlight.scale_y = scale_y
|
|
|
|
-- vl:SetNoDraw(ArcCW.NoDraw)
|
|
-- vl:DrawShadow(false)
|
|
-- local col = atttbl.FlashlightColor or Color(255, 255, 255)
|
|
-- col = Color(255, 0, 0)
|
|
-- newlight.col = col
|
|
-- -- vl:SetColor(col)
|
|
|
|
-- local g_light = {
|
|
-- Model = vl,
|
|
-- Weapon = self
|
|
-- }
|
|
|
|
-- table.insert(ArcCW.CSModelPile, g_light)
|
|
-- end
|
|
-- end
|
|
-- end
|
|
|
|
function SWEP:KillFlashlights()
|
|
self:KillFlashlightsVM()
|
|
-- self:KillFlashlightsWM()
|
|
end
|
|
|
|
function SWEP:KillFlashlightsVM()
|
|
if !self.Flashlights then return end
|
|
|
|
for i, k in pairs(self.Flashlights) do
|
|
if k.light and k.light:IsValid() then
|
|
k.light:Remove()
|
|
end
|
|
end
|
|
|
|
self.Flashlights = nil
|
|
end
|
|
|
|
function SWEP:KillFlashlightsWM()
|
|
-- if !self.CheapFlashlights then return end
|
|
|
|
-- for i, k in pairs(self.CheapFlashlights) do
|
|
-- if k.vlight and k.vlight:IsValid() then
|
|
-- k.vlight:Remove()
|
|
-- end
|
|
-- end
|
|
|
|
-- self.CheapFlashlights = nil
|
|
end
|
|
|
|
-- given fov and distance solve apparent size
|
|
local function solvetriangle(angle, dist)
|
|
local a = angle / 2
|
|
local b = dist
|
|
return b * math.tan(a) * 2
|
|
end
|
|
|
|
local flashlight_mat = Material("models/effects/vol_light002")
|
|
-- local flashlight_mat = Material("effects/blueblacklargebeam")
|
|
|
|
function SWEP:DrawFlashlightsWM()
|
|
-- if !self.CheapFlashlights then
|
|
-- self:CreateFlashlightsWM()
|
|
-- end
|
|
|
|
local owner = self:GetOwner()
|
|
|
|
for i, k in pairs(self.Attachments) do
|
|
if !k.Installed then continue end
|
|
local atttbl = ArcCW.AttachmentTable[k.Installed]
|
|
|
|
if !atttbl or !self:GetBuff_Stat("Flashlight", i) then continue end
|
|
|
|
local maxz = atttbl.FlashlightFarZ or 512
|
|
local bone = atttbl.FlashlightBone or "laser"
|
|
local col = atttbl.FlashlightColor or Color(255, 255, 255)
|
|
|
|
if !k.WElement then continue end
|
|
local model = k.WElement.Model
|
|
if !IsValid(model) then return end
|
|
|
|
local pos, ang, dir
|
|
|
|
if !model then
|
|
pos = owner:EyePos()
|
|
ang = owner:EyeAngles()
|
|
dir = ang:Forward()
|
|
else
|
|
local att = model:LookupAttachment(bone or "laser")
|
|
|
|
att = att == 0 and model:LookupAttachment("muzzle") or att
|
|
|
|
if att == 0 then
|
|
pos = model:GetPos()
|
|
ang = IsValid(owner) and owner:EyeAngles() or model:GetAngles()
|
|
dir = ang:Forward()
|
|
dir_2 = ang:Up()
|
|
else
|
|
local attdata = model:GetAttachment(att)
|
|
pos, ang = attdata.Pos, attdata.Ang
|
|
dir = -ang:Right()
|
|
dir_2 = ang:Up()
|
|
end
|
|
end
|
|
|
|
local maxs = Vector(2, 2, 2)
|
|
local mins = -maxs
|
|
|
|
-- scale volumetric light
|
|
local tr = util.TraceHull({
|
|
start = pos,
|
|
endpos = pos + (dir * maxz),
|
|
mask = MASK_OPAQUE,
|
|
mins = mins,
|
|
maxs = maxs
|
|
})
|
|
|
|
local z = (tr.HitPos - tr.StartPos):Length()
|
|
-- local s_z = z / ArcCW.VolumetricLightZ
|
|
|
|
local xfov = atttbl.FlashlightHFOV or atttbl.FlashlightFOV or 50
|
|
local yfov = atttbl.FlashlightVFOV or atttbl.FlashlightFOV or 50
|
|
|
|
-- local target_x = 128 * (xfov / 90)
|
|
-- local target_y = 128 * (yfov / 90)
|
|
|
|
local target_x = solvetriangle(xfov, z)
|
|
local target_y = target_x
|
|
|
|
if xfov != yfov then
|
|
target_y = solvetriangle(yfov, z)
|
|
end
|
|
|
|
local vs = EyeAngles():Up()
|
|
|
|
local c1 = pos + vs
|
|
local c4 = pos - vs
|
|
local c2 = tr.HitPos + (vs * target_y * 0.75)
|
|
local c3 = tr.HitPos - (vs * target_y * 0.75)
|
|
|
|
render.SetMaterial(flashlight_mat)
|
|
render.DrawQuad(c1,c2,c3,c4, col)
|
|
|
|
-- local scale = Matrix()
|
|
-- scale:Scale(Vector(s_x, s_y, s_z))
|
|
|
|
-- k.vlight:SetPos(pos)
|
|
-- k.vlight:SetAngles(ang + Angle(0, 0, 90))
|
|
-- k.vlight:EnableMatrix("RenderMultiply", scale)
|
|
-- k.vlight:SetColor(Color(255, 0, 0, 255))
|
|
-- k.vlight:SetRenderMode(RENDERMODE_NORMAL)
|
|
-- k.vlight:SetKeyValue("RenderFX", kRenderFxNone)
|
|
-- k.vlight:DrawModel()
|
|
-- place dynamic light to make some light appear
|
|
|
|
local dl = DynamicLight(self:EntIndex())
|
|
|
|
local delta = (z / maxz)
|
|
delta = math.Clamp(delta, 0, 1)
|
|
|
|
if dl then
|
|
dl.pos = tr.HitPos
|
|
dl.r = col.r
|
|
dl.g = col.g
|
|
dl.b = col.b
|
|
dl.brightness = Lerp(delta, atttbl.FlashlightBrightness or 2, 0)
|
|
-- print(z / maxz)
|
|
dl.Decay = 1000 / 1
|
|
dl.dietime = CurTime() + 0.1
|
|
dl.size = xfov * 5
|
|
end
|
|
end
|
|
end
|
|
|
|
function SWEP:DrawFlashlightsVM()
|
|
if !self.Flashlights then
|
|
self:CreateFlashlightsVM()
|
|
end
|
|
|
|
local owner = self:GetOwner()
|
|
|
|
for i, k in pairs(self.Flashlights) do
|
|
local model = (self.Attachments[k.att].VElement or {}).Model
|
|
|
|
local pos, ang
|
|
|
|
if !model then
|
|
pos = owner:EyePos()
|
|
ang = owner:EyeAngles()
|
|
else
|
|
local att = model:LookupAttachment(k.bone or "laser")
|
|
|
|
att = att == 0 and model:LookupAttachment("muzzle") or att
|
|
|
|
if att == 0 then
|
|
pos = model:GetPos()
|
|
ang = owner:EyeAngles()
|
|
else
|
|
local attdata = model:GetAttachment(att)
|
|
pos, ang = attdata.Pos, attdata.Ang
|
|
end
|
|
end
|
|
|
|
local tr = util.TraceLine({
|
|
start = owner:EyePos(),
|
|
endpos = owner:EyePos() - ang:Right() * 128,
|
|
mask = MASK_OPAQUE,
|
|
filter = LocalPlayer(),
|
|
})
|
|
if tr.Fraction < 1 then -- We need to push the flashlight back
|
|
local tr2 = util.TraceLine({
|
|
start = owner:EyePos(),
|
|
endpos = owner:EyePos() + ang:Right() * 128,
|
|
mask = MASK_OPAQUE,
|
|
filter = LocalPlayer(),
|
|
})
|
|
-- push it as back as the area behind us allows
|
|
pos = pos + ang:Right() * 128 * math.min(1 - tr.Fraction, tr2.Fraction)
|
|
end
|
|
|
|
ang:RotateAroundAxis(ang:Up(), 90)
|
|
|
|
k.light:SetPos(pos)
|
|
k.light:SetAngles(ang)
|
|
k.light:Update()
|
|
|
|
-- local col = k.col
|
|
|
|
-- local dl = DynamicLight(self:EntIndex())
|
|
|
|
-- if dl then
|
|
-- dl.pos = pos
|
|
-- dl.r = col.r
|
|
-- dl.g = col.g
|
|
-- dl.b = col.b
|
|
-- dl.brightness = k.br or 2
|
|
-- -- print(z / maxz)
|
|
-- dl.Decay = 1000 / 0.1
|
|
-- dl.dietime = CurTime() + 0.1
|
|
-- dl.size = (k.br or 2) * 64
|
|
-- end
|
|
end
|
|
end
|