mirror of
https://github.com/lifestorm/wnsrc.git
synced 2025-12-16 21:33:46 +03:00
2391 lines
73 KiB
Lua
2391 lines
73 KiB
Lua
|
|
--[[
|
||
|
|
| This file was obtained through the combined efforts
|
||
|
|
| of Madbluntz & Plymouth Antiquarian Society.
|
||
|
|
|
|
||
|
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||
|
|
| Maloy, DrPepper10 @ RIP, Atle!
|
||
|
|
|
|
||
|
|
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||
|
|
--]]
|
||
|
|
|
||
|
|
|
||
|
|
-- 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.Category = "" --The category. Please, just choose something generic or something I've already done if you plan on only doing like one swep.
|
||
|
|
SWEP.Author = "TheForgottenArchitect"
|
||
|
|
SWEP.Contact = "theforgottenarchitect"
|
||
|
|
SWEP.Purpose = ""
|
||
|
|
SWEP.Instructions = ""
|
||
|
|
SWEP.DrawCrosshair = true
|
||
|
|
SWEP.DrawCrosshairIronSights = false
|
||
|
|
SWEP.ViewModelFOV = 65
|
||
|
|
SWEP.ViewModelFlip = false
|
||
|
|
SWEP.Skin = 0 --Viewmodel skin
|
||
|
|
SWEP.Spawnable = false
|
||
|
|
SWEP.IsTFAWeapon = true
|
||
|
|
|
||
|
|
SWEP.LoopedReload = false
|
||
|
|
SWEP.ShotgunEmptyAnim = false
|
||
|
|
SWEP.ShotgunEmptyAnim_Shell = true
|
||
|
|
SWEP.ShotgunStartAnimShell = false --shotgun start anim inserts shell
|
||
|
|
|
||
|
|
SWEP.Secondary.IronSightsEnabled = true
|
||
|
|
|
||
|
|
SWEP.RegularMoveSpeedMultiplier = 1
|
||
|
|
|
||
|
|
SWEP.FireSoundAffectedByClipSize = true
|
||
|
|
|
||
|
|
SWEP.Primary.Damage = -1
|
||
|
|
SWEP.Primary.DamageTypeHandled = true --true will handle damagetype in base
|
||
|
|
SWEP.Primary.NumShots = 1
|
||
|
|
SWEP.Primary.Force = -1
|
||
|
|
SWEP.Primary.Knockback = -1
|
||
|
|
SWEP.Primary.Recoil = 1
|
||
|
|
SWEP.Primary.RPM = 600
|
||
|
|
SWEP.Primary.RPM_Semi = -1
|
||
|
|
SWEP.Primary.RPM_Burst = -1
|
||
|
|
SWEP.Primary.StaticRecoilFactor = 0.5
|
||
|
|
SWEP.Primary.KickUp = 0.5
|
||
|
|
SWEP.Primary.KickDown = 0.5
|
||
|
|
SWEP.Primary.KickRight = 0.5
|
||
|
|
SWEP.Primary.KickHorizontal = 0.5
|
||
|
|
SWEP.Primary.DamageType = nil
|
||
|
|
SWEP.Primary.Ammo = "smg1"
|
||
|
|
SWEP.Primary.AmmoConsumption = 1
|
||
|
|
SWEP.Primary.Spread = 0
|
||
|
|
SWEP.Primary.DisplaySpread = true
|
||
|
|
SWEP.Primary.SpreadMultiplierMax = -1 --How far the spread can expand when you shoot.
|
||
|
|
SWEP.Primary.SpreadIncrement = -1 --What percentage of the modifier is added on, per shot.
|
||
|
|
SWEP.Primary.SpreadRecovery = -1 --How much the spread recovers, per second.
|
||
|
|
SWEP.Primary.SpreadRecoveryDelay = 0
|
||
|
|
SWEP.Primary.IronAccuracy = 0
|
||
|
|
SWEP.Primary.Range = -1--1200
|
||
|
|
SWEP.Primary.RangeFalloff = -1--0.5
|
||
|
|
SWEP.Primary.PenetrationMultiplier = 1
|
||
|
|
SWEP.Primary.DryFireDelay = nil
|
||
|
|
|
||
|
|
--[[Actual clientside values]]--
|
||
|
|
|
||
|
|
SWEP.DrawAmmo = true -- Should draw the default HL2 ammo counter
|
||
|
|
SWEP.DrawWeaponInfoBox = false -- Should draw the weapon info box
|
||
|
|
SWEP.BounceWeaponIcon = false -- Should the weapon icon bounce?
|
||
|
|
|
||
|
|
local sv_tfa_jamming = GetConVar("sv_tfa_jamming")
|
||
|
|
local sv_tfa_jamming_mult = GetConVar("sv_tfa_jamming_mult")
|
||
|
|
local sv_tfa_jamming_factor = GetConVar("sv_tfa_jamming_factor")
|
||
|
|
local sv_tfa_jamming_factor_inc = GetConVar("sv_tfa_jamming_factor_inc")
|
||
|
|
|
||
|
|
-- RP owners always like realism, so this feature might be something they like. Enable it for them!
|
||
|
|
TFA_AUTOJAMMING_ENABLED = string.find(engine.ActiveGamemode(), 'rp') or
|
||
|
|
string.find(engine.ActiveGamemode(), 'roleplay') or
|
||
|
|
string.find(engine.ActiveGamemode(), 'nutscript') or
|
||
|
|
string.find(engine.ActiveGamemode(), 'serious') or
|
||
|
|
TFA_ENABLE_JAMMING_BY_DEFAULT
|
||
|
|
|
||
|
|
SWEP.CanJam = tobool(TFA_AUTOJAMMING_ENABLED)
|
||
|
|
|
||
|
|
SWEP.JamChance = 0.04
|
||
|
|
SWEP.JamFactor = 0.06
|
||
|
|
|
||
|
|
SWEP.BoltAction = false --Unscope/sight after you shoot?
|
||
|
|
SWEP.BoltAction_Forced = false
|
||
|
|
SWEP.Scoped = false --Draw a scope overlay?
|
||
|
|
SWEP.ScopeOverlayThreshold = 0.875 --Percentage you have to be sighted in to see the scope.
|
||
|
|
SWEP.BoltTimerOffset = 0.25 --How long you stay sighted in after shooting, with a bolt action.
|
||
|
|
SWEP.ScopeScale = 0.5
|
||
|
|
SWEP.ReticleScale = 0.7
|
||
|
|
|
||
|
|
SWEP.MuzzleAttachment = "1"
|
||
|
|
SWEP.ShellAttachment = "2"
|
||
|
|
|
||
|
|
SWEP.MuzzleFlashEnabled = true
|
||
|
|
SWEP.MuzzleFlashEffect = nil
|
||
|
|
SWEP.MuzzleFlashEffectSilenced = "tfa_muzzleflash_silenced"
|
||
|
|
SWEP.CustomMuzzleFlash = true
|
||
|
|
|
||
|
|
SWEP.EjectionSmokeEnabled = true
|
||
|
|
|
||
|
|
SWEP.LuaShellEject = false
|
||
|
|
SWEP.LuaShellEjectDelay = 0
|
||
|
|
SWEP.LuaShellEffect = nil --Defaults to blowback
|
||
|
|
|
||
|
|
SWEP.SmokeParticle = nil --Smoke particle (ID within the PCF), defaults to something else based on holdtype
|
||
|
|
|
||
|
|
SWEP.StatusLengthOverride = {} --Changes the status delay of a given animation; only used on reloads. Otherwise, use SequenceLengthOverride or one of the others
|
||
|
|
SWEP.SequenceLengthOverride = {} --Changes both the status delay and the nextprimaryfire of a given animation
|
||
|
|
SWEP.SequenceTimeOverride = {} --Like above but changes animation length to a target
|
||
|
|
SWEP.SequenceRateOverride = {} --Like above but scales animation length rather than being absolute
|
||
|
|
|
||
|
|
SWEP.BlowbackEnabled = false --Enable Blowback?
|
||
|
|
SWEP.BlowbackVector = Vector(0, -1, 0) --Vector to move bone <or root> relative to bone <or view> orientation.
|
||
|
|
SWEP.BlowbackCurrentRoot = 0 --Amount of blowback currently, for root
|
||
|
|
SWEP.BlowbackCurrent = 0 --Amount of blowback currently, for bones
|
||
|
|
SWEP.BlowbackBoneMods = nil --Viewmodel bone mods via SWEP Creation Kit
|
||
|
|
SWEP.Blowback_Only_Iron = true --Only do blowback on ironsights
|
||
|
|
SWEP.Blowback_PistolMode = false --Do we recover from blowback when empty?
|
||
|
|
SWEP.BlowbackAllowAnimation = false
|
||
|
|
|
||
|
|
SWEP.ProceduralHolsterEnabled = nil
|
||
|
|
SWEP.ProceduralHolsterTime = 0.3
|
||
|
|
SWEP.ProceduralHolsterPosition = Vector(3, 0, -5)
|
||
|
|
SWEP.ProceduralHolsterAngle = Vector(-40, -30, 10)
|
||
|
|
|
||
|
|
SWEP.IsProceduralReloadBased = false --Do we reload using lua instead of a .mdl animation
|
||
|
|
SWEP.ProceduralReloadTime = 1 --Time to take when procedurally reloading, including transition in (but not out)
|
||
|
|
|
||
|
|
SWEP.Blowback_PistolMode_Disabled = {
|
||
|
|
[ACT_VM_RELOAD] = true,
|
||
|
|
[ACT_VM_RELOAD_EMPTY] = true,
|
||
|
|
[ACT_VM_DRAW_EMPTY] = true,
|
||
|
|
[ACT_VM_IDLE_EMPTY] = true,
|
||
|
|
[ACT_VM_HOLSTER_EMPTY] = true,
|
||
|
|
[ACT_VM_DRYFIRE] = true,
|
||
|
|
[ACT_VM_FIDGET] = true,
|
||
|
|
[ACT_VM_FIDGET_EMPTY] = true
|
||
|
|
}
|
||
|
|
|
||
|
|
SWEP.Blowback_Shell_Enabled = true
|
||
|
|
SWEP.Blowback_Shell_Effect = "ShellEject"
|
||
|
|
|
||
|
|
SWEP.Secondary.Ammo = ""
|
||
|
|
SWEP.Secondary.ClipSize = -1
|
||
|
|
SWEP.Secondary.DefaultClip = 0
|
||
|
|
|
||
|
|
SWEP.Sights_Mode = TFA.Enum.LOCOMOTION_LUA -- ANI = mdl, HYBRID = lua but continue idle, Lua = stop mdl animation
|
||
|
|
SWEP.Sprint_Mode = TFA.Enum.LOCOMOTION_LUA -- ANI = mdl, HYBRID = ani + lua, Lua = lua only
|
||
|
|
SWEP.Walk_Mode = TFA.Enum.LOCOMOTION_LUA -- ANI = mdl, HYBRID = ani + lua, Lua = lua only
|
||
|
|
SWEP.Customize_Mode = TFA.Enum.LOCOMOTION_LUA -- ANI = mdl, HYBRID = ani + lua, Lua = lua only
|
||
|
|
SWEP.SprintFOVOffset = 5
|
||
|
|
SWEP.Idle_Mode = TFA.Enum.IDLE_BOTH --TFA.Enum.IDLE_DISABLED = no idle, TFA.Enum.IDLE_LUA = lua idle, TFA.Enum.IDLE_ANI = mdl idle, TFA.Enum.IDLE_BOTH = TFA.Enum.IDLE_ANI + TFA.Enum.IDLE_LUA
|
||
|
|
SWEP.Idle_Blend = 0.25 --Start an idle this far early into the end of a transition
|
||
|
|
SWEP.Idle_Smooth = 0.05 --Start an idle this far early into the end of another animation
|
||
|
|
|
||
|
|
SWEP.IronSightTime = 0.3
|
||
|
|
SWEP.IronSightsSensitivity = 1
|
||
|
|
|
||
|
|
SWEP.InspectPosDef = Vector(9.779, -11.658, -2.241)
|
||
|
|
SWEP.InspectAngDef = Vector(24.622, 42.915, 15.477)
|
||
|
|
|
||
|
|
SWEP.SprintViewModelPosition = Vector(0,0,0)
|
||
|
|
SWEP.SprintViewModelAngle = Vector(0,0,0)
|
||
|
|
SWEP.AllowSprintAttack = false --Shoot while sprinting?
|
||
|
|
|
||
|
|
SWEP.CrouchViewModelPosition = Vector(0, -1, -.5)
|
||
|
|
SWEP.CrouchViewModelAngle = Vector(0, 0, 0)
|
||
|
|
|
||
|
|
SWEP.Primary.RecoilLUT_IronSightsMult = 0.5
|
||
|
|
SWEP.Primary.RecoilLUT_AnglePunchMult = 0.25
|
||
|
|
SWEP.Primary.RecoilLUT_ViewPunchMult = 1
|
||
|
|
|
||
|
|
SWEP.EventTable = {}
|
||
|
|
|
||
|
|
SWEP.RTMaterialOverride = nil
|
||
|
|
SWEP.RTOpaque = false
|
||
|
|
SWEP.RTCode = nil--function(self) return end
|
||
|
|
SWEP.RTBGBlur = true
|
||
|
|
|
||
|
|
SWEP.ViewModelPosition = Vector(0,0,0)
|
||
|
|
SWEP.ViewModelAngle = Vector(0,0,0)
|
||
|
|
SWEP.CameraOffset = Angle(0, 0, 0)
|
||
|
|
SWEP.AdditiveViewModelPosition = true
|
||
|
|
|
||
|
|
SWEP.AllowIronSightsDoF = true
|
||
|
|
|
||
|
|
SWEP.Primary.DisplayFalloff = true
|
||
|
|
|
||
|
|
SWEP.IronAnimation = {
|
||
|
|
--[[
|
||
|
|
["in"] = {
|
||
|
|
["type"] = TFA.Enum.ANIMATION_SEQ, --Sequence or act
|
||
|
|
["value"] = "Idle_To_Iron", --Number for act, String/Number for sequence
|
||
|
|
["value_empty"] = "Idle_To_Iron_Dry",
|
||
|
|
["transition"] = true
|
||
|
|
}, --Inward transition
|
||
|
|
["loop"] = {
|
||
|
|
["type"] = TFA.Enum.ANIMATION_SEQ, --Sequence or act
|
||
|
|
["value"] = "Idle_Iron", --Number for act, String/Number for sequence
|
||
|
|
["value_empty"] = "Idle_Iron_Dry"
|
||
|
|
}, --Looping Animation
|
||
|
|
["out"] = {
|
||
|
|
["type"] = TFA.Enum.ANIMATION_SEQ, --Sequence or act
|
||
|
|
["value"] = "Iron_To_Idle", --Number for act, String/Number for sequence
|
||
|
|
["value_empty"] = "Iron_To_Idle_Dry",
|
||
|
|
["transition"] = true
|
||
|
|
}, --Outward transition
|
||
|
|
["shoot"] = {
|
||
|
|
["type"] = TFA.Enum.ANIMATION_SEQ, --Sequence or act
|
||
|
|
["value"] = "Fire_Iron", --Number for act, String/Number for sequence
|
||
|
|
["value_last"] = "Fire_Iron_Last",
|
||
|
|
["value_empty"] = "Fire_Iron_Dry"
|
||
|
|
} --What do you think
|
||
|
|
]]--
|
||
|
|
}
|
||
|
|
|
||
|
|
SWEP.SprintAnimation = {
|
||
|
|
--[[
|
||
|
|
["in"] = {
|
||
|
|
["type"] = TFA.Enum.ANIMATION_SEQ, --Sequence or act
|
||
|
|
["value"] = "Idle_to_Sprint", --Number for act, String/Number for sequence
|
||
|
|
["value_empty"] = "Idle_to_Sprint_Empty",
|
||
|
|
["transition"] = true
|
||
|
|
}, --Inward transition
|
||
|
|
["loop"] = {
|
||
|
|
["type"] = TFA.Enum.ANIMATION_SEQ, --Sequence or act
|
||
|
|
["value"] = "Sprint_", --Number for act, String/Number for sequence
|
||
|
|
["value_empty"] = "Sprint_Empty_",
|
||
|
|
["is_idle"] = true
|
||
|
|
},--looping animation
|
||
|
|
["out"] = {
|
||
|
|
["type"] = TFA.Enum.ANIMATION_SEQ, --Sequence or act
|
||
|
|
["value"] = "Sprint_to_Idle", --Number for act, String/Number for sequence
|
||
|
|
["value_empty"] = "Sprint_to_Idle_Empty",
|
||
|
|
["transition"] = true
|
||
|
|
} --Outward transition
|
||
|
|
]]--
|
||
|
|
}
|
||
|
|
|
||
|
|
SWEP.ShootAnimation = {--[[
|
||
|
|
["in"] = {
|
||
|
|
["type"] = TFA.Enum.ANIMATION_SEQ, --Sequence or act
|
||
|
|
["value"] = "shoot_loop_start", --Number for act, String/Number for sequence
|
||
|
|
["value_is"] = "shoot_loop_iron_start"
|
||
|
|
},
|
||
|
|
["loop"] = {
|
||
|
|
["type"] = TFA.Enum.ANIMATION_SEQ, --Sequence or act
|
||
|
|
["value"] = "shoot_loop", --Number for act, String/Number for sequence
|
||
|
|
["value_is"] = "shoot_loop_iron",
|
||
|
|
["is_idle"] = true
|
||
|
|
},
|
||
|
|
["out"] = {
|
||
|
|
["type"] = TFA.Enum.ANIMATION_SEQ, --Sequence or act
|
||
|
|
["value"] = "shoot_loop_end", --Number for act, String/Number for sequence
|
||
|
|
["value_is"] = "shoot_loop_iron_end"
|
||
|
|
}]]--
|
||
|
|
}
|
||
|
|
|
||
|
|
SWEP.FirstDeployEnabled = nil--Force first deploy enabled
|
||
|
|
|
||
|
|
--[[Dont edit under this unless you know what u r doing]]
|
||
|
|
|
||
|
|
SWEP.IronSightsProgress = 0
|
||
|
|
SWEP.CLIronSightsProgress = 0
|
||
|
|
SWEP.SprintProgress = 0
|
||
|
|
SWEP.WalkProgress = 0
|
||
|
|
SWEP.SpreadRatio = 0
|
||
|
|
SWEP.CrouchingRatio = 0
|
||
|
|
SWEP.SmokeParticles = {
|
||
|
|
pistol = "tfa_ins2_weapon_muzzle_smoke",
|
||
|
|
smg = "tfa_ins2_weapon_muzzle_smoke",
|
||
|
|
grenade = "tfa_ins2_weapon_muzzle_smoke",
|
||
|
|
ar2 = "tfa_ins2_weapon_muzzle_smoke",
|
||
|
|
shotgun = "tfa_ins2_weapon_muzzle_smoke",
|
||
|
|
rpg = "tfa_ins2_weapon_muzzle_smoke",
|
||
|
|
physgun = "tfa_ins2_weapon_muzzle_smoke",
|
||
|
|
crossbow = "tfa_ins2_weapon_muzzle_smoke",
|
||
|
|
melee = "tfa_ins2_weapon_muzzle_smoke",
|
||
|
|
slam = "tfa_ins2_weapon_muzzle_smoke",
|
||
|
|
normal = "tfa_ins2_weapon_muzzle_smoke",
|
||
|
|
melee2 = "tfa_ins2_weapon_muzzle_smoke",
|
||
|
|
knife = "tfa_ins2_weapon_muzzle_smoke",
|
||
|
|
duel = "tfa_ins2_weapon_muzzle_smoke",
|
||
|
|
camera = "tfa_ins2_weapon_muzzle_smoke",
|
||
|
|
magic = "tfa_ins2_weapon_muzzle_smoke",
|
||
|
|
revolver = "tfa_ins2_weapon_muzzle_smoke",
|
||
|
|
silenced = "tfa_ins2_weapon_muzzle_smoke"
|
||
|
|
}
|
||
|
|
--[[ SWEP.SmokeParticles = {
|
||
|
|
pistol = "weapon_muzzle_smoke",
|
||
|
|
smg = "weapon_muzzle_smoke",
|
||
|
|
grenade = "weapon_muzzle_smoke",
|
||
|
|
ar2 = "weapon_muzzle_smoke",
|
||
|
|
shotgun = "weapon_muzzle_smoke_long",
|
||
|
|
rpg = "weapon_muzzle_smoke_long",
|
||
|
|
physgun = "weapon_muzzle_smoke_long",
|
||
|
|
crossbow = "weapon_muzzle_smoke_long",
|
||
|
|
melee = "weapon_muzzle_smoke",
|
||
|
|
slam = "weapon_muzzle_smoke",
|
||
|
|
normal = "weapon_muzzle_smoke",
|
||
|
|
melee2 = "weapon_muzzle_smoke",
|
||
|
|
knife = "weapon_muzzle_smoke",
|
||
|
|
duel = "weapon_muzzle_smoke",
|
||
|
|
camera = "weapon_muzzle_smoke",
|
||
|
|
magic = "weapon_muzzle_smoke",
|
||
|
|
revolver = "weapon_muzzle_smoke_long",
|
||
|
|
silenced = "weapon_muzzle_smoke"
|
||
|
|
}--]]
|
||
|
|
--[[
|
||
|
|
SWEP.SmokeParticles = {
|
||
|
|
pistol = "smoke_trail_controlled",
|
||
|
|
smg = "smoke_trail_tfa",
|
||
|
|
grenade = "smoke_trail_tfa",
|
||
|
|
ar2 = "smoke_trail_tfa",
|
||
|
|
shotgun = "smoke_trail_wild",
|
||
|
|
rpg = "smoke_trail_tfa",
|
||
|
|
physgun = "smoke_trail_tfa",
|
||
|
|
crossbow = "smoke_trail_tfa",
|
||
|
|
melee = "smoke_trail_tfa",
|
||
|
|
slam = "smoke_trail_tfa",
|
||
|
|
normal = "smoke_trail_tfa",
|
||
|
|
melee2 = "smoke_trail_tfa",
|
||
|
|
knife = "smoke_trail_tfa",
|
||
|
|
duel = "smoke_trail_tfa",
|
||
|
|
camera = "smoke_trail_tfa",
|
||
|
|
magic = "smoke_trail_tfa",
|
||
|
|
revolver = "smoke_trail_tfa",
|
||
|
|
silenced = "smoke_trail_controlled"
|
||
|
|
}
|
||
|
|
]]--
|
||
|
|
|
||
|
|
SWEP.Inspecting = false
|
||
|
|
SWEP.InspectingProgress = 0
|
||
|
|
SWEP.LuaShellRequestTime = -1
|
||
|
|
SWEP.BobScale = 0
|
||
|
|
SWEP.SwayScale = 0
|
||
|
|
SWEP.BoltDelay = 1
|
||
|
|
SWEP.ProceduralHolsterProgress = 0
|
||
|
|
SWEP.BurstCount = 0
|
||
|
|
SWEP.DefaultFOV = 90
|
||
|
|
SWEP.m_WeaponDeploySpeed = 255
|
||
|
|
|
||
|
|
--[[ Localize Functions ]]
|
||
|
|
local function l_Lerp(v, f, t)
|
||
|
|
return f + (t - f) * v
|
||
|
|
end
|
||
|
|
local l_mathApproach = math.Approach
|
||
|
|
local l_CT = CurTime
|
||
|
|
--[[Frequently Reused Local Vars]]
|
||
|
|
local stat --Weapon status
|
||
|
|
local ct = 0--Curtime, frametime, real frametime
|
||
|
|
local sp = game.SinglePlayer() --Singleplayer
|
||
|
|
local developer = GetConVar("developer")
|
||
|
|
|
||
|
|
function SWEP:NetworkVarTFA(typeIn, nameIn)
|
||
|
|
if not self.TrackedDTTypes then
|
||
|
|
self.TrackedDTTypes = {
|
||
|
|
Angle = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31},
|
||
|
|
Bool = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31},
|
||
|
|
Entity = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31},
|
||
|
|
Float = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31},
|
||
|
|
Int = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31},
|
||
|
|
String = {0, 1, 2, 3},
|
||
|
|
Vector = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31},
|
||
|
|
}
|
||
|
|
|
||
|
|
if istable(self.dt) then
|
||
|
|
local meta = getmetatable(self.dt)
|
||
|
|
|
||
|
|
if istable(meta) and isfunction(meta.__index) then
|
||
|
|
local name, value = debug.getupvalue(meta.__index, 1)
|
||
|
|
|
||
|
|
if name == "datatable" and istable(value) then
|
||
|
|
for variableName, variableData in SortedPairs(value) do
|
||
|
|
if istable(variableData) and isstring(variableData.typename) and isnumber(variableData.index) then
|
||
|
|
local trackedData = self.TrackedDTTypes[variableData.typename]
|
||
|
|
|
||
|
|
if trackedData then
|
||
|
|
table.RemoveByValue(trackedData, variableData.index)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
if not self.TrackedDTTypes[typeIn] then
|
||
|
|
error("Variable type " .. typeIn .. " is invalid")
|
||
|
|
end
|
||
|
|
|
||
|
|
local gatherindex = table.remove(self.TrackedDTTypes[typeIn], 1)
|
||
|
|
|
||
|
|
if gatherindex then
|
||
|
|
(self["NetworkVar_TFA"] or self["NetworkVar"])(self, typeIn, gatherindex, nameIn)
|
||
|
|
return
|
||
|
|
end
|
||
|
|
|
||
|
|
local get = self["GetNW2" .. typeIn]
|
||
|
|
local set = self["SetNW2" .. typeIn]
|
||
|
|
|
||
|
|
self["Set" .. nameIn] = function(_self, value)
|
||
|
|
set(_self, nameIn, value)
|
||
|
|
end
|
||
|
|
|
||
|
|
self["Get" .. nameIn] = function(_self, def)
|
||
|
|
return get(_self, nameIn, def)
|
||
|
|
end
|
||
|
|
|
||
|
|
if developer:GetBool() then
|
||
|
|
print("[TFA Base] developer 1: Variable " .. nameIn .. " can not use DTVars due to " .. typeIn .. " index exhaust")
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
local IsFirstTimePredicted = IsFirstTimePredicted
|
||
|
|
|
||
|
|
--[[
|
||
|
|
Function Name: SetupDataTables
|
||
|
|
Syntax: Should not be manually called.
|
||
|
|
Returns: Nothing. Simple sets up DTVars to be networked.
|
||
|
|
Purpose: Networking.
|
||
|
|
]]
|
||
|
|
function SWEP:SetupDataTables()
|
||
|
|
self.TrackedDTTypes = nil
|
||
|
|
self.NetworkVar_TFA = self.NetworkVar
|
||
|
|
|
||
|
|
--self:NetworkVarTFA("Bool", "IronSights")
|
||
|
|
self:NetworkVarTFA("Bool", "IronSightsRaw")
|
||
|
|
self:NetworkVarTFA("Bool", "Sprinting")
|
||
|
|
self:NetworkVarTFA("Bool", "Silenced")
|
||
|
|
self:NetworkVarTFA("Bool", "ReloadLoopCancel")
|
||
|
|
self:NetworkVarTFA("Bool", "Walking")
|
||
|
|
self:NetworkVarTFA("Bool", "Customizing")
|
||
|
|
|
||
|
|
self.GetShotgunCancel = self.GetReloadLoopCancel
|
||
|
|
self.SetShotgunCancel = self.SetReloadLoopCancel
|
||
|
|
|
||
|
|
self:NetworkVarTFA("Bool", "FlashlightEnabled")
|
||
|
|
self:NetworkVarTFA("Bool", "Jammed")
|
||
|
|
self:NetworkVarTFA("Bool", "FirstDeployEvent")
|
||
|
|
self:NetworkVarTFA("Bool", "IsCyclingSafety")
|
||
|
|
self:NetworkVarTFA("Bool", "SafetyCycleAnimated")
|
||
|
|
self:NetworkVarTFA("Bool", "HasPlayedEmptyClick")
|
||
|
|
|
||
|
|
self:NetworkVarTFA("Float", "StatusEnd")
|
||
|
|
self:NetworkVarTFA("Float", "NextIdleAnim")
|
||
|
|
self:NetworkVarTFA("Float", "NextLoopSoundCheck")
|
||
|
|
self:NetworkVarTFA("Float", "JamFactor")
|
||
|
|
self:NetworkVarTFA("Float", "EventTimer")
|
||
|
|
self:NetworkVarTFA("Float", "LastGunFire")
|
||
|
|
|
||
|
|
self:NetworkVarTFA("Int", "StatusRaw")
|
||
|
|
self:NetworkVarTFA("Int", "FireMode")
|
||
|
|
self:NetworkVarTFA("Int", "LastActivity")
|
||
|
|
self:NetworkVarTFA("Int", "BurstCount")
|
||
|
|
self:NetworkVarTFA("Int", "ShootStatus")
|
||
|
|
self:NetworkVarTFA("Int", "EventStatus1")
|
||
|
|
self:NetworkVarTFA("Int", "EventStatus2")
|
||
|
|
self:NetworkVarTFA("Int", "EventStatus3")
|
||
|
|
self:NetworkVarTFA("Int", "EventStatus4")
|
||
|
|
self:NetworkVarTFA("Int", "EventStatus5")
|
||
|
|
self:NetworkVarTFA("Int", "EventStatus6")
|
||
|
|
self:NetworkVarTFA("Int", "EventStatus7")
|
||
|
|
self:NetworkVarTFA("Int", "EventStatus8")
|
||
|
|
|
||
|
|
self:NetworkVarTFA("Bool", "RecoilLoop")
|
||
|
|
self:NetworkVarTFA("Bool", "RecoilThink")
|
||
|
|
|
||
|
|
self:NetworkVarTFA("Float", "RecoilInProgress")
|
||
|
|
self:NetworkVarTFA("Float", "RecoilInWait")
|
||
|
|
self:NetworkVarTFA("Float", "RecoilLoopProgress")
|
||
|
|
self:NetworkVarTFA("Float", "RecoilLoopWait")
|
||
|
|
self:NetworkVarTFA("Float", "RecoilOutProgress")
|
||
|
|
|
||
|
|
self:NetworkVarTFA("Float", "LastRecoil")
|
||
|
|
|
||
|
|
if not self.get_event_status_lut then
|
||
|
|
self.get_event_status_lut = {}
|
||
|
|
self.set_event_status_lut = {}
|
||
|
|
|
||
|
|
for i = 1, 8 do
|
||
|
|
self.get_event_status_lut[i] = self['GetEventStatus' .. i]
|
||
|
|
self.set_event_status_lut[i] = self['SetEventStatus' .. i]
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
self:NetworkVarTFA("Entity", "SwapTarget")
|
||
|
|
|
||
|
|
self:NetworkVarNotify("Customizing", self.CustomizingUpdated)
|
||
|
|
|
||
|
|
self:NetworkVarTFA("Float", "SpreadRatio")
|
||
|
|
self:NetworkVarTFA("Float", "IronSightsProgress")
|
||
|
|
self:NetworkVarTFA("Float", "ProceduralHolsterProgress")
|
||
|
|
self:NetworkVarTFA("Float", "InspectingProgress")
|
||
|
|
self:NetworkVarTFA("Float", "JumpRatio")
|
||
|
|
self:NetworkVarTFA("Float", "CrouchingRatio")
|
||
|
|
|
||
|
|
self:NetworkVarTFA("Float", "ViewPunchBuild")
|
||
|
|
self:NetworkVarTFA("Float", "ViewPunchP")
|
||
|
|
self:NetworkVarTFA("Float", "ViewPunchY")
|
||
|
|
|
||
|
|
self:NetworkVarTFA("Float", "SprintProgress")
|
||
|
|
self:NetworkVarTFA("Float", "WalkProgress")
|
||
|
|
self:NetworkVarTFA("Float", "LastVelocity")
|
||
|
|
|
||
|
|
self:NetworkVarTFA("Int", "AnimCycle")
|
||
|
|
|
||
|
|
self:NetworkVarTFA("Vector", "QueuedRecoil")
|
||
|
|
self:NetworkVarTFA("Float", "PrevRecoilAngleTime")
|
||
|
|
self:NetworkVarTFA("Angle", "PrevRecoilAngle")
|
||
|
|
|
||
|
|
self:NetworkVarTFA("Bool", "CustomizeUpdated")
|
||
|
|
self:NetworkVarTFA("Bool", "IronSightsOldFinal")
|
||
|
|
|
||
|
|
function self.NetworkVar(self2, typeIn, slotIn, nameIn)
|
||
|
|
return self2:NetworkVarTFA(typeIn, nameIn)
|
||
|
|
end
|
||
|
|
|
||
|
|
self:NetworkVarTFA("Float", "StatusStart")
|
||
|
|
self:NetworkVarTFA("Float", "LastSafetyShoot")
|
||
|
|
|
||
|
|
self:NetworkVarTFA("Int", "LastSequence")
|
||
|
|
self:NetworkVarTFA("Int", "DownButtons")
|
||
|
|
self:NetworkVarTFA("Int", "LastPressedButtons")
|
||
|
|
|
||
|
|
self:NetworkVarTFA("Float", "LastReloadPressed")
|
||
|
|
|
||
|
|
self:NetworkVarTFA("Float", "LastIronSightsPressed")
|
||
|
|
|
||
|
|
self.GetStatus = self.GetStatusRaw
|
||
|
|
self.GetIronSights = self.GetIronSightsOldFinal
|
||
|
|
self.GetIronSightsDirect = self.GetIronSightsOldFinal
|
||
|
|
|
||
|
|
hook.Run("TFA_SetupDataTables", self)
|
||
|
|
end
|
||
|
|
|
||
|
|
function SWEP:GetStatusProgress(unpredicted)
|
||
|
|
if self:GetStatus() == TFA.Enum.STATUS_IDLE then return 1 end
|
||
|
|
local StatusStart = self:GetStatusStart()
|
||
|
|
|
||
|
|
if StatusStart <= 0 then return end
|
||
|
|
local StatusEnd = self:GetStatusEnd()
|
||
|
|
|
||
|
|
if StatusStart > StatusEnd then return 1 end
|
||
|
|
|
||
|
|
local time = unpredicted and (l_CT() + (self.CurTimePredictionAdvance or 0)) or l_CT()
|
||
|
|
if StatusStart >= time then return 0 end
|
||
|
|
if StatusEnd <= time then return 1 end
|
||
|
|
|
||
|
|
return (time - StatusStart) / (StatusEnd - StatusStart)
|
||
|
|
end
|
||
|
|
|
||
|
|
function SWEP:GetStatusProgressTime(unpredicted)
|
||
|
|
if self:GetStatus() == TFA.Enum.STATUS_IDLE then return 0 end
|
||
|
|
local StatusStart = self:GetStatusStart()
|
||
|
|
|
||
|
|
if StatusStart <= 0 then return end
|
||
|
|
local StatusEnd = self:GetStatusEnd()
|
||
|
|
|
||
|
|
if StatusStart > StatusEnd then return 0 end
|
||
|
|
|
||
|
|
local time = unpredicted and (l_CT() + (self.CurTimePredictionAdvance or 0)) or l_CT()
|
||
|
|
if StatusEnd <= time then return 0 end
|
||
|
|
|
||
|
|
return StatusEnd - time
|
||
|
|
end
|
||
|
|
|
||
|
|
function SWEP:SetStatus(statusIn, timeOn)
|
||
|
|
self:SetStatusRaw(statusIn)
|
||
|
|
self:SetStatusStart(l_CT())
|
||
|
|
|
||
|
|
if timeOn ~= nil then
|
||
|
|
self:SetStatusEnd(timeOn)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
function SWEP:ScheduleStatus(statusIn, timeFor)
|
||
|
|
self:SetStatusRaw(statusIn)
|
||
|
|
local time = l_CT()
|
||
|
|
self:SetStatusStart(time)
|
||
|
|
self:SetStatusEnd(time + timeFor)
|
||
|
|
end
|
||
|
|
|
||
|
|
function SWEP:ExtendStatus(timeFor)
|
||
|
|
self:SetStatusEnd(self:GetStatusEnd() + timeFor)
|
||
|
|
end
|
||
|
|
|
||
|
|
function SWEP:ExtendStatusTo(timeFor)
|
||
|
|
self:SetStatusEnd(math.max(self:GetStatusEnd(), timeFor))
|
||
|
|
end
|
||
|
|
|
||
|
|
--[[
|
||
|
|
Function Name: Initialize
|
||
|
|
Syntax: Should not be normally called.
|
||
|
|
Notes: Called after actual SWEP code, but before deploy, and only once.
|
||
|
|
Returns: Nothing. Sets the intial values for the SWEP when it's created.
|
||
|
|
Purpose: Standard SWEP Function
|
||
|
|
]]
|
||
|
|
|
||
|
|
local PistolHoldTypes = {
|
||
|
|
["pistol"] = true,
|
||
|
|
["357"] = true,
|
||
|
|
["revolver"] = true
|
||
|
|
}
|
||
|
|
local MeleeHoldTypes = {
|
||
|
|
["melee"] = true,
|
||
|
|
["melee2"] = true,
|
||
|
|
["knife"] = true
|
||
|
|
}
|
||
|
|
|
||
|
|
local patch_blacklist
|
||
|
|
|
||
|
|
do
|
||
|
|
local string_sub = string.sub
|
||
|
|
|
||
|
|
function patch_blacklist(input, structure_version)
|
||
|
|
local target = {}
|
||
|
|
|
||
|
|
for key in pairs(input) do
|
||
|
|
target[TFA.RemapStatPath(key, TFA.LatestDataVersion, structure_version)] = true
|
||
|
|
end
|
||
|
|
|
||
|
|
table.Empty(input)
|
||
|
|
|
||
|
|
setmetatable(input, {
|
||
|
|
__index = target,
|
||
|
|
__newindex = function(_, key, value)
|
||
|
|
target[TFA.RemapStatPath(key, TFA.LatestDataVersion, structure_version)] = value
|
||
|
|
end
|
||
|
|
})
|
||
|
|
|
||
|
|
return target
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
function SWEP:Initialize()
|
||
|
|
local self2 = self:GetTable()
|
||
|
|
|
||
|
|
if self2.HasInitialized then
|
||
|
|
ErrorNoHalt(debug.traceback("SWEP:Initialize was called out of order", 2) .. "\n")
|
||
|
|
return
|
||
|
|
end
|
||
|
|
|
||
|
|
self2.HasInitialized = true
|
||
|
|
|
||
|
|
--TFA.MigrateStructure(self, self2, self:GetClass(), true)
|
||
|
|
|
||
|
|
hook.Run("TFA_PreInitialize", self)
|
||
|
|
|
||
|
|
self2.DrawCrosshairDefault = self2.DrawCrosshair
|
||
|
|
|
||
|
|
if not self2.BobScaleCustom or self2.BobScaleCustom <= 0 then
|
||
|
|
self2.BobScaleCustom = 1
|
||
|
|
end
|
||
|
|
|
||
|
|
TFA.UnfoldBaseClass(self2.Primary)
|
||
|
|
TFA.UnfoldBaseClass(self2.Secondary)
|
||
|
|
|
||
|
|
TFA.UnfoldBaseClass(self2.Primary.PenetrationMaterials)
|
||
|
|
|
||
|
|
TFA.UnfoldBaseClass(self2.AttachmentTableOverride)
|
||
|
|
|
||
|
|
--[[for k, v in pairs(self2.AttachmentTableOverride) do
|
||
|
|
if istable(v) and k ~= "BaseClass" then
|
||
|
|
TFA.MigrateStructure(self, v, self:GetClass(), false)
|
||
|
|
end
|
||
|
|
end]]
|
||
|
|
|
||
|
|
self2.Primary.BaseClass = nil
|
||
|
|
self2.Secondary.BaseClass = nil
|
||
|
|
|
||
|
|
if self2.Primary.DisplayIronSpread == nil then
|
||
|
|
self2.Primary.DisplayIronSpread = self2.Primary.DisplaySpread
|
||
|
|
end
|
||
|
|
|
||
|
|
self2.Primary_TFA = table.Copy(self2.Primary)
|
||
|
|
self2.Secondary_TFA = table.Copy(self2.Secondary)
|
||
|
|
|
||
|
|
self2.BobScale = 0
|
||
|
|
self2.SwayScaleCustom = 1
|
||
|
|
self2.SwayScale = 0
|
||
|
|
self2.SetSilenced(self, self2.Silenced or self2.DefaultSilenced)
|
||
|
|
self2.Silenced = self2.Silenced or self2.DefaultSilenced
|
||
|
|
self2.InitializeAnims(self)
|
||
|
|
self2.InitializeMaterialTable(self)
|
||
|
|
self2.PatchAmmoTypeAccessors(self)
|
||
|
|
self2.FixRPM(self)
|
||
|
|
self2.FixIdles(self)
|
||
|
|
self2.FixIS(self)
|
||
|
|
self2.FixCone(self)
|
||
|
|
self2.FixProjectile(self)
|
||
|
|
self2.AutoDetectMuzzle(self)
|
||
|
|
self2.AutoDetectDamage(self)
|
||
|
|
self2.AutoDetectDamageType(self)
|
||
|
|
self2.AutoDetectForce(self)
|
||
|
|
self2.AutoDetectPenetrationPower(self)
|
||
|
|
self2.AutoDetectKnockback(self)
|
||
|
|
self2.AutoDetectSpread(self)
|
||
|
|
self2.AutoDetectRange(self)
|
||
|
|
self2.AutoDetectLowAmmoSound(self)
|
||
|
|
self2.IconFix(self)
|
||
|
|
self2.CreateFireModes(self)
|
||
|
|
self2.FixAkimbo(self)
|
||
|
|
self2.FixSprintAnimBob(self)
|
||
|
|
self2.FixWalkAnimBob(self)
|
||
|
|
|
||
|
|
table.Merge(self2.Primary, self2.Primary_TFA)
|
||
|
|
table.Merge(self2.Secondary, self2.Secondary_TFA)
|
||
|
|
|
||
|
|
TFA.UnfoldBaseClass(self2.StatCache_Blacklist)
|
||
|
|
self2.StatCache_Blacklist_Real = patch_blacklist(self2.StatCache_Blacklist, self2.TFADataVersion)
|
||
|
|
|
||
|
|
TFA.UnfoldBaseClass(self2.Attachments)
|
||
|
|
TFA.UnfoldBaseClass(self:GetStatRaw("ViewModelElements", TFA.LatestDataVersion))
|
||
|
|
TFA.UnfoldBaseClass(self2.ViewModelBoneMods)
|
||
|
|
TFA.UnfoldBaseClass(self2.EventTable)
|
||
|
|
|
||
|
|
TFA.UnfoldBaseClass(self2.Blowback_PistolMode_Disabled)
|
||
|
|
TFA.UnfoldBaseClass(self2.IronAnimation)
|
||
|
|
TFA.UnfoldBaseClass(self2.SprintAnimation)
|
||
|
|
TFA.UnfoldBaseClass(self2.ShootAnimation)
|
||
|
|
TFA.UnfoldBaseClass(self2.SmokeParticles)
|
||
|
|
|
||
|
|
self2.ClearStatCache(self)
|
||
|
|
|
||
|
|
self2.InitAttachments(self)
|
||
|
|
|
||
|
|
self2.WorldModelBodygroups = self:GetStatRawL("WorldModelBodygroups")
|
||
|
|
self2.ViewModelBodygroups = self:GetStatRawL("ViewModelBodygroups")
|
||
|
|
|
||
|
|
if not self:GetStatRawL("AimingDownSightsSpeedMultiplier") then
|
||
|
|
self:SetStatRawL("AimingDownSightsSpeedMultiplier", self:GetStatRawL("RegularMoveSpeedMultiplier") * 0.8)
|
||
|
|
end
|
||
|
|
|
||
|
|
if isnumber(self2.GetStatL(self, "Skin")) then
|
||
|
|
self:SetSkin(self:GetStatL("Skin"))
|
||
|
|
end
|
||
|
|
|
||
|
|
self:SetNextLoopSoundCheck(-1)
|
||
|
|
self:SetShootStatus(TFA.Enum.SHOOT_IDLE)
|
||
|
|
|
||
|
|
if SERVER and self:GetOwner():IsNPC() then
|
||
|
|
local seq = self:GetOwner():LookupSequence("shootp1")
|
||
|
|
|
||
|
|
if MeleeHoldTypes[self2.DefaultHoldType or self2.HoldType] then
|
||
|
|
if self:GetOwner():GetSequenceName(seq) == "shootp1" then
|
||
|
|
self:SetWeaponHoldType("melee2")
|
||
|
|
else
|
||
|
|
self:SetWeaponHoldType("melee")
|
||
|
|
end
|
||
|
|
elseif PistolHoldTypes[self2.DefaultHoldType or self2.HoldType] then
|
||
|
|
if self:GetOwner():GetSequenceName(seq) == "shootp1" then
|
||
|
|
self:SetWeaponHoldType("pistol")
|
||
|
|
else
|
||
|
|
self:SetWeaponHoldType("smg")
|
||
|
|
end
|
||
|
|
else
|
||
|
|
self:SetWeaponHoldType(self2.DefaultHoldType or self2.HoldType)
|
||
|
|
end
|
||
|
|
|
||
|
|
if self:GetOwner():GetClass() == "npc_citizen" then
|
||
|
|
self:GetOwner():Fire( "DisableWeaponPickup", "", 0 )
|
||
|
|
end
|
||
|
|
|
||
|
|
self:GetOwner():SetKeyValue("spawnflags", "256")
|
||
|
|
|
||
|
|
return
|
||
|
|
end
|
||
|
|
|
||
|
|
hook.Run("TFA_Initialize", self)
|
||
|
|
end
|
||
|
|
|
||
|
|
function SWEP:NPCWeaponThinkHook()
|
||
|
|
local self2 = self:GetTable()
|
||
|
|
|
||
|
|
if not self:GetOwner():IsNPC() then
|
||
|
|
hook.Remove("TFA_NPCWeaponThink", self)
|
||
|
|
return
|
||
|
|
end
|
||
|
|
|
||
|
|
self2.Think(self)
|
||
|
|
end
|
||
|
|
|
||
|
|
--[[
|
||
|
|
Function Name: Deploy
|
||
|
|
Syntax: self:Deploy()
|
||
|
|
Notes: Called after self:Initialize(). Called each time you draw the gun. This is also essential to clearing out old networked vars and resetting them.
|
||
|
|
Returns: True/False to allow quickswitch. Why not? You should really return true.
|
||
|
|
Purpose: Standard SWEP Function
|
||
|
|
]]
|
||
|
|
|
||
|
|
function SWEP:Deploy()
|
||
|
|
local self2 = self:GetTable()
|
||
|
|
hook.Run("TFA_PreDeploy", self)
|
||
|
|
local ply = self:GetOwner()
|
||
|
|
|
||
|
|
self2.IsNPCOwned = ply:IsNPC()
|
||
|
|
|
||
|
|
if IsValid(ply) and IsValid(ply:GetViewModel()) then
|
||
|
|
self2.OwnerViewModel = ply:GetViewModel()
|
||
|
|
end
|
||
|
|
|
||
|
|
if SERVER and self:GetStatL("FlashlightAttachment", 0) > 0 and IsValid(ply) and ply:IsPlayer() and ply:FlashlightIsOn() then
|
||
|
|
if not self:GetFlashlightEnabled() then
|
||
|
|
self:ToggleFlashlight(true)
|
||
|
|
end
|
||
|
|
|
||
|
|
ply:Flashlight(false)
|
||
|
|
end
|
||
|
|
|
||
|
|
if not self:VMIV() then
|
||
|
|
print("Invalid VM on owner: ")
|
||
|
|
print(ply)
|
||
|
|
|
||
|
|
return
|
||
|
|
end
|
||
|
|
|
||
|
|
if not self2.HasDetectedValidAnimations then
|
||
|
|
self:CacheAnimations()
|
||
|
|
end
|
||
|
|
|
||
|
|
local _, tanim, ttype = self:ChooseDrawAnim()
|
||
|
|
|
||
|
|
if sp then
|
||
|
|
self:CallOnClient("ChooseDrawAnim", "")
|
||
|
|
end
|
||
|
|
|
||
|
|
local len = self:GetActivityLength(tanim, false, ttype)
|
||
|
|
|
||
|
|
self:ScheduleStatus(TFA.Enum.STATUS_DRAW, len)
|
||
|
|
self:SetFirstDeployEvent(true)
|
||
|
|
|
||
|
|
self:SetNextPrimaryFire(ct + len)
|
||
|
|
self:SetIronSightsRaw(false)
|
||
|
|
|
||
|
|
if not self:GetStatL("PumpAction") then
|
||
|
|
self:SetReloadLoopCancel( false )
|
||
|
|
end
|
||
|
|
|
||
|
|
self:SetBurstCount(0)
|
||
|
|
|
||
|
|
self:SetIronSightsProgress(0)
|
||
|
|
self:SetSprintProgress(0)
|
||
|
|
self:SetInspectingProgress(0)
|
||
|
|
self:SetProceduralHolsterProgress(0)
|
||
|
|
|
||
|
|
if self:GetCustomizing() then
|
||
|
|
self:ToggleCustomize()
|
||
|
|
end
|
||
|
|
|
||
|
|
self2.DefaultFOV = TFADUSKFOV or ( IsValid(ply) and ply:GetFOV() or 90 )
|
||
|
|
|
||
|
|
self:ApplyViewModelModifications()
|
||
|
|
self:CallOnClient("ApplyViewModelModifications")
|
||
|
|
|
||
|
|
local v = hook.Run("TFA_Deploy", self)
|
||
|
|
|
||
|
|
if v ~= nil then return v end
|
||
|
|
|
||
|
|
return true
|
||
|
|
end
|
||
|
|
|
||
|
|
--[[
|
||
|
|
Function Name: Holster
|
||
|
|
Syntax: self:Holster( weapon entity to switch to )
|
||
|
|
Notes: This is kind of broken. I had to manually select the new weapon using ply:ConCommand. Returning true is simply not enough. This is also essential to clearing out old networked vars and resetting them.
|
||
|
|
Returns: True/False to allow holster. Useful for animations.
|
||
|
|
Purpose: Standard SWEP Function
|
||
|
|
]]
|
||
|
|
function SWEP:Holster(target)
|
||
|
|
local self2 = self:GetTable()
|
||
|
|
|
||
|
|
local v = hook.Run("TFA_PreHolster", self, target)
|
||
|
|
if v ~= nil then return v end
|
||
|
|
|
||
|
|
if not IsValid(target) then
|
||
|
|
self2.InspectingProgress = 0
|
||
|
|
|
||
|
|
return true
|
||
|
|
end
|
||
|
|
|
||
|
|
if not IsValid(self) then return end
|
||
|
|
|
||
|
|
stat = self:GetStatus()
|
||
|
|
|
||
|
|
if not TFA.Enum.HolsterStatus[stat] then
|
||
|
|
if stat == TFA.Enum.STATUS_RELOADING_WAIT and self:Clip1() <= self:GetStatL("Primary.ClipSize") and (not self:GetStatL("Primary.DisableChambering")) and (not self:GetStatL("LoopedReload")) then
|
||
|
|
self:ResetFirstDeploy()
|
||
|
|
|
||
|
|
if sp then
|
||
|
|
self:CallOnClient("ResetFirstDeploy", "")
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
local success, tanim, ttype = self:ChooseHolsterAnim()
|
||
|
|
|
||
|
|
if IsFirstTimePredicted() then
|
||
|
|
self:SetSwapTarget(target)
|
||
|
|
end
|
||
|
|
|
||
|
|
self:ScheduleStatus(TFA.Enum.STATUS_HOLSTER, success and self:GetActivityLength(tanim, false, ttype) or (self:GetStatL("ProceduralHolsterTime") / self:GetAnimationRate(ACT_VM_HOLSTER)))
|
||
|
|
|
||
|
|
return false
|
||
|
|
elseif stat == TFA.Enum.STATUS_HOLSTER_READY or stat == TFA.Enum.STATUS_HOLSTER_FINAL then
|
||
|
|
self:ResetViewModelModifications()
|
||
|
|
|
||
|
|
return true
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
function SWEP:FinishHolster()
|
||
|
|
local self2 = self:GetTable()
|
||
|
|
|
||
|
|
self:CleanParticles()
|
||
|
|
|
||
|
|
local v2 = hook.Run("TFA_Holster", self)
|
||
|
|
|
||
|
|
if self:GetOwner():IsNPC() then return end
|
||
|
|
if v2 ~= nil then return v2 end
|
||
|
|
|
||
|
|
if SERVER then
|
||
|
|
local ent = self:GetSwapTarget()
|
||
|
|
self:Holster(ent)
|
||
|
|
|
||
|
|
if IsValid(ent) and ent:IsWeapon() then
|
||
|
|
self:GetOwner():SelectWeapon(ent:GetClass())
|
||
|
|
|
||
|
|
if ent.IsTFAWeapon then
|
||
|
|
ent:ApplyViewModelModifications()
|
||
|
|
ent:CallOnClient("ApplyViewModelModifications")
|
||
|
|
end
|
||
|
|
|
||
|
|
self2.OwnerViewModel = nil
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
--[[
|
||
|
|
Function Name: OnRemove
|
||
|
|
Syntax: self:OnRemove()
|
||
|
|
Notes: Resets bone mods and cleans up.
|
||
|
|
Returns: Nil.
|
||
|
|
Purpose: Standard SWEP Function
|
||
|
|
]]
|
||
|
|
function SWEP:OnRemove()
|
||
|
|
local self2 = self:GetTable()
|
||
|
|
|
||
|
|
if self2.CleanParticles then
|
||
|
|
self2.CleanParticles(self)
|
||
|
|
end
|
||
|
|
|
||
|
|
if self2.ResetViewModelModifications then
|
||
|
|
self2.ResetViewModelModifications(self)
|
||
|
|
end
|
||
|
|
|
||
|
|
return hook.Run("TFA_OnRemove", self)
|
||
|
|
end
|
||
|
|
|
||
|
|
--[[
|
||
|
|
Function Name: OnDrop
|
||
|
|
Syntax: self:OnDrop()
|
||
|
|
Notes: Resets bone mods and cleans up.
|
||
|
|
Returns: Nil.
|
||
|
|
Purpose: Standard SWEP Function
|
||
|
|
]]
|
||
|
|
function SWEP:OnDrop()
|
||
|
|
local self2 = self:GetTable()
|
||
|
|
|
||
|
|
if self2.CleanParticles then
|
||
|
|
self2.CleanParticles(self)
|
||
|
|
end
|
||
|
|
|
||
|
|
-- if self2.ResetViewModelModifications then
|
||
|
|
-- self:ResetViewModelModifications()
|
||
|
|
-- end
|
||
|
|
|
||
|
|
return hook.Run("TFA_OnDrop", self)
|
||
|
|
end
|
||
|
|
|
||
|
|
function SWEP:OwnerChanged() -- TODO: sometimes not called after switching weapon ???
|
||
|
|
if not IsValid(self:GetOwner()) and self.ResetViewModelModifications then
|
||
|
|
self:ResetViewModelModifications()
|
||
|
|
end
|
||
|
|
|
||
|
|
if SERVER then
|
||
|
|
if self.IsNPCOwned and (not IsValid(self:GetOwner()) or not self:GetOwner():IsNPC()) then
|
||
|
|
self:SetClip1(self:GetMaxClip1())
|
||
|
|
self:SetClip2(self:GetMaxClip2())
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
--[[
|
||
|
|
Function Name: Think
|
||
|
|
Syntax: self:Think()
|
||
|
|
Returns: Nothing.
|
||
|
|
Notes: This is blank.
|
||
|
|
Purpose: Standard SWEP Function
|
||
|
|
]]
|
||
|
|
function SWEP:Think()
|
||
|
|
local self2 = self:GetTable()
|
||
|
|
self2.CalculateRatios(self)
|
||
|
|
|
||
|
|
if self:GetOwner():IsNPC() and SERVER then
|
||
|
|
if self2.ThinkNPC then self2.ThinkNPC(self) end
|
||
|
|
self2.Think2(self, false)
|
||
|
|
end
|
||
|
|
|
||
|
|
stat = self2.GetStatus(self)
|
||
|
|
|
||
|
|
if (not sp or SERVER) and not self:GetFirstDeployEvent() then
|
||
|
|
self2.ProcessEvents(self, sp or IsFirstTimePredicted())
|
||
|
|
end
|
||
|
|
|
||
|
|
-- backward compatibility
|
||
|
|
self2.AnimCycle = self:GetAnimCycle()
|
||
|
|
|
||
|
|
if (not sp or SERVER) and ct > self:GetNextIdleAnim() and (TFA.Enum.ReadyStatus[stat] or (stat == TFA.Enum.STATUS_SHOOTING and TFA.Enum.ShootLoopingStatus[self:GetShootStatus()])) then
|
||
|
|
self:ChooseIdleAnim()
|
||
|
|
end
|
||
|
|
|
||
|
|
self2.ProcessLoopFire(self)
|
||
|
|
end
|
||
|
|
|
||
|
|
function SWEP:PlayerThink(plyv, is_working_out_prediction_errors)
|
||
|
|
if not self:NullifyOIV() then return end
|
||
|
|
|
||
|
|
self:Think2(is_working_out_prediction_errors)
|
||
|
|
end
|
||
|
|
|
||
|
|
local sv_cheats = GetConVar("sv_cheats")
|
||
|
|
local host_timescale = GetConVar("host_timescale")
|
||
|
|
|
||
|
|
local function Clamp(a, b, c)
|
||
|
|
if a < b then return b end
|
||
|
|
if a > c then return c end
|
||
|
|
return a
|
||
|
|
end
|
||
|
|
|
||
|
|
local Lerp = Lerp
|
||
|
|
|
||
|
|
function SWEP:ShouldPlaySafetyAnim()
|
||
|
|
if self:IsSafety() then
|
||
|
|
return not self.SprintProgressUnpredicted2 or self.SprintProgressUnpredicted2 < 0.3
|
||
|
|
end
|
||
|
|
|
||
|
|
if not TFA.FriendlyEncounter then return false end
|
||
|
|
return not self:GetIronSights() and (self:GetLastGunFire() + 1 < CurTime()) and (not self.SprintProgressUnpredicted2 or self.SprintProgressUnpredicted2 < 0.3)
|
||
|
|
end
|
||
|
|
|
||
|
|
function SWEP:PlayerThinkCL(plyv)
|
||
|
|
local self2 = self:GetTable()
|
||
|
|
|
||
|
|
if not self:NullifyOIV() then return end
|
||
|
|
|
||
|
|
self:SmokePCFLighting()
|
||
|
|
|
||
|
|
if sp then
|
||
|
|
self:Think2(false)
|
||
|
|
end
|
||
|
|
|
||
|
|
local ft = RealFrameTime() * game.GetTimeScale() * (sv_cheats:GetBool() and host_timescale:GetFloat() or 1)
|
||
|
|
|
||
|
|
if self2.GetStatL(self, "BlowbackEnabled") then
|
||
|
|
if not self2.Blowback_PistolMode or self:Clip1() == -1 or self:Clip1() > 0.1 or self2.Blowback_PistolMode_Disabled[self:GetLastActivity()] or self2.Blowback_PistolMode_Disabled[self:GetLastSequence()] or self2.Blowback_PistolMode_Disabled[self:GetLastSequenceString()] then
|
||
|
|
self2.BlowbackCurrent = l_mathApproach(self2.BlowbackCurrent, 0, self2.BlowbackCurrent * ft * 15)
|
||
|
|
end
|
||
|
|
|
||
|
|
self2.BlowbackCurrentRoot = l_mathApproach(self2.BlowbackCurrentRoot, 0, self2.BlowbackCurrentRoot * ft * 15)
|
||
|
|
end
|
||
|
|
|
||
|
|
local is = self2.GetIronSights(self)
|
||
|
|
local spr = self2.GetSprinting(self)
|
||
|
|
local walk = self2.GetWalking(self)
|
||
|
|
local status = self2.GetStatus(self)
|
||
|
|
|
||
|
|
local ist = is and 1 or 0
|
||
|
|
local ist2 = TFA.Enum.ReloadStatus[self:GetStatus()] and ist * .25 or ist
|
||
|
|
|
||
|
|
local reloadBlendMult, reloadBlendMult2 = 1, 1
|
||
|
|
|
||
|
|
if not self:GetStatL("LoopedReload") and (status == TFA.Enum.STATUS_RELOADING or status == TFA.Enum.STATUS_RELOADING_WAIT) and self2.ReloadAnimationEnd and self2.ReloadAnimationStart then
|
||
|
|
local time = l_CT()
|
||
|
|
local progress = Clamp((time - self2.ReloadAnimationStart) / (self2.ReloadAnimationEnd - self2.ReloadAnimationStart), 0, 1)
|
||
|
|
|
||
|
|
reloadBlendMult = TFA.Cubic(math.max(
|
||
|
|
Clamp(progress - 0.7, 0, 0.3) / 0.3,
|
||
|
|
Clamp(0.1 - progress, 0, 0.1) / 0.1
|
||
|
|
))
|
||
|
|
|
||
|
|
reloadBlendMult2 = (1 + reloadBlendMult) / 2
|
||
|
|
elseif TFA.Enum.ReloadStatus[status] then
|
||
|
|
reloadBlendMult = 0
|
||
|
|
reloadBlendMult2 = 0.5
|
||
|
|
end
|
||
|
|
|
||
|
|
local fidgetBlendMult = 1
|
||
|
|
|
||
|
|
if status == TFA.Enum.STATUS_FIDGET then
|
||
|
|
local progress = self:GetStatusProgress(true)
|
||
|
|
|
||
|
|
fidgetBlendMult = TFA.Cubic(math.max(
|
||
|
|
Clamp(progress - 0.8, 0, 0.2) / 0.2,
|
||
|
|
Clamp(0.1 - progress, 0, 0.1) / 0.1
|
||
|
|
))
|
||
|
|
end
|
||
|
|
|
||
|
|
local sprt = spr and reloadBlendMult or 0
|
||
|
|
local sprt2 = spr and (fidgetBlendMult * reloadBlendMult) or 0
|
||
|
|
local sprt3 = spr and reloadBlendMult2 or 0
|
||
|
|
|
||
|
|
local walkt = walk and 1 or 0
|
||
|
|
|
||
|
|
local IronSightsPosition = self2.GetStatL(self, "IronSightsPosition", self2.SightsPos)
|
||
|
|
local IronSightsAngle = self2.GetStatL(self, "IronSightsAngle", self2.SightsAng)
|
||
|
|
|
||
|
|
if IronSightsPosition then
|
||
|
|
self2.IronSightsPositionCurrent = self2.IronSightsPositionCurrent or Vector(IronSightsPosition)
|
||
|
|
self2.IronSightsAngleCurrent = self2.IronSightsAngleCurrent or Vector(IronSightsAngle)
|
||
|
|
|
||
|
|
self2.IronSightsPositionCurrent.x = Lerp(ft * 11, self2.IronSightsPositionCurrent.x, IronSightsPosition.x)
|
||
|
|
self2.IronSightsPositionCurrent.y = Lerp(ft * 11, self2.IronSightsPositionCurrent.y, IronSightsPosition.y)
|
||
|
|
self2.IronSightsPositionCurrent.z = Lerp(ft * 11, self2.IronSightsPositionCurrent.z, IronSightsPosition.z)
|
||
|
|
|
||
|
|
self2.IronSightsAngleCurrent.x = Lerp(ft * 11, self2.IronSightsAngleCurrent.x, self2.IronSightsAngleCurrent.x - math.AngleDifference(self2.IronSightsAngleCurrent.x, IronSightsAngle.x))
|
||
|
|
self2.IronSightsAngleCurrent.y = Lerp(ft * 11, self2.IronSightsAngleCurrent.y, self2.IronSightsAngleCurrent.y - math.AngleDifference(self2.IronSightsAngleCurrent.y, IronSightsAngle.y))
|
||
|
|
self2.IronSightsAngleCurrent.z = Lerp(ft * 11, self2.IronSightsAngleCurrent.z, self2.IronSightsAngleCurrent.z - math.AngleDifference(self2.IronSightsAngleCurrent.z, IronSightsAngle.z))
|
||
|
|
end
|
||
|
|
|
||
|
|
local adstransitionspeed = is and (12.5 / (self:GetStatL("IronSightTime") / 0.3)) or (spr or walk) and 7.5 or 12.5
|
||
|
|
|
||
|
|
local ply = self:GetOwner()
|
||
|
|
local velocity = self2.LastUnpredictedVelocity or ply:GetVelocity()
|
||
|
|
|
||
|
|
local jr_targ = math.min(math.abs(velocity.z) / 500, 1)
|
||
|
|
self2.JumpRatioUnpredicted = l_mathApproach((self2.JumpRatioUnpredicted or 0), jr_targ, (jr_targ - (self2.JumpRatioUnpredicted or 0)) * ft * 20)
|
||
|
|
self2.CrouchingRatioUnpredicted = l_mathApproach((self2.CrouchingRatioUnpredicted or 0), ((ply:Crouching() or self2.KeyDown(self, IN_DUCK)) and ply:OnGround() and not ply:InVehicle()) and 1 or 0, ft / self2.ToCrouchTime)
|
||
|
|
|
||
|
|
self2.IronSightsProgressUnpredicted = l_mathApproach(self2.IronSightsProgressUnpredicted or 0, ist, (ist - (self2.IronSightsProgressUnpredicted or 0)) * ft * adstransitionspeed * 1.2)
|
||
|
|
self2.IronSightsProgressUnpredicted2 = l_mathApproach(self2.IronSightsProgressUnpredicted2 or 0, ist, (ist - (self2.IronSightsProgressUnpredicted2 or 0)) * ft * adstransitionspeed * 0.4)
|
||
|
|
self2.IronSightsProgressUnpredicted3 = l_mathApproach(self2.IronSightsProgressUnpredicted3 or 0, ist2, (ist2 - (self2.IronSightsProgressUnpredicted3 or 0)) * ft * adstransitionspeed * 0.7)
|
||
|
|
self2.SprintProgressUnpredicted = l_mathApproach(self2.SprintProgressUnpredicted or 0, sprt, (sprt - (self2.SprintProgressUnpredicted or 0)) * ft * adstransitionspeed)
|
||
|
|
self2.SprintProgressUnpredicted2 = l_mathApproach(self2.SprintProgressUnpredicted2 or 0, sprt2, (sprt2 - (self2.SprintProgressUnpredicted2 or 0)) * ft * adstransitionspeed)
|
||
|
|
self2.SprintProgressUnpredicted3 = l_mathApproach(self2.SprintProgressUnpredicted3 or 0, sprt3, (sprt3 - (self2.SprintProgressUnpredicted3 or 0)) * ft * adstransitionspeed)
|
||
|
|
|
||
|
|
if is and not self2.VM_IronPositionScore then
|
||
|
|
self2.VM_IronPositionScore = Clamp(self2.GetStatL(self, "ViewModelPosition"):Distance(self2.IronSightsPositionCurrent or self2.GetStatL(self, "IronSightsPosition", self2.GetStat(self, "SightsPos", vector_origin))) / 7, 0, 1)
|
||
|
|
elseif not is and self2.VM_IronPositionScore and self2.IronSightsProgressUnpredicted2 <= 0.08 then
|
||
|
|
self2.VM_IronPositionScore = nil
|
||
|
|
end
|
||
|
|
|
||
|
|
if self2.IronSightsProgressUnpredicted2 >= 0.8 and not self2.VM_IsScopedIn then
|
||
|
|
self2.VM_IsScopedIn = true
|
||
|
|
--elseif self2.IronSightsProgressUnpredicted2 <= 0.1 and self2.VM_IsScopedIn then
|
||
|
|
elseif self2.IronSightsProgressUnpredicted2 <= 0.15 then
|
||
|
|
self2.VM_IsScopedIn = false
|
||
|
|
end
|
||
|
|
|
||
|
|
local customizingTarget = self:GetCustomizing() and 1 or 0
|
||
|
|
self2.CustomizingProgressUnpredicted = l_mathApproach((self2.CustomizingProgressUnpredicted or 0), customizingTarget, (customizingTarget - (self2.CustomizingProgressUnpredicted or 0)) * ft * 5)
|
||
|
|
|
||
|
|
self2.WalkProgressUnpredicted = l_mathApproach((self2.WalkProgressUnpredicted or 0), walkt, (walkt - (self2.WalkProgressUnpredicted or 0)) * ft * adstransitionspeed)
|
||
|
|
|
||
|
|
if status ~= TFA.Enum.STATUS_FIREMODE or not self:GetIsCyclingSafety() then
|
||
|
|
local safetyTarget = self:ShouldPlaySafetyAnim() and (fidgetBlendMult * reloadBlendMult) or 0
|
||
|
|
self2.SafetyProgressUnpredicted = l_mathApproach(self2.SafetyProgressUnpredicted or 0, safetyTarget, (safetyTarget - (self2.SafetyProgressUnpredicted or 0)) * ft * adstransitionspeed * 0.7)
|
||
|
|
elseif status == TFA.Enum.STATUS_FIREMODE and self:GetIsCyclingSafety() then
|
||
|
|
if not self:ShouldPlaySafetyAnim() then
|
||
|
|
local safetyTarget = 0
|
||
|
|
|
||
|
|
if self:GetSafetyCycleAnimated() then
|
||
|
|
self2.SafetyProgressUnpredicted = l_mathApproach(self2.SafetyProgressUnpredicted or 0, safetyTarget, (safetyTarget - (self2.SafetyProgressUnpredicted or 0)) * ft * adstransitionspeed * 1.1)
|
||
|
|
else
|
||
|
|
self2.SafetyProgressUnpredicted = l_mathApproach(self2.SafetyProgressUnpredicted or 0, safetyTarget, (safetyTarget - (self2.SafetyProgressUnpredicted or 0)) * ft * adstransitionspeed)
|
||
|
|
end
|
||
|
|
else
|
||
|
|
local safetyTarget = fidgetBlendMult * reloadBlendMult
|
||
|
|
|
||
|
|
if not self:GetSafetyCycleAnimated() then
|
||
|
|
self2.SafetyProgressUnpredicted = l_mathApproach(self2.SafetyProgressUnpredicted or 0, safetyTarget, (safetyTarget - (self2.SafetyProgressUnpredicted or 0)) * ft * adstransitionspeed * 0.7)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
local UnPredictedCurTime = UnPredictedCurTime
|
||
|
|
|
||
|
|
--[[
|
||
|
|
Function Name: Think2
|
||
|
|
Syntax: self:Think2(). Called from Think.
|
||
|
|
Returns: Nothing.
|
||
|
|
Notes: Essential for calling other important functions.
|
||
|
|
Purpose: Standard SWEP Function
|
||
|
|
]]
|
||
|
|
function SWEP:Think2(is_working_out_prediction_errors)
|
||
|
|
local self2 = self:GetTable()
|
||
|
|
|
||
|
|
ct = l_CT()
|
||
|
|
|
||
|
|
if not is_working_out_prediction_errors then
|
||
|
|
if CLIENT then
|
||
|
|
self2.CurTimePredictionAdvance = ct - UnPredictedCurTime()
|
||
|
|
end
|
||
|
|
|
||
|
|
if self2.LuaShellRequestTime > 0 and ct > self2.LuaShellRequestTime then
|
||
|
|
self2.LuaShellRequestTime = -1
|
||
|
|
self2.MakeShell(self)
|
||
|
|
end
|
||
|
|
|
||
|
|
if not self2.HasInitialized then
|
||
|
|
self:Initialize()
|
||
|
|
end
|
||
|
|
|
||
|
|
if not self2.HasDetectedValidAnimations then
|
||
|
|
self2.CacheAnimations(self)
|
||
|
|
self2.ChooseDrawAnim(self)
|
||
|
|
end
|
||
|
|
|
||
|
|
self2.InitAttachments(self)
|
||
|
|
|
||
|
|
self2.ProcessBodygroups(self)
|
||
|
|
|
||
|
|
self2.ProcessHoldType(self)
|
||
|
|
self2.ReloadCV(self)
|
||
|
|
self2.IronSightSounds(self)
|
||
|
|
self2.ProcessLoopSound(self)
|
||
|
|
end
|
||
|
|
|
||
|
|
self2.ProcessFireMode(self)
|
||
|
|
|
||
|
|
if (not sp or SERVER) and self:GetFirstDeployEvent() then
|
||
|
|
self2.ProcessEvents(self, sp or not is_working_out_prediction_errors)
|
||
|
|
end
|
||
|
|
|
||
|
|
--if is_working_out_prediction_errors then return end
|
||
|
|
|
||
|
|
if not sp or SERVER then
|
||
|
|
self2.IronSights(self)
|
||
|
|
end
|
||
|
|
|
||
|
|
self2.ProcessStatus(self)
|
||
|
|
end
|
||
|
|
|
||
|
|
SWEP.IronSightsReloadEnabled = false
|
||
|
|
SWEP.IronSightsReloadLock = true
|
||
|
|
|
||
|
|
function SWEP:IronSights()
|
||
|
|
local self2 = self:GetTable()
|
||
|
|
local owent = self:GetOwner()
|
||
|
|
if not IsValid(owent) then return end
|
||
|
|
|
||
|
|
ct = l_CT()
|
||
|
|
stat = self:GetStatus()
|
||
|
|
|
||
|
|
local issprinting = self:GetSprinting()
|
||
|
|
local iswalking = self:GetWalking()
|
||
|
|
|
||
|
|
local issighting = self:GetIronSightsRaw()
|
||
|
|
local isplayer = owent:IsPlayer()
|
||
|
|
local old_iron_sights_final = self:GetIronSightsOldFinal()
|
||
|
|
|
||
|
|
if TFA.Enum.ReloadStatus[stat] and self2.GetStatL(self, "IronSightsReloadLock") then
|
||
|
|
issighting = old_iron_sights_final
|
||
|
|
end
|
||
|
|
|
||
|
|
if issighting and isplayer and owent:InVehicle() and not owent:GetAllowWeaponsInVehicle() then
|
||
|
|
issighting = false
|
||
|
|
self:SetIronSightsRaw(false)
|
||
|
|
end
|
||
|
|
|
||
|
|
-- self:SetLastSightsStatusCached(false)
|
||
|
|
local userstatus = issighting
|
||
|
|
|
||
|
|
if issprinting then
|
||
|
|
issighting = false
|
||
|
|
end
|
||
|
|
|
||
|
|
if issighting and not TFA.Enum.IronStatus[stat] and (not self:GetStatL("IronSightsReloadEnabled") or not TFA.Enum.ReloadStatus[stat]) then
|
||
|
|
issighting = false
|
||
|
|
end
|
||
|
|
|
||
|
|
if issighting and self:IsSafety() then
|
||
|
|
issighting = false
|
||
|
|
end
|
||
|
|
|
||
|
|
if stat == TFA.Enum.STATUS_FIREMODE and self:GetIsCyclingSafety() then
|
||
|
|
issighting = false
|
||
|
|
end
|
||
|
|
|
||
|
|
if self2.GetStatL(self, "BoltAction") or self2.GetStatL(self, "BoltAction_Forced") then
|
||
|
|
if stat == TFA.Enum.STATUS_SHOOTING then
|
||
|
|
if not self2.LastBoltShoot then
|
||
|
|
self2.LastBoltShoot = l_CT()
|
||
|
|
end
|
||
|
|
|
||
|
|
if l_CT() > self2.LastBoltShoot + self2.BoltTimerOffset then
|
||
|
|
issighting = false
|
||
|
|
end
|
||
|
|
elseif (stat == TFA.Enum.STATUS_IDLE and self:GetReloadLoopCancel(true)) or stat == TFA.Enum.STATUS_PUMP then
|
||
|
|
issighting = false
|
||
|
|
else
|
||
|
|
self2.LastBoltShoot = nil
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
if old_iron_sights_final ~= issighting and self2.Sights_Mode == TFA.Enum.LOCOMOTION_LUA then -- and stat == TFA.Enum.STATUS_IDLE then
|
||
|
|
self:SetNextIdleAnim(-1)
|
||
|
|
end
|
||
|
|
|
||
|
|
local smi = (self2.Sights_Mode == TFA.Enum.LOCOMOTION_HYBRID or self2.Sights_Mode == TFA.Enum.LOCOMOTION_ANI)
|
||
|
|
and old_iron_sights_final ~= issighting
|
||
|
|
|
||
|
|
local spi = (self2.Sprint_Mode == TFA.Enum.LOCOMOTION_HYBRID or self2.Sprint_Mode == TFA.Enum.LOCOMOTION_ANI)
|
||
|
|
and self2.sprinting_updated
|
||
|
|
|
||
|
|
local wmi = (self2.Walk_Mode == TFA.Enum.LOCOMOTION_HYBRID or self2.Walk_Mode == TFA.Enum.LOCOMOTION_ANI)
|
||
|
|
and self2.walking_updated
|
||
|
|
|
||
|
|
local cmi = (self2.Customize_Mode == TFA.Enum.LOCOMOTION_HYBRID or self2.Customize_Mode == TFA.Enum.LOCOMOTION_ANI)
|
||
|
|
and self:GetCustomizeUpdated()
|
||
|
|
|
||
|
|
self:SetCustomizeUpdated(false)
|
||
|
|
|
||
|
|
if
|
||
|
|
(smi or spi or wmi or cmi) and
|
||
|
|
(self:GetStatus() == TFA.Enum.STATUS_IDLE or
|
||
|
|
(self:GetStatus() == TFA.Enum.STATUS_SHOOTING and self:CanInterruptShooting()))
|
||
|
|
and not self:GetReloadLoopCancel()
|
||
|
|
then
|
||
|
|
local toggle_is = old_iron_sights_final ~= issighting
|
||
|
|
|
||
|
|
if issighting and self:GetSprinting() then
|
||
|
|
toggle_is = true
|
||
|
|
end
|
||
|
|
|
||
|
|
local success, _ = self:Locomote(toggle_is and (self2.Sights_Mode ~= TFA.Enum.LOCOMOTION_LUA), issighting, spi, issprinting, wmi, iswalking, cmi, self:GetCustomizing())
|
||
|
|
|
||
|
|
if not success and (toggle_is and smi or spi or wmi or cmi) then
|
||
|
|
self:SetNextIdleAnim(-1)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
self:SetIronSightsOldFinal(issighting)
|
||
|
|
|
||
|
|
return userstatus, issighting
|
||
|
|
end
|
||
|
|
|
||
|
|
SWEP.is_sndcache_old = false
|
||
|
|
|
||
|
|
function SWEP:IronSightSounds()
|
||
|
|
local self2 = self:GetTable()
|
||
|
|
|
||
|
|
local is = self:GetIronSights()
|
||
|
|
|
||
|
|
if SERVER or IsFirstTimePredicted() then
|
||
|
|
if is ~= self2.is_sndcache_old and hook.Run("TFA_IronSightSounds", self) == nil then
|
||
|
|
if is then
|
||
|
|
self:EmitSound(self:GetStatL("Secondary.IronSightsInSound", "TFA.IronIn"))
|
||
|
|
else
|
||
|
|
self:EmitSound(self:GetStatL("Secondary.IronSightsOutSound", "TFA.IronOut"))
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
self2.is_sndcache_old = is
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
local legacy_reloads_cv = GetConVar("sv_tfa_reloads_legacy")
|
||
|
|
local dryfire_cvar = GetConVar("sv_tfa_allow_dryfire")
|
||
|
|
|
||
|
|
SWEP.Primary.Sound_DryFire = Sound("Weapon_Pistol.Empty2") -- dryfire sound, played only once
|
||
|
|
SWEP.Primary.Sound_DrySafety = Sound("Weapon_AR2.Empty2") -- safety click sound
|
||
|
|
SWEP.Primary.Sound_Blocked = Sound("Weapon_AR2.Empty") -- underwater click sound
|
||
|
|
SWEP.Primary.Sound_Jammed = Sound("Default.ClipEmpty_Rifle") -- jammed click sound
|
||
|
|
|
||
|
|
SWEP.Primary.SoundHint_Fire = true
|
||
|
|
SWEP.Primary.SoundHint_DryFire = true
|
||
|
|
|
||
|
|
local function Dryfire(self, self2, reload)
|
||
|
|
if not dryfire_cvar:GetBool() and reload then
|
||
|
|
self:Reload(true)
|
||
|
|
end
|
||
|
|
|
||
|
|
if self2.GetHasPlayedEmptyClick(self) then return end
|
||
|
|
|
||
|
|
self2.SetHasPlayedEmptyClick(self, true)
|
||
|
|
|
||
|
|
if SERVER and self:GetStatL("Primary.SoundHint_DryFire") then
|
||
|
|
sound.EmitHint(SOUND_COMBAT, self:GetPos(), 500, 0.2, self:GetOwner())
|
||
|
|
end
|
||
|
|
|
||
|
|
if self:GetOwner():IsNPC() or self:KeyPressed(IN_ATTACK) then
|
||
|
|
local enabled, tanim, ttype = self:ChooseDryFireAnim()
|
||
|
|
|
||
|
|
if enabled then
|
||
|
|
self:SetNextPrimaryFire(l_CT() + self:GetStatL("Primary.DryFireDelay", self:GetActivityLength(tanim, true, ttype)))
|
||
|
|
return
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
if IsFirstTimePredicted() then
|
||
|
|
self:EmitSound(self:GetStatL("Primary.Sound_DryFire"))
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
function SWEP:CanPrimaryAttack()
|
||
|
|
local self2 = self:GetTable()
|
||
|
|
|
||
|
|
local v = hook.Run("TFA_PreCanPrimaryAttack", self)
|
||
|
|
|
||
|
|
if v ~= nil then
|
||
|
|
return v
|
||
|
|
end
|
||
|
|
|
||
|
|
stat = self:GetStatus()
|
||
|
|
|
||
|
|
if not TFA.Enum.ReadyStatus[stat] and stat ~= TFA.Enum.STATUS_SHOOTING then
|
||
|
|
if self:GetStatL("LoopedReload") and TFA.Enum.ReloadStatus[stat] then
|
||
|
|
self:SetReloadLoopCancel(true)
|
||
|
|
end
|
||
|
|
|
||
|
|
return false
|
||
|
|
end
|
||
|
|
|
||
|
|
if self:IsSafety() then
|
||
|
|
if IsFirstTimePredicted() then
|
||
|
|
self:EmitSound(self:GetStatL("Primary.Sound_DrySafety"))
|
||
|
|
|
||
|
|
if SERVER and self:GetStatL("Primary.SoundHint_DryFire") then
|
||
|
|
sound.EmitHint(SOUND_COMBAT, self:GetPos(), 200, 0.2, self:GetOwner())
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
if l_CT() < self:GetLastSafetyShoot() + 0.2 then
|
||
|
|
self:CycleSafety()
|
||
|
|
-- self:SetNextPrimaryFire(l_CT() + 0.1)
|
||
|
|
end
|
||
|
|
|
||
|
|
self:SetLastSafetyShoot(l_CT() + 0.2)
|
||
|
|
|
||
|
|
return
|
||
|
|
end
|
||
|
|
|
||
|
|
if self:GetSprintProgress() >= 0.1 and not self:GetStatL("AllowSprintAttack", false) then
|
||
|
|
return false
|
||
|
|
end
|
||
|
|
|
||
|
|
if self:GetStatL("Primary.ClipSize") <= 0 and self:Ammo1() < self:GetStatL("Primary.AmmoConsumption") then
|
||
|
|
Dryfire(self, self2)
|
||
|
|
return false
|
||
|
|
end
|
||
|
|
|
||
|
|
if self:GetPrimaryClipSize(true) > 0 and self:Clip1() < self:GetStatL("Primary.AmmoConsumption") then
|
||
|
|
Dryfire(self, self2, true)
|
||
|
|
return false
|
||
|
|
end
|
||
|
|
|
||
|
|
if self2.GetStatL(self, "Primary.FiresUnderwater") == false and self:GetOwner():WaterLevel() >= 3 then
|
||
|
|
self:SetNextPrimaryFire(l_CT() + 0.5)
|
||
|
|
self:EmitSound(self:GetStatL("Primary.Sound_Blocked"))
|
||
|
|
return false
|
||
|
|
end
|
||
|
|
|
||
|
|
self2.SetHasPlayedEmptyClick(self, false)
|
||
|
|
|
||
|
|
if l_CT() < self:GetNextPrimaryFire() then return false end
|
||
|
|
|
||
|
|
local v2 = hook.Run("TFA_CanPrimaryAttack", self)
|
||
|
|
|
||
|
|
if v2 ~= nil then
|
||
|
|
return v2
|
||
|
|
end
|
||
|
|
|
||
|
|
if self:CheckJammed() then
|
||
|
|
if IsFirstTimePredicted() then
|
||
|
|
self:EmitSound(self:GetStatL("Primary.Sound_Jammed"))
|
||
|
|
end
|
||
|
|
|
||
|
|
local typev, tanim = self:ChooseAnimation("shoot1_empty")
|
||
|
|
|
||
|
|
if typev ~= TFA.Enum.ANIMATION_SEQ then
|
||
|
|
self:SendViewModelAnim(tanim)
|
||
|
|
else
|
||
|
|
self:SendViewModelSeq(tanim)
|
||
|
|
end
|
||
|
|
|
||
|
|
self:SetNextPrimaryFire(l_CT() + 1)
|
||
|
|
|
||
|
|
return false
|
||
|
|
end
|
||
|
|
|
||
|
|
return true
|
||
|
|
end
|
||
|
|
|
||
|
|
function SWEP:EmitGunfireLoop()
|
||
|
|
local self2 = self:GetTable()
|
||
|
|
local tgtSound = self:GetStatL("Primary.LoopSound")
|
||
|
|
|
||
|
|
if self:GetSilenced() then
|
||
|
|
tgtSound = self:GetStatL("Primary.LoopSoundSilenced", tgtSound)
|
||
|
|
end
|
||
|
|
|
||
|
|
if (not sp and SERVER) or not self:IsFirstPerson() then
|
||
|
|
tgtSound = self:GetSilenced() and self:GetStatL("Primary.LoopSoundSilenced_World", tgtSound) or self:GetStatL("Primary.LoopSound_World", tgtSound)
|
||
|
|
end
|
||
|
|
|
||
|
|
if self:GetNextLoopSoundCheck() < 0 or (l_CT() >= self:GetNextLoopSoundCheck() and self2.LastLoopSound ~= tgtSound) then
|
||
|
|
if self2.LastLoopSound ~= tgtSound and self2.LastLoopSound ~= nil then
|
||
|
|
self:StopSound(self2.LastLoopSound)
|
||
|
|
end
|
||
|
|
|
||
|
|
self2.LastLoopSound = tgtSound
|
||
|
|
self2.GunfireLoopIFTPHack = true
|
||
|
|
|
||
|
|
self:EmitSoundNet(tgtSound)
|
||
|
|
end
|
||
|
|
|
||
|
|
self:SetNextLoopSoundCheck(CurTime() + self:GetFireDelay())
|
||
|
|
end
|
||
|
|
|
||
|
|
function SWEP:EmitGunfireSound(soundscript)
|
||
|
|
self:EmitSoundNet(soundscript)
|
||
|
|
end
|
||
|
|
|
||
|
|
local sv_tfa_nearlyempty = GetConVar("sv_tfa_nearlyempty")
|
||
|
|
|
||
|
|
SWEP.LowAmmoSoundThreshold = 0.33
|
||
|
|
|
||
|
|
function SWEP:EmitLowAmmoSound()
|
||
|
|
if not sv_tfa_nearlyempty:GetBool() then return end
|
||
|
|
|
||
|
|
local self2 = self:GetTable()
|
||
|
|
|
||
|
|
if not self2.FireSoundAffectedByClipSize then return end
|
||
|
|
|
||
|
|
local clip1, maxclip1 = self:Clip1(), self:GetMaxClip1()
|
||
|
|
if clip1 <= 0 then return end
|
||
|
|
|
||
|
|
local nextclip1 = clip1 - self:GetStatL("Primary.AmmoConsumption", 1)
|
||
|
|
if self:GetStatL("IsAkimbo") then
|
||
|
|
nextclip1 = nextclip1 - self:GetAnimCycle()
|
||
|
|
end
|
||
|
|
|
||
|
|
local mult = nextclip1 / maxclip1
|
||
|
|
if mult >= self2.LowAmmoSoundThreshold then return end
|
||
|
|
|
||
|
|
local soundname = (nextclip1 <= 0) and self:GetStatL("LastAmmoSound", "") or self:GetStatL("LowAmmoSound", "")
|
||
|
|
|
||
|
|
if soundname and soundname ~= "" then
|
||
|
|
self2.GonnaAdjustVol = true
|
||
|
|
self2.RequiredVolume = 1 - (mult / math.max(self2.LowAmmoSoundThreshold, 0.01))
|
||
|
|
|
||
|
|
self:EmitSound(soundname)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
function SWEP:TriggerAttack(tableName, clipID)
|
||
|
|
local self2 = self:GetTable()
|
||
|
|
local ply = self:GetOwner()
|
||
|
|
|
||
|
|
local fnname = clipID == 2 and "Secondary" or "Primary"
|
||
|
|
|
||
|
|
if TFA.Enum.ShootReadyStatus[self:GetShootStatus()] then
|
||
|
|
self:SetShootStatus(TFA.Enum.SHOOT_IDLE)
|
||
|
|
end
|
||
|
|
|
||
|
|
if self2.CanBeSilenced and (ply.KeyDown and self:KeyDown(IN_USE)) and (SERVER or not sp) then
|
||
|
|
local _, tanim = self:ChooseSilenceAnim(not self:GetSilenced())
|
||
|
|
self:ScheduleStatus(TFA.Enum.STATUS_SILENCER_TOGGLE, self:GetActivityLength(tanim, true))
|
||
|
|
|
||
|
|
return
|
||
|
|
end
|
||
|
|
|
||
|
|
self["SetNext" .. fnname .. "Fire"](self, self2["GetNextCorrected" .. fnname .. "Fire"](self, self2.GetFireDelay(self)))
|
||
|
|
|
||
|
|
if self:GetMaxBurst() > 1 then
|
||
|
|
self:SetBurstCount(math.max(1, self:GetBurstCount() + 1))
|
||
|
|
end
|
||
|
|
|
||
|
|
if self:GetStatL("PumpAction") and self:GetReloadLoopCancel() then return end
|
||
|
|
|
||
|
|
self:SetStatus(TFA.Enum.STATUS_SHOOTING, self["GetNext" .. fnname .. "Fire"](self))
|
||
|
|
self:ToggleAkimbo()
|
||
|
|
self:IncreaseRecoilLUT()
|
||
|
|
|
||
|
|
local ifp = IsFirstTimePredicted()
|
||
|
|
|
||
|
|
local _, tanim = self:ChooseShootAnim(ifp)
|
||
|
|
|
||
|
|
if not sp or not self:IsFirstPerson() then
|
||
|
|
ply:SetAnimation(PLAYER_ATTACK1)
|
||
|
|
end
|
||
|
|
|
||
|
|
if SERVER and self:GetStatL(tableName .. ".SoundHint_Fire") then
|
||
|
|
sound.EmitHint(bit.bor(SOUND_COMBAT, SOUND_CONTEXT_GUNFIRE), self:GetPos(), self:GetSilenced() and 500 or 1500, 0.2, self:GetOwner())
|
||
|
|
end
|
||
|
|
|
||
|
|
if self:GetStatL(tableName .. ".Sound") and ifp and not (sp and CLIENT) then
|
||
|
|
if ply:IsPlayer() and self:GetStatL(tableName .. ".LoopSound") and (not self:GetStatL(tableName .. ".LoopSoundAutoOnly", false) or self2.Primary_TFA.Automatic) then
|
||
|
|
self:EmitGunfireLoop()
|
||
|
|
else
|
||
|
|
local tgtSound = self:GetStatL(tableName .. ".Sound")
|
||
|
|
|
||
|
|
if self:GetSilenced() then
|
||
|
|
tgtSound = self:GetStatL(tableName .. ".SilencedSound", tgtSound)
|
||
|
|
end
|
||
|
|
|
||
|
|
if (not sp and SERVER) or not self:IsFirstPerson() then
|
||
|
|
tgtSound = self:GetSilenced() and self:GetStatL(tableName .. ".SilencedSound_World", tgtSound) or self:GetStatL(tableName .. ".Sound_World", tgtSound)
|
||
|
|
end
|
||
|
|
|
||
|
|
self:EmitGunfireSound(tgtSound)
|
||
|
|
end
|
||
|
|
|
||
|
|
self:EmitLowAmmoSound()
|
||
|
|
end
|
||
|
|
|
||
|
|
self2["Take" .. fnname .. "Ammo"](self, self:GetStatL(tableName .. ".AmmoConsumption"))
|
||
|
|
|
||
|
|
if self["Clip" .. clipID](self) == 0 and self:GetStatL(tableName .. ".ClipSize") > 0 then
|
||
|
|
self["SetNext" .. fnname .. "Fire"](self, math.max(self["GetNext" .. fnname .. "Fire"](self), l_CT() + (self:GetStatL(tableName .. ".DryFireDelay", self:GetActivityLength(tanim, true)))))
|
||
|
|
end
|
||
|
|
|
||
|
|
self:ShootBulletInformation()
|
||
|
|
self:UpdateJamFactor()
|
||
|
|
local _, CurrentRecoil = self:CalculateConeRecoil()
|
||
|
|
self:Recoil(CurrentRecoil, ifp)
|
||
|
|
|
||
|
|
-- shouldn't this be not required since recoil state is completely networked?
|
||
|
|
if sp and SERVER then
|
||
|
|
self:CallOnClient("Recoil", "")
|
||
|
|
end
|
||
|
|
|
||
|
|
if self:GetStatL(tableName .. ".MuzzleFlashEnabled", self:GetStatL("MuzzleFlashEnabled")) and (not self:IsFirstPerson() or not self:GetStatL(tableName .. ".AutoDetectMuzzleAttachment", self:GetStatL("AutoDetectMuzzleAttachment"))) then
|
||
|
|
self:ShootEffectsCustom()
|
||
|
|
end
|
||
|
|
|
||
|
|
if self:GetStatL(tableName .. ".EjectionSmoke", self:GetStatL("EjectionSmoke")) and CLIENT and ply == LocalPlayer() and ifp and not self:GetStatL(tableName .. ".LuaShellEject", self:GetStatL("LuaShellEject")) then
|
||
|
|
self:EjectionSmoke()
|
||
|
|
end
|
||
|
|
|
||
|
|
self:DoAmmoCheck(clipID)
|
||
|
|
|
||
|
|
-- Condition self:GetStatus() == TFA.Enum.STATUS_SHOOTING is always true?
|
||
|
|
if self:GetStatus() == TFA.Enum.STATUS_SHOOTING and self:GetStatL("PumpAction") then
|
||
|
|
if self["Clip" .. clipID](self) == 0 and self:GetStatL("PumpAction.value_empty") then
|
||
|
|
self:SetReloadLoopCancel(true)
|
||
|
|
elseif (self:GetStatL(tableName .. ".ClipSize") < 0 or self["Clip" .. clipID](self) > 0) and self:GetStatL("PumpAction.value") then
|
||
|
|
self:SetReloadLoopCancel(true)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
self:RollJamChance()
|
||
|
|
end
|
||
|
|
|
||
|
|
function SWEP:PrimaryAttack()
|
||
|
|
local self2 = self:GetTable()
|
||
|
|
local ply = self:GetOwner()
|
||
|
|
if not IsValid(ply) then return end
|
||
|
|
|
||
|
|
if not IsValid(self) then return end
|
||
|
|
if ply:IsPlayer() and not self:VMIV() then return end
|
||
|
|
if not self:CanPrimaryAttack() then return end
|
||
|
|
|
||
|
|
self:PrePrimaryAttack()
|
||
|
|
|
||
|
|
if hook.Run("TFA_PrimaryAttack", self) then return end
|
||
|
|
|
||
|
|
self:TriggerAttack("Primary", 1)
|
||
|
|
|
||
|
|
self:PostPrimaryAttack()
|
||
|
|
hook.Run("TFA_PostPrimaryAttack", self)
|
||
|
|
end
|
||
|
|
|
||
|
|
function SWEP:PrePrimaryAttack()
|
||
|
|
-- override
|
||
|
|
end
|
||
|
|
|
||
|
|
function SWEP:PostPrimaryAttack()
|
||
|
|
-- override
|
||
|
|
end
|
||
|
|
|
||
|
|
function SWEP:CanSecondaryAttack()
|
||
|
|
-- override
|
||
|
|
end
|
||
|
|
|
||
|
|
function SWEP:SecondaryAttack()
|
||
|
|
self:PreSecondaryAttack()
|
||
|
|
|
||
|
|
if hook.Run("TFA_SecondaryAttack", self) then return end
|
||
|
|
|
||
|
|
if not self:GetStatL("Secondary.IronSightsEnabled", false) and self.AltAttack and self:GetOwner():IsPlayer() then
|
||
|
|
self:AltAttack()
|
||
|
|
self:PostSecondaryAttack()
|
||
|
|
return
|
||
|
|
end
|
||
|
|
|
||
|
|
self:PostSecondaryAttack()
|
||
|
|
end
|
||
|
|
|
||
|
|
function SWEP:PreSecondaryAttack()
|
||
|
|
-- override
|
||
|
|
end
|
||
|
|
|
||
|
|
function SWEP:PostSecondaryAttack()
|
||
|
|
-- override
|
||
|
|
end
|
||
|
|
|
||
|
|
function SWEP:GetLegacyReloads()
|
||
|
|
return legacy_reloads_cv:GetBool()
|
||
|
|
end
|
||
|
|
|
||
|
|
do
|
||
|
|
local bit_band = bit.band
|
||
|
|
|
||
|
|
function SWEP:KeyDown(keyIn)
|
||
|
|
return bit_band(self:GetDownButtons(), keyIn) == keyIn
|
||
|
|
end
|
||
|
|
|
||
|
|
function SWEP:KeyPressed(keyIn)
|
||
|
|
return bit_band(self:GetLastPressedButtons(), keyIn) == keyIn
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
if SERVER and sp then
|
||
|
|
util.AddNetworkString("tfa_reload_blending")
|
||
|
|
elseif CLIENT and sp then
|
||
|
|
net.Receive("tfa_reload_blending", function()
|
||
|
|
local self = net.ReadEntity()
|
||
|
|
if not IsValid(self) then return end
|
||
|
|
self.ReloadAnimationStart = net.ReadDouble()
|
||
|
|
self.ReloadAnimationEnd = net.ReadDouble()
|
||
|
|
end)
|
||
|
|
end
|
||
|
|
|
||
|
|
function SWEP:Reload(released)
|
||
|
|
local self2 = self:GetTable()
|
||
|
|
|
||
|
|
self:PreReload(released)
|
||
|
|
|
||
|
|
if hook.Run("TFA_PreReload", self, released) then return end
|
||
|
|
|
||
|
|
local isplayer = self:GetOwner():IsPlayer()
|
||
|
|
local vm = self:VMIV()
|
||
|
|
|
||
|
|
if isplayer and not vm then return end
|
||
|
|
|
||
|
|
if not self:IsJammed() then
|
||
|
|
if self:Ammo1() <= 0 then return end
|
||
|
|
if self:GetStatL("Primary.ClipSize") < 0 then return end
|
||
|
|
end
|
||
|
|
|
||
|
|
if not released and not self:GetLegacyReloads() then return end
|
||
|
|
if self:GetLegacyReloads() and not dryfire_cvar:GetBool() and not self:KeyDown(IN_RELOAD) then return end
|
||
|
|
if self:KeyDown(IN_USE) then return end
|
||
|
|
|
||
|
|
stat = self:GetStatus()
|
||
|
|
|
||
|
|
if self:GetStatL("PumpAction") and self:GetReloadLoopCancel() then
|
||
|
|
if stat == TFA.Enum.STATUS_IDLE then
|
||
|
|
self:DoPump()
|
||
|
|
end
|
||
|
|
elseif TFA.Enum.ReadyStatus[stat] or (stat == TFA.Enum.STATUS_SHOOTING and self:CanInterruptShooting()) or self:IsJammed() then
|
||
|
|
if self:Clip1() < self:GetPrimaryClipSize() or self:IsJammed() then
|
||
|
|
if hook.Run("TFA_Reload", self) then return end
|
||
|
|
self:SetBurstCount(0)
|
||
|
|
|
||
|
|
if self:GetStatL("LoopedReload") then
|
||
|
|
local _, tanim, ttype = self:ChooseShotgunReloadAnim()
|
||
|
|
|
||
|
|
if self:GetStatL("ShotgunStartAnimShell") then
|
||
|
|
self:SetStatus(TFA.Enum.STATUS_RELOADING_LOOP_START_EMPTY)
|
||
|
|
elseif self2.ShotgunEmptyAnim then
|
||
|
|
local _, tg = self:ChooseAnimation("reload_empty")
|
||
|
|
local action = tanim
|
||
|
|
|
||
|
|
if type(tg) == "string" and tonumber(tanim) and tonumber(tanim) > 0 and isplayer then
|
||
|
|
if ttype == TFA.Enum.ANIMATION_ACT then
|
||
|
|
action = vm:GetSequenceName(vm:SelectWeightedSequenceSeeded(tanim, self:GetSeedIrradical()))
|
||
|
|
else
|
||
|
|
action = vm:GetSequenceName(tanim)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
if action == tg and self:GetStatL("ShotgunEmptyAnim_Shell") then
|
||
|
|
self:SetStatus(TFA.Enum.STATUS_RELOADING_LOOP_START_EMPTY)
|
||
|
|
else
|
||
|
|
self:SetStatus(TFA.Enum.STATUS_RELOADING_LOOP_START)
|
||
|
|
end
|
||
|
|
else
|
||
|
|
self:SetStatus(TFA.Enum.STATUS_RELOADING_LOOP_START)
|
||
|
|
end
|
||
|
|
|
||
|
|
self:SetStatusEnd(ct + self:GetActivityLength(tanim, true, ttype))
|
||
|
|
--self:SetNextPrimaryFire(ct + self:GetActivityLength( tanim, false ) )
|
||
|
|
else
|
||
|
|
local _, tanim, ttype = self:ChooseReloadAnim()
|
||
|
|
|
||
|
|
self:SetStatus(TFA.Enum.STATUS_RELOADING)
|
||
|
|
|
||
|
|
if self:GetStatL("IsProceduralReloadBased") then
|
||
|
|
self:SetStatusEnd(ct + self:GetStatL("ProceduralReloadTime"))
|
||
|
|
else
|
||
|
|
self:SetStatusEnd(ct + self:GetActivityLength(tanim, true, ttype))
|
||
|
|
self:SetNextPrimaryFire(ct + self:GetActivityLength(tanim, false, ttype))
|
||
|
|
end
|
||
|
|
|
||
|
|
if CLIENT then
|
||
|
|
self2.ReloadAnimationStart = ct
|
||
|
|
self2.ReloadAnimationEnd = ct + self:GetActivityLength(tanim, false, ttype)
|
||
|
|
elseif sp then
|
||
|
|
net.Start("tfa_reload_blending", true)
|
||
|
|
net.WriteEntity(self)
|
||
|
|
net.WriteDouble(ct)
|
||
|
|
net.WriteDouble(ct + self:GetActivityLength(tanim, false, ttype))
|
||
|
|
net.Broadcast()
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
if not sp or not self:IsFirstPerson() then
|
||
|
|
self:GetOwner():SetAnimation(PLAYER_RELOAD)
|
||
|
|
end
|
||
|
|
|
||
|
|
if self:GetStatL("Primary.ReloadSound") and IsFirstTimePredicted() then
|
||
|
|
self:EmitSound(self:GetStatL("Primary.ReloadSound"))
|
||
|
|
end
|
||
|
|
|
||
|
|
self:SetNextPrimaryFire( -1 )
|
||
|
|
elseif released or self:KeyPressed(IN_RELOAD) then--if self:GetOwner():KeyPressed(IN_RELOAD) or not self:GetLegacyReloads() then
|
||
|
|
self:CheckAmmo()
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
self:PostReload(released)
|
||
|
|
|
||
|
|
hook.Run("TFA_PostReload", self)
|
||
|
|
end
|
||
|
|
|
||
|
|
function SWEP:PreReload(released)
|
||
|
|
-- override
|
||
|
|
end
|
||
|
|
|
||
|
|
function SWEP:PostReload(released)
|
||
|
|
-- override
|
||
|
|
end
|
||
|
|
|
||
|
|
function SWEP:Reload2(released)
|
||
|
|
local self2 = self:GetTable()
|
||
|
|
|
||
|
|
local ply = self:GetOwner()
|
||
|
|
local isplayer = ply:IsPlayer()
|
||
|
|
local vm = self:VMIV()
|
||
|
|
|
||
|
|
if isplayer and not vm then return end
|
||
|
|
|
||
|
|
if self:Ammo2() <= 0 then return end
|
||
|
|
if self:GetStatL("Secondary.ClipSize") < 0 then return end
|
||
|
|
if not released and not self:GetLegacyReloads() then return end
|
||
|
|
if self:GetLegacyReloads() and not dryfire_cvar:GetBool() and not self:KeyDown(IN_RELOAD) then return end
|
||
|
|
if self:KeyDown(IN_USE) then return end
|
||
|
|
|
||
|
|
stat = self:GetStatus()
|
||
|
|
|
||
|
|
if self:GetStatL("PumpAction") and self:GetReloadLoopCancel() then
|
||
|
|
if stat == TFA.Enum.STATUS_IDLE then
|
||
|
|
self:DoPump()
|
||
|
|
end
|
||
|
|
elseif TFA.Enum.ReadyStatus[stat] or ( stat == TFA.Enum.STATUS_SHOOTING and self:CanInterruptShooting() ) then
|
||
|
|
if self:Clip2() < self:GetSecondaryClipSize() then
|
||
|
|
if self:GetStatL("LoopedReload") then
|
||
|
|
local _, tanim, ttype = self:ChooseShotgunReloadAnim()
|
||
|
|
|
||
|
|
if self2.ShotgunEmptyAnim then
|
||
|
|
local _, tg = self:ChooseAnimation("reload_empty")
|
||
|
|
local action = tanim
|
||
|
|
|
||
|
|
if type(tg) == "string" and tonumber(tanim) and tonumber(tanim) > 0 and isplayer then
|
||
|
|
if ttype == TFA.Enum.ANIMATION_ACT then
|
||
|
|
action = vm:GetSequenceName(vm:SelectWeightedSequenceSeeded(tanim, self:GetSeedIrradical()))
|
||
|
|
else
|
||
|
|
action = vm:GetSequenceName(tanim)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
if action == tg and self:GetStatL("ShotgunEmptyAnim_Shell") then
|
||
|
|
self:SetStatus(TFA.Enum.STATUS_RELOADING_LOOP_START_EMPTY)
|
||
|
|
else
|
||
|
|
self:SetStatus(TFA.Enum.STATUS_RELOADING_LOOP_START)
|
||
|
|
end
|
||
|
|
else
|
||
|
|
self:SetStatus(TFA.Enum.STATUS_RELOADING_LOOP_START)
|
||
|
|
end
|
||
|
|
|
||
|
|
self:SetStatusEnd(ct + self:GetActivityLength(tanim, true, ttype))
|
||
|
|
--self:SetNextPrimaryFire(ct + self:GetActivityLength( tanim, false ) )
|
||
|
|
else
|
||
|
|
local _, tanim, ttype = self:ChooseReloadAnim()
|
||
|
|
|
||
|
|
self:SetStatus(TFA.Enum.STATUS_RELOADING)
|
||
|
|
|
||
|
|
if self:GetStatL("IsProceduralReloadBased") then
|
||
|
|
self:SetStatusEnd(ct + self:GetStatL("ProceduralReloadTime"))
|
||
|
|
else
|
||
|
|
self:SetStatusEnd(ct + self:GetActivityLength(tanim, true, ttype))
|
||
|
|
self:SetNextPrimaryFire(ct + self:GetActivityLength(tanim, false, ttype))
|
||
|
|
end
|
||
|
|
|
||
|
|
if CLIENT then
|
||
|
|
self2.ReloadAnimationStart = ct
|
||
|
|
self2.ReloadAnimationEnd = ct + self:GetActivityLength(tanim, false, ttype)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
if not sp or not self:IsFirstPerson() then
|
||
|
|
ply:SetAnimation(PLAYER_RELOAD)
|
||
|
|
end
|
||
|
|
|
||
|
|
if self:GetStatL("Secondary.ReloadSound") and IsFirstTimePredicted() then
|
||
|
|
self:EmitSound(self:GetStatL("Secondary.ReloadSound"))
|
||
|
|
end
|
||
|
|
|
||
|
|
self:SetNextPrimaryFire( -1 )
|
||
|
|
elseif released or self:KeyPressed(IN_RELOAD) then--if ply:KeyPressed(IN_RELOAD) or not self:GetLegacyReloads() then
|
||
|
|
self:CheckAmmo()
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
function SWEP:DoPump()
|
||
|
|
if hook.Run("TFA_Pump", self) then return end
|
||
|
|
|
||
|
|
local _, tanim, activityType = self:PlayAnimation(self:GetStatL("PumpAction"))
|
||
|
|
|
||
|
|
self:ScheduleStatus(TFA.Enum.STATUS_PUMP, self:GetActivityLength(tanim, true, activityType))
|
||
|
|
self:SetNextPrimaryFire(l_CT() + self:GetActivityLength(tanim, false, activityType))
|
||
|
|
self:SetNextIdleAnim(math.max(self:GetNextIdleAnim(), l_CT() + self:GetActivityLength(tanim, false, activityType)))
|
||
|
|
end
|
||
|
|
|
||
|
|
function SWEP:LoadShell()
|
||
|
|
if hook.Run("TFA_LoadShell", self) then return end
|
||
|
|
|
||
|
|
local _, tanim, ttype = self:ChooseReloadAnim()
|
||
|
|
|
||
|
|
if self:GetActivityLength(tanim,true) < self:GetActivityLength(tanim, false, ttype) then
|
||
|
|
self:SetStatusEnd(ct + self:GetActivityLength(tanim, true, ttype))
|
||
|
|
else
|
||
|
|
local sht = self:GetStatL("LoopedReloadInsertTime")
|
||
|
|
if sht then sht = sht / self:GetAnimationRate(ACT_VM_RELOAD) end
|
||
|
|
self:SetStatusEnd(ct + ( sht or self:GetActivityLength(tanim, true, ttype)))
|
||
|
|
end
|
||
|
|
|
||
|
|
return TFA.Enum.STATUS_RELOADING_LOOP
|
||
|
|
end
|
||
|
|
|
||
|
|
function SWEP:CompleteReload()
|
||
|
|
if hook.Run("TFA_CompleteReload", self) then return end
|
||
|
|
|
||
|
|
local maxclip = self:GetPrimaryClipSizeForReload(true)
|
||
|
|
local curclip = self:Clip1()
|
||
|
|
local amounttoreplace = math.min(maxclip - curclip, self:Ammo1())
|
||
|
|
self:TakePrimaryAmmo(amounttoreplace * -1)
|
||
|
|
self:TakePrimaryAmmo(amounttoreplace, true)
|
||
|
|
self:SetJammed(false)
|
||
|
|
end
|
||
|
|
|
||
|
|
function SWEP:CheckAmmo()
|
||
|
|
if hook.Run("TFA_CheckAmmo", self) then return end
|
||
|
|
|
||
|
|
local self2 = self:GetTable()
|
||
|
|
|
||
|
|
if self2.GetIronSights(self) or self2.GetSprinting(self) then return end
|
||
|
|
|
||
|
|
--if self2.NextInspectAnim == nil then
|
||
|
|
-- self2.NextInspectAnim = -1
|
||
|
|
--end
|
||
|
|
|
||
|
|
if self:GetOwner().GetInfoNum and self:GetOwner():GetInfoNum("cl_tfa_keys_inspect", 0) > 0 then
|
||
|
|
return
|
||
|
|
end
|
||
|
|
|
||
|
|
if (self:GetActivityEnabled(ACT_VM_FIDGET) or self2.InspectionActions) and self:GetStatus() == TFA.Enum.STATUS_IDLE then--and CurTime() > self2.NextInspectAnim then
|
||
|
|
local _, tanim, ttype = self:ChooseInspectAnim()
|
||
|
|
self:ScheduleStatus(TFA.Enum.STATUS_FIDGET, self:GetActivityLength(tanim, false, ttype))
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
local cv_strip = GetConVar("sv_tfa_weapon_strip")
|
||
|
|
|
||
|
|
function SWEP:DoAmmoCheck(clipID)
|
||
|
|
if self:GetOwner():IsNPC() then return end
|
||
|
|
if clipID == nil then clipID = 1 end
|
||
|
|
local self2 = self:GetTable()
|
||
|
|
|
||
|
|
if IsValid(self) and SERVER and cv_strip:GetBool() and self["Clip" .. clipID](self) == 0 and self["Ammo" .. clipID](self) == 0 then
|
||
|
|
timer.Simple(.1, function()
|
||
|
|
if SERVER and IsValid(self) and self:OwnerIsValid() then
|
||
|
|
self:GetOwner():StripWeapon(self2.ClassName)
|
||
|
|
end
|
||
|
|
end)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
--[[
|
||
|
|
Function Name: AdjustMouseSensitivity
|
||
|
|
Syntax: Should not normally be called.
|
||
|
|
Returns: SWEP sensitivity multiplier.
|
||
|
|
Purpose: Standard SWEP Function
|
||
|
|
]]
|
||
|
|
|
||
|
|
local fovv
|
||
|
|
local sensval
|
||
|
|
local sensitivity_cvar, sensitivity_fov_cvar, sensitivity_speed_cvar
|
||
|
|
if CLIENT then
|
||
|
|
sensitivity_cvar = GetConVar("cl_tfa_scope_sensitivity")
|
||
|
|
sensitivity_fov_cvar = GetConVar("cl_tfa_scope_sensitivity_autoscale")
|
||
|
|
sensitivity_speed_cvar = GetConVar("sv_tfa_scope_gun_speed_scale")
|
||
|
|
end
|
||
|
|
|
||
|
|
function SWEP:AdjustMouseSensitivity()
|
||
|
|
sensval = 1
|
||
|
|
|
||
|
|
if self:GetIronSights() then
|
||
|
|
sensval = sensval * sensitivity_cvar:GetFloat() / 100
|
||
|
|
|
||
|
|
if sensitivity_fov_cvar:GetBool() then
|
||
|
|
fovv = self:GetStatL("Secondary.OwnerFOV") or 70
|
||
|
|
sensval = sensval * TFA.CalculateSensitivtyScale( fovv, nil, 1 )
|
||
|
|
else
|
||
|
|
sensval = sensval
|
||
|
|
end
|
||
|
|
|
||
|
|
if sensitivity_speed_cvar:GetFloat() then
|
||
|
|
-- weapon heaviness
|
||
|
|
sensval = sensval * self:GetStatL("AimingDownSightsSpeedMultiplier")
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
sensval = sensval * l_Lerp(self:GetIronSightsProgress(), 1, self:GetStatL( "IronSightsSensitivity" ) )
|
||
|
|
return sensval
|
||
|
|
end
|
||
|
|
|
||
|
|
--[[
|
||
|
|
Function Name: TranslateFOV
|
||
|
|
Syntax: Should not normally be called. Takes default FOV as parameter.
|
||
|
|
Returns: New FOV.
|
||
|
|
Purpose: Standard SWEP Function
|
||
|
|
]]
|
||
|
|
|
||
|
|
function SWEP:TranslateFOV(fov)
|
||
|
|
local self2 = self:GetTable()
|
||
|
|
|
||
|
|
self2.LastTranslatedFOV = fov
|
||
|
|
|
||
|
|
local retVal = hook.Run("TFA_PreTranslateFOV", self,fov)
|
||
|
|
|
||
|
|
if retVal then return retVal end
|
||
|
|
|
||
|
|
self:CorrectScopeFOV()
|
||
|
|
|
||
|
|
local nfov = l_Lerp(self2.IronSightsProgressUnpredicted3 or self:GetIronSightsProgress(), fov, fov * math.min(self:GetStatL("Secondary.OwnerFOV") / 90, 1))
|
||
|
|
local ret = l_Lerp(self2.SprintProgressUnpredicted or self:GetSprintProgress(), nfov, nfov + self2.SprintFOVOffset)
|
||
|
|
|
||
|
|
if self:OwnerIsValid() and not self2.IsMelee then
|
||
|
|
local vpa = self:GetOwner():GetViewPunchAngles()
|
||
|
|
|
||
|
|
ret = ret + math.abs(vpa.p) / 4 + math.abs(vpa.y) / 4 + math.abs(vpa.r) / 4
|
||
|
|
end
|
||
|
|
|
||
|
|
ret = hook.Run("TFA_TranslateFOV", self,ret) or ret
|
||
|
|
|
||
|
|
return ret
|
||
|
|
end
|
||
|
|
|
||
|
|
function SWEP:GetPrimaryAmmoType()
|
||
|
|
return self:GetStatL("Primary.Ammo") or ""
|
||
|
|
end
|
||
|
|
|
||
|
|
function SWEP:ToggleInspect()
|
||
|
|
if self:GetOwner():IsNPC() then return false end -- NPCs can't look at guns silly
|
||
|
|
|
||
|
|
local self2 = self:GetTable()
|
||
|
|
|
||
|
|
if (self:GetSprinting() or self:GetIronSights() or self:GetStatus() ~= TFA.Enum.STATUS_IDLE) and not self:GetCustomizing() then return end
|
||
|
|
|
||
|
|
self:SetCustomizing(not self:GetCustomizing())
|
||
|
|
self2.Inspecting = self:GetCustomizing()
|
||
|
|
self:SetCustomizeUpdated(true)
|
||
|
|
|
||
|
|
--if self2.Inspecting then
|
||
|
|
-- gui.EnableScreenClicker(true)
|
||
|
|
--else
|
||
|
|
-- gui.EnableScreenClicker(false)
|
||
|
|
--end
|
||
|
|
|
||
|
|
return self:GetCustomizing()
|
||
|
|
end
|
||
|
|
|
||
|
|
SWEP.ToggleCustomize = SWEP.ToggleInspect
|
||
|
|
|
||
|
|
function SWEP:GetIsInspecting()
|
||
|
|
return self:GetCustomizing()
|
||
|
|
end
|
||
|
|
|
||
|
|
function SWEP:CustomizingUpdated(_, old, new)
|
||
|
|
if old ~= new and self._inspect_hack ~= new then
|
||
|
|
self._inspect_hack = new
|
||
|
|
|
||
|
|
if new then
|
||
|
|
self:OnCustomizationOpen()
|
||
|
|
else
|
||
|
|
self:OnCustomizationClose()
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
function SWEP:OnCustomizationOpen()
|
||
|
|
-- override
|
||
|
|
-- example:
|
||
|
|
--[[
|
||
|
|
if CLIENT then surface.PlaySound("ui/buttonclickrelease.wav") end
|
||
|
|
]]
|
||
|
|
end
|
||
|
|
|
||
|
|
function SWEP:OnCustomizationClose()
|
||
|
|
-- override
|
||
|
|
end
|
||
|
|
|
||
|
|
function SWEP:EmitSoundNet(sound)
|
||
|
|
if CLIENT or sp then
|
||
|
|
if sp and not IsFirstTimePredicted() then return end
|
||
|
|
|
||
|
|
self:EmitSound(sound)
|
||
|
|
|
||
|
|
return
|
||
|
|
end
|
||
|
|
|
||
|
|
local filter = RecipientFilter()
|
||
|
|
filter:AddPAS(self:GetPos())
|
||
|
|
|
||
|
|
if IsValid(self:GetOwner()) then
|
||
|
|
filter:RemovePlayer(self:GetOwner())
|
||
|
|
end
|
||
|
|
|
||
|
|
net.Start("tfaSoundEvent", true)
|
||
|
|
net.WriteEntity(self)
|
||
|
|
net.WriteString(sound)
|
||
|
|
net.Send(filter)
|
||
|
|
end
|
||
|
|
|
||
|
|
function SWEP:CanBeJammed()
|
||
|
|
return self.CanJam and self:GetMaxClip1() > 0 and sv_tfa_jamming:GetBool()
|
||
|
|
end
|
||
|
|
|
||
|
|
-- Use this to increase/decrease factor added based on ammunition/weather conditions/etc
|
||
|
|
function SWEP:GrabJamFactorMult()
|
||
|
|
return 1 -- override
|
||
|
|
end
|
||
|
|
|
||
|
|
function SWEP:UpdateJamFactor()
|
||
|
|
local self2 = self:GetTable()
|
||
|
|
if not self:CanBeJammed() then return self end
|
||
|
|
self:SetJamFactor(math.min(100, self:GetJamFactor() + self2.JamFactor * sv_tfa_jamming_factor_inc:GetFloat() * self:GrabJamFactorMult()))
|
||
|
|
return self
|
||
|
|
end
|
||
|
|
|
||
|
|
function SWEP:IsJammed()
|
||
|
|
if not self:CanBeJammed() then return false end
|
||
|
|
return self:GetJammed()
|
||
|
|
end
|
||
|
|
|
||
|
|
function SWEP:NotifyJam()
|
||
|
|
local ply = self:GetOwner()
|
||
|
|
|
||
|
|
if IsValid(ply) and ply:IsPlayer() and IsFirstTimePredicted() and (not ply._TFA_LastJamMessage or ply._TFA_LastJamMessage < RealTime()) then
|
||
|
|
ply:PrintMessage(HUD_PRINTCENTER, "#tfa.msg.weaponjammed")
|
||
|
|
ply._TFA_LastJamMessage = RealTime() + 4
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
function SWEP:CheckJammed()
|
||
|
|
if not self:IsJammed() then return false end
|
||
|
|
self:NotifyJam()
|
||
|
|
return true
|
||
|
|
end
|
||
|
|
|
||
|
|
function SWEP:RollJamChance()
|
||
|
|
if not self:CanBeJammed() then return false end
|
||
|
|
if self:IsJammed() then return true end
|
||
|
|
|
||
|
|
local chance = self:GetJamChance()
|
||
|
|
local roll = util.SharedRandom('tfa_base_jam', math.max(0.002711997795105, math.pow(chance, 1.19)), 1, l_CT())
|
||
|
|
|
||
|
|
if roll <= chance * sv_tfa_jamming_mult:GetFloat() then
|
||
|
|
self:SetJammed(true)
|
||
|
|
|
||
|
|
if IsFirstTimePredicted() then
|
||
|
|
self:NotifyJam()
|
||
|
|
end
|
||
|
|
|
||
|
|
return true
|
||
|
|
end
|
||
|
|
|
||
|
|
return false
|
||
|
|
end
|
||
|
|
|
||
|
|
function SWEP:GrabJamChanceMult()
|
||
|
|
return 1 -- override
|
||
|
|
end
|
||
|
|
|
||
|
|
function SWEP:GetJamChance()
|
||
|
|
-- you can safely override this with your own logic if you desire
|
||
|
|
local self2 = self:GetTable()
|
||
|
|
if not self:CanBeJammed() then return 0 end
|
||
|
|
return self:GetJamFactor() * sv_tfa_jamming_factor:GetFloat() * (self2.JamChance / 100) * self:GrabJamChanceMult()
|
||
|
|
end
|
||
|
|
|
||
|
|
SWEP.FlashlightSoundToggleOn = Sound("HL2Player.FlashLightOn")
|
||
|
|
SWEP.FlashlightSoundToggleOff = Sound("HL2Player.FlashLightOff")
|
||
|
|
|
||
|
|
function SWEP:ToggleFlashlight(toState)
|
||
|
|
if toState == nil then
|
||
|
|
toState = not self:GetFlashlightEnabled()
|
||
|
|
end
|
||
|
|
|
||
|
|
self:SetFlashlightEnabled(toState)
|
||
|
|
self:EmitSoundNet(self:GetStatL("FlashlightSoundToggle" .. (toState and "On" or "Off")))
|
||
|
|
end
|
||
|
|
|
||
|
|
-- source engine save load
|
||
|
|
function SWEP:OnRestore()
|
||
|
|
self:BuildAttachmentCache()
|
||
|
|
|
||
|
|
self:InitializeAnims()
|
||
|
|
self:InitializeMaterialTable()
|
||
|
|
|
||
|
|
self:IconFix()
|
||
|
|
|
||
|
|
do -- attempt to restore attachments; weapons DO have owner so we don't need the precautions
|
||
|
|
local OldFD = self.IsFirstDeploy
|
||
|
|
|
||
|
|
self.IsFirstDeploy = true -- so extmag attachments don't unload the clip
|
||
|
|
for attName, sel in pairs(self.AttachmentCache or {}) do
|
||
|
|
if sel then
|
||
|
|
local att = TFA.Attachments.Atts[attName]
|
||
|
|
|
||
|
|
if att and att.Attach then
|
||
|
|
att:Attach(self)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
self.IsFirstDeploy = OldFD
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
-- lua autorefresh / weapons.Register
|
||
|
|
function SWEP:OnReloaded()
|
||
|
|
-- queue to next game frame since gmod is a fucking idiot
|
||
|
|
timer.Simple(0, function()
|
||
|
|
if not self:IsValid() then return end
|
||
|
|
|
||
|
|
local baseclassSelf = table.Copy(baseclass.Get(self:GetClass()))
|
||
|
|
if not baseclassSelf then return end
|
||
|
|
|
||
|
|
local self2 = self:GetTable()
|
||
|
|
|
||
|
|
self2.Primary_TFA.RangeFalloffLUTBuilt = nil
|
||
|
|
self2.Primary.RangeFalloffLUTBuilt = nil
|
||
|
|
|
||
|
|
--TFA.MigrateStructure(self, baseclassSelf, self:GetClass(), true)
|
||
|
|
--TFA.MigrateStructure(self, self2, self:GetClass(), true)
|
||
|
|
|
||
|
|
if istable(baseclassSelf.Primary) then
|
||
|
|
self2.Primary_TFA = table.Copy(baseclassSelf.Primary)
|
||
|
|
TFA.UnfoldBaseClass(baseclassSelf.Primary)
|
||
|
|
end
|
||
|
|
|
||
|
|
if istable(baseclassSelf.Secondary) then
|
||
|
|
self2.Secondary_TFA = table.Copy(baseclassSelf.Secondary)
|
||
|
|
TFA.UnfoldBaseClass(baseclassSelf.Secondary)
|
||
|
|
end
|
||
|
|
|
||
|
|
self2.StatCache_Blacklist = baseclassSelf.StatCache_Blacklist
|
||
|
|
TFA.UnfoldBaseClass(self2.StatCache_Blacklist)
|
||
|
|
|
||
|
|
if self2.StatCache_Blacklist_Real then
|
||
|
|
table.Merge(self2.StatCache_Blacklist, self2.StatCache_Blacklist_Real)
|
||
|
|
end
|
||
|
|
|
||
|
|
self2.StatCache_Blacklist_Real = patch_blacklist(self2.StatCache_Blacklist, self2.TFADataVersion)
|
||
|
|
|
||
|
|
self2.event_table_warning = false
|
||
|
|
self2.event_table_built = false
|
||
|
|
|
||
|
|
self2.AutoDetectMuzzle(self)
|
||
|
|
self2.AutoDetectDamage(self)
|
||
|
|
self2.AutoDetectDamageType(self)
|
||
|
|
self2.AutoDetectForce(self)
|
||
|
|
self2.AutoDetectPenetrationPower(self)
|
||
|
|
self2.AutoDetectKnockback(self)
|
||
|
|
self2.AutoDetectSpread(self)
|
||
|
|
self2.AutoDetectRange(self)
|
||
|
|
self2.ClearStatCache(self)
|
||
|
|
end)
|
||
|
|
end
|
||
|
|
|
||
|
|
function SWEP:ProcessLoopSound()
|
||
|
|
if sp and not SERVER then return end
|
||
|
|
if self:GetNextLoopSoundCheck() < 0 or ct < self:GetNextLoopSoundCheck() or self:GetStatus() == TFA.Enum.STATUS_SHOOTING then return end
|
||
|
|
|
||
|
|
self:SetNextLoopSoundCheck(-1)
|
||
|
|
|
||
|
|
local tgtSound = self:GetStatL("Primary.LoopSound")
|
||
|
|
|
||
|
|
if self:GetSilenced() then
|
||
|
|
tgtSound = self:GetStatL("Primary.LoopSoundSilenced", tgtSound)
|
||
|
|
end
|
||
|
|
|
||
|
|
if tgtSound then
|
||
|
|
self:StopSoundNet(tgtSound)
|
||
|
|
end
|
||
|
|
|
||
|
|
if (not sp and SERVER) or not self:IsFirstPerson() then
|
||
|
|
tgtSound = self:GetSilenced() and self:GetStatL("Primary.LoopSoundSilenced_World", tgtSound) or self:GetStatL("Primary.LoopSound_World", tgtSound)
|
||
|
|
|
||
|
|
if tgtSound then
|
||
|
|
self:StopSoundNet(tgtSound)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
tgtSound = self:GetStatL("Primary.LoopSoundTail")
|
||
|
|
|
||
|
|
if self:GetSilenced() then
|
||
|
|
tgtSound = self:GetStatL("Primary.LoopSoundTailSilenced", tgtSound)
|
||
|
|
end
|
||
|
|
|
||
|
|
if (not sp and SERVER) or not self:IsFirstPerson() then
|
||
|
|
tgtSound = self:GetSilenced() and self:GetStatL("Primary.LoopSoundTailSilenced_World", tgtSound) or self:GetStatL("Primary.LoopSoundTail_World", tgtSound)
|
||
|
|
end
|
||
|
|
|
||
|
|
if tgtSound and (SERVER or self.GunfireLoopIFTPHack) then
|
||
|
|
self:EmitSoundNet(tgtSound)
|
||
|
|
self.GunfireLoopIFTPHack = false
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
function SWEP:ProcessLoopFire()
|
||
|
|
local self2 = self:GetTable()
|
||
|
|
if sp and not IsFirstTimePredicted() then return end
|
||
|
|
if (self:GetStatus() == TFA.Enum.STATUS_SHOOTING ) then
|
||
|
|
if TFA.Enum.ShootLoopingStatus[self:GetShootStatus()] then
|
||
|
|
self:SetShootStatus(TFA.Enum.SHOOT_LOOP)
|
||
|
|
end
|
||
|
|
else --not shooting
|
||
|
|
if (not TFA.Enum.ShootReadyStatus[self:GetShootStatus()]) then
|
||
|
|
if ( self:GetShootStatus() ~= TFA.Enum.SHOOT_CHECK ) then
|
||
|
|
self:SetShootStatus(TFA.Enum.SHOOT_CHECK) --move to check first
|
||
|
|
else --if we've checked for one more tick that we're not shooting
|
||
|
|
self:SetShootStatus(TFA.Enum.SHOOT_IDLE) --move to check first
|
||
|
|
if not ( self:GetSprinting() and self2.Sprint_Mode ~= TFA.Enum.LOCOMOTION_LUA ) then --assuming we don't need to transition into sprint
|
||
|
|
self:PlayAnimation(self:GetStatL("ShootAnimation.out")) --exit
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|