334 lines
10 KiB
Lua
334 lines
10 KiB
Lua
SWEP.Flashlights = {} -- tracks projectedlights
|
|
-- {{att = int, light = ProjectedTexture}}
|
|
|
|
function SWEP:GetHasFlashlights()
|
|
for i, k in pairs(self.Attachments) do
|
|
if !k.Installed then continue end
|
|
|
|
local atttbl = TacRP.GetAttTable(k.Installed)
|
|
|
|
if atttbl.Flashlight then return true end
|
|
end
|
|
|
|
return false
|
|
end
|
|
|
|
function SWEP:CreateFlashlights()
|
|
self:KillFlashlights()
|
|
self.Flashlights = {}
|
|
|
|
local total_lights = 0
|
|
|
|
for i, k in pairs(self.Attachments) do
|
|
if !k.Installed then continue end
|
|
|
|
local atttbl = TacRP.GetAttTable(k.Installed)
|
|
|
|
if atttbl.Flashlight then
|
|
local newlight = {
|
|
att = i,
|
|
light = ProjectedTexture(),
|
|
col = Color(255, 255, 255),
|
|
br = 4,
|
|
}
|
|
total_lights = total_lights + 1
|
|
|
|
local l = newlight.light
|
|
if !IsValid(l) then continue end
|
|
|
|
table.insert(self.Flashlights, newlight)
|
|
|
|
l:SetFOV(atttbl.FlashlightFOV or 60)
|
|
|
|
l:SetFarZ(atttbl.FlashlightFarZ or 1024)
|
|
l:SetNearZ(4)
|
|
|
|
l:SetQuadraticAttenuation(100)
|
|
|
|
l:SetColor(atttbl.FlashlightColor or color_white)
|
|
l:SetTexture("effects/flashlight001")
|
|
l:SetBrightness(atttbl.FlashlightBrightness or 1.5)
|
|
l:SetEnableShadows(true)
|
|
l:Update()
|
|
|
|
local g_light = {
|
|
Weapon = self,
|
|
ProjectedTexture = l
|
|
}
|
|
|
|
table.insert(TacRP.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
|
|
|
|
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:DrawFlashlightsVM()
|
|
|
|
if !self:GetTactical() then
|
|
self:KillFlashlights()
|
|
return
|
|
end
|
|
|
|
if !self.Flashlights then
|
|
self:CreateFlashlights()
|
|
end
|
|
|
|
for i, k in pairs(self.Flashlights) do
|
|
local model = self.Attachments[k.att].VModel
|
|
|
|
local pos, ang
|
|
|
|
if !IsValid(model) then
|
|
pos = self:GetOwner():EyePos()
|
|
ang = self:GetOwner():EyeAngles()
|
|
else
|
|
pos = model:GetPos()
|
|
ang = model:GetAngles()
|
|
end
|
|
|
|
local tr = util.TraceLine({
|
|
start = self:GetOwner():EyePos(),
|
|
endpos = self:GetOwner():EyePos() - -ang:Forward() * 128,
|
|
mask = MASK_OPAQUE,
|
|
filter = LocalPlayer(),
|
|
})
|
|
if tr.Fraction < 1 then -- We need to push the flashlight back
|
|
local tr2 = util.TraceLine({
|
|
start = self:GetOwner():EyePos(),
|
|
endpos = self:GetOwner():EyePos() + -ang:Forward() * 128,
|
|
mask = MASK_OPAQUE,
|
|
filter = LocalPlayer(),
|
|
})
|
|
-- push it as back as the area behind us allows
|
|
pos = pos + -ang:Forward() * 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
|
|
|
|
function SWEP:DrawFlashlightsWM()
|
|
if self:GetOwner() != LocalPlayer() then return end
|
|
|
|
if !self.Flashlights then
|
|
self:CreateFlashlights()
|
|
end
|
|
|
|
for i, k in ipairs(self.Flashlights) do
|
|
local model = (k.slottbl or {}).WModel
|
|
|
|
if !IsValid(model) then continue end
|
|
|
|
local pos, ang
|
|
|
|
if !model then
|
|
pos = self:GetOwner():EyePos()
|
|
ang = self:GetOwner():EyeAngles()
|
|
else
|
|
pos = model:GetPos()
|
|
ang = model:GetAngles()
|
|
end
|
|
|
|
-- ang:RotateAroundAxis(ang:Up(), 90)
|
|
|
|
local tr = util.TraceLine({
|
|
start = pos,
|
|
endpos = pos + ang:Forward() * 16,
|
|
mask = MASK_OPAQUE,
|
|
filter = LocalPlayer(),
|
|
})
|
|
if tr.Fraction < 1 then -- We need to push the flashlight back
|
|
local tr2 = util.TraceLine({
|
|
start = pos,
|
|
endpos = pos - ang:Forward() * 16,
|
|
mask = MASK_OPAQUE,
|
|
filter = LocalPlayer(),
|
|
})
|
|
-- push it as back as the area behind us allows
|
|
pos = pos + -ang:Forward() * 16 * math.min(1 - tr.Fraction, tr2.Fraction)
|
|
else
|
|
pos = tr.HitPos
|
|
end
|
|
|
|
k.light:SetPos(pos)
|
|
k.light:SetAngles(ang)
|
|
k.light:Update()
|
|
end
|
|
end
|
|
|
|
local flaremat = Material("tacrp/particle_flare")
|
|
function SWEP:DrawFlashlightGlare(pos, ang, strength, dot)
|
|
strength = strength or 1
|
|
|
|
local diff = EyePos() - pos
|
|
local wep = LocalPlayer():GetActiveWeapon()
|
|
--local dot = math.Clamp((-ang:Forward():Dot(EyeAngles():Forward()) - 0.707) / (1 - 0.707), 0, 1) ^ 2
|
|
if TacRP.ConVars["flashlight_blind"]:GetBool() then
|
|
dot = dot ^ 4
|
|
local tr = util.QuickTrace(pos, diff, {self:GetOwner(), LocalPlayer()})
|
|
local s = math.Clamp(1 - diff:Length() / 328, 0, 1) ^ 1 * dot * 2000 * math.Rand(0.95, 1.05)
|
|
if IsValid(wep) and wep.ArcticTacRP and wep:IsInScope() and wep:GetValue("ScopeOverlay") then
|
|
s = s + math.Clamp(1 - diff:Length() / 4096, 0, 1) ^ 1.2 * wep:GetSightAmount() * dot * 3000 * math.Rand(0.95, 1.05)
|
|
end
|
|
if tr.Fraction == 1 then
|
|
s = TacRP.SS(s)
|
|
local toscreen = pos:ToScreen()
|
|
cam.Start2D()
|
|
surface.SetMaterial(flaremat)
|
|
surface.SetDrawColor(255, 255, 255, 255)
|
|
surface.DrawTexturedRect(toscreen.x - s / 2, toscreen.y - s / 2, s, s)
|
|
cam.End2D()
|
|
end
|
|
end
|
|
|
|
local rad = math.Rand(0.9, 1.1) * 128 * strength
|
|
local a = 50 + strength * 205
|
|
|
|
pos = pos + ang:Forward() * 2
|
|
pos = pos + diff:GetNormalized() * (2 + 14 * strength)
|
|
|
|
render.SetMaterial(flaremat)
|
|
render.DrawSprite(pos, rad, rad, Color(255, 255, 255, a))
|
|
end
|
|
|
|
function SWEP:DrawFlashlightGlares()
|
|
if !self:GetOwner():IsPlayer() then return end
|
|
for i, k in pairs(self.Attachments) do
|
|
if !k.Installed then continue end
|
|
|
|
local atttbl = TacRP.GetAttTable(k.Installed)
|
|
|
|
local src, dir
|
|
if atttbl.Blinding and self:GetTactical() then
|
|
if IsValid(k.WModel) then
|
|
src, dir = k.WModel:GetPos(), self:GetShootDir()
|
|
else
|
|
src, dir = self:GetTracerOrigin(), self:GetShootDir()
|
|
end
|
|
else
|
|
continue
|
|
end
|
|
|
|
local power = 1
|
|
local dot = -dir:Forward():Dot(EyeAngles():Forward())
|
|
local dot2 = dir:Forward():Dot((EyePos() - src):GetNormalized())
|
|
dot = (dot + dot2) / 2
|
|
if dot < 0 then continue end
|
|
|
|
power = power * math.Clamp(dot * 2 - 1, 0, 1)
|
|
local distsqr = (src - EyePos()):LengthSqr()
|
|
power = power * ((1 - math.Clamp(distsqr / 4194304, 0, 1)) ^ 1.25)
|
|
|
|
self:DrawFlashlightGlare(src, dir, power, dot)
|
|
end
|
|
end
|
|
|
|
local glintmat = Material("effects/blueflare1")
|
|
local glintmat2 = Material("tacrp/scope_flare")
|
|
function SWEP:DoScopeGlint()
|
|
--if self:GetOwner() == LocalPlayer() then return end
|
|
if !TacRP.ConVars["glint"]:GetBool() then return end
|
|
if !self:GetValue("ScopeOverlay") then return end
|
|
local src, dir = self:GetTracerOrigin(), self:GetShootDir()
|
|
|
|
local diff = EyePos() - src
|
|
|
|
local dot = -dir:Forward():Dot(EyeAngles():Forward())
|
|
local dot2 = dir:Forward():Dot(diff:GetNormalized())
|
|
dot = math.max(0, (dot + dot2) / 2) ^ 1.5
|
|
|
|
local strength = dot * math.Clamp((diff:Length() - 1024) / 3072, 0, 3) * math.Clamp(90 / self:GetValue("ScopeFOV") / 10, 0, 1)
|
|
|
|
local rad = strength * 128 * (self:GetSightAmount() * 0.5 + 0.5)
|
|
|
|
src = src + dir:Up() * 4 + diff:GetNormalized() * math.Clamp(diff:Length() / 2048, 0, 1) * 16
|
|
|
|
local a = math.min(255, strength * 200 + 100)
|
|
|
|
render.SetMaterial(glintmat)
|
|
render.DrawSprite(src, rad, rad, Color(a, a, a))
|
|
|
|
-- if self:GetSightAmount() > 0 then
|
|
render.SetMaterial(glintmat2)
|
|
render.DrawSprite(src, rad * 2, rad * 2, color_white)
|
|
-- end
|
|
end
|
|
|
|
function SWEP:DoMuzzleLight()
|
|
if (!IsFirstTimePredicted() and !game.SinglePlayer()) or !TacRP.ConVars["muzzlelight"]:GetBool() then return end
|
|
|
|
if IsValid(self.MuzzleLight) then self.MuzzleLight:Remove() end
|
|
|
|
local lamp = ProjectedTexture()
|
|
lamp:SetTexture("tacrp/muzzleflash_light")
|
|
local val1, val2
|
|
if self:GetValue("Silencer") then
|
|
val1, val2 = math.Rand(0.2, 0.4), math.Rand(100, 105)
|
|
lamp:SetBrightness(val1)
|
|
lamp:SetFOV(val2)
|
|
else
|
|
val1, val2 = math.Rand(2, 3), math.Rand(115, 120)
|
|
lamp:SetBrightness(val1)
|
|
lamp:SetFOV(val2)
|
|
end
|
|
|
|
lamp:SetFarZ(600)
|
|
lamp:SetPos(self:GetMuzzleOrigin() + self:GetShootDir():Forward() * 8)
|
|
lamp:SetAngles(self:GetShootDir() + Angle(math.Rand(-1, 1), math.Rand(-1, 1), math.Rand(0, 360)))
|
|
lamp:Update()
|
|
|
|
self.MuzzleLight = lamp
|
|
self.MuzzleLightStart = UnPredictedCurTime()
|
|
self.MuzzleLightEnd = UnPredictedCurTime() + 0.06
|
|
self.MuzzleLightBrightness = val1
|
|
self.MuzzleLightFOV = val2
|
|
|
|
-- In multiplayer the timer will last longer than intended - sh_think should kill the light first.
|
|
-- This is a failsafe for when the weapon stops thinking before light is killed (holstered, removed etc.).
|
|
timer.Simple(0.06, function()
|
|
if IsValid(lamp) then lamp:Remove() end
|
|
end)
|
|
end
|