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 = ""
SWEP.Contact = ""
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.LoopedReloadInsertAmount = 1
SWEP.ShotgunEmptyAnim = false
SWEP.ShotgunEmptyAnim_Shell = true
SWEP.ShotgunStartAnimShell = false --shotgun start anim inserts shell

SWEP.Secondary.IronSightsEnabled = true
SWEP.Secondary.ScopeZoom = 1
SWEP.Secondary.ScopeScreenScale = 0.392592592592592

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.Secondary.AmmoConsumption = 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

--[[
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")

	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

	self:NetworkVarTFA("Bool", "IsFirstDeploy")
	self:NetworkVarTFA("Float", "LastDeployAnim")

	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.RunAutoDetection(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:ResetAnimCycle()
	self:ResetFirstDeploy()

	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 IsValid(ply) and ply:IsPlayer() then
		if CLIENT then
			self:ResetKeyBindHintAlpha()
		elseif sp then
			self:CallOnClient("ResetKeyBindHintAlpha")
		end
	end

	ct = l_CT()

	if not self2.VMIV(self) 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
	ct = l_CT()
	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()

		if IsValid(target) and target:IsWeapon() and not target.IsTFAWeapon then
			if CLIENT then
				self:ResetKeyBindHintAlpha(true)
			elseif sp then
				self:CallOnClient("ResetKeyBindHintAlpha", "true")
			end
		end

		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

local tickInterval = engine.TickInterval()

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
	if is then
		adstransitionspeed = 12.5 / (self:GetStatL("IronSightTime") / 0.3)
	elseif spr or walk then
		adstransitionspeed = 7.5
	else
		adstransitionspeed = 12.5
	end
	adstransitionspeed = math.min(adstransitionspeed, 1000)

	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.IronSightsProgressPredicted = self2.GetIronSightsProgress(self) + (ist - self2.GetIronSightsProgress(self)) * tickInterval * adstransitionspeed * TFA.TickDelta
	self2.SprintProgressPredicted = self2.GetSprintProgress(self) + (sprt - self2.GetSprintProgress(self)) * tickInterval * adstransitionspeed * TFA.TickDelta
	self2.InspectingProgressPredicted = self2.GetInspectingProgress(self) + ((self2.GetCustomizing(self) and 1 or 0) - self2.GetInspectingProgress(self)) * tickInterval * 10 * TFA.TickDelta

	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

	local isbolt = self2.GetStatL(self, "BoltAction")
	local isbolt_forced = self2.GetStatL(self, "BoltAction_Forced")
	if isbolt or isbolt_forced then
		if stat == TFA.Enum.STATUS_SHOOTING and not self2.LastBoltShoot then
			self2.LastBoltShoot = l_CT()
		end

		if self2.LastBoltShoot then
			if stat == TFA.Enum.STATUS_SHOOTING then
				if l_CT() > self2.LastBoltShoot + self2.GetStatL(self, "BoltTimerOffset") then
					issighting = false
				end
			else
				self2.LastBoltShoot = nil
			end
		end

		if (stat == TFA.Enum.STATUS_IDLE and self:GetReloadLoopCancel(true)) or stat == TFA.Enum.STATUS_PUMP then
			issighting = false
		end
	end

	local sightsMode = self2.GetStatL(self, "Sights_Mode")
	local sprintMode = self2.GetStatL(self, "Sprint_Mode")
	local walkMode = self2.GetStatL(self, "Walk_Mode")
	local customizeMode = self2.GetStatL(self, "Customize_Mode")

	if old_iron_sights_final ~= issighting and sightsMode == TFA.Enum.LOCOMOTION_LUA then -- and stat == TFA.Enum.STATUS_IDLE then
		self:SetNextIdleAnim(-1)
	end

	local smi = (sightsMode ~= TFA.Enum.LOCOMOTION_LUA)
		and old_iron_sights_final ~= issighting

	local spi = (sprintMode ~= TFA.Enum.LOCOMOTION_LUA)
		and self2.sprinting_updated

	local wmi = (walkMode ~= TFA.Enum.LOCOMOTION_LUA)
		and self2.walking_updated

	local cmi = (customizeMode ~= TFA.Enum.LOCOMOTION_LUA)
		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 (sightsMode ~= 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 attackKeyPressed = false
	if IsValid(self:GetOwner()) and self:GetOwner():IsPlayer() then
		attackKeyPressed = self:GetOwner():KeyPressed(IN_ATTACK)
	end

	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 attackKeyPressed and self:GetStatL("LoopedReload") and TFA.Enum.ReloadStatus[stat] then
			self:SetReloadLoopCancel(true)
		end

		return false
	end

	if self:IsSafety() then
		if attackKeyPressed 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)
		end

		return false
	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, nil, true)
	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 self:GetStatRawL("CanBeSilenced") and (ply.KeyDown and self:KeyDown(IN_USE)) and (SERVER or not sp) and (ply.GetInfoNum and ply:GetInfoNum("cl_tfa_keys_silencer", 0) == 0) then
		local _, tanim, ttype = self:ChooseSilenceAnim(not self:GetSilenced())
		self:ScheduleStatus(TFA.Enum.STATUS_SILENCER_TOGGLE, self:GetActivityLength(tanim, true, ttype))

		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, ttype = self:ChooseShootAnim(ifp)

	ply:SetAnimation(PLAYER_ATTACK1)

	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 self:ShouldEmitGunfireLoop(tableName) 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, ttype)))))
	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()
	local attackKeyPressed = false
	if IsValid(self:GetOwner()) and self:GetOwner():IsPlayer() then
		attackKeyPressed = self:GetOwner():KeyPressed(IN_ATTACK2)
	end

	local self2 = self:GetTable()

	local v = hook.Run("TFA_PreCanSecondaryAttack", self)

	if v ~= nil then
		return v
	end

	if self:IsSafety() then
		if attackKeyPressed 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()
			end

			self:SetLastSafetyShoot(l_CT() + 0.2)
		end

		return false
	end

	if self:GetSprintProgress() >= 0.1 and not self:GetStatL("AllowSprintAttack", false) then
		return false
	end

	if self:GetStatL("Secondary.ClipSize") <= 0 and self:Ammo2() < self:GetStatL("Secondary.AmmoConsumption") then
		Dryfire(self, self2)
		return false
	end

	if self:GetSecondaryClipSize(true) > 0 and self:Clip2() < self:GetStatL("Secondary.AmmoConsumption") then
		Dryfire(self, self2, true)
		return false
	end

	if self2.GetStatL(self, "Secondary.FiresUnderwater") == false and self:GetOwner():WaterLevel() >= 3 then
		self:SetNextSecondaryFire(l_CT() + 0.5)
		self:EmitSound(self:GetStatL("Primary.Sound_Blocked"))
		return false
	end

	-- self2.SetHasPlayedEmptyClick(self, false)

	if l_CT() < self:GetNextSecondaryFire() then return false end

	local v2 = hook.Run("TFA_CanSecondaryAttack", 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("shoot2_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 -- override
end

function SWEP:SecondaryAttack()
	if not self:CanSecondaryAttack() then return end

	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()
	end

	self:PostSecondaryAttack()
	hook.Run("TFA_PostSecondaryAttack", self)
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 = self2.VMIV(self)

	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

	ct = l_CT()
	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

			self:GetOwner():SetAnimation(PLAYER_RELOAD)

			if self:GetStatL("Primary.ReloadSound") and IsFirstTimePredicted() then
				self:EmitSound(self:GetStatL("Primary.ReloadSound"))
			end

			self:ResetAnimCycle()

			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 isplayer = self:GetOwner():IsPlayer()
	local vm = self2.VMIV(self)

	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

	ct = l_CT()
	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

			self:GetOwner():SetAnimation(PLAYER_RELOAD)

			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 self:GetOwner():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, ttype) < 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
]]

local cv_fov_sprintmult = GetConVar("sv_tfa_fov_sprintmod")

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

	self2.CorrectScopeFOV(self)

	local ironprog = self2.IronSightsProgressPredicted or self2.GetIronSightsProgress(self)
	if self2.GetStatL(self, "Secondary.OwnerFOVUseThreshold", self2.GetStatL(self, "Scoped")) then
		local threshold = math.min(self2.GetStatL(self, "Secondary.OwnerFOVThreshold", self2.GetStatL(self, "ScopeOverlayThreshold")), 0.999999)

		ironprog = ironprog < threshold and 0 or math.max(ironprog - threshold, 0) / (1 - threshold)
	end

	local nfov = l_Lerp(ironprog, fov, fov * math.min(self2.GetStatL(self, "Secondary.OwnerFOV") / 90, 1))

	local ret = nfov
	if cv_fov_sprintmult:GetBool() then
		ret = l_Lerp(self2.SprintProgressPredicted or self2.GetSprintProgress(self), nfov, nfov + self2.GetStatL(self, "SprintFOVOffset", 5))
	end

	if self2.OwnerIsValid(self) 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: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()
	self:RemoveEmptyRTCode()

	do -- attempt to restore attachments; weapons DO have owner so we don't need the precautions
		local OldFD = self:GetIsFirstDeploy()

		self:SetIsFirstDeploy(true) -- so extmag attachments don't unload the clip
		self.IsFirstDeploy = true
		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:SetIsFirstDeploy(OldFD)
		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.IconFix(self)
		self2.RemoveEmptyRTCode(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, nil, true)
		self.GunfireLoopIFTPHack = false
	end
end

function SWEP:ProcessLoopFire()
	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 TFA.Enum.ReadyStatus[self:GetStatus()] then
					self:PlayAnimation(self:GetStatL("ShootAnimation.out")) --exit

					-- force flip walking and sprinting flags when needed
					if self:GetWalking() then
						self.walking_updated = true
					end
					if self:GetSprinting() then
						self.sprinting_updated = true
					end
				end
			end
		end
	end
end
