mirror of
https://github.com/lifestorm/wnsrc.git
synced 2025-12-17 13:53:45 +03:00
Upload
This commit is contained in:
60
lua/weapons/tfa_gun_base/cl_init.lua
Normal file
60
lua/weapons/tfa_gun_base/cl_init.lua
Normal file
@@ -0,0 +1,60 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
-- Copyright (c) 2018-2020 TFA Base Devs
|
||||
|
||||
-- Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
-- of this software and associated documentation files (the "Software"), to deal
|
||||
-- in the Software without restriction, including without limitation the rights
|
||||
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
-- copies of the Software, and to permit persons to whom the Software is
|
||||
-- furnished to do so, subject to the following conditions:
|
||||
|
||||
-- The above copyright notice and this permission notice shall be included in all
|
||||
-- copies or substantial portions of the Software.
|
||||
|
||||
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
-- SOFTWARE.
|
||||
|
||||
include("shared.lua")
|
||||
|
||||
include("common/ai_translations.lua")
|
||||
include("common/anims.lua")
|
||||
include("common/autodetection.lua")
|
||||
include("common/utils.lua")
|
||||
include("common/stat.lua")
|
||||
include("common/attachments.lua")
|
||||
include("common/bullet.lua")
|
||||
include("common/effects.lua")
|
||||
include("common/calc.lua")
|
||||
include("common/akimbo.lua")
|
||||
include("common/events.lua")
|
||||
include("common/nzombies.lua")
|
||||
include("common/ttt.lua")
|
||||
include("common/viewmodel.lua")
|
||||
include("common/skins.lua")
|
||||
|
||||
include("client/effects.lua")
|
||||
include("client/viewbob.lua")
|
||||
include("client/viewmodel.lua")
|
||||
include("client/bobcode.lua")
|
||||
include("client/hud.lua")
|
||||
include("client/mods.lua")
|
||||
include("client/laser.lua")
|
||||
include("client/fov.lua")
|
||||
include("client/flashlight.lua")
|
||||
|
||||
TFA.FillMissingMetaValues(SWEP)
|
||||
247
lua/weapons/tfa_gun_base/client/bobcode.lua
Normal file
247
lua/weapons/tfa_gun_base/client/bobcode.lua
Normal file
@@ -0,0 +1,247 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
-- Copyright (c) 2018-2020 TFA Base Devs
|
||||
|
||||
-- Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
-- of this software and associated documentation files (the "Software"), to deal
|
||||
-- in the Software without restriction, including without limitation the rights
|
||||
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
-- copies of the Software, and to permit persons to whom the Software is
|
||||
-- furnished to do so, subject to the following conditions:
|
||||
|
||||
-- The above copyright notice and this permission notice shall be included in all
|
||||
-- copies or substantial portions of the Software.
|
||||
|
||||
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
-- SOFTWARE.
|
||||
|
||||
local vector_origin = Vector()
|
||||
|
||||
SWEP.ti = 0
|
||||
SWEP.LastCalcBob = 0
|
||||
SWEP.tiView = 0
|
||||
SWEP.LastCalcViewBob = 0
|
||||
local TAU = math.pi * 2
|
||||
local rateScaleFac = 2
|
||||
local rate_up = 6 * rateScaleFac
|
||||
local scale_up = 0.5
|
||||
local rate_right = 3 * rateScaleFac
|
||||
local scale_right = -0.5
|
||||
local rate_forward_view = 3 * rateScaleFac
|
||||
local scale_forward_view = 0.35
|
||||
local rate_right_view = 3 * rateScaleFac
|
||||
local scale_right_view = -1
|
||||
local rate_p = 6 * rateScaleFac
|
||||
local scale_p = 3
|
||||
local rate_y = 3 * rateScaleFac
|
||||
local scale_y = 6
|
||||
local rate_r = 3 * rateScaleFac
|
||||
local scale_r = -6
|
||||
local pist_rate = 3 * rateScaleFac
|
||||
local pist_scale = 9
|
||||
local rate_clamp = 2 * rateScaleFac
|
||||
local walkIntensitySmooth, breathIntensitySmooth = 0, 0
|
||||
local walkRate = 160 / 60 * TAU / 1.085 / 2 * rateScaleFac --steps are at 160bpm at default velocity, then divide that by 60 for per-second, multiply by TAU for trig, divided by default walk rate
|
||||
local walkVec = Vector()
|
||||
local ownerVelocity, ownerVelocityMod = Vector(), Vector()
|
||||
local zVelocity, zVelocitySmooth = 0, 0
|
||||
local xVelocity, xVelocitySmooth, rightVec = 0, 0, Vector()
|
||||
local flatVec = Vector(1, 1, 0)
|
||||
local WalkPos = Vector()
|
||||
local WalkPosLagged = Vector()
|
||||
local gunbob_intensity_cvar = GetConVar("cl_tfa_gunbob_intensity")
|
||||
local gunbob_intensity = 0
|
||||
SWEP.VMOffsetWalk = Vector(0.5, -0.5, -0.5)
|
||||
SWEP.footstepTotal = 0
|
||||
SWEP.footstepTotalTarget = 0
|
||||
local upVec, riVec, fwVec = Vector(0, 0, 1), Vector(1, 0, 0), Vector(0, 1, 0)
|
||||
|
||||
local function l_Lerp(t, a, b)
|
||||
if t <= 0 then return a end
|
||||
if t >= 1 then return b end
|
||||
return a + (b - a) * t
|
||||
end
|
||||
|
||||
function SWEP:WalkBob(pos, ang, breathIntensity, walkIntensity, rate, ftv)
|
||||
local self2 = self:GetTable()
|
||||
if not self2.OwnerIsValid(self) then return end
|
||||
rate = math.min(rate or 0.5, rate_clamp)
|
||||
gunbob_intensity = gunbob_intensity_cvar:GetFloat()
|
||||
|
||||
local ea = self:GetOwner():EyeAngles()
|
||||
local up = ang:Up()
|
||||
local ri = ang:Right()
|
||||
local fw = ang:Forward()
|
||||
local upLocal = upVec
|
||||
local riLocal = riVec
|
||||
local fwLocal = fwVec
|
||||
local delta = ftv
|
||||
local flip_v = self2.ViewModelFlip and -1 or 1
|
||||
--delta = delta * game.GetTimeScale()
|
||||
--self2.LastCalcBob = SysTime()
|
||||
self2.bobRateCached = rate
|
||||
self2.ti = self2.ti + delta * rate
|
||||
|
||||
if self2.SprintStyle == nil then
|
||||
if self:GetStatL("SprintViewModelAngle") and self:GetStatL("SprintViewModelAngle").x > 5 then
|
||||
self2.SprintStyle = 1
|
||||
else
|
||||
self2.SprintStyle = 0
|
||||
end
|
||||
end
|
||||
|
||||
--preceding calcs
|
||||
walkIntensitySmooth = l_Lerp(delta * 10 * rateScaleFac, walkIntensitySmooth, walkIntensity)
|
||||
breathIntensitySmooth = l_Lerp(delta * 10 * rateScaleFac, breathIntensitySmooth, breathIntensity)
|
||||
walkVec = LerpVector(walkIntensitySmooth, vector_origin, self2.VMOffsetWalk)
|
||||
ownerVelocity = self:GetOwner():GetVelocity()
|
||||
zVelocity = ownerVelocity.z
|
||||
zVelocitySmooth = l_Lerp(delta * 7 * rateScaleFac, zVelocitySmooth, zVelocity)
|
||||
ownerVelocityMod = ownerVelocity * flatVec
|
||||
ownerVelocityMod:Normalize()
|
||||
rightVec = ea:Right() * flatVec
|
||||
rightVec:Normalize()
|
||||
xVelocity = ownerVelocity:Length2D() * ownerVelocityMod:Dot(rightVec)
|
||||
xVelocitySmooth = l_Lerp(delta * 5 * rateScaleFac, xVelocitySmooth, xVelocity)
|
||||
|
||||
--multipliers
|
||||
breathIntensity = breathIntensitySmooth * gunbob_intensity * 1.5
|
||||
walkIntensity = walkIntensitySmooth * gunbob_intensity * 1.5
|
||||
|
||||
--breathing / walking while ADS
|
||||
local breatheMult2 = math.Clamp((self2.IronSightsProgressUnpredicted2 or self:GetIronSightsProgress()), 0, 1)
|
||||
--local breatheMult2 = 0
|
||||
local breatheMult1 = 1 - breatheMult2
|
||||
--local breatheMult1 = 1
|
||||
|
||||
pos:Add(riLocal * (math.sin(self2.ti * walkRate) - math.cos(self2.ti * walkRate)) * flip_v * breathIntensity * 0.2 * breatheMult1)
|
||||
pos:Add(upLocal * math.sin(self2.ti * walkRate) * breathIntensity * 0.5 * breatheMult1)
|
||||
|
||||
pos:Add(riLocal * math.cos(self2.ti * walkRate / 2) * flip_v * breathIntensity * 0.6 * breatheMult2)
|
||||
pos:Add(upLocal * math.sin(self2.ti * walkRate) * breathIntensity * 0.3 * breatheMult2)
|
||||
|
||||
--walk anims, danny method because i just can't
|
||||
self2.walkTI = (self2.walkTI or 0) + delta * 160 / 60 * self:GetOwner():GetVelocity():Length2D() / self:GetOwner():GetWalkSpeed()
|
||||
WalkPos.x = l_Lerp(delta * 5 * rateScaleFac, WalkPos.x, -math.sin(self2.ti * walkRate * 0.5) * gunbob_intensity * walkIntensity)
|
||||
WalkPos.y = l_Lerp(delta * 5 * rateScaleFac, WalkPos.y, math.sin(self2.ti * walkRate) / 1.5 * gunbob_intensity * walkIntensity)
|
||||
WalkPosLagged.x = l_Lerp(delta * 5 * rateScaleFac, WalkPosLagged.x, -math.sin((self2.ti * walkRate * 0.5) + math.pi / 3) * gunbob_intensity * walkIntensity)
|
||||
WalkPosLagged.y = l_Lerp(delta * 5 * rateScaleFac, WalkPosLagged.y, math.sin(self2.ti * walkRate + math.pi / 3) / 1.5 * gunbob_intensity * walkIntensity)
|
||||
pos:Add(WalkPos.x * 0.33 * riLocal)
|
||||
pos:Add(WalkPos.y * 0.25 * upLocal)
|
||||
ang:RotateAroundAxis(ri, -WalkPosLagged.y)
|
||||
ang:RotateAroundAxis(up, WalkPosLagged.x)
|
||||
ang:RotateAroundAxis(fw, WalkPos.x)
|
||||
|
||||
--constant offset
|
||||
pos:Add(riLocal * walkVec.x * flip_v)
|
||||
pos:Add(fwLocal * walkVec.y)
|
||||
pos:Add(upLocal * walkVec.z)
|
||||
|
||||
--jumping
|
||||
local trigX = -math.Clamp(zVelocitySmooth / 200, -1, 1) * math.pi / 2
|
||||
local jumpIntensity = (3 + math.Clamp(math.abs(zVelocitySmooth) - 100, 0, 200) / 200 * 4) * (1 - (self2.IronSightsProgressUnpredicted or self:GetIronSightsProgress()) * 0.8)
|
||||
pos:Add(ri * math.sin(trigX) * scale_r * 0.1 * jumpIntensity * flip_v * 0.4)
|
||||
pos:Add(-up * math.sin(trigX) * scale_r * 0.1 * jumpIntensity * 0.4)
|
||||
ang:RotateAroundAxis(ang:Forward(), math.sin(trigX) * scale_r * jumpIntensity * flip_v * 0.4)
|
||||
|
||||
--rolling with horizontal motion
|
||||
local xVelocityClamped = xVelocitySmooth
|
||||
|
||||
if math.abs(xVelocityClamped) > 200 then
|
||||
local sign = (xVelocityClamped < 0) and -1 or 1
|
||||
xVelocityClamped = (math.sqrt((math.abs(xVelocityClamped) - 200) / 50) * 50 + 200) * sign
|
||||
end
|
||||
|
||||
ang:RotateAroundAxis(ang:Forward(), xVelocityClamped * 0.04 * flip_v)
|
||||
|
||||
return pos, ang
|
||||
end
|
||||
|
||||
function SWEP:SprintBob(pos, ang, intensity, origPos, origAng)
|
||||
local self2 = self:GetTable()
|
||||
if not IsValid(self:GetOwner()) or not gunbob_intensity then return pos, ang end
|
||||
local flip_v = self2.ViewModelFlip and -1 or 1
|
||||
|
||||
local eyeAngles = self:GetOwner():EyeAngles()
|
||||
local localUp = ang:Up()
|
||||
local localRight = ang:Right()
|
||||
local localForward = ang:Forward()
|
||||
|
||||
local playerUp = eyeAngles:Up()
|
||||
local playerRight = eyeAngles:Right()
|
||||
local playerForward = eyeAngles:Forward()
|
||||
|
||||
intensity = intensity * gunbob_intensity * 1.5
|
||||
gunbob_intensity = gunbob_intensity_cvar:GetFloat()
|
||||
|
||||
if intensity > 0.005 then
|
||||
if self2.SprintStyle == 1 then
|
||||
local intensity3 = math.max(intensity - 0.3, 0) / (1 - 0.3)
|
||||
ang:RotateAroundAxis(ang:Up(), math.sin(self2.ti * pist_rate) * pist_scale * intensity3 * 0.33 * 0.75)
|
||||
ang:RotateAroundAxis(ang:Forward(), math.sin(self2.ti * pist_rate) * pist_scale * intensity3 * 0.33 * -0.25)
|
||||
pos:Add(ang:Forward() * math.sin(self2.ti * pist_rate * 2 + math.pi) * pist_scale * -0.1 * intensity3 * 0.4)
|
||||
pos:Add(ang:Right() * math.sin(self2.ti * pist_rate) * pist_scale * 0.15 * intensity3 * 0.33 * 0.2)
|
||||
else
|
||||
pos:Add(localUp * math.sin(self2.ti * rate_up + math.pi) * scale_up * intensity * 0.33)
|
||||
pos:Add(localRight * math.sin(self2.ti * rate_right) * scale_right * intensity * flip_v * 0.33)
|
||||
pos:Add(eyeAngles:Forward() * math.max(math.sin(self2.ti * rate_forward_view), 0) * scale_forward_view * intensity * 0.33)
|
||||
pos:Add(eyeAngles:Right() * math.sin(self2.ti * rate_right_view) * scale_right_view * intensity * flip_v * 0.33)
|
||||
|
||||
ang:RotateAroundAxis(localRight, math.sin(self2.ti * rate_p + math.pi) * scale_p * intensity * 0.33)
|
||||
pos:Add(-localUp * math.sin(self2.ti * rate_p + math.pi) * scale_p * 0.1 * intensity * 0.33)
|
||||
|
||||
ang:RotateAroundAxis(localUp, math.sin(self2.ti * rate_y) * scale_y * intensity * flip_v * 0.33)
|
||||
pos:Add(localRight * math.sin(self2.ti * rate_y) * scale_y * 0.1 * intensity * flip_v * 0.33)
|
||||
|
||||
ang:RotateAroundAxis(localForward, math.sin(self2.ti * rate_r) * scale_r * intensity * flip_v * 0.33)
|
||||
pos:Add(localRight * math.sin(self2.ti * rate_r) * scale_r * 0.05 * intensity * flip_v * 0.33)
|
||||
pos:Add(localUp * math.sin(self2.ti * rate_r) * scale_r * 0.1 * intensity * 0.33)
|
||||
end
|
||||
end
|
||||
|
||||
return pos, ang
|
||||
end
|
||||
|
||||
local cv_customgunbob = GetConVar("cl_tfa_gunbob_custom")
|
||||
local fac, bscale
|
||||
|
||||
function SWEP:UpdateEngineBob()
|
||||
local self2 = self:GetTable()
|
||||
|
||||
if cv_customgunbob:GetBool() then
|
||||
self2.BobScale = 0
|
||||
self2.SwayScale = 0
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
local isp = self2.IronSightsProgressUnpredicted or self:GetIronSightsProgress()
|
||||
local wpr = self2.WalkProgressUnpredicted or self:GetWalkProgress()
|
||||
local spr = self:GetSprintProgress()
|
||||
|
||||
fac = gunbob_intensity_cvar:GetFloat() * ((1 - isp) * 0.85 + 0.15)
|
||||
bscale = fac
|
||||
|
||||
if spr > 0.005 then
|
||||
bscale = bscale * l_Lerp(spr, 1, self2.SprintBobMult)
|
||||
elseif wpr > 0.005 then
|
||||
bscale = bscale * l_Lerp(wpr, 1, l_Lerp(isp, self2.WalkBobMult, self2.WalkBobMult_Iron or self2.WalkBobMult))
|
||||
end
|
||||
|
||||
self2.BobScale = bscale
|
||||
self2.SwayScale = fac
|
||||
end
|
||||
202
lua/weapons/tfa_gun_base/client/effects.lua
Normal file
202
lua/weapons/tfa_gun_base/client/effects.lua
Normal file
@@ -0,0 +1,202 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
-- Copyright (c) 2018-2020 TFA Base Devs
|
||||
|
||||
-- Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
-- of this software and associated documentation files (the "Software"), to deal
|
||||
-- in the Software without restriction, including without limitation the rights
|
||||
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
-- copies of the Software, and to permit persons to whom the Software is
|
||||
-- furnished to do so, subject to the following conditions:
|
||||
|
||||
-- The above copyright notice and this permission notice shall be included in all
|
||||
-- copies or substantial portions of the Software.
|
||||
|
||||
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
-- SOFTWARE.
|
||||
|
||||
local vector_up = Vector(0, 0, 1)
|
||||
local math = math
|
||||
local render = render
|
||||
local LerpVector = LerpVector
|
||||
|
||||
--[[
|
||||
Function Name: ComputeSmokeLighting
|
||||
Syntax: self:ComputeSmokeLighting(pos, nrm, pcf).
|
||||
Returns: Nothing.
|
||||
Notes: Used to light the muzzle smoke trail, by setting its PCF Control Point 1
|
||||
Purpose: FX
|
||||
]]--
|
||||
function SWEP:ComputeSmokeLighting( pos, nrm, pcf )
|
||||
if not IsValid(pcf) then return end
|
||||
local licht = render.ComputeLighting(pos, nrm)
|
||||
local lichtFloat = math.Clamp((licht.r + licht.g + licht.b) / 3, 0, TFA.Particles.SmokeLightingClamp) / TFA.Particles.SmokeLightingClamp
|
||||
local lichtFinal = LerpVector(lichtFloat, TFA.Particles.SmokeLightingMin, TFA.Particles.SmokeLightingMax)
|
||||
pcf:SetControlPoint(1, lichtFinal)
|
||||
end
|
||||
|
||||
--[[
|
||||
Function Name: SmokePCFLighting
|
||||
Syntax: self:SmokePCFLighting().
|
||||
Returns: Nothing.
|
||||
Notes: Used to loop through all of our SmokePCF tables and call ComputeSmokeLighting on them
|
||||
Purpose: FX
|
||||
]]--
|
||||
function SWEP:SmokePCFLighting()
|
||||
local mzPos = self:GetMuzzlePos()
|
||||
if not mzPos or not mzPos.Pos then return end
|
||||
local pos = mzPos.Pos
|
||||
if self.SmokePCF then
|
||||
for _, v in pairs(self.SmokePCF) do
|
||||
self:ComputeSmokeLighting(pos, vector_up, v)
|
||||
end
|
||||
end
|
||||
if not self:VMIV() then return end
|
||||
local vm = self.OwnerViewModel
|
||||
if vm.SmokePCF then
|
||||
for _, v in pairs(vm.SmokePCF) do
|
||||
self:ComputeSmokeLighting(pos, vector_up, v)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
Function Name: FireAnimationEvent
|
||||
Syntax: self:FireAnimationEvent( position, angle, event id, options).
|
||||
Returns: Nothing.
|
||||
Notes: Used to capture and disable viewmodel animation events, unless you disable that feature.
|
||||
Purpose: FX
|
||||
]]--
|
||||
function SWEP:FireAnimationEvent(pos, ang, event, options)
|
||||
if self.CustomMuzzleFlash or not self.MuzzleFlashEnabled then
|
||||
-- Disables animation based muzzle event
|
||||
if (event == 21) then return true end
|
||||
-- Disable thirdperson muzzle flash
|
||||
if (event == 5003) then return true end
|
||||
|
||||
-- Disable CS-style muzzle flashes, but chance our muzzle flash attachment if one is given.
|
||||
if (event == 5001 or event == 5011 or event == 5021 or event == 5031) then
|
||||
if self.AutoDetectMuzzleAttachment then
|
||||
self.MuzzleAttachmentRaw = math.Clamp(math.floor((event - 4991) / 10), 1, 4)
|
||||
self:ShootEffectsCustom(true)
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
if (self.LuaShellEject and event ~= 5004) then return true end
|
||||
end
|
||||
|
||||
--[[
|
||||
Function Name: MakeMuzzleSmoke
|
||||
Syntax: self:MakeMuzzleSmoke( entity, attachment).
|
||||
Returns: Nothing.
|
||||
Notes: Deprecated. Used to make the muzzle smoke effect, clientside.
|
||||
Purpose: FX
|
||||
]]--
|
||||
|
||||
local limit_particle_cv = GetConVar("cl_tfa_fx_muzzlesmoke_limited")
|
||||
|
||||
function SWEP:MakeMuzzleSmoke(entity, attachment)
|
||||
if ( not limit_particle_cv ) or limit_particle_cv:GetBool() then
|
||||
self:CleanParticles()
|
||||
end
|
||||
local ht = self.DefaultHoldType and self.DefaultHoldType or self.HoldType
|
||||
|
||||
if (CLIENT and TFA.GetMZSmokeEnabled() and IsValid(entity) and attachment and attachment ~= 0) then
|
||||
ParticleEffectAttach(self.SmokeParticles[ht], PATTACH_POINT_FOLLOW, entity, attachment)
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
Function Name: ImpactEffect
|
||||
Syntax: self:ImpactEffect( position, normal (ang:Up()), materialt ype).
|
||||
Returns: Nothing.
|
||||
Notes: Used to make the impact effect. See utilities code for CanDustEffect.
|
||||
Purpose: FX
|
||||
]]--
|
||||
|
||||
function SWEP:DoImpactEffect(tr, dmgtype)
|
||||
if tr.HitSky then return true end
|
||||
local ib = self.BashBase and IsValid(self) and self:GetBashing()
|
||||
local dmginfo = DamageInfo()
|
||||
dmginfo:SetDamageType(dmgtype)
|
||||
|
||||
if dmginfo:IsDamageType(DMG_SLASH) or (ib and self.Secondary_TFA.BashDamageType == DMG_SLASH and tr.MatType ~= MAT_FLESH and tr.MatType ~= MAT_ALIENFLESH) or (self and self.DamageType and self.DamageType == DMG_SLASH) then
|
||||
util.Decal("ManhackCut", tr.HitPos + tr.HitNormal, tr.HitPos - tr.HitNormal)
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
if ib and self.Secondary_TFA.BashDamageType == DMG_GENERIC then return true end
|
||||
if ib then return end
|
||||
|
||||
if IsValid(self) then
|
||||
self:ImpactEffectFunc(tr.HitPos, tr.HitNormal, tr.MatType)
|
||||
end
|
||||
|
||||
if self.ImpactDecal and self.ImpactDecal ~= "" then
|
||||
util.Decal(self.ImpactDecal, tr.HitPos + tr.HitNormal, tr.HitPos - tr.HitNormal)
|
||||
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
local impact_cl_enabled = GetConVar("cl_tfa_fx_impact_enabled")
|
||||
local impact_sv_enabled = GetConVar("sv_tfa_fx_impact_override")
|
||||
|
||||
function SWEP:ImpactEffectFunc(pos, normal, mattype)
|
||||
local enabled
|
||||
|
||||
if impact_cl_enabled then
|
||||
enabled = impact_cl_enabled:GetBool()
|
||||
else
|
||||
enabled = true
|
||||
end
|
||||
|
||||
if impact_sv_enabled and impact_sv_enabled:GetInt() >= 0 then
|
||||
enabled = impact_sv_enabled:GetBool()
|
||||
end
|
||||
|
||||
if enabled then
|
||||
local fx = EffectData()
|
||||
fx:SetOrigin(pos)
|
||||
fx:SetNormal(normal)
|
||||
|
||||
if self:CanDustEffect(mattype) then
|
||||
TFA.Effects.Create("tfa_dust_impact", fx)
|
||||
end
|
||||
|
||||
if self:CanSparkEffect(mattype) then
|
||||
TFA.Effects.Create("tfa_metal_impact", fx)
|
||||
end
|
||||
|
||||
local scal = math.sqrt(self:GetStatL("Primary.Damage") / 30)
|
||||
if mattype == MAT_FLESH then
|
||||
scal = scal * 0.25
|
||||
end
|
||||
fx:SetEntity(self:GetOwner())
|
||||
fx:SetMagnitude(mattype or 0)
|
||||
fx:SetScale( scal )
|
||||
TFA.Effects.Create("tfa_bullet_impact", fx)
|
||||
|
||||
if self.ImpactEffect then
|
||||
TFA.Effects.Create(self.ImpactEffect, fx)
|
||||
end
|
||||
end
|
||||
end
|
||||
213
lua/weapons/tfa_gun_base/client/flashlight.lua
Normal file
213
lua/weapons/tfa_gun_base/client/flashlight.lua
Normal file
@@ -0,0 +1,213 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
-- Copyright (c) 2018-2020 TFA Base Devs
|
||||
|
||||
-- Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
-- of this software and associated documentation files (the "Software"), to deal
|
||||
-- in the Software without restriction, including without limitation the rights
|
||||
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
-- copies of the Software, and to permit persons to whom the Software is
|
||||
-- furnished to do so, subject to the following conditions:
|
||||
|
||||
-- The above copyright notice and this permission notice shall be included in all
|
||||
-- copies or substantial portions of the Software.
|
||||
|
||||
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
-- SOFTWARE.
|
||||
|
||||
local vector_origin = Vector()
|
||||
|
||||
local att, angpos, attname, elemname, targetent
|
||||
SWEP.FlashlightDistance = 12 * 50 -- default 50 feet
|
||||
SWEP.FlashlightAttachment = 0
|
||||
SWEP.FlashlightBrightness = 1
|
||||
SWEP.FlashlightFOV = 60
|
||||
|
||||
local Material = Material
|
||||
local ProjectedTexture = ProjectedTexture
|
||||
local math = math
|
||||
|
||||
local function IsHolstering(wep)
|
||||
if IsValid(wep) and TFA.Enum.HolsterStatus[wep:GetStatus()] then return true end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
-- TODO: This seems to be *extremely* similar to drawlaser
|
||||
-- Should we merge them?
|
||||
function SWEP:DrawFlashlight(is_vm)
|
||||
local self2 = self:GetTable()
|
||||
|
||||
if not self2.FlashlightDotMaterial then
|
||||
self2.FlashlightDotMaterial = Material(self2.GetStatL(self, "FlashlightMaterial") or "effects/flashlight001")
|
||||
end
|
||||
|
||||
local ply = self:GetOwner()
|
||||
if not IsValid(ply) then return end
|
||||
|
||||
if not self:GetFlashlightEnabled() then
|
||||
self:CleanFlashlight()
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
if is_vm then
|
||||
if not self:VMIV() then
|
||||
self:CleanFlashlight()
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
targetent = ply:GetViewModel()
|
||||
elemname = self2.GetStatL(self, "Flashlight_VElement", self2.GetStatL(self, "Flashlight_Element"))
|
||||
|
||||
local ViewModelElements = self:GetStatRaw("ViewModelElements", TFA.LatestDataVersion)
|
||||
|
||||
if elemname and ViewModelElements[elemname] and IsValid(ViewModelElements[elemname].curmodel) then
|
||||
targetent = ViewModelElements[elemname].curmodel
|
||||
end
|
||||
|
||||
att = self2.GetStatL(self, "FlashlightAttachment")
|
||||
|
||||
attname = self2.GetStatL(self, "FlashlightAttachmentName")
|
||||
|
||||
if attname then
|
||||
att = targetent:LookupAttachment(attname)
|
||||
end
|
||||
|
||||
if (not att) or att <= 0 then
|
||||
self:CleanFlashlight()
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
angpos = targetent:GetAttachment(att)
|
||||
|
||||
if not angpos then
|
||||
self:CleanFlashlight()
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
if self2.FlashlightISMovement and self2.CLIronSightsProgress > 0 then
|
||||
local isang = self2.GetStatL(self, "IronSightsAngle")
|
||||
angpos.Ang:RotateAroundAxis(angpos.Ang:Right(), isang.y * (self2.ViewModelFlip and -1 or 1) * self2.CLIronSightsProgress)
|
||||
angpos.Ang:RotateAroundAxis(angpos.Ang:Up(), -isang.x * self2.CLIronSightsProgress)
|
||||
end
|
||||
|
||||
local localProjAng = select(2, WorldToLocal(vector_origin, angpos.Ang, vector_origin, EyeAngles()))
|
||||
localProjAng.p = localProjAng.p * ply:GetFOV() / self2.ViewModelFOV
|
||||
localProjAng.y = localProjAng.y * ply:GetFOV() / self2.ViewModelFOV
|
||||
local wsProjAng = select(2, LocalToWorld(vector_origin, localProjAng, vector_origin, EyeAngles())) --reprojection for view angle
|
||||
|
||||
if not IsValid(ply.TFAFlashlightGun) and not IsHolstering(self) then
|
||||
local lamp = ProjectedTexture()
|
||||
ply.TFAFlashlightGun = lamp
|
||||
lamp:SetTexture(self2.FlashlightDotMaterial:GetString("$basetexture"))
|
||||
lamp:SetFarZ(self2.GetStatL(self, "FlashlightDistance")) -- How far the light should shine
|
||||
lamp:SetFOV(self2.GetStatL(self, "FlashlightFOV"))
|
||||
lamp:SetPos(angpos.Pos)
|
||||
lamp:SetAngles(angpos.Ang)
|
||||
lamp:SetBrightness(self2.GetStatL(self, "FlashlightBrightness") * (0.9 + 0.1 * math.max(math.sin(CurTime() * 120), math.cos(CurTime() * 40))))
|
||||
lamp:SetNearZ(1)
|
||||
lamp:SetColor(color_white)
|
||||
lamp:SetEnableShadows(true)
|
||||
lamp:Update()
|
||||
end
|
||||
|
||||
local lamp = ply.TFAFlashlightGun
|
||||
|
||||
if IsValid(lamp) then
|
||||
lamp:SetPos(angpos.Pos)
|
||||
lamp:SetAngles(wsProjAng)
|
||||
lamp:SetBrightness(1.4 + 0.1 * math.max(math.sin(CurTime() * 120), math.cos(CurTime() * 40)))
|
||||
lamp:Update()
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
targetent = self
|
||||
|
||||
elemname = self2.GetStatL(self, "Flashlight_WElement", self2.GetStatL(self, "Flashlight_Element"))
|
||||
|
||||
local WorldModelElements = self:GetStatRaw("WorldModelElements", TFA.LatestDataVersion)
|
||||
|
||||
if elemname and WorldModelElements[elemname] and IsValid(WorldModelElements[elemname].curmodel) then
|
||||
targetent = WorldModelElements[elemname].curmodel
|
||||
end
|
||||
|
||||
att = self2.GetStatL(self, "FlashlightAttachmentWorld", self2.GetStatL(self, "FlashlightAttachment"))
|
||||
|
||||
attname = self2.GetStatL(self, "FlashlightAttachmentNameWorld", self2.GetStatL(self, "FlashlightAttachmentName"))
|
||||
|
||||
if attname then
|
||||
att = targetent:LookupAttachment(attname)
|
||||
end
|
||||
|
||||
if (not att) or att <= 0 then
|
||||
self:CleanFlashlight()
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
angpos = targetent:GetAttachment(att)
|
||||
|
||||
if not angpos then
|
||||
angpos = targetent:GetAttachment(1)
|
||||
end
|
||||
|
||||
if not angpos then
|
||||
self:CleanFlashlight()
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
if not IsValid(ply.TFAFlashlightGun) and not IsHolstering(self) then
|
||||
local lamp = ProjectedTexture()
|
||||
ply.TFAFlashlightGun = lamp
|
||||
lamp:SetTexture(self2.FlashlightDotMaterial:GetString("$basetexture"))
|
||||
lamp:SetFarZ(self2.GetStatL(self, "FlashlightDistance")) -- How far the light should shine
|
||||
lamp:SetFOV(self2.GetStatL(self, "FlashlightFOV"))
|
||||
lamp:SetPos(angpos.Pos)
|
||||
lamp:SetAngles(angpos.Ang)
|
||||
lamp:SetBrightness(self2.GetStatL(self, "FlashlightBrightness") * (0.9 + 0.1 * math.max(math.sin(CurTime() * 120), math.cos(CurTime() * 40))))
|
||||
lamp:SetNearZ(1)
|
||||
lamp:SetColor(color_white)
|
||||
lamp:SetEnableShadows(false)
|
||||
lamp:Update()
|
||||
end
|
||||
|
||||
local lamp = ply.TFAFlashlightGun
|
||||
|
||||
if IsValid(lamp) then
|
||||
local lamppos = angpos.Pos
|
||||
local ang = angpos.Ang
|
||||
lamp:SetPos(lamppos)
|
||||
lamp:SetAngles(ang)
|
||||
lamp:SetBrightness(self2.GetStatL(self, "FlashlightBrightness") * (0.9 + 0.1 * math.max(math.sin(CurTime() * 120), math.cos(CurTime() * 40))))
|
||||
lamp:Update()
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:CleanFlashlight()
|
||||
local ply = self:GetOwner()
|
||||
|
||||
if IsValid(ply) and IsValid(ply.TFAFlashlightGun) then
|
||||
ply.TFAFlashlightGun:Remove()
|
||||
end
|
||||
end
|
||||
77
lua/weapons/tfa_gun_base/client/fov.lua
Normal file
77
lua/weapons/tfa_gun_base/client/fov.lua
Normal file
@@ -0,0 +1,77 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
-- Copyright (c) 2018-2020 TFA Base Devs
|
||||
|
||||
-- Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
-- of this software and associated documentation files (the "Software"), to deal
|
||||
-- in the Software without restriction, including without limitation the rights
|
||||
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
-- copies of the Software, and to permit persons to whom the Software is
|
||||
-- furnished to do so, subject to the following conditions:
|
||||
|
||||
-- The above copyright notice and this permission notice shall be included in all
|
||||
-- copies or substantial portions of the Software.
|
||||
|
||||
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
-- SOFTWARE.
|
||||
|
||||
local LocalPlayer = LocalPlayer
|
||||
local math = math
|
||||
|
||||
local function GetScreenAspectRatio()
|
||||
return ScrW() / ScrH()
|
||||
end
|
||||
|
||||
local function ScaleFOVByWidthRatio(fovDegrees, ratio)
|
||||
local halfAngleRadians = fovDegrees * (0.5 * math.pi / 180.0)
|
||||
local t = math.tan(halfAngleRadians)
|
||||
t = t * ratio
|
||||
local retDegrees = (180.0 / math.pi) * math.atan(t)
|
||||
|
||||
return retDegrees * 2.0
|
||||
end
|
||||
|
||||
local default_fov_cv = GetConVar("default_fov")
|
||||
|
||||
function SWEP:GetTrueFOV()
|
||||
local fov = TFADUSKFOV or default_fov_cv:GetFloat()
|
||||
local ply = LocalPlayer()
|
||||
|
||||
if not ply:IsValid() then return fov end
|
||||
|
||||
if ply:GetFOV() < ply:GetDefaultFOV() - 1 then
|
||||
fov = ply:GetFOV()
|
||||
end
|
||||
|
||||
if TFADUSKFOV_FINAL then
|
||||
fov = TFADUSKFOV_FINAL
|
||||
end
|
||||
|
||||
return fov
|
||||
end
|
||||
|
||||
function SWEP:GetViewModelFinalFOV()
|
||||
local fov_default = default_fov_cv:GetFloat()
|
||||
local fov = self:GetTrueFOV()
|
||||
local flFOVOffset = fov_default - fov
|
||||
local fov_vm = self.ViewModelFOV - flFOVOffset
|
||||
local aspectRatio = GetScreenAspectRatio() * 0.75 -- (4/3)
|
||||
--local final_fov = ScaleFOVByWidthRatio( fov, aspectRatio )
|
||||
local final_fovViewmodel = ScaleFOVByWidthRatio(fov_vm, aspectRatio)
|
||||
|
||||
return final_fovViewmodel
|
||||
end
|
||||
1867
lua/weapons/tfa_gun_base/client/hud.lua
Normal file
1867
lua/weapons/tfa_gun_base/client/hud.lua
Normal file
File diff suppressed because it is too large
Load Diff
244
lua/weapons/tfa_gun_base/client/laser.lua
Normal file
244
lua/weapons/tfa_gun_base/client/laser.lua
Normal file
@@ -0,0 +1,244 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
-- Copyright (c) 2018-2020 TFA Base Devs
|
||||
|
||||
-- Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
-- of this software and associated documentation files (the "Software"), to deal
|
||||
-- in the Software without restriction, including without limitation the rights
|
||||
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
-- copies of the Software, and to permit persons to whom the Software is
|
||||
-- furnished to do so, subject to the following conditions:
|
||||
|
||||
-- The above copyright notice and this permission notice shall be included in all
|
||||
-- copies or substantial portions of the Software.
|
||||
|
||||
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
-- SOFTWARE.
|
||||
|
||||
local vector_origin = Vector()
|
||||
|
||||
local att, angpos, attname, elemname, targetent
|
||||
local col = Color(255, 0, 0, 255)
|
||||
local pc
|
||||
local laserline
|
||||
local laserdot
|
||||
local laserFOV = 1.5
|
||||
local traceres
|
||||
|
||||
local render = render
|
||||
local Material = Material
|
||||
local ProjectedTexture = ProjectedTexture
|
||||
local math = math
|
||||
|
||||
SWEP.LaserDistance = 12 * 50 -- default 50 feet
|
||||
SWEP.LaserDistanceVisual = 12 * 4 --default 4 feet
|
||||
|
||||
local function IsHolstering(wep)
|
||||
if IsValid(wep) and TFA.Enum.HolsterStatus[wep:GetStatus()] then return true end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function SWEP:DrawLaser(is_vm)
|
||||
local self2 = self:GetTable()
|
||||
|
||||
if not laserline then
|
||||
laserline = Material(self2.LaserLine or "cable/smoke")
|
||||
end
|
||||
|
||||
if not laserdot then
|
||||
laserdot = Material(self2.LaserDot or "effects/tfalaserdot")
|
||||
end
|
||||
|
||||
local ply = self:GetOwner()
|
||||
if not IsValid(ply) then return end
|
||||
|
||||
if ply:IsPlayer() then
|
||||
local f = ply.GetNW2Vector or ply.GetNWVector
|
||||
pc = f(ply, "TFALaserColor", vector_origin)
|
||||
col.r = pc.x
|
||||
col.g = pc.y
|
||||
col.b = pc.z
|
||||
else
|
||||
col.r = 255
|
||||
col.g = 0
|
||||
col.b = 0
|
||||
end
|
||||
|
||||
if is_vm then
|
||||
if not self:VMIV() then
|
||||
self:CleanLaser()
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
targetent = ply:GetViewModel()
|
||||
elemname = self2.GetStatL(self, "LaserSight_VElement", self2.GetStatL(self, "LaserSight_Element"))
|
||||
|
||||
local ViewModelElements = self:GetStatRaw("ViewModelElements", TFA.LatestDataVersion)
|
||||
|
||||
if elemname and ViewModelElements[elemname] and IsValid(ViewModelElements[elemname].curmodel) then
|
||||
targetent = ViewModelElements[elemname].curmodel
|
||||
end
|
||||
|
||||
att = self2.GetStatL(self, "LaserSightAttachment")
|
||||
attname = self2.GetStatL(self, "LaserSightAttachmentName")
|
||||
|
||||
if attname then
|
||||
att = targetent:LookupAttachment(attname)
|
||||
end
|
||||
|
||||
if (not att) or att <= 0 then
|
||||
self:CleanLaser()
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
angpos = targetent:GetAttachment(att)
|
||||
|
||||
if not angpos then
|
||||
self:CleanLaser()
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
if self2.LaserDotISMovement and self2.CLIronSightsProgress > 0 then
|
||||
local isang = self2.GetStatL(self, "IronSightsAngle")
|
||||
angpos.Ang:RotateAroundAxis(angpos.Ang:Right(), isang.y * (self2.ViewModelFlip and -1 or 1) * self2.CLIronSightsProgress)
|
||||
angpos.Ang:RotateAroundAxis(angpos.Ang:Up(), -isang.x * self2.CLIronSightsProgress)
|
||||
end
|
||||
|
||||
local localProjAng = select(2, WorldToLocal(vector_origin, angpos.Ang, vector_origin, EyeAngles()))
|
||||
localProjAng.p = localProjAng.p * ply:GetFOV() / self2.ViewModelFOV
|
||||
localProjAng.y = localProjAng.y * ply:GetFOV() / self2.ViewModelFOV
|
||||
local wsProjAng = select(2, LocalToWorld(vector_origin, localProjAng, vector_origin, EyeAngles())) --reprojection for trace angle
|
||||
traceres = util.QuickTrace(ply:GetShootPos(), wsProjAng:Forward() * 999999, ply)
|
||||
|
||||
if not IsValid(ply.TFALaserDot) and not IsHolstering(self) then
|
||||
local lamp = ProjectedTexture()
|
||||
ply.TFALaserDot = lamp
|
||||
lamp:SetTexture(laserdot:GetString("$basetexture"))
|
||||
lamp:SetFarZ(self2.LaserDistance) -- How far the light should shine
|
||||
lamp:SetFOV(laserFOV)
|
||||
lamp:SetPos(angpos.Pos)
|
||||
lamp:SetAngles(angpos.Ang)
|
||||
lamp:SetBrightness(5)
|
||||
lamp:SetNearZ(1)
|
||||
lamp:SetEnableShadows(false)
|
||||
lamp:Update()
|
||||
end
|
||||
|
||||
local lamp = ply.TFALaserDot
|
||||
|
||||
if IsValid(lamp) then
|
||||
local lamppos = EyePos() + EyeAngles():Up() * 4
|
||||
local ang = (traceres.HitPos - lamppos):Angle()
|
||||
self2.laserpos_old = traceres.HitPos
|
||||
ang:RotateAroundAxis(ang:Forward(), math.Rand(-180, 180))
|
||||
lamp:SetPos(lamppos)
|
||||
lamp:SetAngles(ang)
|
||||
lamp:SetColor(col)
|
||||
lamp:SetFOV(laserFOV * math.Rand(0.9, 1.1))
|
||||
lamp:Update()
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
targetent = self
|
||||
|
||||
elemname = self2.GetStatL(self, "LaserSight_WElement", self2.GetStatL(self, "LaserSight_Element"))
|
||||
|
||||
local WorldModelElements = self:GetStatRaw("WorldModelElements", TFA.LatestDataVersion)
|
||||
|
||||
if elemname and WorldModelElements[elemname] and IsValid(WorldModelElements[elemname].curmodel) then
|
||||
targetent = WorldModelElements[elemname].curmodel
|
||||
end
|
||||
|
||||
att = self2.GetStatL(self, "LaserSightAttachmentWorld", self2.GetStatL(self, "LaserSightAttachment"))
|
||||
|
||||
attname = self2.GetStatL(self, "LaserSightAttachmentWorldName", self2.GetStatL(self, "LaserSightAttachmentName"))
|
||||
|
||||
if attname then
|
||||
att = targetent:LookupAttachment(attname)
|
||||
end
|
||||
|
||||
if (not att) or att <= 0 then
|
||||
self:CleanLaser()
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
angpos = targetent:GetAttachment(att)
|
||||
|
||||
if not angpos then
|
||||
angpos = targetent:GetAttachment(1)
|
||||
end
|
||||
|
||||
if not angpos then
|
||||
self:CleanLaser()
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
if not IsValid(ply.TFALaserDot) and not IsHolstering(self) then
|
||||
local lamp = ProjectedTexture()
|
||||
ply.TFALaserDot = lamp
|
||||
lamp:SetTexture(laserdot:GetString("$basetexture"))
|
||||
lamp:SetFarZ(self2.LaserDistance) -- How far the light should shine
|
||||
lamp:SetFOV(laserFOV)
|
||||
lamp:SetPos(angpos.Pos)
|
||||
lamp:SetAngles(angpos.Ang)
|
||||
lamp:SetBrightness(5)
|
||||
lamp:SetNearZ(1)
|
||||
lamp:SetEnableShadows(false)
|
||||
lamp:Update()
|
||||
end
|
||||
|
||||
local lamp = ply.TFALaserDot
|
||||
|
||||
if IsValid(lamp) then
|
||||
local ang = angpos.Ang
|
||||
ang:RotateAroundAxis(ang:Forward(), math.Rand(-180, 180))
|
||||
lamp:SetPos(angpos.Pos)
|
||||
lamp:SetAngles(ang)
|
||||
lamp:SetColor(col)
|
||||
lamp:SetFOV(laserFOV * math.Rand(0.9, 1.1))
|
||||
lamp:Update()
|
||||
end
|
||||
|
||||
traceres = util.QuickTrace(angpos.Pos, angpos.Ang:Forward() * self2.LaserDistance, ply)
|
||||
local hpos = traceres.StartPos + angpos.Ang:Forward() * math.min(traceres.HitPos:Distance(angpos.Pos), self2.LaserDistanceVisual )
|
||||
render.SetMaterial(laserline)
|
||||
render.SetColorModulation(1, 1, 1)
|
||||
render.StartBeam(2)
|
||||
col.r = math.sqrt(col.r / 255) * 255
|
||||
col.g = math.sqrt(col.g / 255) * 255
|
||||
col.b = math.sqrt(col.b / 255) * 255
|
||||
render.AddBeam(angpos.Pos, self2.LaserBeamWidth or 0.25, 0, col)
|
||||
col.a = 0
|
||||
render.AddBeam(hpos, 0, 0, col)
|
||||
render.EndBeam()
|
||||
end
|
||||
|
||||
function SWEP:CleanLaser()
|
||||
local ply = self:GetOwner()
|
||||
|
||||
if IsValid(ply) and IsValid(ply.TFALaserDot) then
|
||||
ply.TFALaserDot:Remove()
|
||||
end
|
||||
end
|
||||
1351
lua/weapons/tfa_gun_base/client/mods.lua
Normal file
1351
lua/weapons/tfa_gun_base/client/mods.lua
Normal file
File diff suppressed because it is too large
Load Diff
170
lua/weapons/tfa_gun_base/client/viewbob.lua
Normal file
170
lua/weapons/tfa_gun_base/client/viewbob.lua
Normal file
@@ -0,0 +1,170 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
-- Copyright (c) 2018-2020 TFA Base Devs
|
||||
|
||||
-- Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
-- of this software and associated documentation files (the "Software"), to deal
|
||||
-- in the Software without restriction, including without limitation the rights
|
||||
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
-- copies of the Software, and to permit persons to whom the Software is
|
||||
-- furnished to do so, subject to the following conditions:
|
||||
|
||||
-- The above copyright notice and this permission notice shall be included in all
|
||||
-- copies or substantial portions of the Software.
|
||||
|
||||
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
-- SOFTWARE.
|
||||
|
||||
SWEP.SprintBobMult = 1.5 -- More is more bobbing, proportionally. This is multiplication, not addition. You want to make this > 1 probably for sprinting.
|
||||
SWEP.IronBobMult = 0.0 -- More is more bobbing, proportionally. This is multiplication, not addition. You want to make this < 1 for sighting, 0 to outright disable.
|
||||
SWEP.IronBobMultWalk = 0.2 -- More is more bobbing, proportionally. This is multiplication, not addition. You want to make this < 1 for sighting, 0 to outright disable.
|
||||
SWEP.WalkBobMult = 1 -- More is more bobbing, proportionally. This is multiplication, not addition. You may want to disable it when using animated walk.
|
||||
SWEP.SprintViewBobMult = 4
|
||||
--[[
|
||||
Function Name: CalcView
|
||||
Syntax: Don't ever call this manually.
|
||||
Returns: Nothing.
|
||||
Notes: Used to calculate view angles.
|
||||
Purpose: Feature
|
||||
]]
|
||||
--"
|
||||
--[[
|
||||
|
||||
local ta = Angle()
|
||||
local v = Vector()
|
||||
|
||||
local m_AD = math.AngleDifference
|
||||
local m_NA = math.NormalizeAngle
|
||||
|
||||
local l_LA = function(t,a1,a2)
|
||||
ta.p = m_NA( a1.p + m_AD(a2.p,a1.p) * t )
|
||||
ta.y = m_NA( a1.y + m_AD(a2.y,a1.y) * t )
|
||||
ta.r = m_NA( a1.r + m_AD(a2.r,a1.r) * t )
|
||||
return ta
|
||||
end
|
||||
|
||||
local l_LV = function(t,v1,v2)
|
||||
v = v1 + ( v2 - v1 ) * t
|
||||
return v * 1
|
||||
end
|
||||
]]
|
||||
--
|
||||
SWEP.ViewHolProg = 0
|
||||
SWEP.AttachmentViewOffset = Angle(0, 0, 0)
|
||||
SWEP.ProceduralViewOffset = Angle(0, 0, 0)
|
||||
--local procedural_fadeout = 0.6
|
||||
local procedural_vellimit = 5
|
||||
local l_Lerp = Lerp
|
||||
local l_mathApproach = math.Approach
|
||||
local l_mathClamp = math.Clamp
|
||||
local viewbob_intensity_cvar, viewbob_animated_cvar
|
||||
viewbob_intensity_cvar = GetConVar("cl_tfa_viewbob_intensity")
|
||||
viewbob_animated_cvar = GetConVar("cl_tfa_viewbob_animated")
|
||||
local oldangtmp
|
||||
local mzang_fixed
|
||||
local mzang_fixed_last
|
||||
local mzang_velocity = Angle()
|
||||
local progress = 0
|
||||
local targint, targbool
|
||||
|
||||
function SWEP:CalcView(ply, pos, ang, fov)
|
||||
if not ang then return end
|
||||
if ply ~= LocalPlayer() then return end
|
||||
local vm = ply:GetViewModel()
|
||||
if not IsValid(vm) then return end
|
||||
local self2 = self:GetTable()
|
||||
|
||||
local ftv = math.max(TFA.FrameTime(), 0.001)
|
||||
local viewbobintensity = viewbob_intensity_cvar:GetFloat() * 0.5
|
||||
local holprog = TFA.Enum.HolsterStatus[self2.GetStatus(self)] and 1 or 0
|
||||
self2.ViewHolProg = math.Approach(self2.ViewHolProg, holprog, ftv / 5)
|
||||
|
||||
oldangtmp = ang * 1
|
||||
|
||||
if self2.CameraAngCache and viewbob_animated_cvar:GetBool() then
|
||||
self2.CameraAttachmentScale = self2.CameraAttachmentScale or 1
|
||||
ang:RotateAroundAxis(ang:Right(), (self2.CameraAngCache.p + self2.CameraOffset.p) * viewbobintensity * -self2.CameraAttachmentScale)
|
||||
ang:RotateAroundAxis(ang:Up(), (self2.CameraAngCache.y + self2.CameraOffset.y) * viewbobintensity * self2.CameraAttachmentScale)
|
||||
ang:RotateAroundAxis(ang:Forward(), (self2.CameraAngCache.r + self2.CameraOffset.r) * viewbobintensity * self2.CameraAttachmentScale)
|
||||
-- - self2.MZReferenceAngle--WorldToLocal( angpos.Pos, angpos.Ang, angpos.Pos, oldangtmp + self2.MZReferenceAngle )
|
||||
--* progress )
|
||||
--self2.ProceduralViewOffset.p = l_mathApproach(self2.ProceduralViewOffset.p, 0 , l_mathClamp( procedural_pitchrestorefac - math.min( math.abs( self2.ProceduralViewOffset.p ), procedural_pitchrestorefac ) ,1,procedural_pitchrestorefac)*ftv/5 )
|
||||
--self2.ProceduralViewOffset.y = l_mathApproach(self2.ProceduralViewOffset.y, 0 , l_mathClamp( procedural_pitchrestorefac - math.min( math.abs( self2.ProceduralViewOffset.y ), procedural_pitchrestorefac ) ,1,procedural_pitchrestorefac)*ftv/5 )
|
||||
--self2.ProceduralViewOffset.r = l_mathApproach(self2.ProceduralViewOffset.r, 0 , l_mathClamp( procedural_pitchrestorefac - math.min( math.abs( self2.ProceduralViewOffset.r ), procedural_pitchrestorefac ) ,1,procedural_pitchrestorefac)*ftv/5 )
|
||||
else
|
||||
local vb_d, vb_r, vb_s, idraw, ireload, ihols, stat
|
||||
stat = self:GetStatus()
|
||||
idraw = stat == TFA.Enum.STATUS_DRAW
|
||||
ihols = TFA.Enum.HolsterStatus[stat]
|
||||
ireload = TFA.Enum.ReloadStatus[stat]
|
||||
vb_d = viewbob_animated_cvar:GetBool()
|
||||
vb_r = viewbob_animated_cvar:GetBool()
|
||||
vb_s = viewbob_animated_cvar:GetBool()
|
||||
targbool = (vb_d and idraw) or (vb_r and ireload) or (self2.GetBashing and self2.GetBashing(self)) or (vb_s and stat == TFA.Enum.STATUS_SHOOTING and (self2.ViewBob_Shoot or not self:CanInterruptShooting())) or stat == TFA.Enum.STATUS_PUMP
|
||||
targbool = targbool and not (ihols and self2.GetStatL(self, "ProceduralHolsterEnabled"))
|
||||
targint = targbool and 1 or 0
|
||||
|
||||
if stat == TFA.Enum.STATUS_RELOADING_LOOP_END or stat == TFA.Enum.STATUS_RELOADING or stat == TFA.Enum.STATUS_PUMP or (stat == TFA.Enum.STATUS_RELOADING_WAIT and not self:GetStatL("LoopedReload")) or stat == TFA.Enum.STATUS_SHOOTING or (idraw and vb_d) then
|
||||
targint = math.min(targint, 1 - math.pow(math.max(vm:GetCycle() - 0.5, 0) * 2, 2))
|
||||
end
|
||||
|
||||
progress = l_Lerp(ftv * 15, progress, targint)
|
||||
local att = self2.MuzzleAttachmentRaw or vm:LookupAttachment(self2.MuzzleAttachment)
|
||||
|
||||
if not att then
|
||||
att = 1
|
||||
end
|
||||
|
||||
local angpos = vm:GetAttachment(att)
|
||||
|
||||
if angpos then
|
||||
mzang_fixed = vm:WorldToLocalAngles(angpos.Ang)
|
||||
mzang_fixed:Normalize()
|
||||
end
|
||||
|
||||
self2.ProceduralViewOffset:Normalize()
|
||||
|
||||
if mzang_fixed_last then
|
||||
local delta = mzang_fixed - mzang_fixed_last
|
||||
delta:Normalize()
|
||||
mzang_velocity = mzang_velocity + delta * (2 * (1 - self2.ViewHolProg))
|
||||
mzang_velocity.p = l_mathApproach(mzang_velocity.p, -self2.ProceduralViewOffset.p * 2, ftv * 20)
|
||||
mzang_velocity.p = l_mathClamp(mzang_velocity.p, -procedural_vellimit, procedural_vellimit)
|
||||
self2.ProceduralViewOffset.p = self2.ProceduralViewOffset.p + mzang_velocity.p * ftv
|
||||
self2.ProceduralViewOffset.p = l_mathClamp(self2.ProceduralViewOffset.p, -90, 90)
|
||||
mzang_velocity.y = l_mathApproach(mzang_velocity.y, -self2.ProceduralViewOffset.y * 2, ftv * 20)
|
||||
mzang_velocity.y = l_mathClamp(mzang_velocity.y, -procedural_vellimit, procedural_vellimit)
|
||||
self2.ProceduralViewOffset.y = self2.ProceduralViewOffset.y + mzang_velocity.y * ftv
|
||||
self2.ProceduralViewOffset.y = l_mathClamp(self2.ProceduralViewOffset.y, -90, 90)
|
||||
mzang_velocity.r = l_mathApproach(mzang_velocity.r, -self2.ProceduralViewOffset.r * 2, ftv * 20)
|
||||
mzang_velocity.r = l_mathClamp(mzang_velocity.r, -procedural_vellimit, procedural_vellimit)
|
||||
self2.ProceduralViewOffset.r = self2.ProceduralViewOffset.r + mzang_velocity.r * ftv
|
||||
self2.ProceduralViewOffset.r = l_mathClamp(self2.ProceduralViewOffset.r, -90, 90)
|
||||
end
|
||||
|
||||
self2.ProceduralViewOffset.p = l_mathApproach(self2.ProceduralViewOffset.p, 0, (1 - progress) * ftv * -self2.ProceduralViewOffset.p)
|
||||
self2.ProceduralViewOffset.y = l_mathApproach(self2.ProceduralViewOffset.y, 0, (1 - progress) * ftv * -self2.ProceduralViewOffset.y)
|
||||
self2.ProceduralViewOffset.r = l_mathApproach(self2.ProceduralViewOffset.r, 0, (1 - progress) * ftv * -self2.ProceduralViewOffset.r)
|
||||
mzang_fixed_last = mzang_fixed
|
||||
local ints = viewbob_intensity_cvar:GetFloat() * 1.25
|
||||
ang:RotateAroundAxis(ang:Right(), l_Lerp(progress, 0, -self2.ProceduralViewOffset.p) * ints)
|
||||
ang:RotateAroundAxis(ang:Up(), l_Lerp(progress, 0, self2.ProceduralViewOffset.y / 2) * ints)
|
||||
ang:RotateAroundAxis(ang:Forward(), Lerp(progress, 0, self2.ProceduralViewOffset.r / 3) * ints)
|
||||
end
|
||||
|
||||
return pos, LerpAngle(math.pow(self2.ViewHolProg, 2), ang, oldangtmp), fov
|
||||
end
|
||||
788
lua/weapons/tfa_gun_base/client/viewmodel.lua
Normal file
788
lua/weapons/tfa_gun_base/client/viewmodel.lua
Normal file
@@ -0,0 +1,788 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
-- Copyright (c) 2018-2020 TFA Base Devs
|
||||
|
||||
-- Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
-- of this software and associated documentation files (the "Software"), to deal
|
||||
-- in the Software without restriction, including without limitation the rights
|
||||
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
-- copies of the Software, and to permit persons to whom the Software is
|
||||
-- furnished to do so, subject to the following conditions:
|
||||
|
||||
-- The above copyright notice and this permission notice shall be included in all
|
||||
-- copies or substantial portions of the Software.
|
||||
|
||||
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
-- SOFTWARE.
|
||||
|
||||
local vector_origin = Vector()
|
||||
local angle_zero = Angle()
|
||||
|
||||
local Vector = Vector
|
||||
local Angle = Angle
|
||||
local math = math
|
||||
local LerpVector = LerpVector
|
||||
|
||||
local sv_cheats = GetConVar("sv_cheats")
|
||||
local host_timescale = GetConVar("host_timescale")
|
||||
|
||||
local cv_fov = GetConVar("fov_desired")
|
||||
local cl_vm_nearwall = GetConVar("cl_tfa_viewmodel_nearwall")
|
||||
|
||||
local cl_tfa_viewmodel_offset_x = GetConVar("cl_tfa_viewmodel_offset_x")
|
||||
local cl_tfa_viewmodel_offset_y = GetConVar("cl_tfa_viewmodel_offset_y")
|
||||
local cl_tfa_viewmodel_offset_z = GetConVar("cl_tfa_viewmodel_offset_z")
|
||||
local cl_tfa_viewmodel_centered = GetConVar("cl_tfa_viewmodel_centered")
|
||||
|
||||
local cl_tfa_viewmodel_vp_enabled = GetConVar("cl_tfa_viewmodel_vp_enabled")
|
||||
local cl_tfa_viewmodel_vp_pitch = GetConVar("cl_tfa_viewmodel_vp_pitch")
|
||||
local cl_tfa_viewmodel_vp_pitch_is = GetConVar("cl_tfa_viewmodel_vp_pitch_is")
|
||||
local cl_tfa_viewmodel_vp_vertical = GetConVar("cl_tfa_viewmodel_vp_vertical")
|
||||
local cl_tfa_viewmodel_vp_vertical_is = GetConVar("cl_tfa_viewmodel_vp_vertical_is")
|
||||
local cl_tfa_viewmodel_vp_max_vertical = GetConVar("cl_tfa_viewmodel_vp_max_vertical")
|
||||
local cl_tfa_viewmodel_vp_max_vertical_is = GetConVar("cl_tfa_viewmodel_vp_max_vertical_is")
|
||||
local cl_tfa_viewmodel_vp_yaw = GetConVar("cl_tfa_viewmodel_vp_yaw")
|
||||
local cl_tfa_viewmodel_vp_yaw_is = GetConVar("cl_tfa_viewmodel_vp_yaw_is")
|
||||
|
||||
local sv_tfa_recoil_legacy = GetConVar("sv_tfa_recoil_legacy")
|
||||
|
||||
local cv_customgunbob = GetConVar("cl_tfa_gunbob_custom")
|
||||
|
||||
local function Lerp(t, a, b)
|
||||
return a + (b - a) * t
|
||||
end
|
||||
|
||||
local function Clamp(a, b, c)
|
||||
if a < b then return b end
|
||||
if a > c then return c end
|
||||
return a
|
||||
end
|
||||
|
||||
local math_max = math.max
|
||||
|
||||
local cl_vm_flip_cv = GetConVar("cl_tfa_viewmodel_flip")
|
||||
local fovmod_add = GetConVar("cl_tfa_viewmodel_offset_fov")
|
||||
local fovmod_mult = GetConVar("cl_tfa_viewmodel_multiplier_fov")
|
||||
|
||||
function SWEP:AirWalkScale()
|
||||
return (self:OwnerIsValid() and self:GetOwner():IsOnGround()) and 1 or 0.2
|
||||
end
|
||||
|
||||
SWEP.OldPos = Vector(0, 0, 0)
|
||||
SWEP.OldAng = Angle(0, 0, 0)
|
||||
|
||||
function SWEP:GetViewModelPosition(opos, oang, ...)
|
||||
local self2 = self:GetTable()
|
||||
|
||||
if not self2.pos_cached then return opos, oang end
|
||||
|
||||
local npos, nang = opos * 1, oang * 1
|
||||
|
||||
nang:RotateAroundAxis(nang:Right(), self2.ang_cached.p)
|
||||
nang:RotateAroundAxis(nang:Up(), self2.ang_cached.y)
|
||||
nang:RotateAroundAxis(nang:Forward(), self2.ang_cached.r)
|
||||
npos:Add(nang:Right() * self2.pos_cached.x)
|
||||
npos:Add(nang:Forward() * self2.pos_cached.y)
|
||||
npos:Add(nang:Up() * self2.pos_cached.z)
|
||||
|
||||
if cv_customgunbob:GetBool() then
|
||||
npos, nang = self:Sway(npos, nang)
|
||||
npos, nang = self:SprintBob(npos, nang, Lerp(self2.SprintProgressUnpredicted3 or self2.SprintProgressUnpredicted or self:GetSprintProgress(), 0, self2.SprintBobMult))
|
||||
end
|
||||
|
||||
local pos, ang = self2.SightsAttPos, Angle(self2.SightsAttAng)
|
||||
if not pos or not ang then return npos, nang end
|
||||
|
||||
local ofpos, ofang = WorldToLocal(npos, nang, opos, oang)
|
||||
|
||||
self2.OldPos = npos
|
||||
self2.OldAng = nang
|
||||
|
||||
if self.IronSightsProgressUnpredicted > 0.005 then
|
||||
local _opos, _oang = opos * 1, oang * 1
|
||||
|
||||
-- tfa base vm offset
|
||||
local right, up, fwd = _oang:Right(), _oang:Up(), _oang:Forward()
|
||||
|
||||
_opos = _opos - ofpos.y * right + ofpos.x * fwd + ofpos.z * up
|
||||
_oang:RotateAroundAxis(fwd, ofang.r)
|
||||
_oang:RotateAroundAxis(right, -ofang.p)
|
||||
_oang:RotateAroundAxis(up, ofang.y)
|
||||
|
||||
-- sight offset
|
||||
|
||||
_oang:RotateAroundAxis(_oang:Forward(), -ang.r)
|
||||
_oang:RotateAroundAxis(_oang:Right(), ang.p)
|
||||
_oang:RotateAroundAxis(_oang:Up(), -ang.y)
|
||||
|
||||
right, up, fwd = _oang:Right(), _oang:Up(), _oang:Forward()
|
||||
|
||||
_opos = _opos - pos.x * fwd + pos.y * right - pos.z * up
|
||||
|
||||
self2.OldPos = LerpVector(self2.IronSightsProgressUnpredicted, npos, _opos)
|
||||
self2.OldAng = LerpAngle(self2.IronSightsProgressUnpredicted, nang, _oang)
|
||||
end
|
||||
|
||||
return self2.OldPos, self2.OldAng
|
||||
end
|
||||
|
||||
function SWEP:CalculateViewModelFlip()
|
||||
local self2 = self:GetTable()
|
||||
|
||||
if self2.ViewModelFlipDefault == nil then
|
||||
self2.ViewModelFlipDefault = self2.ViewModelFlip
|
||||
end
|
||||
|
||||
local righthanded = true
|
||||
|
||||
if cl_vm_flip_cv:GetBool() then
|
||||
righthanded = false
|
||||
end
|
||||
|
||||
local shouldflip = self2.ViewModelFlipDefault
|
||||
|
||||
if not righthanded then
|
||||
shouldflip = not self2.ViewModelFlipDefault
|
||||
end
|
||||
|
||||
if self2.ViewModelFlip ~= shouldflip then
|
||||
self2.ViewModelFlip = shouldflip
|
||||
end
|
||||
|
||||
self2.ViewModelFOV_OG = self2.ViewModelFOV_OG or self2.ViewModelFOV
|
||||
|
||||
local cam_fov = self2.LastTranslatedFOV or cv_fov:GetInt() or 90
|
||||
local iron_add = cam_fov * (1 - 90 / cam_fov) * math.max(1 - self2.GetStatL(self, "Secondary.OwnerFOV", 90) / 90, 0)
|
||||
|
||||
local ironSightsProgress = TFA.Cosine(self2.IronSightsProgressUnpredicted or self:GetIronSightsProgress())
|
||||
self2.ViewModelFOV = Lerp(ironSightsProgress, self2.ViewModelFOV_OG, self2.GetStatL(self, "Secondary.ViewModelFOV", self2.ViewModelFOV_OG)) * fovmod_mult:GetFloat() + fovmod_add:GetFloat() + iron_add * ironSightsProgress
|
||||
end
|
||||
|
||||
function SWEP:UpdateWeaponLength()
|
||||
local self2 = self:GetTable()
|
||||
if not self:VMIV() then return end
|
||||
local vm = self2.OwnerViewModel
|
||||
local mzpos = self:GetMuzzlePos()
|
||||
if not mzpos then return end
|
||||
if not mzpos.Pos then return end
|
||||
if GetViewEntity and GetViewEntity() ~= self:GetOwner() then return end
|
||||
local mzVec = vm:WorldToLocal(mzpos.Pos)
|
||||
self2.WeaponLength = math.abs(mzVec.x)
|
||||
end
|
||||
|
||||
function SWEP:CalculateNearWall(p, a)
|
||||
local self2 = self:GetTable()
|
||||
if not self:OwnerIsValid() then return p, a end
|
||||
|
||||
if not cl_vm_nearwall:GetBool() then return p, a end
|
||||
|
||||
local ply = self:GetOwner()
|
||||
|
||||
local sp = ply:GetShootPos()
|
||||
local ea = ply:EyeAngles()
|
||||
local et = util.QuickTrace(sp,ea:Forward()*128,{self,ply})--self:GetOwner():GetEyeTrace()
|
||||
local dist = et.HitPos:Distance(sp)
|
||||
|
||||
if dist<1 then
|
||||
et=util.QuickTrace(sp,ea:Forward()*128,{self,ply,et.Entity})
|
||||
dist = et.HitPos:Distance(sp)
|
||||
end
|
||||
|
||||
self:UpdateWeaponLength()
|
||||
|
||||
local nw_offset_vec = LerpVector(self2.IronSightsProgressUnpredicted or self:GetIronSightsProgress(), self2.NearWallVector, self2.NearWallVectorADS)
|
||||
local off = self2.WeaponLength - dist
|
||||
self2.LastNearWallOffset = self2.LastNearWallOffset or 0
|
||||
|
||||
local ft = RealFrameTime() * game.GetTimeScale() * (sv_cheats:GetBool() and host_timescale:GetFloat() or 1)
|
||||
|
||||
if off > self2.LastNearWallOffset then
|
||||
self2.LastNearWallOffset = math.min(self2.LastNearWallOffset + math.max(ft * 66, off * 0.1), off, 34)
|
||||
elseif off < self2.LastNearWallOffset then
|
||||
self2.LastNearWallOffset = math.max(self2.LastNearWallOffset - ft * 66, off, 0)
|
||||
end
|
||||
|
||||
off = TFA.Cosine(self2.LastNearWallOffset / 34) * 34
|
||||
|
||||
if off > 0 then
|
||||
p = p + nw_offset_vec * off / 2
|
||||
local posCompensated = sp * 1
|
||||
posCompensated:Add(ea:Right() * nw_offset_vec.x * off / 2 * (self2.ViewModelFlip and -1 or 1))
|
||||
posCompensated:Add(ea:Forward() * nw_offset_vec.y * off / 2)
|
||||
posCompensated:Add(ea:Up() * nw_offset_vec.z * off / 2)
|
||||
local angleComp = (et.HitPos - posCompensated):Angle()
|
||||
a.x = a.x - math.AngleDifference(angleComp.p, ea.p) / 2
|
||||
a.y = a.y + math.AngleDifference(angleComp.y, ea.y) / 2
|
||||
end
|
||||
|
||||
return p, a
|
||||
end
|
||||
|
||||
local centered_sprintpos = Vector(0, -1, 1)
|
||||
local centered_sprintang = Vector(-15, 0, 0)
|
||||
|
||||
local bezierVectorBuffer = {}
|
||||
|
||||
local function bezierVector(t, vec1, vec2, vec3)
|
||||
local _1, _2 = vec1.x, vec3.x
|
||||
bezierVectorBuffer[1] = _1
|
||||
bezierVectorBuffer[2] = _1
|
||||
bezierVectorBuffer[3] = _1
|
||||
bezierVectorBuffer[4] = _1
|
||||
bezierVectorBuffer[5] = vec2.x
|
||||
bezierVectorBuffer[6] = _2
|
||||
bezierVectorBuffer[7] = _2
|
||||
bezierVectorBuffer[8] = _2
|
||||
bezierVectorBuffer[9] = _2
|
||||
|
||||
local x = TFA.tbezier(t, bezierVectorBuffer)
|
||||
|
||||
_1, _2 = vec1.y, vec3.y
|
||||
bezierVectorBuffer[1] = _1
|
||||
bezierVectorBuffer[2] = _1
|
||||
bezierVectorBuffer[3] = _1
|
||||
bezierVectorBuffer[4] = _1
|
||||
bezierVectorBuffer[5] = vec2.y
|
||||
bezierVectorBuffer[6] = _2
|
||||
bezierVectorBuffer[7] = _2
|
||||
bezierVectorBuffer[8] = _2
|
||||
bezierVectorBuffer[9] = _2
|
||||
|
||||
local y = TFA.tbezier(t, bezierVectorBuffer)
|
||||
|
||||
_1, _2 = vec1.z, vec3.z
|
||||
bezierVectorBuffer[1] = _1
|
||||
bezierVectorBuffer[2] = _1
|
||||
bezierVectorBuffer[3] = _1
|
||||
bezierVectorBuffer[4] = _1
|
||||
bezierVectorBuffer[5] = vec2.z
|
||||
bezierVectorBuffer[6] = _2
|
||||
bezierVectorBuffer[7] = _2
|
||||
bezierVectorBuffer[8] = _2
|
||||
bezierVectorBuffer[9] = _2
|
||||
|
||||
local z = TFA.tbezier(t, bezierVectorBuffer)
|
||||
|
||||
return Vector(x, y, z)
|
||||
end
|
||||
|
||||
function SWEP:CalculateViewModelOffset(delta)
|
||||
local self2 = self:GetTable()
|
||||
|
||||
local target_pos, target_ang
|
||||
local additivePos = self2.GetStatL(self, "AdditiveViewModelPosition")
|
||||
|
||||
if additivePos then
|
||||
target_pos, target_ang = Vector(), Vector()
|
||||
else
|
||||
target_pos = Vector(self2.GetStatL(self, "ViewModelPosition"))
|
||||
target_ang = Vector(self2.GetStatL(self, "ViewModelAngle"))
|
||||
end
|
||||
|
||||
local CenteredViewModelPosition = self2.GetStatL(self, "CenteredViewModelPosition")
|
||||
local CenteredViewModelAngle = self2.GetStatL(self, "CenteredViewModelAngle")
|
||||
local IronSightsPosition = self2.GetStatL(self, "IronSightsPosition", self2.SightsPos)
|
||||
local IronSightsAngle = self2.GetStatL(self, "IronSightsAngle", self2.SightsAng)
|
||||
|
||||
local targetPosCenter, targetAngCenter
|
||||
|
||||
if CenteredViewModelPosition then
|
||||
targetPosCenter = Vector(CenteredViewModelPosition)
|
||||
|
||||
if CenteredViewModelAngle then
|
||||
targetAngCenter = Vector(CenteredViewModelAngle)
|
||||
end
|
||||
elseif IronSightsPosition then
|
||||
targetPosCenter = Vector((self2.IronSightsPositionCurrent or IronSightsPosition).x, target_pos.y, target_pos.z - 3)
|
||||
|
||||
if IronSightsAngle then
|
||||
targetAngCenter = Vector(0, (self2.IronSightsAngleCurrent or IronSightsAngle).y, 0)
|
||||
end
|
||||
else
|
||||
targetPosCenter, targetAngCenter = target_pos, target_ang
|
||||
end
|
||||
|
||||
if cl_tfa_viewmodel_centered:GetBool() then
|
||||
target_pos:Set(targetPosCenter)
|
||||
target_ang:Set(targetAngCenter)
|
||||
end
|
||||
|
||||
local stat = self:GetStatus()
|
||||
|
||||
local holsterStatus = TFA.Enum.HolsterStatus[stat] and self2.GetStatL(self, "ProceduralHolsterEnabled")
|
||||
local proceduralReloadStatus = TFA.Enum.ReloadStatus[stat] and self2.GetStatL(self, "IsProceduralReloadBased")
|
||||
local holsterProgress = 0
|
||||
local statusProgress = self:GetStatusProgress()
|
||||
|
||||
if proceduralReloadStatus then
|
||||
holsterProgress = TFA.Quintic(Clamp((statusProgress >= 0.5 and (2 - statusProgress * 2) or (statusProgress * 2)), 0, 1))
|
||||
elseif self2.GetStatL(self, "ProceduralHolsterEnabled") then
|
||||
if TFA.Enum.HolsterStatusFinal[stat] then
|
||||
holsterProgress = 1
|
||||
elseif TFA.Enum.HolsterStatus[stat] then
|
||||
holsterProgress = TFA.Quintic(Clamp(statusProgress * 1.1, 0, 1))
|
||||
end
|
||||
end
|
||||
|
||||
local sprintAnimAllowed = self2.Sprint_Mode == TFA.Enum.LOCOMOTION_LUA or self2.Sprint_Mode == TFA.Enum.LOCOMOTION_HYBRID
|
||||
|
||||
local isSafety = self:IsSafety()
|
||||
|
||||
local ironSights = self:GetIronSights()
|
||||
local isSprinting = self:GetSprinting()
|
||||
local sprintProgress = sprintAnimAllowed and TFA.Cubic(self2.SprintProgressUnpredicted2 or self2.SprintProgressUnpredicted or self:GetSprintProgress()) or 0
|
||||
local safetyProgress = Lerp(sprintProgress, TFA.Cubic(self2.SafetyProgressUnpredicted or 0), 0)
|
||||
|
||||
local ironSightsProgress = Clamp(
|
||||
Lerp(
|
||||
math_max(holsterProgress, sprintProgress, safetyProgress),
|
||||
TFA.Cubic(self2.IronSightsProgressUnpredicted2 or self2.IronSightsProgressUnpredicted or self:GetIronSightsProgress()),
|
||||
0)
|
||||
, 0, 1)
|
||||
|
||||
--local ironSightsProgress = TFA.tbezier(self2.IronSightsProgressUnpredicted or self:GetIronSightsProgress(), IRON_SIGHTS_BEZIER)
|
||||
|
||||
local crouchRatio = Lerp(math_max(ironSightsProgress, holsterProgress, Clamp(sprintProgress * 2, 0, 1), safetyProgress), TFA.Quintic(self2.CrouchingRatioUnpredicted or self:GetCrouchingRatio()), 0)
|
||||
|
||||
if crouchRatio > 0.01 then
|
||||
target_pos = LerpVector(crouchRatio, target_pos, self2.GetStatL(self, "CrouchViewModelPosition"))
|
||||
target_ang = LerpVector(crouchRatio, target_ang, self2.GetStatL(self, "CrouchViewModelAngle"))
|
||||
end
|
||||
|
||||
if holsterStatus or proceduralReloadStatus then
|
||||
local targetHolsterPos = Vector(self2.GetStatL(self, "ProceduralHolsterPosition"))
|
||||
local targetHolsterAng = Vector(self2.GetStatL(self, "ProceduralHolsterAngle"))
|
||||
|
||||
if self2.ViewModelFlip then
|
||||
targetHolsterPos.x = -targetHolsterPos.x
|
||||
|
||||
targetHolsterAng.y = -targetHolsterAng.y
|
||||
targetHolsterAng.z = -targetHolsterAng.z
|
||||
end
|
||||
|
||||
target_pos = LerpVector(holsterProgress, target_pos, targetHolsterPos)
|
||||
target_ang = LerpVector(holsterProgress, target_ang, targetHolsterAng)
|
||||
end
|
||||
|
||||
if
|
||||
(sprintProgress > 0.01 or safetyProgress > 0.01) and
|
||||
(sprintAnimAllowed and sprintProgress > 0.01 or safetyProgress > 0.01)
|
||||
and stat ~= TFA.Enum.STATUS_BASHING
|
||||
then
|
||||
if cl_tfa_viewmodel_centered:GetBool() then
|
||||
target_pos = target_pos + centered_sprintpos
|
||||
target_ang = target_ang + centered_sprintang
|
||||
else
|
||||
target_pos = LerpVector(safetyProgress, target_pos, self2.GetStatL(self, "SafetyPos", self2.GetStatL(self, "SprintViewModelPosition")))
|
||||
target_ang = LerpVector(safetyProgress, target_ang, self2.GetStatL(self, "SafetyAng", self2.GetStatL(self, "SprintViewModelAngle")))
|
||||
|
||||
if sprintAnimAllowed then
|
||||
target_pos = LerpVector(sprintProgress, target_pos, self2.GetStatL(self, "SprintViewModelPosition"))
|
||||
target_ang = LerpVector(sprintProgress, target_ang, self2.GetStatL(self, "SprintViewModelAngle"))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if ironSightsProgress > 0.02 and (self2.Sights_Mode == TFA.Enum.LOCOMOTION_LUA or self2.Sights_Mode == TFA.Enum.LOCOMOTION_HYBRID) then
|
||||
local score = self2.VM_IronPositionScore or 1
|
||||
local getSightsPos = self2.IronSightsPositionCurrent or IronSightsPosition or self2.GetStatL(self, "SightsPos", vector_origin)
|
||||
|
||||
if targetPosCenter and score > 0.04 then
|
||||
target_pos = bezierVector(ironSightsProgress, target_pos, LerpVector(score, getSightsPos, targetPosCenter), getSightsPos)
|
||||
else
|
||||
target_pos = LerpVector(ironSightsProgress, target_pos, getSightsPos)
|
||||
end
|
||||
|
||||
if targetAngCenter and score > 0.04 then
|
||||
local deviate = 30 * score
|
||||
|
||||
if self2.VM_IsScopedIn then
|
||||
deviate = -deviate
|
||||
end
|
||||
|
||||
if self2.ViewModelFlip then
|
||||
deviate = -deviate
|
||||
end
|
||||
|
||||
local targetAngCenter2 = Vector(targetAngCenter.x * score, targetAngCenter.y * score, targetAngCenter.z * score + deviate)
|
||||
target_ang = bezierVector(ironSightsProgress, target_ang, targetAngCenter2, self2.IronSightsAngleCurrent or IronSightsAngle or self2.GetStatL(self, "SightsAng", vector_origin))
|
||||
else
|
||||
target_ang = LerpVector(ironSightsProgress, target_ang, self2.IronSightsAngleCurrent or IronSightsAngle or self2.GetStatL(self, "SightsAng", vector_origin))
|
||||
end
|
||||
end
|
||||
|
||||
target_pos.x = target_pos.x + cl_tfa_viewmodel_offset_x:GetFloat() * (1 - ironSightsProgress)
|
||||
target_pos.y = target_pos.y + cl_tfa_viewmodel_offset_y:GetFloat() * (1 - ironSightsProgress)
|
||||
target_pos.z = target_pos.z + cl_tfa_viewmodel_offset_z:GetFloat() * (1 - ironSightsProgress)
|
||||
|
||||
local customizationProgress = TFA.Quintic(self2.CustomizingProgressUnpredicted or self:GetInspectingProgress())
|
||||
|
||||
if customizationProgress > 0.01 and self2.Customize_Mode ~= TFA.Enum.LOCOMOTION_ANI then
|
||||
if not self2.InspectPos then
|
||||
self2.InspectPos = Vector(self2.InspectPosDef)
|
||||
|
||||
if self2.ViewModelFlip then
|
||||
self2.InspectPos.x = self2.InspectPos.x * -1
|
||||
end
|
||||
end
|
||||
|
||||
if not self2.InspectAng then
|
||||
self2.InspectAng = Vector(self2.InspectAngDef)
|
||||
|
||||
if self2.ViewModelFlip then
|
||||
self2.InspectAng.y = self2.InspectAngDef.y * -1
|
||||
self2.InspectAng.z = self2.InspectAngDef.z * -1
|
||||
end
|
||||
end
|
||||
|
||||
target_pos = LerpVector(customizationProgress, target_pos, self2.GetStatL(self, "InspectPos"))
|
||||
target_ang = LerpVector(customizationProgress, target_ang, self2.GetStatL(self, "InspectAng"))
|
||||
end
|
||||
|
||||
target_pos, target_ang = self:CalculateNearWall(target_pos, target_ang)
|
||||
|
||||
if additivePos then
|
||||
target_pos:Add(self2.GetStatL(self, "ViewModelPosition"))
|
||||
target_ang:Add(self2.GetStatL(self, "ViewModelAngle"))
|
||||
end
|
||||
|
||||
target_ang.z = target_ang.z + -7.5 * (1 - math.abs(0.5 - ironSightsProgress) * 2) * (self:GetIronSights() and 1 or 0.5) * (self2.ViewModelFlip and 1 or -1) * (self2.VM_IronPositionScore or 1)
|
||||
|
||||
if self:GetHidden() then
|
||||
target_pos.z = target_pos.z - 5
|
||||
end
|
||||
|
||||
if self2.GetStatL(self, "BlowbackEnabled") and self2.BlowbackCurrentRoot > 0.01 then
|
||||
local bbvec = self2.GetStatL(self, "BlowbackVector")
|
||||
target_pos = target_pos + bbvec * self2.BlowbackCurrentRoot
|
||||
local bbang = self2.GetStatL(self, "BlowbackAngle") or angle_zero
|
||||
bbvec = bbvec * 1
|
||||
bbvec.x = bbang.p
|
||||
bbvec.y = bbang.y
|
||||
bbvec.z = bbang.r
|
||||
target_ang = target_ang + bbvec * self2.BlowbackCurrentRoot
|
||||
bbang = self2.BlowbackRandomAngle * (1 - math.max(0, ironSightsProgress) * .8)
|
||||
bbvec.x = bbang.p
|
||||
bbvec.y = bbang.y
|
||||
bbvec.z = bbang.r
|
||||
target_ang = target_ang + bbvec * self2.BlowbackCurrentRoot
|
||||
end
|
||||
|
||||
if not sv_tfa_recoil_legacy:GetBool() and cl_tfa_viewmodel_vp_enabled:GetBool() then
|
||||
if self:HasRecoilLUT() then
|
||||
if not ironSights then
|
||||
local ang = self:GetRecoilLUTAngle()
|
||||
|
||||
target_ang.x = target_ang.x - ang.p / 2 * Lerp(ironSightsProgress, self:GetStatL("ViewModelPunchPitchMultiplier") * cl_tfa_viewmodel_vp_pitch:GetFloat(), self:GetStatL("ViewModelPunchPitchMultiplier_IronSights") * cl_tfa_viewmodel_vp_pitch_is:GetFloat())
|
||||
target_ang.y = target_ang.y + ang.y / 2 * Lerp(ironSightsProgress, self:GetStatL("ViewModelPunchYawMultiplier") * cl_tfa_viewmodel_vp_yaw:GetFloat(), self:GetStatL("ViewModelPunchYawMultiplier_IronSights") * cl_tfa_viewmodel_vp_yaw_is:GetFloat())
|
||||
end
|
||||
else
|
||||
target_ang.x = target_ang.x - self:GetViewPunchP() * Lerp(ironSightsProgress, self:GetStatL("ViewModelPunchPitchMultiplier") * cl_tfa_viewmodel_vp_pitch:GetFloat(), self:GetStatL("ViewModelPunchPitchMultiplier_IronSights") * cl_tfa_viewmodel_vp_pitch_is:GetFloat())
|
||||
target_ang.y = target_ang.y + self:GetViewPunchY() * Lerp(ironSightsProgress, self:GetStatL("ViewModelPunchYawMultiplier") * cl_tfa_viewmodel_vp_yaw:GetFloat(), self:GetStatL("ViewModelPunchYawMultiplier_IronSights") * cl_tfa_viewmodel_vp_yaw_is:GetFloat())
|
||||
|
||||
local ViewModelPunch_MaxVertialOffset = Lerp(ironSightsProgress, self:GetStatL("ViewModelPunch_MaxVertialOffset") * cl_tfa_viewmodel_vp_max_vertical:GetFloat(), self:GetStatL("ViewModelPunch_MaxVertialOffset_IronSights") * cl_tfa_viewmodel_vp_max_vertical_is:GetFloat())
|
||||
|
||||
target_pos.y = target_pos.y + math.Clamp(
|
||||
self:GetViewPunchP() * Lerp(ironSightsProgress, self:GetStatL("ViewModelPunch_VertialMultiplier") * cl_tfa_viewmodel_vp_vertical:GetFloat(), self:GetStatL("ViewModelPunch_VertialMultiplier_IronSights") * cl_tfa_viewmodel_vp_vertical_is:GetFloat()),
|
||||
-ViewModelPunch_MaxVertialOffset,
|
||||
ViewModelPunch_MaxVertialOffset)
|
||||
end
|
||||
end
|
||||
|
||||
if not cv_customgunbob:GetBool() then
|
||||
self2.pos_cached, self2.ang_cached = Vector(target_pos), Angle(target_ang.x, target_ang.y, target_ang.z)
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
local intensityWalk = math.min(self:GetOwner():GetVelocity():Length2D() / self:GetOwner():GetWalkSpeed(), 1) * Lerp(ironSightsProgress, self2.WalkBobMult, self2.WalkBobMult_Iron or self2.WalkBobMult)
|
||||
local intensityBreath = Lerp(ironSightsProgress, self2.GetStatL(self, "BreathScale", 0.2), self2.GetStatL(self, "IronBobMultWalk", 0.5) * intensityWalk)
|
||||
intensityWalk = (1 - ironSightsProgress) * intensityWalk
|
||||
local intensityRun = Lerp(self2.SprintProgressUnpredicted3 or self2.SprintProgressUnpredicted or self:GetSprintProgress(), 0, self2.SprintBobMult)
|
||||
local velocity = math.max(self:GetOwner():GetVelocity():Length2D() * self:AirWalkScale() - self:GetOwner():GetVelocity().z * 0.5, 0)
|
||||
local rate = math.min(math.max(0.15, math.sqrt(velocity / self:GetOwner():GetRunSpeed()) * 1.75), self:GetSprinting() and 5 or 3)
|
||||
|
||||
self2.pos_cached, self2.ang_cached = self:WalkBob(
|
||||
target_pos,
|
||||
Angle(target_ang.x, target_ang.y, target_ang.z),
|
||||
math.max(intensityBreath - intensityWalk - intensityRun, 0),
|
||||
math.max(intensityWalk - intensityRun, 0), rate, delta)
|
||||
end
|
||||
|
||||
local rft, eyeAngles, viewPunch, oldEyeAngles, delta, motion, counterMotion, compensation, fac, positionCompensation, swayRate, wiggleFactor, flipFactor
|
||||
|
||||
local gunswaycvar = GetConVar("cl_tfa_gunbob_intensity")
|
||||
local sv_tfa_weapon_weight = GetConVar("sv_tfa_weapon_weight")
|
||||
|
||||
function SWEP:Sway(pos, ang, ftv)
|
||||
local self2 = self:GetTable()
|
||||
--sanity check
|
||||
if not self:OwnerIsValid() then return pos, ang end
|
||||
--convar
|
||||
fac = gunswaycvar:GetFloat() * 3 * ((1 - ((self2.IronSightsProgressUnpredicted or self:GetIronSightsProgress()) or 0)) * 0.85 + 0.15)
|
||||
flipFactor = (self2.ViewModelFlip and -1 or 1)
|
||||
--init vars
|
||||
delta = delta or Angle()
|
||||
motion = motion or Angle()
|
||||
counterMotion = counterMotion or Angle()
|
||||
compensation = compensation or Angle()
|
||||
|
||||
if ftv then
|
||||
--grab eye angles
|
||||
eyeAngles = self:GetOwner():EyeAngles()
|
||||
viewPunch = self:GetOwner():GetViewPunchAngles()
|
||||
eyeAngles.p = eyeAngles.p - viewPunch.p
|
||||
eyeAngles.y = eyeAngles.y - viewPunch.y
|
||||
oldEyeAngles = oldEyeAngles or eyeAngles
|
||||
--calculate delta
|
||||
wiggleFactor = (1 - (sv_tfa_weapon_weight:GetBool() and self2.GetStatL(self, "RegularMoveSpeedMultiplier") or 1)) / 0.6 + 0.15
|
||||
swayRate = math.pow(sv_tfa_weapon_weight:GetBool() and self2.GetStatL(self, "RegularMoveSpeedMultiplier") or 1, 1.5) * 10
|
||||
rft = math.Clamp(ftv, 0.001, 1 / 20)
|
||||
local clampFac = 1.1 - math.min((math.abs(motion.p) + math.abs(motion.y) + math.abs(motion.r)) / 20, 1)
|
||||
delta.p = math.AngleDifference(eyeAngles.p, oldEyeAngles.p) / rft / 120 * clampFac
|
||||
delta.y = math.AngleDifference(eyeAngles.y, oldEyeAngles.y) / rft / 120 * clampFac
|
||||
delta.r = math.AngleDifference(eyeAngles.r, oldEyeAngles.r) / rft / 120 * clampFac
|
||||
oldEyeAngles = eyeAngles
|
||||
--calculate motions, based on Juckey's methods
|
||||
counterMotion = LerpAngle(rft * (swayRate * (0.75 + math.max(0, 0.5 - wiggleFactor))), counterMotion, -motion)
|
||||
compensation.p = math.AngleDifference(motion.p, -counterMotion.p)
|
||||
compensation.y = math.AngleDifference(motion.y, -counterMotion.y)
|
||||
motion = LerpAngle(rft * swayRate, motion, delta + compensation)
|
||||
end
|
||||
|
||||
--modify position/angle
|
||||
positionCompensation = 0.2 + 0.2 * ((self2.IronSightsProgressUnpredicted or self:GetIronSightsProgress()) or 0)
|
||||
pos:Add(-motion.y * positionCompensation * 0.66 * fac * ang:Right() * flipFactor) --compensate position for yaw
|
||||
pos:Add(-motion.p * positionCompensation * fac * ang:Up()) --compensate position for pitch
|
||||
ang:RotateAroundAxis(ang:Right(), motion.p * fac)
|
||||
ang:RotateAroundAxis(ang:Up(), -motion.y * 0.66 * fac * flipFactor)
|
||||
ang:RotateAroundAxis(ang:Forward(), counterMotion.r * 0.5 * fac * flipFactor)
|
||||
|
||||
return pos, ang
|
||||
end
|
||||
|
||||
local mirror = Matrix()
|
||||
|
||||
hook.Add("PostRender", "TFA:CacheSightsPos", function()
|
||||
local self = LocalPlayer():GetActiveWeapon()
|
||||
if not IsValid(self) then return end
|
||||
local self2 = self:GetTable()
|
||||
if not self2.IsTFAWeapon then return end
|
||||
if not self2.ViewModelFlip then return end
|
||||
|
||||
local vm = self2.OwnerViewModel
|
||||
|
||||
self2.ViewModelFlip = false
|
||||
|
||||
vm:SetRenderOrigin(vector_origin)
|
||||
vm:SetRenderAngles(angle_zero)
|
||||
|
||||
vm:InvalidateBoneCache()
|
||||
vm:SetupBones()
|
||||
|
||||
local ViewModelElements = self:GetStatRaw("ViewModelElements", TFA.LatestDataVersion)
|
||||
|
||||
if ViewModelElements and self2.HasInitAttachments then
|
||||
if not self2.vRenderOrder then
|
||||
self:RebuildModsRenderOrder()
|
||||
end
|
||||
|
||||
TFA._IncNextSetupBones()
|
||||
|
||||
for index = 1, #self2.vRenderOrder do
|
||||
local name = self2.vRenderOrder[index]
|
||||
local element = ViewModelElements[name]
|
||||
|
||||
if not element then
|
||||
self:RebuildModsRenderOrder()
|
||||
break
|
||||
end
|
||||
|
||||
if element.type ~= "Model" then goto CONTINUE end
|
||||
|
||||
if element.hide then goto CONTINUE end
|
||||
if not element.bone then goto CONTINUE end
|
||||
|
||||
if self2.GetStatL(self, "ViewModelElements." .. name .. ".active") == false then goto CONTINUE end
|
||||
|
||||
local pos, ang = self:GetBoneOrientation(ViewModelElements, element, vm, nil, true)
|
||||
if not pos and not element.bonemerge then goto CONTINUE end
|
||||
|
||||
self:PrecacheElement(element, true)
|
||||
|
||||
local model = element.curmodel
|
||||
local sprite = element.spritemat
|
||||
|
||||
if IsValid(model) then
|
||||
if not element.bonemerge then
|
||||
model:SetPos(pos + ang:Forward() * element.pos.x + ang:Right() * element.pos.y + ang:Up() * element.pos.z)
|
||||
ang:RotateAroundAxis(ang:Up(), element.angle.y)
|
||||
ang:RotateAroundAxis(ang:Right(), element.angle.p)
|
||||
ang:RotateAroundAxis(ang:Forward(), element.angle.r)
|
||||
model:SetAngles(ang)
|
||||
mirror:Identity()
|
||||
mirror:Scale(element.size)
|
||||
model:EnableMatrix("RenderMultiply", mirror)
|
||||
end
|
||||
|
||||
if not self2.VElementsBodygroupsCache[index] then
|
||||
self2.VElementsBodygroupsCache[index] = #model:GetBodyGroups() - 1
|
||||
end
|
||||
|
||||
if self2.VElementsBodygroupsCache[index] then
|
||||
for _b = 0, self2.VElementsBodygroupsCache[index] do
|
||||
local newbg = self2.GetStatL(self, "ViewModelElements." .. name .. ".bodygroup." .. _b, 0) -- names are not supported, use overridetable
|
||||
|
||||
if model:GetBodygroup(_b) ~= newbg then
|
||||
model:SetBodygroup(_b, newbg)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if element.bonemerge then
|
||||
if element.rel and ViewModelElements[element.rel] and IsValid(ViewModelElements[element.rel].curmodel) then
|
||||
element.parModel = ViewModelElements[element.rel].curmodel
|
||||
else
|
||||
element.parModel = self2.OwnerViewModel or self
|
||||
end
|
||||
|
||||
if model:GetParent() ~= element.parModel then
|
||||
model:SetParent(element.parModel)
|
||||
end
|
||||
|
||||
if not model:IsEffectActive(EF_BONEMERGE) then
|
||||
model:AddEffects(EF_BONEMERGE)
|
||||
model:AddEffects(EF_BONEMERGE_FASTCULL)
|
||||
model:SetMoveType(MOVETYPE_NONE)
|
||||
model:SetLocalPos(vector_origin)
|
||||
model:SetLocalAngles(angle_zero)
|
||||
end
|
||||
elseif model:IsEffectActive(EF_BONEMERGE) then
|
||||
model:RemoveEffects(EF_BONEMERGE)
|
||||
model:SetParent(NULL)
|
||||
end
|
||||
|
||||
model:InvalidateBoneCache()
|
||||
model:SetupBones()
|
||||
model.tfa_next_setup_bones = TFA._GetNextSetupBones()
|
||||
end
|
||||
|
||||
::CONTINUE::
|
||||
end
|
||||
end
|
||||
|
||||
self:CacheSightsPos(vm, true)
|
||||
|
||||
vm:SetRenderOrigin()
|
||||
vm:SetRenderAngles()
|
||||
|
||||
self.ViewModelFlip = true
|
||||
vm:InvalidateBoneCache()
|
||||
end)
|
||||
|
||||
function SWEP:CacheSightsPos(vm, flipped)
|
||||
self.SightsAttPos, self.SightsAttAng = nil, nil
|
||||
|
||||
if not self:GetStat("ProceduralSight", false) then return end
|
||||
|
||||
local model = vm
|
||||
local attname = self:GetStat("ProceduralSight_VElement")
|
||||
|
||||
if attname then
|
||||
if not self:GetStat("VElements." .. attname .. ".active", false) then return end
|
||||
|
||||
model = self.VElements[attname].curmodel
|
||||
end
|
||||
|
||||
if not IsValid(model) then return end
|
||||
|
||||
local ViewModelElements = self:GetStatRaw("ViewModelElements", TFA.LatestDataVersion)
|
||||
|
||||
TFA._IncNextSetupBones()
|
||||
|
||||
if self:GetStat("ProceduralSight_PositionType", TFA.Enum.SIGHTSPOS_ATTACH) == TFA.Enum.SIGHTSPOS_BONE then
|
||||
local boneid = self:GetStat("ProceduralSight_Bone")
|
||||
if not boneid then return end
|
||||
|
||||
if type(boneid) == "string" then
|
||||
boneid = model:LookupBone(boneid)
|
||||
end
|
||||
|
||||
if not boneid or boneid < 0 then return end
|
||||
|
||||
self.SightsAttPos, self.SightsAttAng = model:GetBonePosition(boneid)
|
||||
else
|
||||
local attid = self:GetStat("ProceduralSight_Attachment")
|
||||
if not attid then return end
|
||||
|
||||
if type(attid) == "string" then
|
||||
attid = model:LookupAttachment(attid)
|
||||
end
|
||||
|
||||
if not attid or attid <= 0 then return end
|
||||
|
||||
local attpos = model:GetAttachment(attid)
|
||||
|
||||
self.SightsAttPos, self.SightsAttAng = attpos.Pos, attpos.Ang
|
||||
end
|
||||
|
||||
if self.SightsAttPos and self.SightsAttAng then
|
||||
if not flipped then
|
||||
local transform = Matrix()
|
||||
transform:Translate(vm:GetPos())
|
||||
transform:Rotate(vm:GetAngles())
|
||||
transform:Invert()
|
||||
|
||||
transform:Translate(self.SightsAttPos)
|
||||
transform:Rotate(self.SightsAttAng)
|
||||
|
||||
self.SightsAttPos, self.SightsAttAng = transform:GetTranslation(), transform:GetAngles()
|
||||
end
|
||||
|
||||
local OffsetPos = self:GetStatL("ProceduralSight_OffsetPos")
|
||||
|
||||
if OffsetPos then
|
||||
if GetConVarNumber("developer") > 0 then -- draw pre-offset pos
|
||||
local a, b = LocalToWorld(self.SightsAttPos, self.SightsAttAng, vm:GetPos(), vm:GetAngles())
|
||||
|
||||
render.DrawLine(a, a + b:Forward() * 1, Color(127, 0, 0), false)
|
||||
render.DrawLine(a, a - b:Right() * 1, Color(0, 127, 0), false)
|
||||
render.DrawLine(a, a + b:Up() * 1, Color(0, 0, 127), false)
|
||||
end
|
||||
|
||||
self.SightsAttPos:Add(self.SightsAttAng:Right() * OffsetPos.x)
|
||||
self.SightsAttPos:Add(self.SightsAttAng:Forward() * OffsetPos.y)
|
||||
self.SightsAttPos:Add(self.SightsAttAng:Up() * OffsetPos.z)
|
||||
end
|
||||
|
||||
local OffsetAng = self:GetStatL("ProceduralSight_OffsetAng")
|
||||
|
||||
if OffsetAng then
|
||||
self.SightsAttAng:RotateAroundAxis(self.SightsAttAng:Right(), OffsetAng.p)
|
||||
self.SightsAttAng:RotateAroundAxis(self.SightsAttAng:Up(), OffsetAng.y)
|
||||
self.SightsAttAng:RotateAroundAxis(self.SightsAttAng:Forward(), OffsetAng.r)
|
||||
end
|
||||
|
||||
if GetConVarNumber("developer") > 0 then -- draw final pos
|
||||
local a, b = LocalToWorld(self.SightsAttPos, self.SightsAttAng, vm:GetPos(), vm:GetAngles())
|
||||
|
||||
render.DrawLine(a, a + b:Forward() * 1, Color(255, 0, 0), false)
|
||||
render.DrawLine(a, a - b:Right() * 1, Color(0, 255, 0), false)
|
||||
render.DrawLine(a, a + b:Up() * 1, Color(0, 0, 255), false)
|
||||
end
|
||||
end
|
||||
end
|
||||
181
lua/weapons/tfa_gun_base/common/ai_translations.lua
Normal file
181
lua/weapons/tfa_gun_base/common/ai_translations.lua
Normal file
@@ -0,0 +1,181 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
-- Copyright (c) 2018-2020 TFA Base Devs
|
||||
|
||||
-- Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
-- of this software and associated documentation files (the "Software"), to deal
|
||||
-- in the Software without restriction, including without limitation the rights
|
||||
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
-- copies of the Software, and to permit persons to whom the Software is
|
||||
-- furnished to do so, subject to the following conditions:
|
||||
|
||||
-- The above copyright notice and this permission notice shall be included in all
|
||||
-- copies or substantial portions of the Software.
|
||||
|
||||
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
-- SOFTWARE.
|
||||
|
||||
local HoldTypeTable = {
|
||||
["melee"] = {
|
||||
[ACT_IDLE] = ACT_IDLE_MELEE,
|
||||
[ACT_IDLE_ANGRY] = ACT_IDLE_MELEE,
|
||||
[ACT_IDLE_RELAXED] = ACT_IDLE_MELEE,
|
||||
[ACT_IDLE_STIMULATED] = ACT_IDLE_MELEE,
|
||||
[ACT_IDLE_AGITATED] = ACT_IDLE_MELEE,
|
||||
[ACT_IDLE_AIM_RELAXED] = ACT_IDLE_MELEE,
|
||||
[ACT_IDLE_AIM_STIMULATED] = ACT_IDLE_MELEE,
|
||||
[ACT_IDLE_AIM_AGITATED] = ACT_IDLE_MELEE,
|
||||
[ACT_RANGE_ATTACK1] = ACT_RANGE_ATTACK_THROW,
|
||||
[ACT_RANGE_ATTACK1_LOW] = ACT_MELEE_ATTACK_SWING,
|
||||
[ACT_MELEE_ATTACK1] = ACT_MELEE_ATTACK_SWING,
|
||||
[ACT_MELEE_ATTACK2] = ACT_MELEE_ATTACK_SWING,
|
||||
[ACT_SPECIAL_ATTACK1] = ACT_RANGE_ATTACK_THROW,
|
||||
[ACT_RANGE_AIM_LOW] = ACT_IDLE_MELEE,
|
||||
[ACT_COVER_LOW] = ACT_IDLE_MELEE,
|
||||
[ACT_WALK] = ACT_WALK_SUITCASE,
|
||||
[ACT_WALK_RELAXED] = ACT_WALK_SUITCASE,
|
||||
[ACT_WALK_STIMULATED] = ACT_WALK_SUITCASE,
|
||||
[ACT_WALK_AGITATED] = ACT_WALK_SUITCASE,
|
||||
[ACT_RUN_CROUCH] = ACT_RUN_CROUCH,
|
||||
[ACT_RUN_CROUCH_AIM] = ACT_RUN_CROUCH,
|
||||
[ACT_RUN] = ACT_RUN,
|
||||
[ACT_RUN_AIM_RELAXED] = ACT_RUN,
|
||||
[ACT_RUN_AIM_STIMULATED] = ACT_RUN,
|
||||
[ACT_RUN_AIM_AGITATED] = ACT_RUN,
|
||||
[ACT_RUN_AIM] = ACT_RUN,
|
||||
[ACT_SMALL_FLINCH] = ACT_RANGE_ATTACK_PISTOL,
|
||||
[ACT_BIG_FLINCH] = ACT_RANGE_ATTACK_PISTOL
|
||||
},
|
||||
["melee2"] = {
|
||||
[ACT_IDLE] = ACT_IDLE_ANGRY_MELEE,
|
||||
[ACT_IDLE_ANGRY] = ACT_IDLE_ANGRY_MELEE,
|
||||
[ACT_IDLE_RELAXED] = ACT_IDLE,
|
||||
[ACT_IDLE_STIMULATED] = ACT_IDLE,
|
||||
[ACT_IDLE_AGITATED] = ACT_IDLE_ANGRY_MELEE,
|
||||
[ACT_MP_RUN] = ACT_HL2MP_RUN_SUITCASE,
|
||||
[ACT_RUN] = ACT_RUN,
|
||||
[ACT_RUN_AIM_RELAXED] = ACT_RUN,
|
||||
[ACT_RUN_AIM_STIMULATED] = ACT_RUN,
|
||||
[ACT_RUN_AIM_AGITATED] = ACT_RUN,
|
||||
[ACT_RUN_AIM] = ACT_RUN,
|
||||
[ACT_WALK] = ACT_WALK_SUITCASE,
|
||||
[ACT_MELEE_ATTACK1] = ACT_MELEE_ATTACK_SWING,
|
||||
[ACT_RANGE_ATTACK1] = ACT_MELEE_ATTACK_SWING,
|
||||
[ACT_MELEE_ATTACK2] = ACT_MELEE_ATTACK_SWING,
|
||||
[ACT_RANGE_ATTACK2] = ACT_MELEE_ATTACK_SWING,
|
||||
[ACT_SPECIAL_ATTACK1] = ACT_RANGE_ATTACK_THROW,
|
||||
[ACT_SMALL_FLINCH] = ACT_RANGE_ATTACK_PISTOL,
|
||||
[ACT_BIG_FLINCH] = ACT_RANGE_ATTACK_PISTOL
|
||||
},
|
||||
["pistol"] = {
|
||||
[ACT_IDLE] = ACT_IDLE_PISTOL,
|
||||
[ACT_IDLE_ANGRY] = ACT_IDLE_ANGRY_PISTOL,
|
||||
[ACT_IDLE_AGITATED] = ACT_IDLE_ANGRY_PISTOL,
|
||||
[ACT_RANGE_ATTACK1] = ACT_RANGE_ATTACK_PISTOL,
|
||||
[ACT_RELOAD] = ACT_RELOAD_PISTOL,
|
||||
[ACT_WALK] = ACT_WALK_PISTOL,
|
||||
[ACT_WALK_AIM] = ACT_WALK_AIM_PISTOL,
|
||||
[ACT_RUN] = ACT_RUN_PISTOL,
|
||||
[ACT_RUN_AIM] = ACT_RUN_AIM_PISTOL,
|
||||
[ACT_RANGE_ATTACK1] = ACT_RANGE_ATTACK_PISTOL,
|
||||
[ACT_GESTURE_RANGE_ATTACK1] = ACT_GESTURE_RANGE_ATTACK_PISTOL,
|
||||
[ACT_RELOAD_LOW] = ACT_RELOAD_PISTOL_LOW,
|
||||
[ACT_RANGE_ATTACK1_LOW] = ACT_RANGE_ATTACK_PISTOL_LOW,
|
||||
[ACT_COVER_LOW] = ACT_COVER_PISTOL_LOW,
|
||||
[ACT_RANGE_AIM_LOW] = ACT_RANGE_AIM_PISTOL_LOW,
|
||||
[ACT_GESTURE_RELOAD] = ACT_GESTURE_RELOAD_PISTOL
|
||||
},
|
||||
["ar2"] = {
|
||||
[ACT_RANGE_ATTACK1] = ACT_RANGE_ATTACK_AR2,
|
||||
[ACT_RELOAD] = ACT_RELOAD_SMG1,
|
||||
[ACT_IDLE] = ACT_IDLE_SMG1,
|
||||
[ACT_IDLE_ANGRY] = ACT_IDLE_ANGRY_SMG1,
|
||||
[ACT_WALK] = ACT_WALK_RIFLE,
|
||||
[ACT_IDLE_RELAXED] = ACT_IDLE_SMG1_RELAXED,
|
||||
[ACT_IDLE_STIMULATED] = ACT_IDLE_SMG1_STIMULATED,
|
||||
[ACT_IDLE_AGITATED] = ACT_IDLE_ANGRY_SMG1,
|
||||
[ACT_WALK_RELAXED] = ACT_WALK_RIFLE_RELAXED,
|
||||
[ACT_WALK_STIMULATED] = ACT_WALK_RIFLE_STIMULATED,
|
||||
[ACT_WALK_AGITATED] = ACT_WALK_AIM_RIFLE,
|
||||
[ACT_RUN_RELAXED] = ACT_RUN_RIFLE_RELAXED,
|
||||
[ACT_RUN_STIMULATED] = ACT_RUN_RIFLE_STIMULATED,
|
||||
[ACT_RUN_AGITATED] = ACT_RUN_AIM_RIFLE,
|
||||
[ACT_IDLE_AIM_RELAXED] = ACT_IDLE_SMG1_RELAXED,
|
||||
[ACT_IDLE_AIM_STIMULATED] = ACT_IDLE_AIM_RIFLE_STIMULATED,
|
||||
[ACT_IDLE_AIM_AGITATED] = ACT_IDLE_ANGRY_SMG1,
|
||||
[ACT_WALK_AIM_RELAXED] = ACT_WALK_RIFLE_RELAXED,
|
||||
[ACT_WALK_AIM_STIMULATED] = ACT_WALK_AIM_RIFLE_STIMULATED,
|
||||
[ACT_WALK_AIM_AGITATED] = ACT_WALK_AIM_RIFLE,
|
||||
[ACT_RUN_AIM_RELAXED] = ACT_RUN_RIFLE_RELAXED,
|
||||
[ACT_RUN_AIM_STIMULATED] = ACT_RUN_AIM_RIFLE_STIMULATED,
|
||||
[ACT_RUN_AIM_AGITATED] = ACT_RUN_AIM_RIFLE,
|
||||
[ACT_WALK_AIM] = ACT_WALK_AIM_RIFLE,
|
||||
[ACT_WALK_CROUCH] = ACT_WALK_CROUCH_RIFLE,
|
||||
[ACT_WALK_CROUCH_AIM] = ACT_WALK_CROUCH_AIM_RIFLE,
|
||||
[ACT_RUN] = ACT_RUN_RIFLE,
|
||||
[ACT_RUN_AIM] = ACT_RUN_AIM_RIFLE,
|
||||
[ACT_RUN_CROUCH] = ACT_RUN_CROUCH_RIFLE,
|
||||
[ACT_RUN_CROUCH_AIM] = ACT_RUN_CROUCH_AIM_RIFLE,
|
||||
[ACT_GESTURE_RANGE_ATTACK1] = ACT_GESTURE_RANGE_ATTACK_AR2,
|
||||
[ACT_COVER_LOW] = ACT_COVER_SMG1_LOW,
|
||||
[ACT_RANGE_AIM_LOW] = ACT_RANGE_AIM_AR2_LOW,
|
||||
[ACT_RANGE_ATTACK1_LOW] = ACT_RANGE_ATTACK_SMG1_LOW,
|
||||
[ACT_RELOAD_LOW] = ACT_RELOAD_SMG1_LOW,
|
||||
[ACT_GESTURE_RELOAD] = ACT_GESTURE_RELOAD_SMG1
|
||||
},
|
||||
["smg"] = {
|
||||
[ACT_IDLE] = ACT_IDLE_SMG1,
|
||||
[ACT_IDLE_ANGRY] = ACT_IDLE_ANGRY_SMG1,
|
||||
[ACT_RANGE_ATTACK1] = ACT_RANGE_ATTACK_SMG1,
|
||||
[ACT_RELOAD] = ACT_RELOAD_SMG1,
|
||||
[ACT_WALK_AIM] = ACT_WALK_AIM_RIFLE,
|
||||
[ACT_RUN_AIM] = ACT_RUN_AIM_RIFLE,
|
||||
[ACT_GESTURE_RANGE_ATTACK1] = ACT_GESTURE_RANGE_ATTACK_SMG1,
|
||||
[ACT_RELOAD_LOW] = ACT_RELOAD_SMG1_LOW,
|
||||
[ACT_RANGE_ATTACK1_LOW] = ACT_RANGE_ATTACK_SMG1_LOW,
|
||||
[ACT_COVER_LOW] = ACT_COVER_SMG1_LOW,
|
||||
[ACT_RANGE_AIM_LOW] = ACT_RANGE_AIM_SMG1_LOW,
|
||||
[ACT_GESTURE_RELOAD] = ACT_GESTURE_RELOAD_SMG1
|
||||
}
|
||||
}
|
||||
|
||||
function SWEP:SetupWeaponHoldTypeForAI(t)
|
||||
local usedT = HoldTypeTable[t or "ar2"] or HoldTypeTable["ar2"]
|
||||
self.ActivityTranslateAI = table.Copy(usedT)
|
||||
end
|
||||
|
||||
function SWEP:TranslateActivity(act)
|
||||
if (self:GetOwner():IsNPC()) then
|
||||
if (self.ActivityTranslateAI[act]) then return self.ActivityTranslateAI[act] end
|
||||
|
||||
return -1
|
||||
end
|
||||
|
||||
if (self.ActivityTranslate[act] ~= nil) then return self.ActivityTranslate[act] end
|
||||
|
||||
return -1
|
||||
end
|
||||
|
||||
function SWEP:GetCapabilities()
|
||||
local ht = self.DefaultHoldType or self.HoldType or "pistol"
|
||||
|
||||
if ht == "melee" or ht == "melee2" or ht == "knife" or self.IsKnife then
|
||||
return CAP_WEAPON_MELEE_ATTACK1
|
||||
else
|
||||
return bit.bor(CAP_WEAPON_RANGE_ATTACK1, CAP_INNATE_RANGE_ATTACK1)
|
||||
end
|
||||
end
|
||||
59
lua/weapons/tfa_gun_base/common/akimbo.lua
Normal file
59
lua/weapons/tfa_gun_base/common/akimbo.lua
Normal file
@@ -0,0 +1,59 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
-- Copyright (c) 2018-2020 TFA Base Devs
|
||||
|
||||
-- Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
-- of this software and associated documentation files (the "Software"), to deal
|
||||
-- in the Software without restriction, including without limitation the rights
|
||||
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
-- copies of the Software, and to permit persons to whom the Software is
|
||||
-- furnished to do so, subject to the following conditions:
|
||||
|
||||
-- The above copyright notice and this permission notice shall be included in all
|
||||
-- copies or substantial portions of the Software.
|
||||
|
||||
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
-- SOFTWARE.
|
||||
|
||||
SWEP.AnimCycle = SWEP.ViewModelFlip and 0 or 1
|
||||
|
||||
function SWEP:FixAkimbo()
|
||||
if not self:GetStatL("IsAkimbo") or self.Secondary_TFA.ClipSize <= 0 then return end
|
||||
|
||||
self.Primary_TFA.ClipSize = self.Primary_TFA.ClipSize + self.Secondary_TFA.ClipSize
|
||||
self.Secondary_TFA.ClipSize = -1
|
||||
self.Primary_TFA.RPM = self.Primary_TFA.RPM * 2
|
||||
self.Akimbo_Inverted = self.ViewModelFlip
|
||||
self.AnimCycle = self.ViewModelFlip and 0 or 1
|
||||
self:SetAnimCycle(self.AnimCycle)
|
||||
self:ClearStatCache()
|
||||
|
||||
timer.Simple(FrameTime(), function()
|
||||
timer.Simple(0.01, function()
|
||||
if IsValid(self) and self:OwnerIsValid() then
|
||||
self:SetClip1(self.Primary_TFA.ClipSize)
|
||||
end
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
||||
function SWEP:ToggleAkimbo(arg1)
|
||||
if self:GetStatL("IsAkimbo") then
|
||||
self:SetAnimCycle(1 - self:GetAnimCycle())
|
||||
self.AnimCycle = self:GetAnimCycle()
|
||||
end
|
||||
end
|
||||
1370
lua/weapons/tfa_gun_base/common/anims.lua
Normal file
1370
lua/weapons/tfa_gun_base/common/anims.lua
Normal file
File diff suppressed because it is too large
Load Diff
727
lua/weapons/tfa_gun_base/common/attachments.lua
Normal file
727
lua/weapons/tfa_gun_base/common/attachments.lua
Normal file
@@ -0,0 +1,727 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
-- Copyright (c) 2018-2020 TFA Base Devs
|
||||
|
||||
-- Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
-- of this software and associated documentation files (the "Software"), to deal
|
||||
-- in the Software without restriction, including without limitation the rights
|
||||
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
-- copies of the Software, and to permit persons to whom the Software is
|
||||
-- furnished to do so, subject to the following conditions:
|
||||
|
||||
-- The above copyright notice and this permission notice shall be included in all
|
||||
-- copies or substantial portions of the Software.
|
||||
|
||||
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
-- SOFTWARE.
|
||||
|
||||
local ATT_DIMENSION
|
||||
local ATT_MAX_SCREEN_RATIO = 1 / 3
|
||||
local tableCopy = table.Copy
|
||||
|
||||
SWEP.Attachments = {} --[MDL_ATTACHMENT] = = { offset = { 0, 0 }, atts = { "sample_attachment_1", "sample_attachment_2" }, sel = 1, order = 1 } --offset will move the offset the display from the weapon attachment when using CW2.0 style attachment display --atts is a table containing the visible attachments --sel allows you to have an attachment pre-selected, and is used internally by the base to show which attachment is selected in each category. --order is the order it will appear in the TFA style attachment menu
|
||||
SWEP.AttachmentCache = {} --["att_name"] = true
|
||||
SWEP.AttachmentTableCache = {}
|
||||
SWEP.AttachmentCount = 0
|
||||
SWEP.AttachmentDependencies = {} --{["si_acog"] = {"bg_rail"}}
|
||||
SWEP.AttachmentExclusions = {} --{ ["si_iron"] = {"bg_heatshield"} }
|
||||
SWEP.AttachmentTableOverride = {}
|
||||
|
||||
local pairs, type, tonumber = pairs, type, tonumber
|
||||
local string, IsValid = string, IsValid
|
||||
local table = table
|
||||
|
||||
function SWEP:RemoveUnusedAttachments()
|
||||
for k, v in pairs(self.Attachments) do
|
||||
if v.atts then
|
||||
local t = {}
|
||||
local i = 1
|
||||
|
||||
for _, b in pairs(v.atts) do
|
||||
if TFA.Attachments.Atts[b] then
|
||||
t[i] = b
|
||||
i = i + 1
|
||||
end
|
||||
end
|
||||
|
||||
v.atts = tableCopy(t)
|
||||
end
|
||||
|
||||
if #v.atts <= 0 then
|
||||
self.Attachments[k] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function select_function_table(target)
|
||||
-- idk
|
||||
local found_table
|
||||
|
||||
for i_index, base_value in pairs(target) do
|
||||
if istable(base_value) then
|
||||
found_table = base_value
|
||||
end
|
||||
end
|
||||
|
||||
if not found_table then
|
||||
found_table = {}
|
||||
table.insert(target, found_table)
|
||||
end
|
||||
|
||||
return found_table
|
||||
end
|
||||
|
||||
local function get(path, target)
|
||||
if #path == 1 then
|
||||
return target[path[1]]
|
||||
end
|
||||
|
||||
local _target = target[path[1]]
|
||||
|
||||
if _target == nil then
|
||||
target[path[1]] = {}
|
||||
_target = target[path[1]]
|
||||
end
|
||||
|
||||
for i = 2, #path do
|
||||
if not istable(_target) then
|
||||
return
|
||||
end
|
||||
|
||||
if _target[path[i]] == nil then _target[path[i]] = {} end
|
||||
|
||||
if istable(_target[path[i]]) and _target[path[i]].functionTable and i ~= #path then
|
||||
_target = select_function_table(_target[path[i]])
|
||||
else
|
||||
_target = _target[path[i]]
|
||||
end
|
||||
end
|
||||
|
||||
return _target
|
||||
end
|
||||
|
||||
local function set(path, target, value)
|
||||
if #path == 1 then
|
||||
target[path[1]] = value
|
||||
return value
|
||||
end
|
||||
|
||||
local _target = target[path[1]]
|
||||
|
||||
if _target == nil then
|
||||
target[path[1]] = {}
|
||||
_target = target[path[1]]
|
||||
end
|
||||
|
||||
for i = 2, #path - 1 do
|
||||
if not istable(_target) then
|
||||
return value
|
||||
end
|
||||
|
||||
if _target[path[i]] == nil then _target[path[i]] = {} end
|
||||
|
||||
if _target[path[i]].functionTable then
|
||||
_target = select_function_table(_target[path[i]])
|
||||
else
|
||||
_target = _target[path[i]]
|
||||
end
|
||||
end
|
||||
|
||||
if istable(_target) then
|
||||
if istable(_target[path[#path]]) and _target[path[#path]].functionTable then
|
||||
table.insert(select_function_table(_target[path[#path]]), value)
|
||||
else
|
||||
_target[path[#path]] = value
|
||||
end
|
||||
end
|
||||
|
||||
return value
|
||||
end
|
||||
|
||||
local function CloneTableRecursive(source, target, root, source_version, target_version)
|
||||
for index, value in pairs(source) do
|
||||
local _root = root == "" and index or (root .. "." .. index)
|
||||
|
||||
-- merge two tables
|
||||
if istable(value) then
|
||||
local baseTable = get(TFA.GetStatPath(_root, source_version, target_version), target)
|
||||
|
||||
-- target is a function table
|
||||
if istable(baseTable) and baseTable.functionTable then
|
||||
local found_table
|
||||
|
||||
for i_index, base_value in pairs(baseTable) do
|
||||
if istable(base_value) then
|
||||
found_table = base_value
|
||||
end
|
||||
end
|
||||
|
||||
if not found_table then
|
||||
found_table = {}
|
||||
table.insert(baseTable, 1, found_table)
|
||||
end
|
||||
|
||||
CloneTableRecursive(value, target, _root, source_version, target_version)
|
||||
-- target is a regular table
|
||||
else
|
||||
if not istable(baseTable) then
|
||||
set(TFA.GetStatPath(_root, source_version, target_version), target, {})
|
||||
end
|
||||
|
||||
CloneTableRecursive(value, target, _root, source_version, target_version)
|
||||
end
|
||||
-- final value is determined by function
|
||||
elseif isfunction(value) then
|
||||
local temp
|
||||
local get_path = TFA.GetStatPath(_root, source_version, target_version)
|
||||
local get_table = get(get_path, target)
|
||||
|
||||
if get_table ~= nil and not istable(get_table) then
|
||||
temp = get_table
|
||||
end
|
||||
|
||||
local get_value = not istable(get_table) and set(get_path, target, {}) or get_table
|
||||
|
||||
-- mark this table as function based
|
||||
get_value.functionTable = true
|
||||
|
||||
if temp ~= nil then
|
||||
-- insert variable that was there before
|
||||
table.insert(get_value, temp)
|
||||
end
|
||||
|
||||
-- insert function
|
||||
table.insert(get_value, value)
|
||||
-- final value is a scalar
|
||||
else
|
||||
local get_table = get(TFA.GetStatPath(_root, source_version, target_version), target)
|
||||
|
||||
if istable(get_table) and get_table.functionTable then
|
||||
table.insert(get_table, 1, value)
|
||||
else
|
||||
set(TFA.GetStatPath(_root, source_version, target_version), target, value)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:BuildAttachmentCache()
|
||||
self.AttachmentCount = 0
|
||||
|
||||
for k, v in pairs(self.Attachments) do
|
||||
if v.atts then
|
||||
for l, b in pairs(v.atts) do
|
||||
self.AttachmentCount = self.AttachmentCount + 1
|
||||
self.AttachmentCache[b] = (v.sel == l) and k or false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
table.Empty(self.AttachmentTableCache)
|
||||
|
||||
for attName, sel in pairs(self.AttachmentCache) do
|
||||
if not sel then goto CONTINUE end
|
||||
if not TFA.Attachments.Atts[attName] then goto CONTINUE end
|
||||
|
||||
local srctbl = TFA.Attachments.Atts[attName].WeaponTable
|
||||
|
||||
if istable(srctbl) then
|
||||
CloneTableRecursive(srctbl, self.AttachmentTableCache, "", TFA.Attachments.Atts[attName].TFADataVersion or 0, self.TFADataVersion or 0)
|
||||
end
|
||||
|
||||
if istable(self.AttachmentTableOverride[attName]) then
|
||||
CloneTableRecursive(self.AttachmentTableOverride[attName], self.AttachmentTableCache, "", self.TFADataVersion or 0, self.TFADataVersion or 0)
|
||||
end
|
||||
|
||||
::CONTINUE::
|
||||
end
|
||||
|
||||
self:ClearStatCache()
|
||||
self:ClearMaterialCache()
|
||||
end
|
||||
|
||||
function SWEP:IsAttached(attn)
|
||||
return isnumber(self.AttachmentCache[attn])
|
||||
end
|
||||
|
||||
local tc
|
||||
|
||||
function SWEP:CanAttach(attn)
|
||||
local retVal = hook.Run("TFA_PreCanAttach", self, attn)
|
||||
if retVal ~= nil then return retVal end
|
||||
local self2 = self:GetTable()
|
||||
|
||||
if not self2.HasBuiltMutualExclusions then
|
||||
tc = tableCopy(self2.AttachmentExclusions)
|
||||
|
||||
for k, v in pairs(tc) do
|
||||
if k ~= "BaseClass" then
|
||||
for _, b in pairs(v) do
|
||||
self2.AttachmentExclusions[b] = self2.AttachmentExclusions[b] or {}
|
||||
|
||||
if not table.HasValue(self2.AttachmentExclusions[b]) then
|
||||
self2.AttachmentExclusions[b][#self2.AttachmentExclusions[b] + 1] = k
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
self2.HasBuiltMutualExclusions = true
|
||||
end
|
||||
|
||||
if self.AttachmentExclusions[attn] then
|
||||
for _, v in pairs(self.AttachmentExclusions[attn]) do
|
||||
if self:IsAttached(v) then return false end
|
||||
end
|
||||
end
|
||||
|
||||
if self2.AttachmentDependencies[attn] then
|
||||
local t = self2.AttachmentDependencies[attn]
|
||||
|
||||
if isstring(t) then
|
||||
if t ~= "BaseClass" and not self2.IsAttached(self, t) then return false end
|
||||
elseif istable(t) then
|
||||
t.type = t.type or "OR"
|
||||
|
||||
if t.type == "AND" then
|
||||
for k, v in pairs(self.AttachmentDependencies[attn]) do
|
||||
if k ~= "BaseClass" and k ~= "type" and not self2.IsAttached(self, v) then return false end
|
||||
end
|
||||
else
|
||||
local cnt = 0
|
||||
|
||||
for k, v in pairs(self.AttachmentDependencies[attn]) do
|
||||
if k ~= "BaseClass" and k ~= "type" and self2.IsAttached(self, v) then
|
||||
cnt = cnt + 1
|
||||
end
|
||||
end
|
||||
|
||||
if cnt == 0 then return false end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local atTable = TFA.Attachments.Atts[attn]
|
||||
if not atTable or not atTable:CanAttach(self) then return false end
|
||||
|
||||
local retVal2 = hook.Run("TFA_CanAttach", self, attn)
|
||||
if retVal2 ~= nil then return retVal2 end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
local ATTACHMENT_SORTING_DEPENDENCIES = false
|
||||
function SWEP:ForceAttachmentReqs(attn)
|
||||
if not ATTACHMENT_SORTING_DEPENDENCIES then
|
||||
ATTACHMENT_SORTING_DEPENDENCIES = true
|
||||
local related = {}
|
||||
|
||||
for k, v in pairs(self.AttachmentDependencies) do
|
||||
if istable(v) then
|
||||
for _, b in pairs(v) do
|
||||
if k == attn then
|
||||
related[b] = true
|
||||
elseif b == attn then
|
||||
related[k] = true
|
||||
end
|
||||
end
|
||||
elseif isstring(v) then
|
||||
if k == attn then
|
||||
related[v] = true
|
||||
elseif v == attn then
|
||||
related[k] = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for k, v in pairs(self.AttachmentExclusions) do
|
||||
if istable(v) then
|
||||
for _, b in pairs(v) do
|
||||
if k == attn then
|
||||
related[b] = true
|
||||
elseif b == attn then
|
||||
related[k] = true
|
||||
end
|
||||
end
|
||||
elseif isstring(v) then
|
||||
if k == attn then
|
||||
related[v] = true
|
||||
elseif v == attn then
|
||||
related[k] = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for k, v in pairs(self.AttachmentCache) do
|
||||
if v and related[k] and not self:CanAttach(k) then
|
||||
self:SetTFAAttachment(v, 0, true, true)
|
||||
end
|
||||
end
|
||||
|
||||
ATTACHMENT_SORTING_DEPENDENCIES = false
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local self3, att_neue, att_old
|
||||
|
||||
local function attach()
|
||||
att_neue:Attach(self3)
|
||||
end
|
||||
|
||||
local function detach()
|
||||
att_old:Detach(self3)
|
||||
end
|
||||
|
||||
function SWEP:SetTFAAttachment(cat, id, nw, force)
|
||||
self3 = self
|
||||
local self2 = self:GetTable()
|
||||
|
||||
if not self2.Attachments[cat] then return false end
|
||||
|
||||
if isstring(id) then
|
||||
if id == "" then
|
||||
id = -1
|
||||
else
|
||||
id = table.KeyFromValue(self2.Attachments[cat].atts, id)
|
||||
if not id then return false end
|
||||
end
|
||||
end
|
||||
|
||||
if id <= 0 and self2.Attachments[cat].default and type(self2.Attachments[cat].default) == "string" and self2.Attachments[cat].default ~= "" then
|
||||
return self2.SetTFAAttachment(self, cat, self2.Attachments[cat].default, nw, force)
|
||||
end
|
||||
|
||||
local attn = self2.Attachments[cat].atts[id] or ""
|
||||
local attn_old = self2.Attachments[cat].atts[self2.Attachments[cat].sel or -1] or ""
|
||||
if SERVER and id > 0 and not (force or self2.CanAttach(self, attn)) then return false end
|
||||
|
||||
if id ~= self2.Attachments[cat].sel then
|
||||
att_old = TFA.Attachments.Atts[self2.Attachments[cat].atts[self2.Attachments[cat].sel] or -1]
|
||||
local detach_status = att_old == nil
|
||||
|
||||
if att_old then
|
||||
detach_status = ProtectedCall(detach)
|
||||
|
||||
if detach_status then
|
||||
hook.Run("TFA_Attachment_Detached", self, attn_old, att_old, cat, id, force)
|
||||
end
|
||||
end
|
||||
|
||||
att_neue = TFA.Attachments.Atts[self2.Attachments[cat].atts[id] or -1]
|
||||
local attach_status = att_neue == nil
|
||||
|
||||
if detach_status then
|
||||
if att_neue then
|
||||
attach_status = ProtectedCall(attach)
|
||||
|
||||
if attach_status then
|
||||
hook.Run("TFA_Attachment_Attached", self, attn, att_neue, cat, id, force)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if detach_status and attach_status then
|
||||
if id > 0 then
|
||||
self2.Attachments[cat].sel = id
|
||||
else
|
||||
self2.Attachments[cat].sel = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
self2.BuildAttachmentCache(self)
|
||||
self2.ForceAttachmentReqs(self, (id > 0) and attn or attn_old)
|
||||
|
||||
if nw and (not isentity(nw) or SERVER) then
|
||||
net.Start("TFA_Attachment_Set")
|
||||
net.WriteUInt(cat, 8)
|
||||
net.WriteString(attn)
|
||||
|
||||
if SERVER then
|
||||
net.WriteEntity(self)
|
||||
|
||||
if isentity(nw) then
|
||||
local filter = RecipientFilter()
|
||||
filter:AddPVS(self:GetPos())
|
||||
filter:RemovePlayer(nw)
|
||||
net.Send(filter)
|
||||
else
|
||||
net.SendPVS(self:GetPos())
|
||||
end
|
||||
elseif CLIENT then
|
||||
net.SendToServer()
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:Attach(attname, force)
|
||||
if not attname or not IsValid(self) then return false end
|
||||
if self.AttachmentCache[attname] == nil then return false end
|
||||
|
||||
for cat, tbl in pairs(self.Attachments) do
|
||||
local atts = tbl.atts
|
||||
|
||||
for id, att in ipairs(atts) do
|
||||
if att == attname then return self:SetTFAAttachment(cat, id, true, force) end
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function SWEP:Detach(attname, force)
|
||||
if not attname or not IsValid(self) then return false end
|
||||
local cat = self.AttachmentCache[attname]
|
||||
if not cat then return false end
|
||||
|
||||
return self:SetTFAAttachment(cat, 0, true, force)
|
||||
end
|
||||
|
||||
function SWEP:RandomizeAttachments(force)
|
||||
for key, slot in pairs(self.AttachmentCache) do
|
||||
if slot then
|
||||
self:Detach(key)
|
||||
end
|
||||
end
|
||||
|
||||
for category, def in pairs(self.Attachments) do
|
||||
if istable(def) and istable(def.atts) and #def.atts > 0 then
|
||||
if math.random() > 0.3 then
|
||||
local randkey = math.random(1, #def.atts)
|
||||
self:SetTFAAttachment(category, randkey, true, force)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local attachments_sorted_alphabetically = GetConVar("sv_tfa_attachments_alphabetical")
|
||||
|
||||
function SWEP:InitAttachments()
|
||||
if self.HasInitAttachments then return end
|
||||
hook.Run("TFA_PreInitAttachments", self)
|
||||
self.HasInitAttachments = true
|
||||
|
||||
for k, v in pairs(self.Attachments) do
|
||||
if type(k) == "string" then
|
||||
local tatt = self:VMIV() and self.OwnerViewModel:LookupAttachment(k) or self:LookupAttachment(k)
|
||||
|
||||
if tatt > 0 then
|
||||
self.Attachments[tatt] = v
|
||||
end
|
||||
|
||||
self.Attachments[k] = nil
|
||||
elseif (not attachments_sorted_alphabetically) and attachments_sorted_alphabetically:GetBool() then
|
||||
local sval = v.atts[v.sel]
|
||||
|
||||
table.sort(v.atts, function(a, b)
|
||||
local aname = ""
|
||||
local bname = ""
|
||||
local att_a = TFA.Attachments.Atts[a]
|
||||
|
||||
if att_a then
|
||||
aname = att_a.Name or a
|
||||
end
|
||||
|
||||
local att_b = TFA.Attachments.Atts[b]
|
||||
|
||||
if att_b then
|
||||
bname = att_b.Name or b
|
||||
end
|
||||
|
||||
return aname < bname
|
||||
end)
|
||||
|
||||
if sval then
|
||||
v.sel = table.KeyFromValue(v.atts, sval) or v.sel
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for k, v in pairs(self.Attachments) do
|
||||
if v.sel then
|
||||
local vsel = v.sel
|
||||
v.sel = nil
|
||||
|
||||
if type(vsel) == "string" then
|
||||
vsel = table.KeyFromValue(v.atts, vsel) or tonumber(vsel)
|
||||
|
||||
if not vsel then goto CONTINUE end
|
||||
end
|
||||
|
||||
timer.Simple(0, function()
|
||||
if IsValid(self) and self.SetTFAAttachment then
|
||||
self:SetTFAAttachment(k, vsel, false)
|
||||
end
|
||||
end)
|
||||
|
||||
if SERVER and game.SinglePlayer() then
|
||||
timer.Simple(0.05, function()
|
||||
if IsValid(self) and self.SetTFAAttachment then
|
||||
self:SetTFAAttachment(k, vsel, true)
|
||||
end
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
::CONTINUE::
|
||||
end
|
||||
|
||||
hook.Run("TFA_PostInitAttachments", self)
|
||||
self:RemoveUnusedAttachments()
|
||||
self:BuildAttachmentCache()
|
||||
hook.Run("TFA_FinalInitAttachments", self)
|
||||
end
|
||||
|
||||
function SWEP:GenerateVGUIAttachmentTable()
|
||||
self.VGUIAttachments = {}
|
||||
local keyz = table.GetKeys(self.Attachments)
|
||||
table.RemoveByValue(keyz, "BaseClass")
|
||||
|
||||
table.sort(keyz, function(a, b)
|
||||
--A and B are keys
|
||||
local v1 = self.Attachments[a]
|
||||
local v2 = self.Attachments[b]
|
||||
|
||||
if v1 and v2 and (v1.order or v2.order) then
|
||||
return (v1.order or a) < (v2.order or b)
|
||||
else
|
||||
return a < b
|
||||
end
|
||||
end)
|
||||
|
||||
for _, k in ipairs(keyz) do
|
||||
local v = self.Attachments[k]
|
||||
|
||||
if not v.hidden then
|
||||
local aTbl = tableCopy(v)
|
||||
|
||||
aTbl.cat = k
|
||||
aTbl.offset = nil
|
||||
aTbl.order = nil
|
||||
|
||||
table.insert(self.VGUIAttachments, aTbl)
|
||||
end
|
||||
end
|
||||
|
||||
ATT_DIMENSION = math.Round(TFA.ScaleH(TFA.Attachments.IconSize))
|
||||
local max_row_atts = math.floor(ScrW() * ATT_MAX_SCREEN_RATIO / ATT_DIMENSION)
|
||||
local i = 1
|
||||
|
||||
while true do
|
||||
local v = self.VGUIAttachments[i]
|
||||
if not v then break end
|
||||
i = i + 1
|
||||
|
||||
for l, b in pairs(v.atts) do
|
||||
if not istable(b) then
|
||||
v.atts[l] = {b, l} --name, ID
|
||||
end
|
||||
end
|
||||
|
||||
if (#v.atts > max_row_atts) then
|
||||
while (#v.atts > max_row_atts) do
|
||||
local t = tableCopy(v)
|
||||
|
||||
for _ = 1, max_row_atts do
|
||||
table.remove(t.atts, 1)
|
||||
end
|
||||
|
||||
for _ = 1, #v.atts - max_row_atts do
|
||||
table.remove(v.atts)
|
||||
end
|
||||
|
||||
table.insert(self.VGUIAttachments, i, t)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local bgt = {}
|
||||
SWEP.ViewModelBodygroups = {}
|
||||
SWEP.WorldModelBodygroups = {}
|
||||
|
||||
function SWEP:IterateBodygroups(entity, tablename, version)
|
||||
local self2 = self:GetTable()
|
||||
|
||||
bgt = self2.GetStatVersioned(self, tablename, version or 0, self2[tablename])
|
||||
|
||||
for k, v in pairs(bgt) do
|
||||
if isnumber(k) then
|
||||
local bgn = entity:GetBodygroupName(k)
|
||||
|
||||
if bgt[bgn] then
|
||||
v = bgt[bgn]
|
||||
end
|
||||
|
||||
if entity:GetBodygroup(k) ~= v then
|
||||
entity:SetBodygroup(k, v)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:ProcessBodygroups()
|
||||
local self2 = self:GetTable()
|
||||
local ViewModelBodygroups = self:GetStatRawL("ViewModelBodygroups")
|
||||
local WorldModelBodygroups = self:GetStatRawL("WorldModelBodygroups")
|
||||
|
||||
if not self2.HasFilledBodygroupTables then
|
||||
if self2.VMIV(self) then
|
||||
for i = 0, #(self2.OwnerViewModel:GetBodyGroups() or ViewModelBodygroups) do
|
||||
ViewModelBodygroups[i] = ViewModelBodygroups[i] or 0
|
||||
end
|
||||
end
|
||||
|
||||
for i = 0, #(self:GetBodyGroups() or WorldModelBodygroups) do
|
||||
WorldModelBodygroups[i] = WorldModelBodygroups[i] or 0
|
||||
end
|
||||
|
||||
self2.HasFilledBodygroupTables = true
|
||||
end
|
||||
|
||||
if self2.VMIV(self) then
|
||||
self2.IterateBodygroups(self, self2.OwnerViewModel, "ViewModelBodygroups", TFA.LatestDataVersion)
|
||||
end
|
||||
|
||||
self2.IterateBodygroups(self, self, "WorldModelBodygroups", TFA.LatestDataVersion)
|
||||
end
|
||||
|
||||
function SWEP:CallAttFunc(funcName, ...)
|
||||
for attName, sel in pairs(self.AttachmentCache or {}) do
|
||||
if not sel then goto CONTINUE end
|
||||
|
||||
local att = TFA.Attachments.Atts[attName]
|
||||
if not att then goto CONTINUE end
|
||||
|
||||
local attFunc = att[funcName]
|
||||
if attFunc and type(attFunc) == "function" then
|
||||
local _ret1, _ret2, _ret3, _ret4, _ret5, _ret6, _ret7, _ret8, _ret9, _ret10 = attFunc(att, self, ...)
|
||||
|
||||
if _ret1 ~= nil then
|
||||
return _ret1, _ret2, _ret3, _ret4, _ret5, _ret6, _ret7, _ret8, _ret9, _ret10
|
||||
end
|
||||
end
|
||||
|
||||
::CONTINUE::
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
797
lua/weapons/tfa_gun_base/common/autodetection.lua
Normal file
797
lua/weapons/tfa_gun_base/common/autodetection.lua
Normal file
@@ -0,0 +1,797 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
-- Copyright (c) 2018-2020 TFA Base Devs
|
||||
|
||||
-- Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
-- of this software and associated documentation files (the "Software"), to deal
|
||||
-- in the Software without restriction, including without limitation the rights
|
||||
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
-- copies of the Software, and to permit persons to whom the Software is
|
||||
-- furnished to do so, subject to the following conditions:
|
||||
|
||||
-- The above copyright notice and this permission notice shall be included in all
|
||||
-- copies or substantial portions of the Software.
|
||||
|
||||
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
-- SOFTWARE.
|
||||
|
||||
function SWEP:FixSprintAnimBob()
|
||||
local self2 = self:GetTable()
|
||||
|
||||
if self:GetStatRawL("Sprint_Mode") == TFA.Enum.LOCOMOTION_ANI then
|
||||
self:SetStatRawL("SprintBobMult", 0)
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:FixWalkAnimBob()
|
||||
local self2 = self:GetTable()
|
||||
if self:GetStatRawL("Walk_Mode") == TFA.Enum.LOCOMOTION_ANI then
|
||||
self:SetStatRawL("WalkBobMult_Iron", self:GetStatRawL("WalkBobMult"))
|
||||
self:SetStatRawL("WalkBobMult", 0)
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:PatchAmmoTypeAccessors()
|
||||
local self2 = self:GetTable()
|
||||
self:SetStatRawL("GetPrimaryAmmoTypeOld", self:GetStatRawL("GetPrimaryAmmoTypeOld") or self:GetStatRawL("GetPrimaryAmmoType"))
|
||||
self:SetStatRawL("GetPrimaryAmmoType", function(myself, ...) return myself.GetPrimaryAmmoTypeC(myself, ...) end)
|
||||
self:SetStatRawL("GetSecondaryAmmoTypeOld", self:GetStatRawL("GetSecondaryAmmoTypeOld") or self:GetStatRawL("GetSecondaryAmmoType"))
|
||||
self:SetStatRawL("GetSecondaryAmmoType", function(myself, ...) return myself.GetSecondaryAmmoTypeC(myself, ...) end)
|
||||
end
|
||||
|
||||
function SWEP:FixProjectile()
|
||||
local self2 = self:GetTable()
|
||||
if self:GetStatRawL("ProjectileEntity") and self:GetStatRawL("ProjectileEntity") ~= "" then
|
||||
self:SetStatRawL("Primary.Projectile", self:GetStatRawL("ProjectileEntity"))
|
||||
self:SetStatRawL("ProjectileEntity", nil)
|
||||
end
|
||||
|
||||
if self:GetStatRawL("ProjectileModel") and self:GetStatRawL("ProjectileModel") ~= "" then
|
||||
self:SetStatRawL("Primary.ProjectileModel", self:GetStatRawL("ProjectileModel"))
|
||||
self:SetStatRawL("ProjectileModel", nil)
|
||||
end
|
||||
|
||||
if self:GetStatRawL("ProjectileVelocity") and self:GetStatRawL("ProjectileVelocity") ~= "" then
|
||||
self:SetStatRawL("Primary.ProjectileVelocity", self:GetStatRawL("ProjectileVelocity"))
|
||||
self:SetStatRawL("ProjectileVelocity", nil)
|
||||
end
|
||||
end
|
||||
|
||||
local sv_tfa_range_modifier = GetConVar("sv_tfa_range_modifier")
|
||||
|
||||
function SWEP:AutoDetectRange()
|
||||
local self2 = self:GetTable()
|
||||
|
||||
if self:GetStatL("Primary.FalloffMetricBased") and not self:GetStatRawL("Primary.RangeFalloffLUT") then
|
||||
self:SetStatRawL("Primary.RangeFalloffLUT_IsConverted", true)
|
||||
|
||||
self:SetStatRawL("Primary.RangeFalloffLUT", {
|
||||
bezier = false,
|
||||
range_func = "linear", -- function to spline range
|
||||
units = "meters",
|
||||
lut = {
|
||||
{range = self:GetStatL("Primary.MinRangeStartFalloff"), damage = 1},
|
||||
{range = self:GetStatL("Primary.MinRangeStartFalloff") + self:GetStatL("Primary.MaxFalloff") / self:GetStatL("Primary.FalloffByMeter"),
|
||||
damage = (self:GetStatL("Primary.Damage") - self:GetStatL("Primary.MaxFalloff")) / self:GetStatL("Primary.Damage")},
|
||||
}
|
||||
})
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
if self:GetStatL("Primary.FalloffMetricBased") or self:GetStatL("Primary.RangeFalloffLUT") then return end
|
||||
|
||||
if self:GetStatL("Primary.Range") <= 0 then
|
||||
self:SetStatRawL("Primary.Range", math.sqrt(self:GetStatL("Primary.Damage") / 32) * self:MetersToUnits(350) * self:AmmoRangeMultiplier())
|
||||
end
|
||||
|
||||
if self:GetStatL("Primary.RangeFalloff") <= 0 then
|
||||
self:SetStatRawL("Primary.RangeFalloff", 0.5)
|
||||
end
|
||||
|
||||
self:SetStatRawL("Primary.RangeFalloffLUT_IsConverted", true)
|
||||
|
||||
self:SetStatRawL("Primary.RangeFalloffLUT", {
|
||||
bezier = false,
|
||||
range_func = "linear", -- function to spline range
|
||||
units = "hammer",
|
||||
lut = {
|
||||
{range = self:GetStatL("Primary.Range") * self:GetStatL("Primary.RangeFalloff"), damage = 1},
|
||||
{range = self:GetStatL("Primary.Range"), damage = 1 - sv_tfa_range_modifier:GetFloat()},
|
||||
}
|
||||
})
|
||||
end
|
||||
|
||||
function SWEP:FixProceduralReload()
|
||||
-- do nothing
|
||||
end
|
||||
|
||||
function SWEP:FixRPM()
|
||||
local self2 = self:GetTable()
|
||||
if not self:GetStatRawL("Primary.RPM") then
|
||||
if self:GetStatRawL("Primary.Delay") then
|
||||
self:SetStatRawL("Primary.RPM", 60 / self:GetStatRawL("Primary.Delay"))
|
||||
else
|
||||
self:SetStatRawL("Primary.RPM", 120)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:FixCone()
|
||||
local self2 = self:GetTable()
|
||||
if self:GetStatRawL("Primary.Cone") then
|
||||
if (not self:GetStatRawL("Primary.Spread")) or self:GetStatRawL("Primary.Spread") < 0 then
|
||||
self:SetStatRawL("Primary.Spread", self:GetStatRawL("Primary.Cone"))
|
||||
end
|
||||
|
||||
self:SetStatRawL("Primary.Cone", nil)
|
||||
end
|
||||
end
|
||||
|
||||
--legacy compatibility
|
||||
function SWEP:FixIdles()
|
||||
local self2 = self:GetTable()
|
||||
if self:GetStatRawL("DisableIdleAnimations") ~= nil and self:GetStatRawL("DisableIdleAnimations") == true then
|
||||
self:SetStatRawL("Idle_Mode", TFA.Enum.IDLE_LUA)
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:FixIS()
|
||||
local self2 = self:GetTable()
|
||||
if self:GetStatRawL("SightsPos") and (not self:GetStatRawL("IronSightsPosition") or (self:GetStatRawL("IronSightsPosition").x ~= self:GetStatRawL("SightsPos").x and self:GetStatRawL("SightsPos").x ~= 0)) then
|
||||
self:SetStatRawL("IronSightsPosition", self:GetStatRawL("SightsPos") or Vector())
|
||||
self:SetStatRawL("IronSightsAngle", self:GetStatRawL("SightsAng") or Vector())
|
||||
end
|
||||
end
|
||||
|
||||
local legacy_spread_cv = GetConVar("sv_tfa_spread_legacy")
|
||||
|
||||
function SWEP:AutoDetectSpread()
|
||||
local self2 = self:GetTable()
|
||||
if legacy_spread_cv and legacy_spread_cv:GetBool() then
|
||||
self:SetUpSpreadLegacy()
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
if self:GetStatRawL("Primary.SpreadMultiplierMax") == -1 or not self:GetStatRawL("Primary.SpreadMultiplierMax") then
|
||||
self:SetStatRawL("Primary.SpreadMultiplierMax", math.Clamp(math.sqrt(math.sqrt(self:GetStatRawL("Primary.Damage") / 35) * 10 / 5) * 5, 0.01 / self:GetStatRawL("Primary.Spread"), 0.1 / self:GetStatRawL("Primary.Spread")))
|
||||
end
|
||||
|
||||
if self:GetStatRawL("Primary.SpreadIncrement") == -1 or not self:GetStatRawL("Primary.SpreadIncrement") then
|
||||
self:SetStatRawL("Primary.SpreadIncrement", self:GetStatRawL("Primary.SpreadMultiplierMax") * 60 / self:GetStatRawL("Primary.RPM") * 0.85 * 1.5)
|
||||
end
|
||||
|
||||
if self:GetStatRawL("Primary.SpreadRecovery") == -1 or not self:GetStatRawL("Primary.SpreadRecovery") then
|
||||
self:SetStatRawL("Primary.SpreadRecovery", math.max(self:GetStatRawL("Primary.SpreadMultiplierMax") * math.pow(self:GetStatRawL("Primary.RPM") / 600, 1 / 3) * 0.75, self:GetStatRawL("Primary.SpreadMultiplierMax") / 1.5))
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
Function Name: AutoDetectMuzzle
|
||||
Syntax: self:AutoDetectMuzzle(). Call only once, or it's redundant.
|
||||
Returns: Nothing.
|
||||
Notes: Detects the proper muzzle flash effect if you haven't specified one.
|
||||
Purpose: Autodetection
|
||||
]]
|
||||
--
|
||||
function SWEP:AutoDetectMuzzle()
|
||||
local self2 = self:GetTable()
|
||||
if not self:GetStatRawL("MuzzleFlashEffect") then
|
||||
local a = string.lower(self:GetStatRawL("Primary.Ammo"))
|
||||
local cat = string.lower(self:GetStatRawL("Category") and self:GetStatRawL("Category") or "")
|
||||
|
||||
if self:GetStatRawL("Silenced") or self:GetSilenced() then
|
||||
self:SetStatRawL("MuzzleFlashEffect", "tfa_muzzleflash_silenced")
|
||||
elseif string.find(a, "357") or self:GetStatRawL("Revolver") or string.find(cat, "revolver") then
|
||||
self:SetStatRawL("MuzzleFlashEffect", "tfa_muzzleflash_revolver")
|
||||
elseif self:GetStatL("LoopedReload") or a == "buckshot" or a == "slam" or a == "airboatgun" or string.find(cat, "shotgun") then
|
||||
self:SetStatRawL("MuzzleFlashEffect", "tfa_muzzleflash_shotgun")
|
||||
elseif string.find(a, "smg") or string.find(cat, "smg") or string.find(cat, "submachine") or string.find(cat, "sub-machine") then
|
||||
self:SetStatRawL("MuzzleFlashEffect", "tfa_muzzleflash_smg")
|
||||
elseif string.find(a, "sniper") or string.find(cat, "sniper") then
|
||||
self:SetStatRawL("MuzzleFlashEffect", "tfa_muzzleflash_sniper")
|
||||
elseif string.find(a, "pistol") or string.find(cat, "pistol") then
|
||||
self:SetStatRawL("MuzzleFlashEffect", "tfa_muzzleflash_pistol")
|
||||
elseif string.find(a, "ar2") or string.find(a, "rifle") or (string.find(cat, "revolver") and not string.find(cat, "rifle")) then
|
||||
self:SetStatRawL("MuzzleFlashEffect", "tfa_muzzleflash_rifle")
|
||||
else
|
||||
self:SetStatRawL("MuzzleFlashEffect", "tfa_muzzleflash_generic")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
Function Name: AutoDetectDamage
|
||||
Syntax: self:AutoDetectDamage(). Call only once. Hopefully you call this only once on like SWEP:Initialize() or something.
|
||||
Returns: Nothing.
|
||||
Notes: Fixes the damage for GDCW.
|
||||
Purpose: Autodetection
|
||||
]]
|
||||
--
|
||||
function SWEP:AutoDetectDamage()
|
||||
local self2 = self:GetTable()
|
||||
if self:GetStatRawL("Primary.Damage") and self:GetStatRawL("Primary.Damage") ~= -1 then return end
|
||||
|
||||
if self:GetStatRawL("Primary.Round") then
|
||||
local rnd = string.lower(self:GetStatRawL("Primary.Round"))
|
||||
|
||||
if string.find(rnd, ".50bmg") then
|
||||
self:SetStatRawL("Primary.Damage", 185)
|
||||
elseif string.find(rnd, "5.45x39") then
|
||||
self:SetStatRawL("Primary.Damage", 22)
|
||||
elseif string.find(rnd, "5.56x45") then
|
||||
self:SetStatRawL("Primary.Damage", 30)
|
||||
elseif string.find(rnd, "338_lapua") then
|
||||
self:SetStatRawL("Primary.Damage", 120)
|
||||
elseif string.find(rnd, "338") then
|
||||
self:SetStatRawL("Primary.Damage", 100)
|
||||
elseif string.find(rnd, "7.62x51") then
|
||||
self:SetStatRawL("Primary.Damage", 100)
|
||||
elseif string.find(rnd, "9x39") then
|
||||
self:SetStatRawL("Primary.Damage", 32)
|
||||
elseif string.find(rnd, "9mm") then
|
||||
self:SetStatRawL("Primary.Damage", 22)
|
||||
elseif string.find(rnd, "9x19") then
|
||||
self:SetStatRawL("Primary.Damage", 22)
|
||||
elseif string.find(rnd, "9x18") then
|
||||
self:SetStatRawL("Primary.Damage", 20)
|
||||
end
|
||||
|
||||
if string.find(rnd, "ap") then
|
||||
self:SetStatRawL("Primary.Damage", self:GetStatRawL("Primary.Damage") * 1.2)
|
||||
end
|
||||
end
|
||||
|
||||
if (not self:GetStatRawL("Primary.Damage")) or (self:GetStatRawL("Primary.Damage") <= 0.01) and self:GetStatRawL("Velocity") then
|
||||
self:SetStatRawL("Primary.Damage", self:GetStatRawL("Velocity") / 5)
|
||||
end
|
||||
|
||||
if (not self:GetStatRawL("Primary.Damage")) or (self:GetStatRawL("Primary.Damage") <= 0.01) then
|
||||
self:SetStatRawL("Primary.Damage", (self:GetStatRawL("Primary.KickUp") + self:GetStatRawL("Primary.KickUp") + self:GetStatRawL("Primary.KickUp")) * 10)
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
Function Name: AutoDetectDamageType
|
||||
Syntax: self:AutoDetectDamageType(). Call only once. Hopefully you call this only once on like SWEP:Initialize() or something.
|
||||
Returns: Nothing.
|
||||
Notes: Sets a damagetype
|
||||
Purpose: Autodetection
|
||||
]]
|
||||
--
|
||||
function SWEP:AutoDetectDamageType()
|
||||
local self2 = self:GetTable()
|
||||
if self:GetStatRawL("Primary.DamageType") == -1 or not self:GetStatRawL("Primary.DamageType") then
|
||||
if self:GetStatRawL("DamageType") and not self:GetStatRawL("Primary.DamageType") then
|
||||
self:SetStatRawL("Primary.DamageType", self:GetStatRawL("DamageType"))
|
||||
else
|
||||
self:SetStatRawL("Primary.DamageType", DMG_BULLET)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
Function Name: AutoDetectForce
|
||||
Syntax: self:AutoDetectForce(). Call only once. Hopefully you call this only once on like SWEP:Initialize() or something.
|
||||
Returns: Nothing.
|
||||
Notes: Detects force from damage
|
||||
Purpose: Autodetection
|
||||
]]
|
||||
--
|
||||
function SWEP:AutoDetectForce()
|
||||
local self2 = self:GetTable()
|
||||
if self:GetStatRawL("Primary.Force") == -1 or not self:GetStatRawL("Primary.Force") then
|
||||
self:SetStatRawL("Primary.Force", self:GetStatRawL("Force") or (math.sqrt(self:GetStatRawL("Primary.Damage") / 16) * 3 / math.sqrt(self:GetStatRawL("Primary.NumShots"))))
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:AutoDetectPenetrationPower()
|
||||
local self2 = self:GetTable()
|
||||
|
||||
if self:GetStatRawL("Primary.PenetrationPower") == -1 or not self:GetStatRawL("Primary.PenetrationPower") then
|
||||
local am = string.lower(self:GetStatL("Primary.Ammo"))
|
||||
local m = 1
|
||||
|
||||
if (am == "pistol") then
|
||||
m = 0.4
|
||||
elseif (am == "357") then
|
||||
m = 1.75
|
||||
elseif (am == "smg1") then
|
||||
m = 0.34
|
||||
elseif (am == "ar2") then
|
||||
m = 1.1
|
||||
elseif (am == "buckshot") then
|
||||
m = 0.3
|
||||
elseif (am == "airboatgun") then
|
||||
m = 2.25
|
||||
elseif (am == "sniperpenetratedround") then
|
||||
m = 3
|
||||
end
|
||||
|
||||
self:SetStatRawL("Primary.PenetrationPower", self:GetStatRawL("PenetrationPower") or math.sqrt(self:GetStatRawL("Primary.Force") * 200 * m))
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
Function Name: AutoDetectKnockback
|
||||
Syntax: self:AutoDetectKnockback(). Call only once. Hopefully you call this only once on like SWEP:Initialize() or something.
|
||||
Returns: Nothing.
|
||||
Notes: Detects knockback from force
|
||||
Purpose: Autodetection
|
||||
]]
|
||||
--
|
||||
function SWEP:AutoDetectKnockback()
|
||||
local self2 = self:GetTable()
|
||||
if self:GetStatRawL("Primary.Knockback") == -1 or not self:GetStatRawL("Primary.Knockback") then
|
||||
self:SetStatRawL("Primary.Knockback", self:GetStatRawL("Knockback") or math.max(math.pow(self:GetStatRawL("Primary.Force") - 3.25, 2), 0) * math.pow(self:GetStatRawL("Primary.NumShots"), 1 / 3))
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
Function Name: IconFix
|
||||
Syntax: self:IconFix(). Call only once. Hopefully you call this only once on like SWEP:Initialize() or something.
|
||||
Returns: Nothing.
|
||||
Notes: Fixes the icon. Call this if you give it a texture path, or just nothing.
|
||||
Purpose: Autodetection
|
||||
]]
|
||||
--
|
||||
local selicon_final = {}
|
||||
|
||||
function SWEP:IconFix()
|
||||
local self2 = self:GetTable()
|
||||
|
||||
if not surface then return end
|
||||
|
||||
local class = self2.ClassName
|
||||
|
||||
if selicon_final[class] then
|
||||
self:SetStatRawL("WepSelectIcon", selicon_final[class])
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
if self2.WepSelectIcon and type(self2.WepSelectIcon) == "string" then
|
||||
self:SetStatRawL("WepSelectIcon", surface.GetTextureID(self2.WepSelectIcon))
|
||||
else
|
||||
if file.Exists("materials/vgui/hud/" .. class .. ".png", "GAME") then
|
||||
self:SetStatRawL("WepSelectIcon", Material("vgui/hud/" .. class .. ".png", "smooth noclamp")) -- NOTHING should access this variable directly and our DrawWeaponSelection override supports IMaterial.
|
||||
elseif file.Exists("materials/vgui/hud/" .. class .. ".vmt", "GAME") then
|
||||
self:SetStatRawL("WepSelectIcon", surface.GetTextureID("vgui/hud/" .. class))
|
||||
end
|
||||
end
|
||||
|
||||
selicon_final[class] = self2.WepSelectIcon
|
||||
end
|
||||
|
||||
--[[
|
||||
Function Name: CorrectScopeFOV
|
||||
Syntax: self:CorrectScopeFOV( fov ). Call only once. Hopefully you call this only once on like SWEP:Initialize() or something.
|
||||
Returns: Nothing.
|
||||
Notes: If you're using scopezoom instead of FOV, this translates it.
|
||||
Purpose: Autodetection
|
||||
]]
|
||||
--
|
||||
function SWEP:CorrectScopeFOV(fov)
|
||||
local self2 = self:GetTable()
|
||||
fov = fov or self:GetStatRawL("DefaultFOV")
|
||||
|
||||
if not self:GetStatRawL("Secondary.OwnerFOV") or self:GetStatRawL("Secondary.OwnerFOV") <= 0 then
|
||||
if self:GetStatRawL("Scoped") then
|
||||
self:SetStatRawL("Secondary.OwnerFOV", fov / (self:GetStatRawL("Secondary.ScopeZoom") and self:GetStatRawL("Secondary.ScopeZoom") or 2))
|
||||
else
|
||||
self:SetStatRawL("Secondary.OwnerFOV", 32)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
Function Name: CreateFireModes
|
||||
Syntax: self:CreateFireModes( is first draw). Call as much as you like. isfirstdraw controls whether the default fire mode is set.
|
||||
Returns: Nothing.
|
||||
Notes: Autodetects fire modes depending on what params you set up.
|
||||
Purpose: Autodetection
|
||||
]]
|
||||
--
|
||||
SWEP.FireModeCache = {}
|
||||
|
||||
function SWEP:CreateFireModes(isfirstdraw)
|
||||
local self2 = self:GetTable()
|
||||
if not self2.FireModes then
|
||||
self:SetStatRawL("FireModes", {})
|
||||
local burstcnt = self:FindEvenBurstNumber()
|
||||
|
||||
if self2.SelectiveFire then
|
||||
if self2.OnlyBurstFire then
|
||||
if burstcnt then
|
||||
self2.FireModes[1] = burstcnt .. "Burst"
|
||||
self2.FireModes[2] = "Single"
|
||||
else
|
||||
self2.FireModes[1] = "Single"
|
||||
end
|
||||
else
|
||||
self2.FireModes[1] = "Automatic"
|
||||
|
||||
if self2.DisableBurstFire then
|
||||
self2.FireModes[2] = "Single"
|
||||
else
|
||||
if burstcnt then
|
||||
self2.FireModes[2] = burstcnt .. "Burst"
|
||||
self2.FireModes[3] = "Single"
|
||||
else
|
||||
self2.FireModes[2] = "Single"
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
if self2.Primary_TFA.Automatic then
|
||||
self2.FireModes[1] = "Automatic"
|
||||
|
||||
if self2.OnlyBurstFire and burstcnt then
|
||||
self2.FireModes[1] = burstcnt .. "Burst"
|
||||
end
|
||||
else
|
||||
self2.FireModes[1] = "Single"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if self2.FireModes[#self2.FireModes] ~= "Safe" then
|
||||
self2.FireModes[#self2.FireModes + 1] = "Safe"
|
||||
end
|
||||
|
||||
if not self2.FireModeCache or #self2.FireModeCache <= 0 then
|
||||
for k, v in ipairs(self2.FireModes) do
|
||||
self2.FireModeCache[v] = k
|
||||
end
|
||||
|
||||
if type(self2.DefaultFireMode) == "number" then
|
||||
self:SetFireMode(self2.DefaultFireMode or (self2.Primary_TFA.Automatic and 1 or #self2.FireModes - 1))
|
||||
else
|
||||
self:SetFireMode(self2.FireModeCache[self2.DefaultFireMode] or (self2.Primary_TFA.Automatic and 1 or #self2.FireModes - 1))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
Function Name: CacheAnimations
|
||||
Syntax: self:CacheAnimations(). Call as much as you like.
|
||||
Returns: Nothing.
|
||||
Notes: This is what autodetects animations for the SWEP.SequenceEnabled and SWEP.SequenceLength tables.
|
||||
Purpose: Autodetection
|
||||
]]
|
||||
--
|
||||
--SWEP.actlist = {ACT_VM_DRAW, ACT_VM_DRAW_EMPTY, ACT_VM_DRAW_SILENCED, ACT_VM_DRAW_DEPLOYED, ACT_VM_HOLSTER, ACT_VM_HOLSTER_EMPTY, ACT_VM_IDLE, ACT_VM_IDLE_EMPTY, ACT_VM_IDLE_SILENCED, ACT_VM_PRIMARYATTACK, ACT_VM_PRIMARYATTACK_1, ACT_VM_PRIMARYATTACK_EMPTY, ACT_VM_PRIMARYATTACK_SILENCED, ACT_VM_SECONDARYATTACK, ACT_VM_RELOAD, ACT_VM_RELOAD_EMPTY, ACT_VM_RELOAD_SILENCED, ACT_VM_ATTACH_SILENCER, ACT_VM_RELEASE, ACT_VM_DETACH_SILENCER, ACT_VM_FIDGET, ACT_VM_FIDGET_EMPTY, ACT_VM_FIDGET_SILENCED, ACT_SHOTGUN_RELOAD_START, ACT_VM_DRYFIRE, ACT_VM_DRYFIRE_SILENCED }
|
||||
--If you really want, you can remove things from SWEP.actlist and manually enable animations and set their lengths.
|
||||
SWEP.SequenceEnabled = {}
|
||||
SWEP.SequenceLength = {}
|
||||
SWEP.SequenceLengthOverride = {} --Override this if you want to change the length of a sequence but not the next idle
|
||||
SWEP.ActCache = {}
|
||||
local vm, seq
|
||||
|
||||
function SWEP:CacheAnimations()
|
||||
local self2 = self:GetTable()
|
||||
table.Empty(self2.ActCache)
|
||||
|
||||
if self:GetStatRawL("CanBeSilenced") and self2.SequenceEnabled[ACT_VM_IDLE_SILENCED] == nil then
|
||||
self2.SequenceEnabled[ACT_VM_IDLE_SILENCED] = true
|
||||
end
|
||||
|
||||
if not self:VMIV() then return end
|
||||
vm = self2.OwnerViewModel
|
||||
|
||||
if IsValid(vm) then
|
||||
self:BuildAnimActivities()
|
||||
|
||||
for _, v in ipairs(table.GetKeys(self2.AnimationActivities)) do
|
||||
if isnumber(v) then
|
||||
seq = vm:SelectWeightedSequence(v)
|
||||
|
||||
if seq ~= -1 and vm:GetSequenceActivity(seq) == v and not self2.ActCache[seq] then
|
||||
self2.SequenceEnabled[v] = true
|
||||
self2.SequenceLength[v] = vm:SequenceDuration(seq)
|
||||
self2.ActCache[seq] = v
|
||||
else
|
||||
self2.SequenceEnabled[v] = false
|
||||
self2.SequenceLength[v] = 0.0
|
||||
end
|
||||
else
|
||||
local s = vm:LookupSequence(v)
|
||||
|
||||
if s and s > 0 then
|
||||
self2.SequenceEnabled[v] = true
|
||||
self2.SequenceLength[v] = vm:SequenceDuration(s)
|
||||
self2.ActCache[s] = v
|
||||
else
|
||||
self2.SequenceEnabled[v] = false
|
||||
self2.SequenceLength[v] = 0.0
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
return false
|
||||
end
|
||||
|
||||
if self:GetStatRawL("ProceduralHolsterEnabled") == nil then
|
||||
if self2.SequenceEnabled[ACT_VM_HOLSTER] then
|
||||
self:SetStatRawL("ProceduralHolsterEnabled", false)
|
||||
else
|
||||
self:SetStatRawL("ProceduralHolsterEnabled", true)
|
||||
end
|
||||
end
|
||||
|
||||
self:SetStatRawL("HasDetectedValidAnimations", true)
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function SWEP:GetType()
|
||||
local self2 = self:GetTable()
|
||||
if self:GetStatRawL("Type") then return self:GetStatRawL("Type") end
|
||||
local at = string.lower(self:GetStatRawL("Primary.Ammo") or "")
|
||||
local ht = string.lower((self:GetStatRawL("DefaultHoldType") or self:GetStatRawL("HoldType")) or "")
|
||||
local rpm = self:GetStatRawL("Primary.RPM_Displayed") or self:GetStatRawL("Primary.RPM") or 600
|
||||
|
||||
if self:GetStatRawL("Primary.ProjectileEntity") or self:GetStatRawL("ProjectileEntity") then
|
||||
if (self:GetStatRawL("ProjectileVelocity") or self:GetStatRawL("Primary.ProjectileVelocity")) > 400 then
|
||||
self:SetStatRawL("Type", "Launcher")
|
||||
else
|
||||
self:SetStatRawL("Type", "Grenade")
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if at == "buckshot" then
|
||||
self:SetStatRawL("Type", "Shotgun")
|
||||
|
||||
return self:GetType()
|
||||
end
|
||||
|
||||
if self:GetStatRawL("Pistol") or (at == "pistol" and ht == "pistol") then
|
||||
self:SetStatRawL("Type", "Pistol")
|
||||
|
||||
return self:GetType()
|
||||
end
|
||||
|
||||
if self:GetStatRawL("SMG") or (at == "smg1" and (ht == "smg" or ht == "pistol" or ht == "357")) then
|
||||
self:SetStatRawL("Type", "Sub-Machine Gun")
|
||||
|
||||
return self:GetType()
|
||||
end
|
||||
|
||||
if self:GetStatRawL("Revolver") or (at == "357" and ht == "revolver") then
|
||||
self:SetStatRawL("Type", "Revolver")
|
||||
|
||||
return self:GetType()
|
||||
end
|
||||
|
||||
--Detect Sniper Type
|
||||
if ( (self:GetStatRawL("Scoped") or self:GetStatRawL("Scoped_3D")) and rpm < 600 ) or at == "sniperpenetratedround" then
|
||||
if rpm > 180 and (self:GetStatRawL("Primary.Automatic") or self:GetStatRawL("Primary.SelectiveFire")) then
|
||||
self:SetStatRawL("Type", "Designated Marksman Rifle")
|
||||
|
||||
return self:GetType()
|
||||
else
|
||||
self:SetStatRawL("Type", "Sniper Rifle")
|
||||
|
||||
return self:GetType()
|
||||
end
|
||||
end
|
||||
|
||||
--Detect based on holdtype
|
||||
if ht == "pistol" then
|
||||
if self:GetStatRawL("Primary.Automatic") then
|
||||
self:SetStatRawL("Type", "Machine Pistol")
|
||||
else
|
||||
self:SetStatRawL("Type", "Pistol")
|
||||
end
|
||||
|
||||
return self:GetType()
|
||||
end
|
||||
|
||||
if ht == "duel" then
|
||||
if at == "pistol" then
|
||||
self:SetStatRawL("Type", "Dual Pistols")
|
||||
|
||||
return self:GetType()
|
||||
elseif at == "357" then
|
||||
self:SetStatRawL("Type", "Dual Revolvers")
|
||||
|
||||
return self:GetType()
|
||||
elseif at == "smg1" then
|
||||
self:SetStatRawL("Type", "Dual Sub-Machine Guns")
|
||||
|
||||
return self:GetType()
|
||||
else
|
||||
self:SetStatRawL("Type", "Dual Guns")
|
||||
|
||||
return self:GetType()
|
||||
end
|
||||
end
|
||||
|
||||
--If it's using rifle ammo, it's a rifle or a carbine
|
||||
if at == "ar2" then
|
||||
if self:GetStatRawL("Primary.ClipSize") >= 60 then
|
||||
self:SetStatRawL("Type", "Light Machine Gun")
|
||||
|
||||
return self:GetType()
|
||||
elseif ht == "rpg" or ht == "revolver" then
|
||||
self:SetStatRawL("Type", "Carbine")
|
||||
|
||||
return self:GetType()
|
||||
else
|
||||
self:SetStatRawL("Type", "Rifle")
|
||||
|
||||
return self:GetType()
|
||||
end
|
||||
end
|
||||
|
||||
--Check SMG one last time
|
||||
if ht == "smg" or at == "smg1" then
|
||||
self:SetStatRawL("Type", "Sub-Machine Gun")
|
||||
|
||||
return self:GetType()
|
||||
end
|
||||
|
||||
--Fallback to generic
|
||||
self:SetStatRawL("Type", "Weapon")
|
||||
|
||||
return self:GetType()
|
||||
end
|
||||
|
||||
function SWEP:SetUpSpreadLegacy()
|
||||
local self2 = self:GetTable()
|
||||
local ht = self:GetStatRawL("DefaultHoldType") and self:GetStatRawL("DefaultHoldType") or self:GetStatRawL("HoldType")
|
||||
|
||||
if not self:GetStatRawL("Primary.SpreadMultiplierMax") or self:GetStatRawL("Primary.SpreadMultiplierMax") <= 0 or self:GetStatRawL("AutoDetectSpreadMultiplierMax") then
|
||||
self:SetStatRawL("Primary.SpreadMultiplierMax", 2.5 * math.max(self:GetStatRawL("Primary.RPM"), 400) / 600 * math.sqrt(self:GetStatRawL("Primary.Damage") / 30 * self:GetStatRawL("Primary.NumShots"))) --How far the spread can expand when you shoot.
|
||||
|
||||
if ht == "smg" then
|
||||
self:SetStatRawL("Primary.SpreadMultiplierMax", self:GetStatRawL("Primary.SpreadMultiplierMax") * 0.8)
|
||||
end
|
||||
|
||||
if ht == "revolver" then
|
||||
self:SetStatRawL("Primary.SpreadMultiplierMax", self:GetStatRawL("Primary.SpreadMultiplierMax") * 2)
|
||||
end
|
||||
|
||||
if self:GetStatRawL("Scoped") then
|
||||
self:SetStatRawL("Primary.SpreadMultiplierMax", self:GetStatRawL("Primary.SpreadMultiplierMax") * 1.5)
|
||||
end
|
||||
|
||||
self:SetStatRawL("AutoDetectSpreadMultiplierMax", true)
|
||||
end
|
||||
|
||||
if not self:GetStatRawL("Primary.SpreadIncrement") or self:GetStatRawL("Primary.SpreadIncrement") <= 0 or self:GetStatRawL("AutoDetectSpreadIncrement") then
|
||||
self:SetStatRawL("AutoDetectSpreadIncrement", true)
|
||||
self:SetStatRawL("Primary.SpreadIncrement", 1 * math.Clamp(math.sqrt(self:GetStatRawL("Primary.RPM")) / 24.5, 0.7, 3) * math.sqrt(self:GetStatRawL("Primary.Damage") / 30 * self:GetStatRawL("Primary.NumShots"))) --What percentage of the modifier is added on, per shot.
|
||||
|
||||
if ht == "revolver" then
|
||||
self:SetStatRawL("Primary.SpreadIncrement", self:GetStatRawL("Primary.SpreadIncrement") * 2)
|
||||
end
|
||||
|
||||
if ht == "pistol" then
|
||||
self:SetStatRawL("Primary.SpreadIncrement", self:GetStatRawL("Primary.SpreadIncrement") * 1.35)
|
||||
end
|
||||
|
||||
if ht == "ar2" or ht == "rpg" then
|
||||
self:SetStatRawL("Primary.SpreadIncrement", self:GetStatRawL("Primary.SpreadIncrement") * 0.65)
|
||||
end
|
||||
|
||||
if ht == "smg" then
|
||||
self:SetStatRawL("Primary.SpreadIncrement", self:GetStatRawL("Primary.SpreadIncrement") * 1.75)
|
||||
self:SetStatRawL("Primary.SpreadIncrement", self:GetStatRawL("Primary.SpreadIncrement") * (math.Clamp((self:GetStatRawL("Primary.RPM") - 650) / 150, 0, 1) + 1))
|
||||
end
|
||||
|
||||
if ht == "pistol" and self:GetStatRawL("Primary.Automatic") == true then
|
||||
self:SetStatRawL("Primary.SpreadIncrement", self:GetStatRawL("Primary.SpreadIncrement") * 1.5)
|
||||
end
|
||||
|
||||
if self:GetStatRawL("Scoped") then
|
||||
self:SetStatRawL("Primary.SpreadIncrement", self:GetStatRawL("Primary.SpreadIncrement") * 1.25)
|
||||
end
|
||||
|
||||
self:SetStatRawL("Primary.SpreadIncrement", self:GetStatRawL("Primary.SpreadIncrement") * math.sqrt(self:GetStatRawL("Primary.Recoil") * (self:GetStatRawL("Primary.KickUp") + self:GetStatRawL("Primary.KickDown") + self:GetStatRawL("Primary.KickHorizontal"))) * 0.8)
|
||||
end
|
||||
|
||||
if not self:GetStatRawL("Primary.SpreadRecovery") or self:GetStatRawL("Primary.SpreadRecovery") <= 0 or self:GetStatRawL("AutoDetectSpreadRecovery") then
|
||||
self:SetStatRawL("AutoDetectSpreadRecovery", true)
|
||||
self:SetStatRawL("Primary.SpreadRecovery", math.sqrt(math.max(self:GetStatRawL("Primary.RPM"), 300)) / 29 * 4) --How much the spread recovers, per second.
|
||||
|
||||
if ht == "smg" then
|
||||
self:SetStatRawL("Primary.SpreadRecovery", self:GetStatRawL("Primary.SpreadRecovery") * (1 - math.Clamp((self:GetStatRawL("Primary.RPM") - 600) / 200, 0, 1) * 0.33))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
SWEP.LowAmmoSoundTypeBlacklist = {
|
||||
["launcher"] = true,
|
||||
["grenade"] = true,
|
||||
}
|
||||
|
||||
SWEP.LowAmmoSoundByType = {
|
||||
["handgun"] = "TFA.LowAmmo.Handgun",
|
||||
["pistol"] = "TFA.LowAmmo.Handgun",
|
||||
["dualpistols"] = "TFA.LowAmmo.Handgun",
|
||||
["machinepistol"] = "TFA.LowAmmo.Handgun",
|
||||
["handcannon"] = "TFA.LowAmmo.Revolver",
|
||||
["revolver"] = "TFA.LowAmmo.Revolver",
|
||||
["dualrevolvers"] = "TFA.LowAmmo.Revolver",
|
||||
["shotgun"] = "TFA.LowAmmo.Shotgun",
|
||||
["machinegun"] = "TFA.LowAmmo.MachineGun",
|
||||
["lightmachinegun"] = "TFA.LowAmmo.MachineGun",
|
||||
["heavymachinegun"] = "TFA.LowAmmo.MachineGun",
|
||||
["carbine"] = "TFA.LowAmmo.AssaultRifle",
|
||||
["rifle"] = "TFA.LowAmmo.AssaultRifle",
|
||||
["assaultrifle"] = "TFA.LowAmmo.AssaultRifle",
|
||||
["dmr"] = "TFA.LowAmmo.DMR",
|
||||
["designatedmarksmanrifle"] = "TFA.LowAmmo.DMR",
|
||||
["sniperrifle"] = "TFA.LowAmmo.Sniper",
|
||||
["smg"] = "TFA.LowAmmo.SMG",
|
||||
["submachinegun"] = "TFA.LowAmmo.SMG",
|
||||
}
|
||||
SWEP.LastAmmoSoundByType = {
|
||||
["handgun"] = "TFA.LowAmmo.Handgun_Dry",
|
||||
["pistol"] = "TFA.LowAmmo.Handgun_Dry",
|
||||
["dualpistols"] = "TFA.LowAmmo.Handgun_Dry",
|
||||
["machinepistol"] = "TFA.LowAmmo.Handgun_Dry",
|
||||
["handcannon"] = "TFA.LowAmmo.Revolver_Dry",
|
||||
["revolver"] = "TFA.LowAmmo.Revolver_Dry",
|
||||
["dualrevolvers"] = "TFA.LowAmmo.Revolver_Dry",
|
||||
["shotgun"] = "TFA.LowAmmo.Shotgun_Dry",
|
||||
["machinegun"] = "TFA.LowAmmo.MachineGun_Dry",
|
||||
["lightmachinegun"] = "TFA.LowAmmo.MachineGun_Dry",
|
||||
["heavymachinegun"] = "TFA.LowAmmo.MachineGun_Dry",
|
||||
["carbine"] = "TFA.LowAmmo.AssaultRifle_Dry",
|
||||
["rifle"] = "TFA.LowAmmo.AssaultRifle_Dry",
|
||||
["assaultrifle"] = "TFA.LowAmmo.AssaultRifle_Dry",
|
||||
["dmr"] = "TFA.LowAmmo.DMR_Dry",
|
||||
["designatedmarksmanrifle"] = "TFA.LowAmmo.DMR_Dry",
|
||||
["sniperrifle"] = "TFA.LowAmmo.Sniper_Dry",
|
||||
["smg"] = "TFA.LowAmmo.SMG_Dry",
|
||||
["submachinegun"] = "TFA.LowAmmo.SMG_Dry",
|
||||
}
|
||||
|
||||
function SWEP:AutoDetectLowAmmoSound()
|
||||
if not self.FireSoundAffectedByClipSize then return end
|
||||
|
||||
local t1, t2 = self:GetType():lower():gsub("[^%w]+", ""), (self:GetStatRawL("Type_Displayed") or ""):lower():gsub("[^%w]+", "")
|
||||
|
||||
if self.LowAmmoSoundTypeBlacklist[t2] or self.LowAmmoSoundTypeBlacklist[t1] then return end
|
||||
|
||||
local clip1 = self:GetStatRawL("Primary.ClipSize")
|
||||
if (not clip1 or clip1 <= 4) then return end
|
||||
|
||||
if not self.LowAmmoSound then
|
||||
local snd = self.LowAmmoSoundByType[t2] or self.LowAmmoSoundByType[t1] or "TFA.LowAmmo"
|
||||
|
||||
if (t2 == "shotgun" or t1 == "shotgun") and not self:GetStatL("LoopedReload") then
|
||||
snd = "TFA.LowAmmo.AutoShotgun"
|
||||
end
|
||||
|
||||
self:SetStatRawL("LowAmmoSound", snd)
|
||||
end
|
||||
|
||||
if not self.LastAmmoSound then
|
||||
local snd = self.LastAmmoSoundByType[t2] or self.LastAmmoSoundByType[t1] or "TFA.LowAmmo_Dry"
|
||||
|
||||
if (t2 == "shotgun" or t1 == "shotgun") and not self:GetStatL("LoopedReload") then
|
||||
snd = "TFA.LowAmmo.AutoShotgun_Dry"
|
||||
end
|
||||
|
||||
self:SetStatRawL("LastAmmoSound", snd)
|
||||
end
|
||||
end
|
||||
1151
lua/weapons/tfa_gun_base/common/bullet.lua
Normal file
1151
lua/weapons/tfa_gun_base/common/bullet.lua
Normal file
File diff suppressed because it is too large
Load Diff
313
lua/weapons/tfa_gun_base/common/calc.lua
Normal file
313
lua/weapons/tfa_gun_base/common/calc.lua
Normal file
@@ -0,0 +1,313 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
-- Copyright (c) 2018-2020 TFA Base Devs
|
||||
|
||||
-- Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
-- of this software and associated documentation files (the "Software"), to deal
|
||||
-- in the Software without restriction, including without limitation the rights
|
||||
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
-- copies of the Software, and to permit persons to whom the Software is
|
||||
-- furnished to do so, subject to the following conditions:
|
||||
|
||||
-- The above copyright notice and this permission notice shall be included in all
|
||||
-- copies or substantial portions of the Software.
|
||||
|
||||
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
-- SOFTWARE.
|
||||
|
||||
TFA.GUESS_NPC_WALKSPEED = 160
|
||||
|
||||
local function l_Lerp(t, a, b) return a + (b - a) * t end
|
||||
local function l_mathMin(a, b) return (a < b) and a or b end
|
||||
local function l_mathMax(a, b) return (a > b) and a or b end
|
||||
local function l_ABS(a) return (a < 0) and -a or a end
|
||||
local function l_mathClamp(t, a, b)
|
||||
if a > b then return b end
|
||||
|
||||
if t > b then
|
||||
return b
|
||||
end
|
||||
|
||||
if t < a then
|
||||
return a
|
||||
end
|
||||
|
||||
return t
|
||||
end
|
||||
|
||||
local function l_mathApproach(a, b, delta)
|
||||
if a < b then
|
||||
return l_mathMin(a + l_ABS(delta), b)
|
||||
else
|
||||
return l_mathMax(a - l_ABS(delta), b)
|
||||
end
|
||||
end
|
||||
|
||||
local sprint_cv = GetConVar("sv_tfa_sprint_enabled")
|
||||
local sv_tfa_weapon_weight = GetConVar("sv_tfa_weapon_weight")
|
||||
|
||||
function SWEP:TFAFinishMove(ply, velocity, movedata)
|
||||
local ft = FrameTime()
|
||||
local self2 = self:GetTable()
|
||||
local isply = ply:IsPlayer()
|
||||
|
||||
if CLIENT then
|
||||
self2.LastUnpredictedVelocity = velocity
|
||||
end
|
||||
|
||||
local speedmult = Lerp(self:GetIronSightsProgress(), sv_tfa_weapon_weight:GetBool() and self:GetStatL("RegularMoveSpeedMultiplier") or 1, self:GetStatL("AimingDownSightsSpeedMultiplier"))
|
||||
|
||||
local jr_targ = math.min(math.abs(velocity.z) / 500, 1)
|
||||
self:SetJumpRatio(l_mathApproach(self:GetJumpRatio(), jr_targ, (jr_targ - self:GetJumpRatio()) * ft * 20))
|
||||
self2.JumpRatio = self:GetJumpRatio()
|
||||
self:SetCrouchingRatio(l_mathApproach(self:GetCrouchingRatio(), (self:IsOwnerCrouching()) and 1 or 0, ft / self2.ToCrouchTime))
|
||||
self2.CrouchingRatio = self:GetCrouchingRatio()
|
||||
|
||||
local status = self2.GetStatus(self)
|
||||
local oldsprinting, oldwalking = self:GetSprinting(), self:GetWalking()
|
||||
local vellen = velocity:Length2D()
|
||||
|
||||
--if TFA.Enum.ReloadStatus[status] then
|
||||
-- self:SetSprinting(false)
|
||||
--elseif sprint_cv:GetBool() and not self:GetStatL("AllowSprintAttack", false) and movedata then
|
||||
if sprint_cv:GetBool() and not self:GetStatL("AllowSprintAttack", false) and movedata then
|
||||
self:SetSprinting(vellen > ply:GetRunSpeed() * 0.6 * speedmult and movedata:KeyDown(IN_SPEED) and ply:OnGround())
|
||||
else
|
||||
self:SetSprinting(false)
|
||||
end
|
||||
|
||||
self:SetWalking(vellen > ((isply and ply:GetWalkSpeed() or TFA.GUESS_NPC_WALKSPEED) * (sv_tfa_weapon_weight:GetBool() and self:GetStatL("RegularMoveSpeedMultiplier", 1) or 1) * .75) and ply:GetNW2Bool("TFA_IsWalking") and ply:OnGround() and not self:GetSprinting() and not self:GetCustomizing())
|
||||
|
||||
self2.walking_updated = oldwalking ~= self:GetWalking()
|
||||
self2.sprinting_updated = oldsprinting ~= self:GetSprinting()
|
||||
|
||||
if self:GetCustomizing() and (self2.GetIronSights(self) or self:GetSprinting() or not TFA.Enum.ReadyStatus[status]) then
|
||||
self:ToggleCustomize()
|
||||
end
|
||||
|
||||
local spr = self:GetSprinting()
|
||||
local walk = self:GetWalking()
|
||||
|
||||
local sprt = spr and 1 or 0
|
||||
local walkt = walk and 1 or 0
|
||||
local adstransitionspeed = (spr or walk) and 7.5 or 12.5
|
||||
|
||||
self:SetSprintProgress(l_mathApproach(self:GetSprintProgress(), sprt, (sprt - self:GetSprintProgress()) * ft * adstransitionspeed))
|
||||
self:SetWalkProgress(l_mathApproach(self:GetWalkProgress(), walkt, (walkt - self:GetWalkProgress()) * ft * adstransitionspeed))
|
||||
|
||||
self:SetLastVelocity(vellen)
|
||||
end
|
||||
|
||||
local sp = game.SinglePlayer()
|
||||
local sv_tfa_recoil_legacy = GetConVar("sv_tfa_recoil_legacy")
|
||||
|
||||
function SWEP:CalculateRatios()
|
||||
local owent = self:GetOwner()
|
||||
--if not IsValid(owent) or not owent:IsPlayer() then return end
|
||||
if not IsValid(owent) then return end
|
||||
|
||||
local self2 = self:GetTable()
|
||||
|
||||
if self2.ratios_calc == nil then
|
||||
self2.ratios_calc = true
|
||||
end
|
||||
|
||||
local ft = FrameTime()
|
||||
local time = CurTime()
|
||||
|
||||
if ft <= 0 then return end
|
||||
|
||||
local is = self2.GetIronSights(self)
|
||||
local spr = self2.GetSprinting(self)
|
||||
local walk = self2.GetWalking(self)
|
||||
|
||||
local ist = is and 1 or 0
|
||||
local sprt = spr and 1 or 0
|
||||
local adstransitionspeed
|
||||
|
||||
if is then
|
||||
adstransitionspeed = 12.5 / (self:GetStatL("IronSightTime") / 0.3)
|
||||
elseif spr or walk then
|
||||
adstransitionspeed = 7.5
|
||||
else
|
||||
adstransitionspeed = 12.5
|
||||
end
|
||||
|
||||
if not owent:IsPlayer() then
|
||||
self:TFAFinishMove(owent, owent:GetVelocity())
|
||||
end
|
||||
|
||||
local lastrecoiltime = self2.GetLastRecoil(self, -1)
|
||||
|
||||
if lastrecoiltime < 0 or time >= (lastrecoiltime + self2.GetStatL(self, "Primary.SpreadRecoveryDelay")) then
|
||||
self:SetSpreadRatio(l_mathClamp(self:GetSpreadRatio() - self2.GetStatL(self, "Primary.SpreadRecovery") * ft, 1, self2.GetStatL(self, "Primary.SpreadMultiplierMax")))
|
||||
end
|
||||
|
||||
self:SetIronSightsProgress(l_mathApproach(self:GetIronSightsProgress(), ist, (ist - self:GetIronSightsProgress()) * ft * adstransitionspeed))
|
||||
self:SetProceduralHolsterProgress(l_mathApproach(self:GetProceduralHolsterProgress(), sprt, (sprt - self:GetSprintProgress()) * ft * self2.ProceduralHolsterTime * 15))
|
||||
self:SetInspectingProgress(l_mathApproach(self:GetInspectingProgress(), self:GetCustomizing() and 1 or 0, ((self:GetCustomizing() and 1 or 0) - self:GetInspectingProgress()) * ft * 10))
|
||||
|
||||
if self:GetRecoilThink() then
|
||||
if self:GetRecoilLoop() then
|
||||
-- loop or after loop
|
||||
|
||||
if self:GetRecoilLoopWait() < time then
|
||||
self:SetRecoilOutProgress(l_mathMin(1, self:GetRecoilOutProgress() + ft / self2.Primary_TFA.RecoilLUT["out"].cooldown_speed))
|
||||
|
||||
if self:GetRecoilOutProgress() == 1 then
|
||||
self:SetRecoilThink(false)
|
||||
self:SetRecoilLoop(false)
|
||||
self:SetRecoilLoopProgress(0)
|
||||
self:SetRecoilInProgress(0)
|
||||
self:SetRecoilOutProgress(0)
|
||||
end
|
||||
end
|
||||
else
|
||||
-- IN only
|
||||
|
||||
if self:GetRecoilInWait() < time then
|
||||
self:SetRecoilInProgress(l_mathMax(0, self:GetRecoilInProgress() - ft / self2.Primary_TFA.RecoilLUT["in"].cooldown_speed))
|
||||
|
||||
if self:GetRecoilInProgress() == 0 then
|
||||
self:SetRecoilThink(false)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if not sv_tfa_recoil_legacy:GetBool() then
|
||||
ft = l_mathClamp(ft, 0, 1)
|
||||
self:SetViewPunchBuild(l_mathMax(0, self:GetViewPunchBuild() - self:GetViewPunchBuild() * ft))
|
||||
local build = l_mathMax(0, 4.5 - self:GetViewPunchBuild())
|
||||
ft = ft * build * build
|
||||
self:SetViewPunchP(self:GetViewPunchP() - self:GetViewPunchP() * ft)
|
||||
self:SetViewPunchY(self:GetViewPunchY() - self:GetViewPunchY() * ft)
|
||||
end
|
||||
|
||||
self2.SpreadRatio = self:GetSpreadRatio()
|
||||
self2.IronSightsProgress = self:GetIronSightsProgress()
|
||||
self2.SprintProgress = self:GetSprintProgress()
|
||||
self2.WalkProgress = self:GetWalkProgress()
|
||||
self2.ProceduralHolsterProgress = self:GetProceduralHolsterProgress()
|
||||
self2.InspectingProgress = self:GetInspectingProgress()
|
||||
|
||||
if sp and CLIENT then
|
||||
self2.Inspecting = self:GetCustomizing() --compatibility
|
||||
end
|
||||
|
||||
self2.CLIronSightsProgress = self:GetIronSightsProgress() --compatibility
|
||||
end
|
||||
|
||||
SWEP.Primary.IronRecoilMultiplier = 0.5 --Multiply recoil by this factor when we're in ironsights. This is proportional, not inversely.
|
||||
SWEP.CrouchRecoilMultiplier = 0.65 --Multiply recoil by this factor when we're crouching. This is proportional, not inversely.
|
||||
SWEP.JumpRecoilMultiplier = 1.3 --Multiply recoil by this factor when we're crouching. This is proportional, not inversely.
|
||||
SWEP.WallRecoilMultiplier = 1.1 --Multiply recoil by this factor when we're changing state e.g. not completely ironsighted. This is proportional, not inversely.
|
||||
SWEP.ChangeStateRecoilMultiplier = 1.3 --Multiply recoil by this factor when we're crouching. This is proportional, not inversely.
|
||||
SWEP.CrouchAccuracyMultiplier = 0.5 --Less is more. Accuracy * 0.5 = Twice as accurate, Accuracy * 0.1 = Ten times as accurate
|
||||
SWEP.ChangeStateAccuracyMultiplier = 1.5 --Less is more. A change of state is when we're in the progress of doing something, like crouching or ironsighting. Accuracy * 2 = Half as accurate. Accuracy * 5 = 1/5 as accurate
|
||||
SWEP.JumpAccuracyMultiplier = 2 --Less is more. Accuracy * 2 = Half as accurate. Accuracy * 5 = 1/5 as accurate
|
||||
SWEP.WalkAccuracyMultiplier = 1.35 --Less is more. Accuracy * 2 = Half as accurate. Accuracy * 5 = 1/5 as accurate
|
||||
SWEP.ToCrouchTime = 0.25
|
||||
|
||||
local mult_cvar = GetConVar("sv_tfa_spread_multiplier")
|
||||
local dynacc_cvar = GetConVar("sv_tfa_dynamicaccuracy")
|
||||
local ccon, crec
|
||||
|
||||
SWEP.JumpRatio = 0
|
||||
|
||||
function SWEP:CalculateConeRecoil()
|
||||
local dynacc = false
|
||||
local self2 = self:GetTable()
|
||||
local isr = self:GetIronSightsProgress()
|
||||
|
||||
if dynacc_cvar:GetBool() and (self2.GetStatL(self, "Primary.NumShots") <= 1) then
|
||||
dynacc = true
|
||||
end
|
||||
|
||||
local isr_1 = l_mathClamp(isr * 2, 0, 1)
|
||||
local isr_2 = l_mathClamp((isr - 0.5) * 2, 0, 1)
|
||||
local acv = self2.GetStatL(self, "Primary.Spread") or self2.GetStatL(self, "Primary.Accuracy")
|
||||
local recv = self2.GetStatL(self, "Primary.Recoil") * 5
|
||||
|
||||
if dynacc then
|
||||
ccon = l_Lerp(isr_2, l_Lerp(isr_1, acv, acv * self2.GetStatL(self, "ChangeStateAccuracyMultiplier")), self2.GetStatL(self, "Primary.IronAccuracy"))
|
||||
crec = l_Lerp(isr_2, l_Lerp(isr_1, recv, recv * self2.GetStatL(self, "ChangeStateRecoilMultiplier")), recv * self2.GetStatL(self, "Primary.IronRecoilMultiplier"))
|
||||
else
|
||||
ccon = l_Lerp(isr, acv, self2.GetStatL(self, "Primary.IronAccuracy"))
|
||||
crec = l_Lerp(isr, recv, recv * self2.GetStatL(self, "Primary.IronRecoilMultiplier"))
|
||||
end
|
||||
|
||||
local crc_1 = l_mathClamp(self:GetCrouchingRatio() * 2, 0, 1)
|
||||
local crc_2 = l_mathClamp((self:GetCrouchingRatio() - 0.5) * 2, 0, 1)
|
||||
|
||||
if dynacc then
|
||||
ccon = l_Lerp(crc_2, l_Lerp(crc_1, ccon, ccon * self2.GetStatL(self, "ChangeStateAccuracyMultiplier")), ccon * self2.GetStatL(self, "CrouchAccuracyMultiplier"))
|
||||
crec = l_Lerp(crc_2, l_Lerp(crc_1, crec, self2.GetStatL(self, "Primary.Recoil") * self2.GetStatL(self, "ChangeStateRecoilMultiplier")), crec * self2.GetStatL(self, "CrouchRecoilMultiplier"))
|
||||
end
|
||||
|
||||
local owner = self:GetOwner()
|
||||
local isply = owner:IsPlayer()
|
||||
local ovel
|
||||
|
||||
if IsValid(owner) then
|
||||
if owner:IsPlayer() then
|
||||
ovel = self:GetLastVelocity()
|
||||
else
|
||||
ovel = owner:GetVelocity():Length2D()
|
||||
end
|
||||
else
|
||||
ovel = 0
|
||||
end
|
||||
|
||||
local vfc_1 = l_mathClamp(ovel / (isply and owner:GetWalkSpeed() or TFA.GUESS_NPC_WALKSPEED), 0, 2)
|
||||
|
||||
if dynacc then
|
||||
ccon = l_Lerp(vfc_1, ccon, ccon * self2.GetStatL(self, "WalkAccuracyMultiplier"))
|
||||
crec = l_Lerp(vfc_1, crec, crec * self2.GetStatL(self, "WallRecoilMultiplier"))
|
||||
end
|
||||
|
||||
local jr = self:GetJumpRatio()
|
||||
|
||||
if dynacc then
|
||||
ccon = l_Lerp(jr, ccon, ccon * self2.GetStatL(self, "JumpAccuracyMultiplier"))
|
||||
crec = l_Lerp(jr, crec, crec * self2.GetStatL(self, "JumpRecoilMultiplier"))
|
||||
end
|
||||
|
||||
ccon = ccon * self:GetSpreadRatio()
|
||||
|
||||
if mult_cvar then
|
||||
ccon = ccon * mult_cvar:GetFloat()
|
||||
end
|
||||
|
||||
if not isply and IsValid(owner) then
|
||||
local prof = owner:GetCurrentWeaponProficiency()
|
||||
|
||||
if prof == WEAPON_PROFICIENCY_POOR then
|
||||
ccon = ccon * 8
|
||||
elseif prof == WEAPON_PROFICIENCY_AVERAGE then
|
||||
ccon = ccon * 5
|
||||
elseif prof == WEAPON_PROFICIENCY_GOOD then
|
||||
ccon = ccon * 3
|
||||
elseif prof == WEAPON_PROFICIENCY_VERY_GOOD then
|
||||
ccon = ccon * 2
|
||||
elseif prof == WEAPON_PROFICIENCY_PERFECT then
|
||||
ccon = ccon * 1.5
|
||||
end
|
||||
end
|
||||
|
||||
return ccon, crec
|
||||
end
|
||||
383
lua/weapons/tfa_gun_base/common/effects.lua
Normal file
383
lua/weapons/tfa_gun_base/common/effects.lua
Normal file
@@ -0,0 +1,383 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
-- Copyright (c) 2018-2020 TFA Base Devs
|
||||
|
||||
-- Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
-- of this software and associated documentation files (the "Software"), to deal
|
||||
-- in the Software without restriction, including without limitation the rights
|
||||
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
-- copies of the Software, and to permit persons to whom the Software is
|
||||
-- furnished to do so, subject to the following conditions:
|
||||
|
||||
-- The above copyright notice and this permission notice shall be included in all
|
||||
-- copies or substantial portions of the Software.
|
||||
|
||||
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
-- SOFTWARE.
|
||||
|
||||
local fx, sp = nil, game.SinglePlayer()
|
||||
local shelltype
|
||||
|
||||
function SWEP:PCFTracer(bul, hitpos, ovrride)
|
||||
if bul.PCFTracer then
|
||||
self:UpdateMuzzleAttachment()
|
||||
local mzp = self:GetMuzzlePos()
|
||||
if bul.PenetrationCount > 0 and not ovrride then return end --Taken care of with the pen effect
|
||||
|
||||
if (CLIENT or game.SinglePlayer()) and self.Scoped and self:IsCurrentlyScoped() and self:IsFirstPerson() then
|
||||
TFA.ParticleTracer(bul.PCFTracer, self:GetOwner():GetShootPos() - self:GetOwner():EyeAngles():Up() * 5, hitpos, false, 0, -1)
|
||||
else
|
||||
local vent = self
|
||||
|
||||
if (CLIENT or game.SinglePlayer()) and self:IsFirstPerson() then
|
||||
vent = self.OwnerViewModel
|
||||
end
|
||||
|
||||
if sp and not self:IsFirstPerson() then
|
||||
TFA.ParticleTracer(bul.PCFTracer, self:GetOwner():GetShootPos() + self:GetOwner():GetAimVector() * 32, hitpos, false)
|
||||
else
|
||||
TFA.ParticleTracer(bul.PCFTracer, mzp.Pos, hitpos, false, vent, self.MuzzleAttachmentRaw or 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:EventShell()
|
||||
if SERVER and self.processing_events and sp then return end
|
||||
|
||||
if SERVER then
|
||||
net.Start("tfaBaseShellSV", true)
|
||||
net.WriteEntity(self)
|
||||
|
||||
if self:GetOwner():IsPlayer() then
|
||||
if sp then
|
||||
net.Broadcast()
|
||||
else
|
||||
net.SendOmit(self:GetOwner())
|
||||
end
|
||||
else
|
||||
net.SendPVS(self:GetPos())
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
self:MakeShellBridge()
|
||||
end
|
||||
|
||||
function SWEP:MakeShellBridge(ifp)
|
||||
if ifp == false then return end
|
||||
|
||||
if self.LuaShellEjectDelay > 0 then
|
||||
self.LuaShellRequestTime = CurTime() + self.LuaShellEjectDelay / self:GetAnimationRate(ACT_VM_PRIMARYATTACK)
|
||||
else
|
||||
self:MakeShell()
|
||||
end
|
||||
end
|
||||
|
||||
SWEP.ShellEffectOverride = nil -- ???
|
||||
SWEP.ShellEjectionQueue = 0
|
||||
|
||||
function SWEP:GetShellAttachmentID(ent, isVM)
|
||||
local raw = self:GetStatL("ShellAttachmentRaw")
|
||||
local israw = false
|
||||
local attid
|
||||
|
||||
if raw and ent:GetAttachment(raw) then
|
||||
attid = raw
|
||||
israw = true
|
||||
else
|
||||
attid = ent:LookupAttachment(self:GetStatL("ShellAttachment"))
|
||||
end
|
||||
|
||||
if self:GetStatL("IsAkimbo") and not israw then
|
||||
return 3 + self:GetAnimCycle()
|
||||
end
|
||||
|
||||
if attid and attid <= 0 then attid = 2 end
|
||||
|
||||
attid = math.Clamp(attid and attid or 2, 1, 127)
|
||||
|
||||
return attid
|
||||
end
|
||||
|
||||
function SWEP:GetShellEjectPosition(ent, isVM)
|
||||
local attid = self:GetShellAttachmentID(ent, isVM)
|
||||
|
||||
local angpos = ent:GetAttachment(attid)
|
||||
|
||||
if angpos then
|
||||
return angpos.Pos, angpos.Ang, attid
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:MakeShell(eject_now)
|
||||
if not self:IsValid() then return end -- what
|
||||
if self.current_event_iftp == false then return end
|
||||
|
||||
local retVal = hook.Run("TFA_MakeShell", self)
|
||||
|
||||
if retVal ~= nil then
|
||||
return retVal
|
||||
end
|
||||
|
||||
if self:GetStatL("ShellEffectOverride") then
|
||||
shelltype = self:GetStatL("ShellEffectOverride")
|
||||
elseif TFA.GetLegacyShellsEnabled() then
|
||||
shelltype = "tfa_shell_legacy"
|
||||
else
|
||||
shelltype = "tfa_shell"
|
||||
end
|
||||
|
||||
local ent = self
|
||||
local isVM = false
|
||||
|
||||
if self:IsFirstPerson() then
|
||||
if not eject_now and CLIENT then
|
||||
self.ShellEjectionQueue = self.ShellEjectionQueue + 1
|
||||
return
|
||||
end
|
||||
|
||||
ent = self.OwnerViewModel or self
|
||||
isVM = ent == self.OwnerViewModel
|
||||
end
|
||||
|
||||
self:EjectionSmoke(true)
|
||||
|
||||
if not isstring(shelltype) or shelltype == "" then return end -- allows to disable shells by setting override to "" - will shut up all rp fags
|
||||
|
||||
if not IsValid(ent) then return end
|
||||
local pos, ang, attid = self:GetShellEjectPosition(ent, isVM)
|
||||
|
||||
if not pos then return end
|
||||
|
||||
fx = EffectData()
|
||||
fx:SetEntity(self)
|
||||
fx:SetAttachment(attid)
|
||||
fx:SetMagnitude(1)
|
||||
fx:SetScale(1)
|
||||
fx:SetOrigin(pos)
|
||||
fx:SetNormal(ang:Forward())
|
||||
TFA.Effects.Create(shelltype, fx)
|
||||
end
|
||||
|
||||
--[[
|
||||
Function Name: CleanParticles
|
||||
Syntax: self:CleanParticles().
|
||||
Returns: Nothing.
|
||||
Notes: Cleans up particles.
|
||||
Purpose: FX
|
||||
]]
|
||||
--
|
||||
function SWEP:CleanParticles()
|
||||
if not IsValid(self) then return end
|
||||
|
||||
if self.StopParticles then
|
||||
self:StopParticles()
|
||||
end
|
||||
|
||||
if self.StopParticleEmission then
|
||||
self:StopParticleEmission()
|
||||
end
|
||||
|
||||
if not self:VMIV() then return end
|
||||
local vm = self.OwnerViewModel
|
||||
|
||||
if IsValid(vm) then
|
||||
if vm.StopParticles then
|
||||
vm:StopParticles()
|
||||
end
|
||||
|
||||
if vm.StopParticleEmission then
|
||||
vm:StopParticleEmission()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
Function Name: EjectionSmoke
|
||||
Syntax: self:EjectionSmoke().
|
||||
Returns: Nothing.
|
||||
Notes: Puff of smoke on shell attachment.
|
||||
Purpose: FX
|
||||
]]
|
||||
--
|
||||
function SWEP:EjectionSmoke(ovrr)
|
||||
local retVal = hook.Run("TFA_EjectionSmoke",self)
|
||||
if retVal ~= nil then
|
||||
return retVal
|
||||
end
|
||||
if TFA.GetEJSmokeEnabled() and (self:GetStatL("EjectionSmokeEnabled") or ovrr) then
|
||||
local vm = self:IsFirstPerson() and self.OwnerViewModel or self
|
||||
|
||||
if IsValid(vm) then
|
||||
local att = vm:LookupAttachment(self:GetStatL("ShellAttachment"))
|
||||
|
||||
if not att or att <= 0 then
|
||||
att = 2
|
||||
end
|
||||
|
||||
local oldatt = att
|
||||
att = self:GetStatL("ShellAttachmentRaw", att)
|
||||
local angpos = vm:GetAttachment(att)
|
||||
|
||||
if not angpos then
|
||||
att = oldatt
|
||||
angpos = vm:GetAttachment(att)
|
||||
end
|
||||
|
||||
if angpos then
|
||||
fx = EffectData()
|
||||
fx:SetEntity(self)
|
||||
fx:SetOrigin(angpos.Pos)
|
||||
fx:SetAttachment(att)
|
||||
fx:SetNormal(angpos.Ang:Forward())
|
||||
TFA.Effects.Create("tfa_shelleject_smoke", fx)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
Function Name: ShootEffectsCustom
|
||||
Syntax: self:ShootEffectsCustom().
|
||||
Returns: Nothing.
|
||||
Notes: Calls the proper muzzleflash, muzzle smoke, muzzle light code.
|
||||
Purpose: FX
|
||||
]]
|
||||
--
|
||||
function SWEP:MuzzleSmoke(spv)
|
||||
local retVal = hook.Run("TFA_MuzzleSmoke",self)
|
||||
if retVal ~= nil then
|
||||
return retVal
|
||||
end
|
||||
if self.SmokeParticle == nil then
|
||||
self.SmokeParticle = self.SmokeParticles[self.DefaultHoldType or self.HoldType]
|
||||
end
|
||||
|
||||
if self:GetStatL("SmokeParticle") and self:GetStatL("SmokeParticle") ~= "" then
|
||||
self:UpdateMuzzleAttachment()
|
||||
local att = self:GetMuzzleAttachment()
|
||||
fx = EffectData()
|
||||
fx:SetOrigin(self:GetOwner():GetShootPos())
|
||||
fx:SetNormal(self:GetOwner():EyeAngles():Forward())
|
||||
fx:SetEntity(self)
|
||||
fx:SetAttachment(att)
|
||||
TFA.Effects.Create("tfa_muzzlesmoke", fx)
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:MuzzleFlashCustom(spv)
|
||||
local retVal = hook.Run("TFA_MuzzleFlash",self)
|
||||
if retVal ~= nil then
|
||||
return retVal
|
||||
end
|
||||
local att = self:GetMuzzleAttachment()
|
||||
fx = EffectData()
|
||||
fx:SetOrigin(self:GetOwner():GetShootPos())
|
||||
fx:SetNormal(self:GetOwner():EyeAngles():Forward())
|
||||
fx:SetEntity(self)
|
||||
fx:SetAttachment(att)
|
||||
local mzsil = self:GetStatL("MuzzleFlashEffectSilenced")
|
||||
|
||||
if (self:GetSilenced() and mzsil and mzsil ~= "") then
|
||||
TFA.Effects.Create(mzsil, fx)
|
||||
else
|
||||
TFA.Effects.Create(self:GetStatL("MuzzleFlashEffect", self.MuzzleFlashEffect or ""), fx)
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:ShootEffectsCustom(ifp)
|
||||
if self.DoMuzzleFlash ~= nil then
|
||||
self.MuzzleFlashEnabled = self.DoMuzzleFlash
|
||||
self.DoMuzzleFlash = nil
|
||||
end
|
||||
|
||||
if not self.MuzzleFlashEnabled then return end
|
||||
if self:IsFirstPerson() and not self:VMIV() then return end
|
||||
if not self:GetOwner().GetShootPos then return end
|
||||
ifp = ifp or IsFirstTimePredicted()
|
||||
|
||||
if (SERVER and sp and self.ParticleMuzzleFlash) or (SERVER and not sp) then
|
||||
net.Start("tfa_base_muzzle_mp", true)
|
||||
net.WriteEntity(self)
|
||||
|
||||
if sp or not self:GetOwner():IsPlayer() then
|
||||
net.SendPVS(self:GetPos())
|
||||
else
|
||||
net.SendOmit(self:GetOwner())
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
if (CLIENT and ifp and not sp) or (sp and SERVER) then
|
||||
self:UpdateMuzzleAttachment()
|
||||
self:MuzzleFlashCustom(sp)
|
||||
self:MuzzleSmoke(sp)
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
Function Name: CanDustEffect
|
||||
Syntax: self:CanDustEffect( concise material name ).
|
||||
Returns: True/False
|
||||
Notes: Used for the impact effect. Should be used with GetMaterialConcise.
|
||||
Purpose: Utility
|
||||
]]
|
||||
--
|
||||
local DustEffects = {
|
||||
[MAT_DIRT] = true,
|
||||
[MAT_CONCRETE] = true,
|
||||
[MAT_PLASTIC] = true,
|
||||
[MAT_WOOD] = true
|
||||
}
|
||||
function SWEP:CanDustEffect(matv)
|
||||
if DustEffects[matv] then return true end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
--[[
|
||||
Function Name: CanSparkEffect
|
||||
Syntax: self:CanSparkEffect( concise material name ).
|
||||
Returns: True/False
|
||||
Notes: Used for the impact effect. Should be used with GetMaterialConcise.
|
||||
Purpose: Utility
|
||||
]]
|
||||
--
|
||||
local SparkEffects = {
|
||||
[MAT_METAL] = true,
|
||||
[MAT_GRATE] = true,
|
||||
[MAT_VENT] = true
|
||||
}
|
||||
function SWEP:CanSparkEffect(matv)
|
||||
if SparkEffects[matv] then return true end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
-- Returns muzzle attachment position for HL2 tracers
|
||||
function SWEP:GetTracerOrigin(...)
|
||||
local att = self:GetMuzzleAttachment()
|
||||
|
||||
local attpos = (self:IsFirstPerson() and self.OwnerViewModel or self):GetAttachment(att)
|
||||
|
||||
if attpos and attpos.Pos then
|
||||
return attpos.Pos
|
||||
end
|
||||
end
|
||||
625
lua/weapons/tfa_gun_base/common/events.lua
Normal file
625
lua/weapons/tfa_gun_base/common/events.lua
Normal file
@@ -0,0 +1,625 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
-- Copyright (c) 2018-2020 TFA Base Devs
|
||||
|
||||
-- Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
-- of this software and associated documentation files (the "Software"), to deal
|
||||
-- in the Software without restriction, including without limitation the rights
|
||||
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
-- copies of the Software, and to permit persons to whom the Software is
|
||||
-- furnished to do so, subject to the following conditions:
|
||||
|
||||
-- The above copyright notice and this permission notice shall be included in all
|
||||
-- copies or substantial portions of the Software.
|
||||
|
||||
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
-- SOFTWARE.
|
||||
|
||||
local lshift = bit.lshift
|
||||
local band = bit.band
|
||||
local bor = bit.bor
|
||||
|
||||
local sp = game.SinglePlayer()
|
||||
local l_CT = CurTime
|
||||
|
||||
local is, spr, wlk, cst
|
||||
|
||||
--[[
|
||||
Function Name: ResetEvents
|
||||
Syntax: self:ResetEvents()
|
||||
Returns: Nothing.
|
||||
Purpose: Cleans up events table.
|
||||
]]--
|
||||
function SWEP:ResetEvents()
|
||||
self:SetEventStatus1(0x00000000)
|
||||
self:SetEventStatus2(0x00000000)
|
||||
self:SetEventStatus3(0x00000000)
|
||||
self:SetEventStatus4(0x00000000)
|
||||
self:SetEventStatus5(0x00000000)
|
||||
self:SetEventStatus6(0x00000000)
|
||||
self:SetEventStatus7(0x00000000)
|
||||
self:SetEventStatus8(0x00000000)
|
||||
|
||||
self:SetEventTimer(l_CT())
|
||||
-- self:SetFirstDeployEvent(false)
|
||||
|
||||
if self.EventTable then
|
||||
for _, eventtable in pairs(self.EventTable) do
|
||||
for i = 1, #eventtable do
|
||||
eventtable[i].called = false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if self.event_table_overflow then
|
||||
local editcts = self.EventTableEdict
|
||||
|
||||
if editcts[0] then
|
||||
editcts[0].called = false
|
||||
|
||||
for i = 1, #editcts do
|
||||
editcts[i].called = false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if sp then
|
||||
self:CallOnClient("ResetEvents", "")
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:GetEventPlayed(event_slot)
|
||||
if self.event_table_overflow then
|
||||
return assert(self.EventTableEdict[event_slot], string.format("Unknown event %d", event_slot)).called
|
||||
end
|
||||
|
||||
local inner_index = event_slot % 32
|
||||
local outer_index = (event_slot - inner_index) / 32 + 1
|
||||
local lindex = lshift(1, inner_index)
|
||||
return band(self.get_event_status_lut[outer_index](self), lindex) ~= 0, inner_index, outer_index, lindex
|
||||
end
|
||||
|
||||
function SWEP:SetEventPlayed(event_slot)
|
||||
if self.event_table_overflow then
|
||||
assert(self.EventTableEdict[event_slot], string.format("Unknown event %d", event_slot)).called = true
|
||||
return
|
||||
end
|
||||
|
||||
local inner_index = event_slot % 32
|
||||
local outer_index = (event_slot - inner_index) / 32 + 1
|
||||
local lindex = lshift(1, inner_index)
|
||||
|
||||
self.set_event_status_lut[outer_index](self, bor(self.get_event_status_lut[outer_index](self), lindex))
|
||||
return inner_index, outer_index, lindex
|
||||
end
|
||||
|
||||
--[[
|
||||
Function Name: ProcessEvents
|
||||
Syntax: self:ProcessEvents().
|
||||
Returns: Nothing.
|
||||
Notes: Critical for the event table to function.
|
||||
Purpose: Main SWEP function
|
||||
]]--
|
||||
|
||||
SWEP._EventSlotCount = 0
|
||||
SWEP.EventTableEdict = {}
|
||||
|
||||
function SWEP:DispatchLuaEvent(arg)
|
||||
if not self.event_table_built then
|
||||
self:RebuildEventEdictTable()
|
||||
end
|
||||
|
||||
local fn = assert(assert(self.EventTableEdict[tonumber(arg)], "No such event with edict " .. arg).value, "Event is missing a function to call")
|
||||
assert(isfunction(fn), "Event " .. arg .. " is not a Lua event")
|
||||
fn(self, self:VMIV(), true)
|
||||
end
|
||||
|
||||
function SWEP:DispatchBodygroupEvent(arg)
|
||||
if not self.event_table_built then
|
||||
self:RebuildEventEdictTable()
|
||||
end
|
||||
|
||||
local event = assert(self.EventTableEdict[tonumber(arg)], "No such event with edict " .. arg)
|
||||
assert(isstring(event.name), "Event " .. arg .. " is missing bodygroup name to set")
|
||||
assert(isstring(event.value), "Event " .. arg .. " is missing bodygroup value to set")
|
||||
|
||||
if event.view then
|
||||
self.ViewModelBodygroups[event.name] = event.value
|
||||
end
|
||||
|
||||
if event.world then
|
||||
self.WorldModelBodygroups[event.name] = event.value
|
||||
end
|
||||
end
|
||||
|
||||
local isstring = isstring
|
||||
|
||||
local function eventtablesorter(a, b)
|
||||
local sa, sb = isstring(a), isstring(b)
|
||||
|
||||
if sa and not sb or not sa and sb then
|
||||
if sa then
|
||||
return false
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
return a < b
|
||||
end
|
||||
|
||||
function SWEP:RebuildEventEdictTable()
|
||||
local self2 = self:GetTable()
|
||||
local slot = 0
|
||||
|
||||
for i = #self2.EventTableEdict, 0, -1 do
|
||||
self2.EventTableEdict[i] = nil
|
||||
end
|
||||
|
||||
self:ResetEvents()
|
||||
|
||||
local eventtable = self2.EventTable
|
||||
local keys = table.GetKeys(eventtable)
|
||||
table.sort(keys, eventtablesorter)
|
||||
|
||||
for _, key in ipairs(keys) do
|
||||
local value = eventtable[key]
|
||||
|
||||
if istable(value) then
|
||||
for _, event in SortedPairs(value) do
|
||||
if istable(event) then
|
||||
event.slot = slot
|
||||
slot = slot + 1
|
||||
|
||||
if not event.autodetect then
|
||||
if event.type == "lua" then
|
||||
if event.server == nil then
|
||||
event.server = true
|
||||
end
|
||||
elseif event.type == "snd" or event.type == "sound" then
|
||||
if event.server == nil then
|
||||
event.server = false
|
||||
end
|
||||
elseif event.type == "bg" or event.type == "bodygroup" then
|
||||
if event.server == nil then event.server = true end
|
||||
if event.view == nil then event.view = true end
|
||||
if event.world == nil then event.world = true end
|
||||
end
|
||||
|
||||
if event.client == nil then
|
||||
event.client = true
|
||||
end
|
||||
|
||||
event.autodetect = true
|
||||
end
|
||||
|
||||
event.called = false
|
||||
|
||||
if slot > 256 and not self.event_table_warning then
|
||||
ErrorNoHalt("[TFA Base] Weapon " .. self:GetClass() .. " got too many events! 256 is maximum! Event table would NOT be properly predicted this time!\n")
|
||||
self.event_table_warning = true
|
||||
end
|
||||
|
||||
self2.EventTableEdict[event.slot] = event
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
self.event_table_overflow = slot > 256
|
||||
self._built_event_debug_string_fn = nil
|
||||
|
||||
self._EventSlotCount = math.ceil(slot / 32)
|
||||
self._EventSlotNum = slot - 1
|
||||
self.event_table_built = true
|
||||
end
|
||||
|
||||
function SWEP:ProcessEvents(firstprediction)
|
||||
local viewmodel = self:VMIVNPC()
|
||||
if not viewmodel then return end
|
||||
|
||||
if not self.event_table_built then
|
||||
self:RebuildEventEdictTable()
|
||||
end
|
||||
|
||||
if sp and CLIENT then return end
|
||||
if sp and SERVER then return self:ProcessEventsSP() end
|
||||
|
||||
local ply = self:GetOwner()
|
||||
local isplayer = ply:IsPlayer()
|
||||
|
||||
local evtbl = self.EventTable[self:GetLastActivity() or -1] or self.EventTable[viewmodel:GetSequenceName(viewmodel:GetSequence())]
|
||||
if not evtbl then return end
|
||||
|
||||
local curtime = l_CT()
|
||||
local eventtimer = self:GetEventTimer()
|
||||
local is_local = CLIENT and ply == LocalPlayer()
|
||||
local animrate = self:GetAnimationRate(self:GetLastActivity() or -1)
|
||||
|
||||
self.current_event_iftp = firstprediction
|
||||
self.processing_events = true
|
||||
|
||||
for i = 1, #evtbl do
|
||||
local event = evtbl[i]
|
||||
if self:GetEventPlayed(event.slot) or curtime < eventtimer + event.time / animrate then goto CONTINUE end
|
||||
self:SetEventPlayed(event.slot)
|
||||
event.called = true
|
||||
|
||||
if not event.autodetect then
|
||||
if event.type == "lua" then
|
||||
if event.server == nil then
|
||||
event.server = true
|
||||
end
|
||||
elseif event.type == "snd" or event.type == "sound" then
|
||||
if event.server == nil then
|
||||
event.server = false
|
||||
end
|
||||
elseif event.type == "bg" or event.type == "bodygroup" then
|
||||
if event.server == nil then event.server = true end
|
||||
if event.view == nil then event.view = true end
|
||||
if event.world == nil then event.world = true end
|
||||
end
|
||||
|
||||
if event.client == nil then
|
||||
event.client = true
|
||||
end
|
||||
|
||||
event.autodetect = true
|
||||
end
|
||||
|
||||
if event.type == "lua" then
|
||||
if ((event.client and CLIENT and (not event.client_predictedonly or is_local)) or (event.server and SERVER)) and event.value then
|
||||
event.value(self, viewmodel, firstprediction)
|
||||
end
|
||||
elseif event.type == "snd" or event.type == "sound" then
|
||||
if SERVER then
|
||||
if event.client then
|
||||
if not isplayer and player.GetCount() ~= 0 then
|
||||
net.Start("tfaSoundEvent", true)
|
||||
net.WriteEntity(self)
|
||||
net.WriteString(event.value or "")
|
||||
net.SendPVS(self:GetPos())
|
||||
elseif isplayer then
|
||||
net.Start("tfaSoundEvent", true)
|
||||
net.WriteEntity(self)
|
||||
net.WriteString(event.value or "")
|
||||
net.SendOmit(ply)
|
||||
end
|
||||
elseif event.server and event.value and event.value ~= "" then
|
||||
self:EmitSound(event.value)
|
||||
end
|
||||
elseif event.client and is_local and not sp and event.value and event.value ~= "" then
|
||||
if firstprediction or firstprediction == nil then
|
||||
if event.time <= 0.01 then
|
||||
self:EmitSoundSafe(event.value)
|
||||
else
|
||||
self:EmitSound(event.value)
|
||||
end
|
||||
end
|
||||
end
|
||||
elseif event.type == "bg" or event.type == "bodygroup" then
|
||||
if ((event.client and CLIENT and (not event.client_predictedonly or is_local)) or
|
||||
(event.server and SERVER)) and (event.name and event.value and event.value ~= "") then
|
||||
|
||||
if event.view then
|
||||
self.ViewModelBodygroups[event.name] = event.value
|
||||
end
|
||||
|
||||
if event.world then
|
||||
self.WorldModelBodygroups[event.name] = event.value
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
::CONTINUE::
|
||||
end
|
||||
|
||||
self.processing_events = false
|
||||
self.current_event_iftp = nil
|
||||
end
|
||||
|
||||
-- This function is exclusively targeting singleplayer
|
||||
function SWEP:ProcessEventsSP(firstprediction)
|
||||
local viewmodel = self:VMIVNPC()
|
||||
if not viewmodel then return end
|
||||
|
||||
local evtbl = self.EventTable[self:GetLastActivity() or -1] or self.EventTable[viewmodel:GetSequenceName(viewmodel:GetSequence())]
|
||||
if not evtbl then return end
|
||||
|
||||
local curtime = l_CT()
|
||||
local eventtimer = self:GetEventTimer()
|
||||
local is_local = self:GetOwner() == Entity(1)
|
||||
local animrate = self:GetAnimationRate(self:GetLastActivity() or -1)
|
||||
|
||||
self.processing_events = true
|
||||
|
||||
for i = 1, #evtbl do
|
||||
local event = evtbl[i]
|
||||
if self:GetEventPlayed(event.slot) or curtime < eventtimer + event.time / animrate then goto CONTINUE end
|
||||
self:SetEventPlayed(event.slot)
|
||||
event.called = true
|
||||
|
||||
if not event.autodetect then
|
||||
if event.type == "lua" then
|
||||
if event.server == nil then
|
||||
event.server = true
|
||||
end
|
||||
elseif event.type == "snd" or event.type == "sound" then
|
||||
if event.server == nil then
|
||||
event.server = false
|
||||
end
|
||||
elseif event.type == "bg" or event.type == "bodygroup" then
|
||||
if event.server == nil then event.server = true end
|
||||
if event.view == nil then event.view = true end
|
||||
if event.world == nil then event.world = true end
|
||||
end
|
||||
|
||||
if event.client == nil then
|
||||
event.client = true
|
||||
end
|
||||
|
||||
event.autodetect = true
|
||||
end
|
||||
|
||||
if event.type == "lua" then
|
||||
if event.value then
|
||||
if event.server then
|
||||
event.value(self, viewmodel, true)
|
||||
end
|
||||
|
||||
if event.client and (not event.client_predictedonly or is_local) then
|
||||
self:CallOnClient("DispatchLuaEvent", tostring(event.slot))
|
||||
end
|
||||
end
|
||||
elseif event.type == "snd" or event.type == "sound" then
|
||||
if event.client then
|
||||
net.Start("tfaSoundEvent", true)
|
||||
net.WriteEntity(self)
|
||||
net.WriteString(event.value or "")
|
||||
net.Broadcast()
|
||||
elseif event.server and event.value and event.value ~= "" then
|
||||
self:EmitSound(event.value)
|
||||
end
|
||||
elseif event.type == "bg" or event.type == "bodygroup" then
|
||||
if event.name and event.value and event.value ~= "" then
|
||||
if event.server then
|
||||
if event.view then
|
||||
self.ViewModelBodygroups[event.name] = event.value
|
||||
end
|
||||
|
||||
if event.world then
|
||||
self.WorldModelBodygroups[event.name] = event.value
|
||||
end
|
||||
end
|
||||
|
||||
if event.client and (not event.client_predictedonly or is_local) then
|
||||
self:CallOnClient("DispatchBodygroupEvent", tostring(event.slot))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
::CONTINUE::
|
||||
end
|
||||
|
||||
self.processing_events = false
|
||||
end
|
||||
|
||||
function SWEP:EmitSoundSafe(snd)
|
||||
timer.Simple(0, function()
|
||||
if IsValid(self) and snd then self:EmitSound(snd) end
|
||||
end)
|
||||
end
|
||||
|
||||
local ct, stat, statend, finalstat, waittime, lact
|
||||
|
||||
function SWEP:ProcessStatus()
|
||||
local self2 = self:GetTable()
|
||||
|
||||
is = self2.GetIronSightsRaw(self)
|
||||
spr = self2.GetSprinting(self)
|
||||
wlk = self2.GetWalking(self)
|
||||
cst = self2.GetCustomizing(self)
|
||||
|
||||
local ply = self:GetOwner()
|
||||
local isplayer = ply:IsPlayer()
|
||||
|
||||
if stat == TFA.Enum.STATUS_FIDGET and is then
|
||||
self:SetStatusEnd(0)
|
||||
|
||||
self2.Idle_Mode_Old = self2.Idle_Mode
|
||||
self2.Idle_Mode = TFA.Enum.IDLE_BOTH
|
||||
self2.ChooseIdleAnim(self)
|
||||
|
||||
if sp then
|
||||
self:CallOnClient("ChooseIdleAnim", "")
|
||||
end
|
||||
|
||||
self2.Idle_Mode = self2.Idle_Mode_Old
|
||||
self2.Idle_Mode_Old = nil
|
||||
statend = -1
|
||||
end
|
||||
|
||||
is = self:GetIronSights()
|
||||
stat = self:GetStatus()
|
||||
statend = self:GetStatusEnd()
|
||||
|
||||
ct = l_CT()
|
||||
|
||||
if stat ~= TFA.Enum.STATUS_IDLE and ct > statend then
|
||||
self:SetFirstDeployEvent(false)
|
||||
finalstat = TFA.Enum.STATUS_IDLE
|
||||
|
||||
--Holstering
|
||||
if stat == TFA.Enum.STATUS_HOLSTER then
|
||||
finalstat = TFA.Enum.STATUS_HOLSTER_READY
|
||||
self:SetStatusEnd(ct)
|
||||
elseif stat == TFA.Enum.STATUS_HOLSTER_READY then
|
||||
self2.FinishHolster(self)
|
||||
finalstat = TFA.Enum.STATUS_HOLSTER_FINAL
|
||||
self:SetStatusEnd(ct + 0.6)
|
||||
elseif stat == TFA.Enum.STATUS_RELOADING_LOOP_START_EMPTY then
|
||||
--Shotgun Reloading from empty
|
||||
if not self2.IsJammed(self) then
|
||||
self2.TakePrimaryAmmo(self, 1, true)
|
||||
self2.TakePrimaryAmmo(self, -1)
|
||||
end
|
||||
|
||||
if self2.Ammo1(self) <= 0 or self:Clip1() >= self2.GetPrimaryClipSize(self) or self:GetReloadLoopCancel() then
|
||||
finalstat = TFA.Enum.STATUS_RELOADING_LOOP_END
|
||||
local _, tanim = self2.ChooseShotgunPumpAnim(self)
|
||||
self:SetStatusEnd(ct + self:GetActivityLength(tanim))
|
||||
self:SetReloadLoopCancel(false)
|
||||
|
||||
if not self:GetReloadLoopCancel() then
|
||||
self:SetJammed(false)
|
||||
end
|
||||
else
|
||||
lact = self:GetLastActivity()
|
||||
waittime = self2.GetActivityLength(self, lact, false) - self2.GetActivityLength(self, lact, true)
|
||||
|
||||
if waittime > 0.01 then
|
||||
finalstat = TFA.Enum.STATUS_RELOADING_WAIT
|
||||
self:SetStatusEnd(ct + waittime)
|
||||
else
|
||||
finalstat = self2.LoadShell(self)
|
||||
end
|
||||
|
||||
self:SetJammed(false)
|
||||
--finalstat = self:LoadShell()
|
||||
--self:SetStatusEnd( self:GetNextPrimaryFire() )
|
||||
end
|
||||
elseif stat == TFA.Enum.STATUS_RELOADING_LOOP_START then
|
||||
--Shotgun Reloading
|
||||
finalstat = self2.LoadShell(self)
|
||||
elseif stat == TFA.Enum.STATUS_RELOADING_LOOP then
|
||||
self2.TakePrimaryAmmo(self, 1, true)
|
||||
self2.TakePrimaryAmmo(self, -1)
|
||||
lact = self:GetLastActivity()
|
||||
|
||||
if self2.GetActivityLength(self, lact, true) < self2.GetActivityLength(self, lact, false) - 0.01 then
|
||||
local sht = self2.GetStatL(self, "LoopedReloadInsertTime")
|
||||
|
||||
if sht then
|
||||
sht = sht / self2.GetAnimationRate(self, ACT_VM_RELOAD)
|
||||
end
|
||||
|
||||
waittime = (sht or self2.GetActivityLength(self, lact, false)) - self2.GetActivityLength(self, lact, true)
|
||||
else
|
||||
waittime = 0
|
||||
end
|
||||
|
||||
if waittime > 0.01 then
|
||||
finalstat = TFA.Enum.STATUS_RELOADING_WAIT
|
||||
self:SetStatusEnd(ct + waittime)
|
||||
else
|
||||
if self2.Ammo1(self) <= 0 or self:Clip1() >= self:GetPrimaryClipSize() or self:GetReloadLoopCancel() then
|
||||
finalstat = TFA.Enum.STATUS_RELOADING_LOOP_END
|
||||
local _, tanim = self2.ChooseShotgunPumpAnim(self)
|
||||
self:SetStatusEnd(ct + self:GetActivityLength(tanim))
|
||||
self:SetReloadLoopCancel(false)
|
||||
else
|
||||
finalstat = self2.LoadShell(self)
|
||||
end
|
||||
end
|
||||
elseif stat == TFA.Enum.STATUS_RELOADING then
|
||||
self2.CompleteReload(self)
|
||||
lact = self:GetLastActivity()
|
||||
waittime = self2.GetActivityLength(self, lact, false) - self2.GetActivityLength(self, lact, true)
|
||||
|
||||
if waittime > 0.01 then
|
||||
finalstat = TFA.Enum.STATUS_RELOADING_WAIT
|
||||
self:SetStatusEnd(ct + waittime)
|
||||
end
|
||||
elseif stat == TFA.Enum.STATUS_SILENCER_TOGGLE then
|
||||
--self:SetStatusEnd( self:GetNextPrimaryFire() )
|
||||
self:SetSilenced(not self:GetSilenced())
|
||||
self2.Silenced = self:GetSilenced()
|
||||
elseif stat == TFA.Enum.STATUS_RELOADING_WAIT and self:GetStatL("LoopedReload") then
|
||||
if self2.Ammo1(self) <= 0 or self:Clip1() >= self:GetPrimaryClipSize() or self:GetReloadLoopCancel() then
|
||||
finalstat = TFA.Enum.STATUS_RELOADING_LOOP_END
|
||||
local _, tanim = self2.ChooseShotgunPumpAnim(self)
|
||||
self:SetStatusEnd(ct + self:GetActivityLength(tanim))
|
||||
--self:SetReloadLoopCancel( false )
|
||||
else
|
||||
finalstat = self2.LoadShell(self)
|
||||
end
|
||||
elseif stat == TFA.Enum.STATUS_RELOADING_LOOP_END and self:GetStatL("LoopedReload") then
|
||||
self:SetReloadLoopCancel(false)
|
||||
elseif self2.GetStatL(self, "PumpAction") and stat == TFA.Enum.STATUS_PUMP then
|
||||
self:SetReloadLoopCancel(false)
|
||||
elseif stat == TFA.Enum.STATUS_SHOOTING and self2.GetStatL(self, "PumpAction") then
|
||||
if self:Clip1() == 0 and self2.GetStatL(self, "PumpAction").value_empty then
|
||||
--finalstat = TFA.Enum.STATUS_PUMP_READY
|
||||
self:SetReloadLoopCancel(true)
|
||||
elseif (self2.GetStatL(self, "Primary.ClipSize") < 0 or self:Clip1() > 0) and self2.GetStatL(self, "PumpAction").value then
|
||||
--finalstat = TFA.Enum.STATUS_PUMP_READY
|
||||
self:SetReloadLoopCancel(true)
|
||||
end
|
||||
end
|
||||
|
||||
--self:SetStatusEnd( math.huge )
|
||||
self:SetStatus(finalstat)
|
||||
local smi = self2.Sights_Mode == TFA.Enum.LOCOMOTION_HYBRID or self2.Sights_Mode == TFA.Enum.LOCOMOTION_ANI
|
||||
local spi = self2.Sprint_Mode == TFA.Enum.LOCOMOTION_HYBRID or self2.Sprint_Mode == TFA.Enum.LOCOMOTION_ANI
|
||||
local wmi = self2.Walk_Mode == TFA.Enum.LOCOMOTION_HYBRID or self2.Walk_Mode == TFA.Enum.LOCOMOTION_ANI
|
||||
local cmi = self2.Customize_Mode == TFA.Enum.LOCOMOTION_HYBRID or self2.Customize_Mode == TFA.Enum.LOCOMOTION_ANI
|
||||
|
||||
if
|
||||
not TFA.Enum.ReadyStatus[stat] and
|
||||
stat ~= TFA.Enum.STATUS_SHOOTING and
|
||||
stat ~= TFA.Enum.STATUS_PUMP and
|
||||
finalstat == TFA.Enum.STATUS_IDLE and
|
||||
((smi or spi) or (cst and cmi))
|
||||
then
|
||||
is = self2.GetIronSights(self, true)
|
||||
|
||||
if (is and smi) or (spr and spi) or (wlk and wmi) or (cst and cmi) then
|
||||
local success, _ = self2.Locomote(self, is and smi, is, spr and spi, spr, wlk and wmi, wlk, cst and cmi, cst)
|
||||
|
||||
if success == false then
|
||||
self:SetNextIdleAnim(-1)
|
||||
else
|
||||
self:SetNextIdleAnim(math.max(self:GetNextIdleAnim(), ct + 0.1))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
self2.LastBoltShoot = nil
|
||||
|
||||
if self:GetBurstCount() > 0 then
|
||||
if finalstat ~= TFA.Enum.STATUS_SHOOTING and finalstat ~= TFA.Enum.STATUS_IDLE then
|
||||
self:SetBurstCount(0)
|
||||
elseif self:GetBurstCount() < self:GetMaxBurst() and self:Clip1() > 0 then
|
||||
self:PrimaryAttack()
|
||||
else
|
||||
self:SetBurstCount(0)
|
||||
self:SetNextPrimaryFire(self2.GetNextCorrectedPrimaryFire(self, self2.GetBurstDelay(self)))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--if stat == TFA.Enum.STATUS_IDLE and self:GetReloadLoopCancel() and (self2.GetStatL(self, "AllowSprintAttack") or self:GetSprintProgress() < 0.1) then
|
||||
if stat == TFA.Enum.STATUS_IDLE and self:GetReloadLoopCancel() then
|
||||
if self2.GetStatL(self, "PumpAction") then
|
||||
if ct > self:GetNextPrimaryFire() and not self:KeyDown(IN_ATTACK) then
|
||||
self2.DoPump(self)
|
||||
end
|
||||
else
|
||||
self:SetReloadLoopCancel(false)
|
||||
end
|
||||
end
|
||||
end
|
||||
126
lua/weapons/tfa_gun_base/common/nzombies.lua
Normal file
126
lua/weapons/tfa_gun_base/common/nzombies.lua
Normal file
@@ -0,0 +1,126 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
-- Copyright (c) 2018-2020 TFA Base Devs
|
||||
|
||||
-- Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
-- of this software and associated documentation files (the "Software"), to deal
|
||||
-- in the Software without restriction, including without limitation the rights
|
||||
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
-- copies of the Software, and to permit persons to whom the Software is
|
||||
-- furnished to do so, subject to the following conditions:
|
||||
|
||||
-- The above copyright notice and this permission notice shall be included in all
|
||||
-- copies or substantial portions of the Software.
|
||||
|
||||
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
-- SOFTWARE.
|
||||
|
||||
SWEP.OldPaP = false
|
||||
SWEP.OldSpCola = false
|
||||
SWEP.SpeedColaFactor = 2 --Amount to speed up by when u get dat speed cola
|
||||
SWEP.SpeedColaActivities = {
|
||||
[ACT_VM_DRAW] = true,
|
||||
[ACT_VM_DRAW_EMPTY] = true,
|
||||
[ACT_VM_DRAW_SILENCED] = true,
|
||||
[ACT_VM_DRAW_DEPLOYED or 0] = true,
|
||||
[ACT_VM_RELOAD] = true,
|
||||
[ACT_VM_RELOAD_EMPTY] = true,
|
||||
[ACT_VM_RELOAD_SILENCED] = true,
|
||||
[ACT_VM_HOLSTER] = true,
|
||||
[ACT_VM_HOLSTER_EMPTY] = true,
|
||||
[ACT_VM_HOLSTER_SILENCED] = true,
|
||||
[ACT_SHOTGUN_RELOAD_START] = true,
|
||||
[ACT_SHOTGUN_RELOAD_FINISH] = true
|
||||
}
|
||||
SWEP.DTapActivities = {
|
||||
[ACT_VM_PRIMARYATTACK] = true,
|
||||
[ACT_VM_PRIMARYATTACK_EMPTY] = true,
|
||||
[ACT_VM_PRIMARYATTACK_SILENCED] = true,
|
||||
[ACT_VM_PRIMARYATTACK_1] = true,
|
||||
[ACT_VM_SECONDARYATTACK] = true,
|
||||
[ACT_VM_HITCENTER] = true,
|
||||
[ACT_SHOTGUN_PUMP] = true
|
||||
}
|
||||
SWEP.DTapSpeed = 1 / 0.8
|
||||
SWEP.DTap2Speed = 1 / 0.8
|
||||
|
||||
local nzombies
|
||||
|
||||
local count, upperclamp
|
||||
|
||||
function SWEP:NZMaxAmmo()
|
||||
if nzombies == nil then
|
||||
nzombies = engine.ActiveGamemode() == "nzombies"
|
||||
end
|
||||
local at = self:GetPrimaryAmmoType()
|
||||
local at2 = self.GetSecondaryAmmoType and self:GetSecondaryAmmoType() or self.Secondary_TFA.Ammo
|
||||
|
||||
if IsValid(self:GetOwner()) then
|
||||
if self:GetStatL("Primary.ClipSize") <= 0 then
|
||||
count = math.Clamp(10, 300 / (self:GetStatL("Primary.Damage") / 30), 10, 300)
|
||||
if self.Primary_TFA.NZMaxAmmo and self.Primary_TFA.NZMaxAmmo > 0 then
|
||||
count = self.Primary_TFA.NZMaxAmmo
|
||||
if self:GetPaP() then
|
||||
count = count * 5 / 3
|
||||
end
|
||||
end
|
||||
self:GetOwner():SetAmmo(count, at)
|
||||
else
|
||||
upperclamp = self:GetPaP() and 600 or 300
|
||||
count = math.Clamp(math.abs(self:GetStatL("Primary.ClipSize")) * 10, 10, upperclamp)
|
||||
count = count + self:GetStatL("Primary.ClipSize") - self:Clip1()
|
||||
if self.Primary_TFA.NZMaxAmmo and self.Primary_TFA.NZMaxAmmo > 0 then
|
||||
count = self.Primary_TFA.NZMaxAmmo
|
||||
if self:GetPaP() then
|
||||
count = count * 5 / 3
|
||||
end
|
||||
end
|
||||
self:GetOwner():SetAmmo(count, at)
|
||||
end
|
||||
if self:GetStatL("Secondary.ClipSize") > 0 or self:GetSecondaryAmmoType() >= 0 then
|
||||
if self:GetStatL("Secondary.ClipSize") <= 0 then
|
||||
count = math.ceil( math.Clamp(10, 300 / math.pow( ( self:GetStatL("Secondary.Damage") or 100 ) / 30, 2 ), 10, 300) / 5 ) * 5
|
||||
if self.Secondary_TFA.NZMaxAmmo and self.Secondary_TFA.NZMaxAmmo > 0 then
|
||||
count = self.Secondary_TFA.NZMaxAmmo
|
||||
if self:GetPaP() then
|
||||
count = count * 5 / 3
|
||||
end
|
||||
end
|
||||
self:GetOwner():SetAmmo(count, at2)
|
||||
else
|
||||
upperclamp = self:GetPaP() and 600 or 300
|
||||
count = math.Clamp(math.abs(self:GetStatL("Secondary.ClipSize")) * 10, 10, upperclamp)
|
||||
count = count + self:GetStatL("Secondary.ClipSize") - self:Clip2()
|
||||
if self.Secondary_TFA.NZMaxAmmo and self.Secondary_TFA.NZMaxAmmo > 0 then
|
||||
count = self.Secondary_TFA.NZMaxAmmo
|
||||
if self:GetPaP() then
|
||||
count = count * 5 / 3
|
||||
end
|
||||
end
|
||||
self:GetOwner():SetAmmo(count, at2)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:GetPaP()
|
||||
return ( self.HasNZModifier and self:HasNZModifier("pap") ) or self.pap or false
|
||||
end
|
||||
|
||||
function SWEP:IsPaP()
|
||||
return self:GetPaP()
|
||||
end
|
||||
69
lua/weapons/tfa_gun_base/common/skins.lua
Normal file
69
lua/weapons/tfa_gun_base/common/skins.lua
Normal file
@@ -0,0 +1,69 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
-- Copyright (c) 2018-2020 TFA Base Devs
|
||||
|
||||
-- Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
-- of this software and associated documentation files (the "Software"), to deal
|
||||
-- in the Software without restriction, including without limitation the rights
|
||||
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
-- copies of the Software, and to permit persons to whom the Software is
|
||||
-- furnished to do so, subject to the following conditions:
|
||||
|
||||
-- The above copyright notice and this permission notice shall be included in all
|
||||
-- copies or substantial portions of the Software.
|
||||
|
||||
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
-- SOFTWARE.
|
||||
|
||||
SWEP.MaterialTable = {}
|
||||
SWEP.MaterialTable_V = {}
|
||||
SWEP.MaterialTable_W = {}
|
||||
|
||||
function SWEP:InitializeMaterialTable()
|
||||
if not self.HasSetMaterialMeta then
|
||||
setmetatable(self.MaterialTable_V, {
|
||||
["__index"] = function(t,k) return self:GetStatL("MaterialTable")[k] end
|
||||
})
|
||||
|
||||
setmetatable(self.MaterialTable_W, {
|
||||
["__index"] = function(t,k) return self:GetStatL("MaterialTable")[k] end
|
||||
})
|
||||
|
||||
self.HasSetMaterialMeta = true
|
||||
end
|
||||
end
|
||||
|
||||
--if both nil then we can just clear it all
|
||||
function SWEP:ClearMaterialCache(view, world)
|
||||
if view == nil and world == nil then
|
||||
self.MaterialCached_V = nil
|
||||
self.MaterialCached_W = nil
|
||||
self.MaterialCached = nil
|
||||
self.SCKMaterialCached_V = nil
|
||||
self.SCKMaterialCached_W = nil
|
||||
else
|
||||
if view then
|
||||
self.MaterialCached_V = nil
|
||||
self.SCKMaterialCached_V = nil
|
||||
end
|
||||
|
||||
if world then
|
||||
self.MaterialCached_W = nil
|
||||
self.SCKMaterialCached_W = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
413
lua/weapons/tfa_gun_base/common/stat.lua
Normal file
413
lua/weapons/tfa_gun_base/common/stat.lua
Normal file
@@ -0,0 +1,413 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
-- Copyright (c) 2018-2020 TFA Base Devs
|
||||
|
||||
-- Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
-- of this software and associated documentation files (the "Software"), to deal
|
||||
-- in the Software without restriction, including without limitation the rights
|
||||
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
-- copies of the Software, and to permit persons to whom the Software is
|
||||
-- furnished to do so, subject to the following conditions:
|
||||
|
||||
-- The above copyright notice and this permission notice shall be included in all
|
||||
-- copies or substantial portions of the Software.
|
||||
|
||||
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
-- SOFTWARE.
|
||||
|
||||
local tableCopy = table.Copy
|
||||
|
||||
function SWEP:GetStatRecursive(srctbl, stbl, ...)
|
||||
local val = srctbl[stbl[1]]
|
||||
for i = 2, #stbl do
|
||||
if (val) then
|
||||
val = val[stbl[i]]
|
||||
else
|
||||
return true, ...
|
||||
end
|
||||
end
|
||||
|
||||
if val == nil then
|
||||
return true, ...
|
||||
end
|
||||
|
||||
if istable(val) and val.functionTable then
|
||||
local currentStat, isFinal, nocache, nct
|
||||
nocache = false
|
||||
|
||||
for i = 1, #val do
|
||||
local v = val[i]
|
||||
|
||||
if isfunction(v) then
|
||||
if currentStat == nil then
|
||||
currentStat, isFinal, nct = v(self, ...)
|
||||
else
|
||||
currentStat, isFinal, nct = v(self, currentStat)
|
||||
end
|
||||
|
||||
nocache = nocache or nct
|
||||
|
||||
if isFinal then break end
|
||||
elseif v then
|
||||
currentStat = v
|
||||
end
|
||||
end
|
||||
|
||||
if currentStat ~= nil then
|
||||
return false, currentStat, nocache
|
||||
end
|
||||
|
||||
return true, ...
|
||||
end
|
||||
|
||||
return false, val
|
||||
end
|
||||
|
||||
SWEP.StatCache_Blacklist = {
|
||||
["ViewModelBoneMods"] = true,
|
||||
["WorldModelBoneMods"] = true,
|
||||
["MaterialTable"] = true,
|
||||
["MaterialTable_V"] = true,
|
||||
["MaterialTable_W"] = true,
|
||||
["ViewModelBodygroups"] = true,
|
||||
["Bodygroups_V"] = true,
|
||||
["WorldModelBodygroups"] = true,
|
||||
["Skin"] = true
|
||||
}
|
||||
|
||||
SWEP.StatCache = {}
|
||||
SWEP.StatCache2 = {}
|
||||
SWEP.StatStringCache = {}
|
||||
|
||||
SWEP.LastClearStatCache = 0
|
||||
SWEP.ClearStatCacheWarnCount = 0
|
||||
SWEP.ClearStatCacheWarned = false
|
||||
|
||||
local IdealCSCDeltaTime = engine.TickInterval() * 2
|
||||
|
||||
local LatestDataVersion = TFA.LatestDataVersion
|
||||
|
||||
function SWEP:ClearStatCache(vn)
|
||||
return self:ClearStatCacheVersioned(vn, 0)
|
||||
end
|
||||
|
||||
function SWEP:ClearStatCacheL(vn)
|
||||
return self:ClearStatCacheVersioned(vn, LatestDataVersion)
|
||||
end
|
||||
|
||||
local trigger_lut_rebuild = {
|
||||
FalloffMetricBased = true,
|
||||
Range = true,
|
||||
RangeFalloff = true,
|
||||
}
|
||||
|
||||
function SWEP:ClearStatCacheVersioned(vn, path_version)
|
||||
local self2 = self:GetTable()
|
||||
self2.ignore_stat_cache = true
|
||||
local getpath, getpath2
|
||||
|
||||
if isstring(vn) then
|
||||
vn = TFA.RemapStatPath(vn, path_version, self.TFADataVersion)
|
||||
end
|
||||
|
||||
if not vn and not self2.ClearStatCacheWarned then
|
||||
local ct = CurTime()
|
||||
local delta = ct - self2.LastClearStatCache
|
||||
|
||||
if delta < IdealCSCDeltaTime and debug.traceback():find("Think2") then
|
||||
self2.ClearStatCacheWarnCount = self2.ClearStatCacheWarnCount + 1
|
||||
|
||||
if self2.ClearStatCacheWarnCount >= 5 then
|
||||
self2.ClearStatCacheWarned = true
|
||||
|
||||
print(("[TFA Base] Weapon %s (%s) is abusing ClearStatCache function from Think2! This will lead to really bad performance issues, tell weapon's author to fix it ASAP!"):format(self2.PrintName, self:GetClass()))
|
||||
end
|
||||
elseif self2.ClearStatCacheWarnCount > 0 then
|
||||
self2.ClearStatCacheWarnCount = 0
|
||||
end
|
||||
|
||||
self2.LastClearStatCache = ct
|
||||
end
|
||||
|
||||
if vn then
|
||||
local list = TFA.GetStatPathChildren(vn, path_version, self.TFADataVersion)
|
||||
|
||||
for i = 1, #list do
|
||||
self2.StatCache[list[i]] = nil
|
||||
self2.StatCache2[list[i]] = nil
|
||||
end
|
||||
|
||||
getpath2 = self2.GetStatPath(self, vn)
|
||||
getpath = getpath2[1]
|
||||
else
|
||||
table.Empty(self2.StatCache)
|
||||
table.Empty(self2.StatCache2)
|
||||
end
|
||||
|
||||
if vn == "Primary" or not vn then
|
||||
table.Empty(self2.Primary)
|
||||
|
||||
local temp = {}
|
||||
|
||||
setmetatable(self2.Primary, {
|
||||
__index = function(self3, key)
|
||||
return self2.GetStatVersioned(self, "Primary." .. key, self2.TFADataVersion)
|
||||
end,
|
||||
|
||||
__newindex = function() end
|
||||
})
|
||||
|
||||
for k in pairs(self2.Primary_TFA) do
|
||||
if isstring(k) then
|
||||
temp[k] = self2.GetStatVersioned(self, "Primary." .. k, self2.TFADataVersion)
|
||||
end
|
||||
end
|
||||
|
||||
setmetatable(self2.Primary, nil)
|
||||
|
||||
for k, v in pairs(temp) do
|
||||
self2.Primary[k] = v
|
||||
end
|
||||
|
||||
if self2.Primary_TFA.RangeFalloffLUT_IsConverted then
|
||||
self2.Primary_TFA.RangeFalloffLUT = nil
|
||||
self2.AutoDetectRange(self)
|
||||
end
|
||||
|
||||
local getLUT = self2.GetStatL(self, "Primary.RangeFalloffLUT", nil, true)
|
||||
|
||||
if getLUT then
|
||||
self2.Primary.RangeFalloffLUTBuilt = self:BuildFalloffTable(getLUT)
|
||||
end
|
||||
|
||||
if self2.Primary_TFA.RecoilLUT then
|
||||
if self2.Primary_TFA.RecoilLUT["in"] then
|
||||
self2.Primary_TFA.RecoilLUT["in"].points_p = {0}
|
||||
self2.Primary_TFA.RecoilLUT["in"].points_y = {0}
|
||||
|
||||
for _, point in ipairs(self2.Primary_TFA.RecoilLUT["in"].points) do
|
||||
table.insert(self2.Primary_TFA.RecoilLUT["in"].points_p, point.p)
|
||||
table.insert(self2.Primary_TFA.RecoilLUT["in"].points_y, point.y)
|
||||
end
|
||||
end
|
||||
|
||||
if self2.Primary_TFA.RecoilLUT["loop"] then
|
||||
self2.Primary_TFA.RecoilLUT["loop"].points_p = {}
|
||||
self2.Primary_TFA.RecoilLUT["loop"].points_y = {}
|
||||
|
||||
for _, point in ipairs(self2.Primary_TFA.RecoilLUT["loop"].points) do
|
||||
table.insert(self2.Primary_TFA.RecoilLUT["loop"].points_p, point.p)
|
||||
table.insert(self2.Primary_TFA.RecoilLUT["loop"].points_y, point.y)
|
||||
end
|
||||
|
||||
table.insert(self2.Primary_TFA.RecoilLUT["loop"].points_p, self2.Primary_TFA.RecoilLUT["loop"].points[1].p)
|
||||
table.insert(self2.Primary_TFA.RecoilLUT["loop"].points_y, self2.Primary_TFA.RecoilLUT["loop"].points[1].y)
|
||||
end
|
||||
|
||||
if self2.Primary_TFA.RecoilLUT["out"] then
|
||||
self2.Primary_TFA.RecoilLUT["out"].points_p = {0}
|
||||
self2.Primary_TFA.RecoilLUT["out"].points_y = {0}
|
||||
|
||||
for _, point in ipairs(self2.Primary_TFA.RecoilLUT["out"].points) do
|
||||
table.insert(self2.Primary_TFA.RecoilLUT["out"].points_p, point.p)
|
||||
table.insert(self2.Primary_TFA.RecoilLUT["out"].points_y, point.y)
|
||||
end
|
||||
|
||||
table.insert(self2.Primary_TFA.RecoilLUT["out"].points_p, 0)
|
||||
table.insert(self2.Primary_TFA.RecoilLUT["out"].points_y, 0)
|
||||
end
|
||||
end
|
||||
elseif getpath == "Primary_TFA" and isstring(getpath2[2]) then
|
||||
if trigger_lut_rebuild[getpath2[2]] and self2.Primary_TFA.RangeFalloffLUT_IsConverted then
|
||||
self2.Primary_TFA.RangeFalloffLUT = nil
|
||||
self2.AutoDetectRange(self)
|
||||
end
|
||||
|
||||
self2.Primary[getpath[2]] = self2.GetStatVersioned(self, vn, path_version)
|
||||
end
|
||||
|
||||
if vn == "Secondary" or not vn then
|
||||
table.Empty(self2.Secondary)
|
||||
|
||||
local temp = {}
|
||||
|
||||
setmetatable(self2.Secondary, {
|
||||
__index = function(self3, key)
|
||||
return self2.GetStatVersioned(self, "Secondary." .. key, self2.TFADataVersion)
|
||||
end,
|
||||
|
||||
__newindex = function() end
|
||||
})
|
||||
|
||||
for k in pairs(self.Secondary_TFA) do
|
||||
if isstring(k) then
|
||||
temp[k] = self2.GetStatVersioned(self, "Secondary." .. k, self2.TFADataVersion)
|
||||
end
|
||||
end
|
||||
|
||||
setmetatable(self2.Secondary, nil)
|
||||
|
||||
for k, v in pairs(temp) do
|
||||
self2.Secondary[k] = v
|
||||
end
|
||||
elseif getpath == "Secondary_TFA" and isstring(getpath2[2]) then
|
||||
self2.Secondary[getpath[2]] = self2.GetStatVersioned(self, vn, path_version)
|
||||
end
|
||||
|
||||
if CLIENT then
|
||||
self:RebuildModsRenderOrder()
|
||||
end
|
||||
|
||||
self2.ignore_stat_cache = false
|
||||
hook.Run("TFA_ClearStatCache", self)
|
||||
end
|
||||
|
||||
local ccv = GetConVar("cl_tfa_debug_cache")
|
||||
|
||||
function SWEP:GetStatPath(stat, path_version)
|
||||
return TFA.GetStatPath(stat, path_version or 0, self.TFADataVersion)
|
||||
end
|
||||
|
||||
function SWEP:RemapStatPath(stat, path_version)
|
||||
return TFA.RemapStatPath(stat, path_version or 0, self.TFADataVersion)
|
||||
end
|
||||
|
||||
function SWEP:GetStatPathRaw(stat)
|
||||
return TFA.GetStatPathRaw(stat)
|
||||
end
|
||||
|
||||
function SWEP:GetStatRaw(stat, path_version)
|
||||
local self2 = self:GetTable()
|
||||
local path = TFA.GetStatPath(stat, path_version or 0, self2.TFADataVersion)
|
||||
local value = self2[path[1]]
|
||||
|
||||
for i = 2, #path do
|
||||
if not istable(value) then return end
|
||||
value = value[path[i]]
|
||||
end
|
||||
|
||||
return value
|
||||
end
|
||||
|
||||
function SWEP:GetStatRawL(stat)
|
||||
return self:GetStatRaw(stat, LatestDataVersion)
|
||||
end
|
||||
|
||||
function SWEP:SetStatRaw(stat, path_version, _value)
|
||||
local self2 = self:GetTable()
|
||||
local path = TFA.GetStatPath(stat, path_version or 0, self2.TFADataVersion)
|
||||
|
||||
if #path == 1 then
|
||||
self2[path[1]] = _value
|
||||
return self
|
||||
end
|
||||
|
||||
local value = self2[path[1]]
|
||||
|
||||
for i = 2, #path - 1 do
|
||||
if not istable(value) then return self end
|
||||
value = value[path[i]]
|
||||
end
|
||||
|
||||
if istable(value) then
|
||||
value[path[#path]] = _value
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
function SWEP:SetStatRawL(stat, _value)
|
||||
return self:SetStatRaw(stat, LatestDataVersion, _value)
|
||||
end
|
||||
|
||||
function SWEP:GetStat(stat, default, dontMergeTables)
|
||||
return self:GetStatVersioned(stat, 0, default, dontMergeTables)
|
||||
end
|
||||
|
||||
function SWEP:GetStatL(stat, default, dontMergeTables)
|
||||
return self:GetStatVersioned(stat, LatestDataVersion, default, dontMergeTables)
|
||||
end
|
||||
|
||||
function SWEP:GetStatVersioned(stat, path_version, default, dontMergeTables)
|
||||
local self2 = self:GetTable()
|
||||
local statPath, currentVersionStat, translate = self2.GetStatPath(self, stat, path_version)
|
||||
|
||||
if self2.StatCache2[currentVersionStat] ~= nil then
|
||||
local finalReturn
|
||||
|
||||
if self2.StatCache[currentVersionStat] ~= nil then
|
||||
finalReturn = self2.StatCache[currentVersionStat]
|
||||
else
|
||||
local isDefault, retval = self2.GetStatRecursive(self, self2, statPath)
|
||||
|
||||
if retval ~= nil then
|
||||
if not isDefault then
|
||||
self2.StatCache[currentVersionStat] = retval
|
||||
end
|
||||
|
||||
finalReturn = retval
|
||||
else
|
||||
finalReturn = istable(default) and tableCopy(default) or default
|
||||
end
|
||||
end
|
||||
|
||||
--local getstat = hook.Run("TFA_GetStat", self, currentVersionStat, finalReturn)
|
||||
--if getstat ~= nil then return translate(getstat) end
|
||||
|
||||
return translate(finalReturn)
|
||||
end
|
||||
|
||||
if not self2.OwnerIsValid(self) then
|
||||
local finalReturn = default
|
||||
|
||||
if IsValid(self) then
|
||||
local _
|
||||
_, finalReturn = self2.GetStatRecursive(self, self2, statPath, istable(default) and tableCopy(default) or default)
|
||||
end
|
||||
|
||||
--local getstat = hook.Run("TFA_GetStat", self, currentVersionStat, finalReturn)
|
||||
--if getstat ~= nil then return translate(getstat) end
|
||||
|
||||
return translate(finalReturn)
|
||||
end
|
||||
|
||||
local isDefault, statSelf = self2.GetStatRecursive(self, self2, statPath, istable(default) and tableCopy(default) or default)
|
||||
local isDefaultAtt, statAttachment, noCache = self2.GetStatRecursive(self, self2.AttachmentTableCache, statPath, istable(statSelf) and tableCopy(statSelf) or statSelf)
|
||||
local shouldCache = not noCache and
|
||||
not (self2.StatCache_Blacklist_Real or self2.StatCache_Blacklist)[currentVersionStat] and
|
||||
not (self2.StatCache_Blacklist_Real or self2.StatCache_Blacklist)[statPath[1]] and
|
||||
not (ccv and ccv:GetBool())
|
||||
|
||||
if istable(statAttachment) and istable(statSelf) and not dontMergeTables then
|
||||
statSelf = table.Merge(tableCopy(statSelf), statAttachment)
|
||||
else
|
||||
statSelf = statAttachment
|
||||
end
|
||||
|
||||
if shouldCache and not self2.ignore_stat_cache then
|
||||
if not isDefault or not isDefaultAtt then
|
||||
self2.StatCache[currentVersionStat] = statSelf
|
||||
end
|
||||
|
||||
self2.StatCache2[currentVersionStat] = true
|
||||
end
|
||||
|
||||
--local getstat = hook.Run("TFA_GetStat", self, currentVersionStat, statSelf)
|
||||
--if getstat ~= nil then return translate(getstat) end
|
||||
|
||||
return translate(statSelf)
|
||||
end
|
||||
224
lua/weapons/tfa_gun_base/common/ttt.lua
Normal file
224
lua/weapons/tfa_gun_base/common/ttt.lua
Normal file
@@ -0,0 +1,224 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
-- Copyright (c) 2018-2020 TFA Base Devs
|
||||
|
||||
-- Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
-- of this software and associated documentation files (the "Software"), to deal
|
||||
-- in the Software without restriction, including without limitation the rights
|
||||
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
-- copies of the Software, and to permit persons to whom the Software is
|
||||
-- furnished to do so, subject to the following conditions:
|
||||
|
||||
-- The above copyright notice and this permission notice shall be included in all
|
||||
-- copies or substantial portions of the Software.
|
||||
|
||||
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
-- SOFTWARE.
|
||||
|
||||
SWEP.HeadshotMultiplier = 2.7
|
||||
SWEP.StoredAmmo = 0
|
||||
SWEP.IsDropped = false
|
||||
SWEP.DeploySpeed = 1.4
|
||||
SWEP.fingerprints = {}
|
||||
|
||||
-- crosshair
|
||||
if CLIENT then
|
||||
-- luacheck: globals LANG Key
|
||||
local SafeTranslation = function(x) return x end
|
||||
local GetPTranslation = LANG and LANG.GetParamTranslation or SafeTranslation
|
||||
|
||||
-- Many non-gun weapons benefit from some help
|
||||
local help_spec = {
|
||||
text = "",
|
||||
font = "TabLarge",
|
||||
xalign = TEXT_ALIGN_CENTER
|
||||
}
|
||||
|
||||
function SWEP:DrawHelp()
|
||||
local data = self.HUDHelp
|
||||
local translate = data.translatable
|
||||
local primary = data.primary
|
||||
local secondary = data.secondary
|
||||
|
||||
if translate then
|
||||
primary = primary and GetPTranslation(primary, data.translate_params)
|
||||
secondary = secondary and GetPTranslation(secondary, data.translate_params)
|
||||
end
|
||||
|
||||
help_spec.pos = {ScrW() / 2.0, ScrH() - 40}
|
||||
help_spec.text = secondary or primary
|
||||
draw.TextShadow(help_spec, 2)
|
||||
|
||||
-- if no secondary exists, primary is drawn at the bottom and no top line
|
||||
-- is drawn
|
||||
if secondary then
|
||||
help_spec.pos[2] = ScrH() - 60
|
||||
help_spec.text = primary
|
||||
draw.TextShadow(help_spec, 2)
|
||||
end
|
||||
end
|
||||
|
||||
local function SafeKey(binding, default)
|
||||
local b = input.LookupBinding(binding)
|
||||
if not b then return default end
|
||||
|
||||
return string.upper(b)
|
||||
end
|
||||
|
||||
local Key = Key or SafeKey
|
||||
|
||||
-- mousebuttons are enough for most weapons
|
||||
local default_key_params = {
|
||||
primaryfire = Key("+attack", "LEFT MOUSE"),
|
||||
secondaryfire = Key("+attack2", "RIGHT MOUSE"),
|
||||
usekey = Key("+use", "USE")
|
||||
}
|
||||
|
||||
function SWEP:AddHUDHelp(primary_text, secondary_text, translate, extra_params)
|
||||
extra_params = extra_params or {}
|
||||
|
||||
self.HUDHelp = {
|
||||
primary = primary_text,
|
||||
secondary = secondary_text,
|
||||
translatable = translate,
|
||||
translate_params = table.Merge(extra_params, default_key_params)
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:GetHeadshotMultiplier(victim, dmginfo)
|
||||
return self.HeadshotMultiplier or 2
|
||||
end
|
||||
|
||||
function SWEP:IsEquipment()
|
||||
-- luacheck: globals WEPS
|
||||
if WEPS and WEPS.IsEquipment then
|
||||
local val = WEPS.IsEquipment(self)
|
||||
|
||||
if val ~= nil then
|
||||
return val
|
||||
else
|
||||
return false
|
||||
end
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
-- The OnDrop() hook is useless for this as it happens AFTER the drop. OwnerChange
|
||||
-- does not occur when a drop happens for some reason. Hence this thing.
|
||||
function SWEP:PreDrop()
|
||||
if not IsValid(self) then return end
|
||||
if not self.Ammo1 then return end
|
||||
|
||||
if SERVER and IsValid(self:GetOwner()) and self.Primary_TFA.Ammo ~= "none" then
|
||||
local ammo = self:Ammo1()
|
||||
|
||||
-- Do not drop ammo if we have another gun that uses this type
|
||||
for _, w in pairs(self:GetOwner():GetWeapons()) do
|
||||
if IsValid(w) and w ~= self and w:GetPrimaryAmmoType() == self:GetPrimaryAmmoType() then
|
||||
ammo = 0
|
||||
end
|
||||
end
|
||||
|
||||
self.StoredAmmo = ammo
|
||||
|
||||
if ammo > 0 then
|
||||
self:GetOwner():RemoveAmmo(ammo, self.Primary_TFA.Ammo)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:DampenDrop()
|
||||
if not IsValid(self) then return end
|
||||
-- For some reason gmod drops guns on death at a speed of 400 units, which
|
||||
-- catapults them away from the body. Here we want people to actually be able
|
||||
-- to find a given corpse's weapon, so we override the velocity here and call
|
||||
-- this when dropping guns on death.
|
||||
local phys = self:GetPhysicsObject()
|
||||
|
||||
if IsValid(phys) then
|
||||
phys:SetVelocityInstantaneous(Vector(0, 0, -75) + phys:GetVelocity() * 0.001)
|
||||
phys:AddAngleVelocity(phys:GetAngleVelocity() * -0.99)
|
||||
end
|
||||
end
|
||||
|
||||
local SF_WEAPON_START_CONSTRAINED = 1
|
||||
|
||||
-- Picked up by player. Transfer of stored ammo and such.
|
||||
function SWEP:EquipTTT(newowner)
|
||||
if engine.ActiveGamemode() ~= "terrortown" then return end
|
||||
|
||||
if SERVER then
|
||||
if self:IsOnFire() then
|
||||
self:Extinguish()
|
||||
end
|
||||
|
||||
self.fingerprints = self.fingerprints or {}
|
||||
|
||||
if not table.HasValue(self.fingerprints, newowner) then
|
||||
table.insert(self.fingerprints, newowner)
|
||||
end
|
||||
|
||||
if self:HasSpawnFlags(SF_WEAPON_START_CONSTRAINED) then
|
||||
-- If this weapon started constrained, unset that spawnflag, or the
|
||||
-- weapon will be re-constrained and float
|
||||
local flags = self:GetSpawnFlags()
|
||||
local newflags = bit.band(flags, bit.bnot(SF_WEAPON_START_CONSTRAINED))
|
||||
self:SetKeyValue("spawnflags", newflags)
|
||||
end
|
||||
end
|
||||
|
||||
if not self.Ammo1 then return end
|
||||
|
||||
if SERVER and IsValid(newowner) and self.StoredAmmo > 0 and self.Primary_TFA.Ammo ~= "none" then
|
||||
local ammo = newowner:GetAmmoCount(self.Primary_TFA.Ammo)
|
||||
self.Primary_TFA.ClipMax = self.Primary_TFA.ClipMax or (math.abs(self.Primary_TFA.ClipSize) * 4)
|
||||
local given = math.min(self.StoredAmmo, self.Primary_TFA.ClipMax - ammo)
|
||||
newowner:GiveAmmo(given, self.Primary_TFA.Ammo)
|
||||
self.StoredAmmo = 0
|
||||
end
|
||||
end
|
||||
|
||||
-- We were bought as special equipment, some weapons will want to do something
|
||||
-- extra for their buyer
|
||||
function SWEP:WasBought(buyer)
|
||||
end
|
||||
|
||||
function SWEP:DyingShot()
|
||||
local fired = false
|
||||
-- if self:GetIronSightsProgress() and self:GetIronSightsProgress() > 0.01 then
|
||||
self:SetIronSightsRaw(false)
|
||||
if self:GetNextPrimaryFire() > CurTime() then return fired end
|
||||
|
||||
-- Owner should still be alive here
|
||||
if IsValid(self:GetOwner()) then
|
||||
local punch = self.Primary_TFA.Recoil or 5
|
||||
-- Punch view to disorient aim before firing dying shot
|
||||
local eyeang = self:GetOwner():EyeAngles()
|
||||
eyeang.pitch = eyeang.pitch - math.Rand(-punch, punch)
|
||||
eyeang.yaw = eyeang.yaw - math.Rand(-punch, punch)
|
||||
self:GetOwner():SetEyeAngles(eyeang)
|
||||
MsgN(self:GetOwner():Nick() .. " fired his DYING SHOT")
|
||||
self:GetOwner().dying_wep = self
|
||||
self:PrimaryAttack()
|
||||
fired = true
|
||||
end
|
||||
-- end
|
||||
|
||||
return fired
|
||||
end
|
||||
1202
lua/weapons/tfa_gun_base/common/utils.lua
Normal file
1202
lua/weapons/tfa_gun_base/common/utils.lua
Normal file
File diff suppressed because it is too large
Load Diff
107
lua/weapons/tfa_gun_base/common/viewmodel.lua
Normal file
107
lua/weapons/tfa_gun_base/common/viewmodel.lua
Normal file
@@ -0,0 +1,107 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
-- Copyright (c) 2018-2020 TFA Base Devs
|
||||
|
||||
-- Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
-- of this software and associated documentation files (the "Software"), to deal
|
||||
-- in the Software without restriction, including without limitation the rights
|
||||
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
-- copies of the Software, and to permit persons to whom the Software is
|
||||
-- furnished to do so, subject to the following conditions:
|
||||
|
||||
-- The above copyright notice and this permission notice shall be included in all
|
||||
-- copies or substantial portions of the Software.
|
||||
|
||||
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
-- SOFTWARE.
|
||||
|
||||
local vector_origin = Vector()
|
||||
local angle_zero = Angle()
|
||||
|
||||
SWEP.WeaponLength = 0
|
||||
|
||||
SWEP.NearWallVector = Vector(0.091287083923817, -0.4564354121685, -0.18257416784763)
|
||||
SWEP.NearWallVectorADS = Vector(0, 0, 0)
|
||||
|
||||
SWEP.ViewModelPunchPitchMultiplier = 0.5
|
||||
SWEP.ViewModelPunchPitchMultiplier_IronSights = 0.09
|
||||
|
||||
SWEP.ViewModelPunch_MaxVertialOffset = 3
|
||||
SWEP.ViewModelPunch_MaxVertialOffset_IronSights = 1.95
|
||||
SWEP.ViewModelPunch_VertialMultiplier = 1
|
||||
SWEP.ViewModelPunch_VertialMultiplier_IronSights = 0.25
|
||||
|
||||
SWEP.ViewModelPunchYawMultiplier = 0.6
|
||||
SWEP.ViewModelPunchYawMultiplier_IronSights = 0.25
|
||||
|
||||
local onevec = Vector(1, 1, 1)
|
||||
|
||||
local function RBP(vm)
|
||||
local bc = vm:GetBoneCount()
|
||||
if not bc or bc <= 0 then return end
|
||||
|
||||
for i = 0, bc do
|
||||
vm:ManipulateBoneScale(i, onevec)
|
||||
vm:ManipulateBoneAngles(i, angle_zero)
|
||||
vm:ManipulateBonePosition(i, vector_origin)
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:ApplyViewModelModifications()
|
||||
local self2 = self:GetTable()
|
||||
if not self2.VMIV(self) then return end
|
||||
|
||||
local vm = self2.OwnerViewModel
|
||||
|
||||
local bgcount = #(vm:GetBodyGroups() or {})
|
||||
local ViewModelBodygroups = self2.GetStatRawL(self, "ViewModelBodygroups")
|
||||
local bgt = ViewModelBodygroups or self2.Bodygroups or {}
|
||||
|
||||
for i = 0, bgcount - 1 do
|
||||
vm:SetBodygroup(i, bgt[i] or 0)
|
||||
end
|
||||
|
||||
local skinind = self2.GetStatL(self, "Skin")
|
||||
|
||||
if skinind and isnumber(skinind) then
|
||||
vm:SetSkin(skinind)
|
||||
self:SetSkin(skinind)
|
||||
end
|
||||
|
||||
self2.ClearMaterialCache(self)
|
||||
end
|
||||
|
||||
function SWEP:ResetViewModelModifications()
|
||||
local self2 = self:GetTable()
|
||||
if not self2.VMIV(self) then return end
|
||||
|
||||
local vm = self2.OwnerViewModel
|
||||
|
||||
RBP(vm)
|
||||
|
||||
vm:SetSkin(0)
|
||||
|
||||
local matcount = #(vm:GetMaterials() or {})
|
||||
|
||||
for i = 0, matcount do
|
||||
vm:SetSubMaterial(i, "")
|
||||
end
|
||||
|
||||
for i = 0, #(vm:GetBodyGroups() or {}) - 1 do
|
||||
vm:SetBodygroup(i, 0)
|
||||
end
|
||||
end
|
||||
162
lua/weapons/tfa_gun_base/init.lua
Normal file
162
lua/weapons/tfa_gun_base/init.lua
Normal file
@@ -0,0 +1,162 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
-- Copyright (c) 2018-2020 TFA Base Devs
|
||||
|
||||
-- Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
-- of this software and associated documentation files (the "Software"), to deal
|
||||
-- in the Software without restriction, including without limitation the rights
|
||||
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
-- copies of the Software, and to permit persons to whom the Software is
|
||||
-- furnished to do so, subject to the following conditions:
|
||||
|
||||
-- The above copyright notice and this permission notice shall be included in all
|
||||
-- copies or substantial portions of the Software.
|
||||
|
||||
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
-- SOFTWARE.
|
||||
|
||||
include("shared.lua")
|
||||
|
||||
include("common/ai_translations.lua")
|
||||
include("common/anims.lua")
|
||||
include("common/autodetection.lua")
|
||||
include("common/utils.lua")
|
||||
include("common/stat.lua")
|
||||
include("common/attachments.lua")
|
||||
include("common/bullet.lua")
|
||||
include("common/effects.lua")
|
||||
include("common/calc.lua")
|
||||
include("common/akimbo.lua")
|
||||
include("common/events.lua")
|
||||
include("common/nzombies.lua")
|
||||
include("common/ttt.lua")
|
||||
include("common/viewmodel.lua")
|
||||
include("common/skins.lua")
|
||||
|
||||
AddCSLuaFile("common/ai_translations.lua")
|
||||
AddCSLuaFile("common/anims.lua")
|
||||
AddCSLuaFile("common/autodetection.lua")
|
||||
AddCSLuaFile("common/utils.lua")
|
||||
AddCSLuaFile("common/stat.lua")
|
||||
AddCSLuaFile("common/attachments.lua")
|
||||
AddCSLuaFile("common/bullet.lua")
|
||||
AddCSLuaFile("common/effects.lua")
|
||||
AddCSLuaFile("common/calc.lua")
|
||||
AddCSLuaFile("common/akimbo.lua")
|
||||
AddCSLuaFile("common/events.lua")
|
||||
AddCSLuaFile("common/nzombies.lua")
|
||||
AddCSLuaFile("common/ttt.lua")
|
||||
AddCSLuaFile("common/viewmodel.lua")
|
||||
AddCSLuaFile("common/skins.lua")
|
||||
|
||||
AddCSLuaFile("shared.lua")
|
||||
AddCSLuaFile("cl_init.lua")
|
||||
|
||||
AddCSLuaFile("client/effects.lua")
|
||||
AddCSLuaFile("client/viewbob.lua")
|
||||
AddCSLuaFile("client/hud.lua")
|
||||
AddCSLuaFile("client/mods.lua")
|
||||
AddCSLuaFile("client/laser.lua")
|
||||
AddCSLuaFile("client/fov.lua")
|
||||
AddCSLuaFile("client/flashlight.lua")
|
||||
AddCSLuaFile("client/viewmodel.lua")
|
||||
AddCSLuaFile("client/bobcode.lua")
|
||||
|
||||
SWEP.Weight = 60 -- Decides whether we should switch from/to this
|
||||
SWEP.AutoSwitchTo = true -- Auto switch to
|
||||
SWEP.AutoSwitchFrom = true -- Auto switch from
|
||||
|
||||
local sv_tfa_npc_burst = GetConVar("sv_tfa_npc_burst")
|
||||
|
||||
function SWEP:NPCShoot_Primary()
|
||||
if self:Clip1() <= 0 and self:GetMaxClip1() > 0 then
|
||||
self:GetOwner():SetSchedule(SCHED_RELOAD)
|
||||
return
|
||||
end
|
||||
|
||||
return self:PrimaryAttack()
|
||||
end
|
||||
|
||||
function SWEP:GetNPCRestTimes()
|
||||
if sv_tfa_npc_burst:GetBool() or self:GetStatL("NPCBurstOverride", false) then
|
||||
return self:GetStatL("NPCMinRest", self:GetFireDelay()), self:GetStatL("NPCMaxRest", self:GetFireDelay() * 2)
|
||||
end
|
||||
|
||||
if self:GetStatL("Primary.Automatic") then
|
||||
return 0, 0
|
||||
else
|
||||
return self:GetFireDelay(), self:GetFireDelay() * 2
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:GetNPCBurstSettings()
|
||||
if sv_tfa_npc_burst:GetBool() or self:GetStatL("NPCBurstOverride", false) then
|
||||
return self:GetStatL("NPCMinBurst", 1), self:GetStatL("NPCMinBurst", 6), self:GetStatL("NPCBurstDelay", self:GetFireDelay() * self:GetMaxBurst())
|
||||
end
|
||||
|
||||
if self:GetMaxClip1() > 0 then
|
||||
local burst = self:GetMaxBurst()
|
||||
local value = math.ceil(self:Clip1() / burst)
|
||||
local delay = self:GetFireDelay() * burst
|
||||
|
||||
if self:GetStatL("Primary.Automatic") then
|
||||
return math.min(4, value), math.min(12, value), delay
|
||||
else
|
||||
return 1, math.min(4, value), delay
|
||||
end
|
||||
else
|
||||
return 1, 30, self:GetFireDelay() * self:GetMaxBurst()
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:GetNPCBulletSpread()
|
||||
return 1 -- we handle this manually, in calculate cone, recoil and shootbullet
|
||||
end
|
||||
|
||||
function SWEP:CanBePickedUpByNPCs()
|
||||
return true
|
||||
end
|
||||
|
||||
local sv_tfa_npc_randomize_atts = GetConVar("sv_tfa_npc_randomize_atts")
|
||||
|
||||
function SWEP:Equip(...)
|
||||
local owner = self:GetOwner()
|
||||
|
||||
if owner:IsNPC() then
|
||||
self.IsNPCOwned = true
|
||||
|
||||
if not self.IsFirstEquip and sv_tfa_npc_randomize_atts:GetBool() then
|
||||
self:RandomizeAttachments(true)
|
||||
end
|
||||
|
||||
local function closure()
|
||||
self:NPCWeaponThinkHook()
|
||||
end
|
||||
|
||||
hook.Add("TFA_NPCWeaponThink", self, function()
|
||||
ProtectedCall(closure)
|
||||
end)
|
||||
else
|
||||
self.IsNPCOwned = false
|
||||
end
|
||||
|
||||
self.IsFirstEquip = true
|
||||
self.OwnerViewModel = nil
|
||||
self:EquipTTT(...)
|
||||
end
|
||||
|
||||
TFA.FillMissingMetaValues(SWEP)
|
||||
2390
lua/weapons/tfa_gun_base/shared.lua
Normal file
2390
lua/weapons/tfa_gun_base/shared.lua
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user