local sp = game.SinglePlayer()

SWEP.Locomotion_Data_Queued = nil

local ServersideLooped = {
	[ACT_VM_FIDGET] = true,
	[ACT_VM_FIDGET_EMPTY] = true
}

--[ACT_VM_IDLE] = true,
--[ACT_VM_IDLE_EMPTY] = true,
--[ACT_VM_IDLE_SILENCED] = true
local d, pbr

-- Override this after SWEP:Initialize, for example, in attachments
SWEP.BaseAnimations = {
	["draw_first"] = {
		["type"] = TFA.Enum.ANIMATION_ACT, --Sequence or act
		["value"] = ACT_VM_DRAW_DEPLOYED,
		["enabled"] = nil --Manually force a sequence to be enabled
	},
	["draw"] = {
		["type"] = TFA.Enum.ANIMATION_ACT, --Sequence or act
		["value"] = ACT_VM_DRAW
	},
	["draw_empty"] = {
		["type"] = TFA.Enum.ANIMATION_ACT, --Sequence or act
		["value"] = ACT_VM_DRAW_EMPTY
	},
	["draw_silenced"] = {
		["type"] = TFA.Enum.ANIMATION_ACT, --Sequence or act
		["value"] = ACT_VM_DRAW_SILENCED
	},
	["shoot1"] = {
		["type"] = TFA.Enum.ANIMATION_ACT, --Sequence or act
		["value"] = ACT_VM_PRIMARYATTACK
	},
	["shoot1_last"] = {
		["type"] = TFA.Enum.ANIMATION_ACT, --Sequence or act
		["value"] = ACT_VM_PRIMARYATTACK_EMPTY
	},
	["shoot1_empty"] = {
		["type"] = TFA.Enum.ANIMATION_ACT, --Sequence or act
		["value"] = ACT_VM_DRYFIRE
	},
	["shoot1_silenced"] = {
		["type"] = TFA.Enum.ANIMATION_ACT, --Sequence or act
		["value"] = ACT_VM_PRIMARYATTACK_SILENCED
	},
	["shoot1_silenced_empty"] = {
		["type"] = TFA.Enum.ANIMATION_ACT, --Sequence or act
		["value"] = ACT_VM_DRYFIRE_SILENCED or 0
	},
	["shoot1_is"] = {
		["type"] = TFA.Enum.ANIMATION_ACT, --Sequence or act
		["value"] = ACT_VM_PRIMARYATTACK_1
	},
	["shoot2"] = {
		["type"] = TFA.Enum.ANIMATION_ACT, --Sequence or act
		["value"] = ACT_VM_SECONDARYATTACK
	},
	["shoot2_last"] = {
		["type"] = TFA.Enum.ANIMATION_SEQ, --Sequence or act
		["value"] = "shoot2_last"
	},
	["shoot2_empty"] = {
		["type"] = TFA.Enum.ANIMATION_ACT, --Sequence or act
		["value"] = ACT_VM_DRYFIRE
	},
	["shoot2_silenced"] = {
		["type"] = TFA.Enum.ANIMATION_SEQ, --Sequence or act
		["value"] = "shoot2_silenced"
	},
	["shoot2_is"] = {
		["type"] = TFA.Enum.ANIMATION_ACT, --Sequence or act
		["value"] = ACT_VM_ISHOOT_M203
	},
	["idle"] = {
		["type"] = TFA.Enum.ANIMATION_ACT, --Sequence or act
		["value"] = ACT_VM_IDLE
	},
	["idle_empty"] = {
		["type"] = TFA.Enum.ANIMATION_ACT, --Sequence or act
		["value"] = ACT_VM_IDLE_EMPTY
	},
	["idle_silenced"] = {
		["type"] = TFA.Enum.ANIMATION_ACT, --Sequence or act
		["value"] = ACT_VM_IDLE_SILENCED
	},
	["reload"] = {
		["type"] = TFA.Enum.ANIMATION_ACT, --Sequence or act
		["value"] = ACT_VM_RELOAD
	},
	["reload_empty"] = {
		["type"] = TFA.Enum.ANIMATION_ACT, --Sequence or act
		["value"] = ACT_VM_RELOAD_EMPTY
	},
	["reload_silenced"] = {
		["type"] = TFA.Enum.ANIMATION_ACT, --Sequence or act
		["value"] = ACT_VM_RELOAD_SILENCED
	},
	["reload_shotgun_start"] = {
		["type"] = TFA.Enum.ANIMATION_ACT,
		["value"] = ACT_SHOTGUN_RELOAD_START
	},
	["reload_shotgun_finish"] = {
		["type"] = TFA.Enum.ANIMATION_ACT,
		["value"] = ACT_SHOTGUN_RELOAD_FINISH
	},
	["reload_is"] = {
		["type"] = TFA.Enum.ANIMATION_ACT,
		["value"] = ACT_VM_RELOAD_ADS
	},
	["reload_empty_is"] = {
		["type"] = TFA.Enum.ANIMATION_ACT,
		["value"] = ACT_VM_RELOAD_EMPTY_ADS
	},
	["reload_silenced_is"] = {
		["type"] = TFA.Enum.ANIMATION_ACT,
		["value"] = ACT_VM_RELOAD_SILENCED_ADS
	},
	["reload_shotgun_start_is"] = {
		["type"] = TFA.Enum.ANIMATION_ACT,
		["value"] = ACT_SHOTGUN_RELOAD_START_ADS
	},
	["reload_shotgun_finish_is"] = {
		["type"] = TFA.Enum.ANIMATION_ACT,
		["value"] = ACT_SHOTGUN_RELOAD_FINISH_ADS
	},
	["holster"] = {
		["type"] = TFA.Enum.ANIMATION_ACT, --Sequence or act
		["value"] = ACT_VM_HOLSTER
	},
	["holster_empty"] = {
		["type"] = TFA.Enum.ANIMATION_ACT, --Sequence or act
		["value"] = ACT_VM_HOLSTER_EMPTY
	},
	["holster_silenced"] = {
		["type"] = TFA.Enum.ANIMATION_ACT, --Sequence or act
		["value"] = ACT_VM_HOLSTER_SILENCED
	},
	["silencer_attach"] = {
		["type"] = TFA.Enum.ANIMATION_ACT, --Sequence or act
		["value"] = ACT_VM_ATTACH_SILENCER
	},
	["silencer_detach"] = {
		["type"] = TFA.Enum.ANIMATION_ACT, --Sequence or act
		["value"] = ACT_VM_DETACH_SILENCER
	},
	["rof"] = {
		["type"] = TFA.Enum.ANIMATION_ACT, --Sequence or act
		["value"] = ACT_VM_FIREMODE
	},
	["rof_is"] = {
		["type"] = TFA.Enum.ANIMATION_ACT, --Sequence or act
		["value"] = ACT_VM_IFIREMODE
	},
	["bash"] = {
		["type"] = TFA.Enum.ANIMATION_ACT, --Sequence or act
		["value"] = ACT_VM_HITCENTER
	},
	["bash_silenced"] = {
		["type"] = TFA.Enum.ANIMATION_ACT, --Sequence or act
		["value"] = ACT_VM_HITCENTER2
	},
	["bash_empty"] = {
		["type"] = TFA.Enum.ANIMATION_ACT, --Sequence or act
		["value"] = ACT_VM_MISSCENTER
	},
	["bash_empty_silenced"] = {
		["type"] = TFA.Enum.ANIMATION_ACT, --Sequence or act
		["value"] = ACT_VM_MISSCENTER2
	},
	["inspect"] = {
		["type"] = TFA.Enum.ANIMATION_ACT, --Sequence or act
		["value"] = ACT_VM_FIDGET
	},
	["inspect_empty"] = {
		["type"] = TFA.Enum.ANIMATION_ACT, --Sequence or act
		["value"] = ACT_VM_FIDGET_EMPTY
	},
	["inspect_silenced"] = {
		["type"] = TFA.Enum.ANIMATION_ACT, --Sequence or act
		["value"] = ACT_VM_FIDGET_SILENCED
	}
}

SWEP.Animations = {}

function SWEP:InitializeAnims()
	local self2 = self:GetTable()

	setmetatable(self2.Animations, {
		__index = function(t, k) return self2.BaseAnimations[k] end
	})
end

function SWEP:BuildAnimActivities()
	local self2 = self:GetTable()
	self2.AnimationActivities = self2.AnimationActivities or {}

	for k, v in pairs(self2.BaseAnimations) do
		if v.value then
			self2.AnimationActivities[v.value] = k
		end

		local kvt = self2.GetStatL(self, "Animations." .. k)

		if kvt.value then
			self2.AnimationActivities[kvt.value] = k
		end
	end

	for k, _ in pairs(self2.Animations) do
		local kvt = self2.GetStatL(self, "Animations." .. k)

		if kvt.value then
			self2.AnimationActivities[kvt.value] = k
		end
	end
end

function SWEP:GetActivityEnabled(act)
	local self2 = self:GetTable()
	local stat = self2.GetStatL(self, "SequenceEnabled." .. act)
	if stat then return stat end

	if not self2.AnimationActivities then
		self:BuildAnimActivities()
	end

	local keysel = self2.AnimationActivities[act] or ""
	local kv = self2.GetStatL(self, "Animations." .. keysel)
	if not kv then return false end

	if kv["enabled"] then
		return kv["enabled"]
	else
		return false
	end
end

function SWEP:ChooseAnimation(keyOrData)
	local self2 = self:GetTable()

	local data

	if isstring(keyOrData) then
		data = self2.GetStatL(self, "Animations." .. keyOrData)
	elseif istable(keyOrData) then
		data = keyOrData
	else
		error("Unknown value type " .. type(keyOrData) .. " passed!")
	end

	if not data then return 0, 0 end
	if not data["type"] then return 0, 0 end
	if not data["value"] then return 0, 0 end

	local retType, retValue = data["type"], data["value"]

	if self:Clip1() <= 0 and self2.GetStatL(self, "Primary.ClipSize") >= 0 then
		if data.value_empty then
			retValue = data.value_empty
			retType = data.type_empty or retType
		end
	end

	if self:Clip1() == 1 and self2.GetStatL(self, "Primary.ClipSize") >= 0 then
		if data.value_last then
			retValue = data.value_last
			retType = data.type_last or retType
		end
	end

	if self2.GetSilenced(self) then
		local previousRetType = retType

		if data.value_sil then
			retValue = data.value_sil
			retType = data.type_sil or previousRetType
		end

		if self:Clip1() <= 0 and self2.GetStatL(self, "Primary.ClipSize") >= 0 then
			if data.value_sil_empty then
				retValue = data.value_sil_empty
				retType = data.type_sil_empty or previousRetType
			end
		end
	end

	if self:GetIronSights() then
		local previousRetType = retType

		if data.value_is then
			retValue = data.value_is
			retType = data.type_is or previousRetType
		end

		if self:Clip1() <= 0 and self2.GetStatL(self, "Primary.ClipSize") >= 0 then
			if data.value_is_empty then
				retValue = data.value_is_empty
				retType = data.type_is_empty or previousRetType
			end
		end

		if self:Clip1() == 1 and self2.GetStatL(self, "Primary.ClipSize") >= 0 then
			if data.value_is_last then
				retValue = data.value_is_last
				retType = data.type_is_last or previousRetType
			end
		end

		if self2.GetSilenced(self) then
			if data.value_is_sil then
				retValue = data.value_is_sil
				retType = data.type_is_sil or previousRetType
			end

			if self:Clip1() <= 0 and self2.GetStatL(self, "Primary.ClipSize") >= 0 then
				if data.value_is_sil_empty then
					retValue = data.value_is_sil_empty
					retType = data.type_is_sil_empty or previousRetType
				end
			end

			if self:Clip1() == 1 and self2.GetStatL(self, "Primary.ClipSize") >= 0 then
				if data.value_is_sil_last then
					retValue = data.value_is_sil_last
					retType = data.type_is_sil_last or previousRetType
				end
			end
		end
	end

	if retType == TFA.Enum.ANIMATION_ACT and isstring(retValue) then
		retValue = tonumber(retValue) or -1
	elseif retType == TFA.Enum.ANIMATION_SEQ and isstring(retValue) then
		retValue = self2.OwnerViewModel:LookupSequence(retValue)
	end

	return retType, retValue
end

function SWEP:GetAnimationRate(ani, animationType)
	local self2 = self:GetTable()
	local rate = 1
	if not ani or ani < 0 or not self2.VMIV(self) then return rate end

	local nm

	if animationType == TFA.Enum.ANIMATION_ACT or animationType == nil then
		nm = self2.OwnerViewModel:GetSequenceName(self2.OwnerViewModel:SelectWeightedSequence(ani))
	elseif isnumber(ani) then
		nm = self2.OwnerViewModel:GetSequenceName(ani)
	elseif isstring(ani) then
		nm = ani
	else
		error("ani argument is typeof " .. type(ani))
	end

	local sqto = self2.GetStatL(self, "SequenceTimeOverride." .. nm) or self2.GetStatL(self, "SequenceTimeOverride." .. (ani or "0"))
	local sqro = self2.GetStatL(self, "SequenceRateOverride." .. nm) or self2.GetStatL(self, "SequenceRateOverride." .. (ani or "0"))

	if sqro then
		rate = rate * sqro
	elseif sqto then
		local t = self:GetActivityLengthRaw(ani, false)

		if t then
			rate = rate * t / sqto
		end
	end

	rate = hook.Run("TFA_AnimationRate", self, ani, rate) or rate

	return rate
end

function SWEP:SendViewModelAnim(act, rate, targ, blend)
	local self2 = self:GetTable()
	if not self2.VMIV(self) then return false, act end
	local vm = self2.OwnerViewModel

	if rate and not targ then
		rate = math.max(rate, 0.0001)
	end

	if not rate then
		rate = 1
	end

	if targ then
		rate = rate / self:GetAnimationRate(act)
	else
		rate = rate * self:GetAnimationRate(act)
	end

	if act < 0 then return false, act end
	local seq = vm:SelectWeightedSequenceSeeded(act, self:GetSeedIrradical())

	if seq < 0 then
		if act == ACT_VM_IDLE_EMPTY then
			seq = vm:SelectWeightedSequenceSeeded(ACT_VM_IDLE, self:GetSeedIrradical())
		elseif act == ACT_VM_PRIMARYATTACK_EMPTY then
			seq = vm:SelectWeightedSequenceSeeded(ACT_VM_PRIMARYATTACK, self:GetSeedIrradical())
		else
			return false, 0
		end

		if seq < 0 then return false, act end
	end

	local preLastActivity = self:GetLastActivity()
	--local preLastSequence = self:GetLastActivity()
	self:SetLastActivity(act)
	self:SetLastSequence(seq)
	self:ResetEvents()

	if preLastActivity == act and ServersideLooped[act] then
		self:ChooseIdleAnim()
		d = vm:SequenceDuration(seq)
		pbr = targ and (d / (rate or 1)) or (rate or 1)

		if IsValid(self) then
			if blend == nil then
				blend = self2.Idle_Smooth
			end

			self:SetNextIdleAnim(CurTime() + d / pbr - blend)
		end

		if IsFirstTimePredicted() then
			timer.Simple(0, function()
				vm:SendViewModelMatchingSequence(seq)
				d = vm:SequenceDuration()
				pbr = targ and (d / (rate or 1)) or (rate or 1)
				vm:SetPlaybackRate(pbr)

				if IsValid(self) then
					if blend == nil then
						blend = self2.Idle_Smooth
					end

					self:SetNextIdleAnim(CurTime() + d / pbr - blend)
					self:SetLastActivity(act)
				end
			end)
		end
	else
		if seq >= 0 then
			vm:SendViewModelMatchingSequence(seq)
		end

		d = vm:SequenceDuration()
		pbr = targ and (d / (rate or 1)) or (rate or 1)
		vm:SetPlaybackRate(pbr)

		if blend == nil then
			blend = self2.Idle_Smooth
		end

		self:SetNextIdleAnim(CurTime() + math.max(d / pbr - blend, self2.Idle_Smooth))
	end

	return true, act
end

function SWEP:SendViewModelSeq(seq, rate, targ, blend)
	local self2 = self:GetTable()
	local seqold = seq

	if not self2.VMIV(self) then return false, 0 end
	local vm = self2.OwnerViewModel

	if isstring(seq) then
		seq = vm:LookupSequence(seq) or 0
	end

	local act = vm:GetSequenceActivity(seq)

	if self2.SequenceRateOverride[seqold] then
		rate = self2.SequenceRateOverride[seqold]
		targ = false
	elseif self2.SequenceRateOverride[act] then
		rate = self2.SequenceRateOverride[act]
		targ = false
	elseif self2.SequenceTimeOverride[seqold] then
		rate = self2.SequenceTimeOverride[seqold]
		targ = true
	elseif self2.SequenceTimeOverride[act] then
		rate = self2.SequenceTimeOverride[act]
		targ = true
	end

	if not rate then
		rate = 1
	end

	if targ then
		rate = rate / self:GetAnimationRate(seq, TFA.Enum.ANIMATION_SEQ)
	else
		rate = rate * self:GetAnimationRate(seq, TFA.Enum.ANIMATION_SEQ)
	end

	if seq < 0 then return false, seq end

	local preLastActivity = self:GetLastActivity()
	--local preLastSequence = self:GetLastSequence()
	self:SetLastActivity(act)
	self:SetLastSequence(seq)
	self:ResetEvents()

	if preLastActivity == act and ServersideLooped[act] then
		vm:SendViewModelMatchingSequence(act == 0 and 1 or 0)
		vm:SetPlaybackRate(0)
		vm:SetCycle(0)
		self:SetNextIdleAnim(CurTime() + 0.03)

		if IsFirstTimePredicted() then
			timer.Simple(0, function()
				vm:SendViewModelMatchingSequence(seq)
				d = vm:SequenceDuration()
				pbr = targ and (d / (rate or 1)) or (rate or 1)
				vm:SetPlaybackRate(pbr)

				if IsValid(self) then
					if blend == nil then
						blend = self2.Idle_Smooth
					end

					self:SetNextIdleAnim(CurTime() + d / pbr - blend)
					self:SetLastActivity(act)
				end
			end)
		end
	else
		if seq >= 0 then
			vm:SendViewModelMatchingSequence(seq)
		end

		d = vm:SequenceDuration()
		pbr = targ and (d / (rate or 1)) or (rate or 1)
		vm:SetPlaybackRate(pbr)

		if IsValid(self) then
			if blend == nil then
				blend = self2.Idle_Smooth
			end

			self:SetNextIdleAnim(CurTime() + d / pbr - blend)
		end
	end

	return true, seq
end

function SWEP:PlayAnimation(data, fade, rate, targ)
	local self2 = self:GetTable()
	if not self2.VMIV(self) then return false, -1 end
	if not data then return false, -1 end

	local ttype, tval = self:ChooseAnimation(data)

	if ttype == TFA.Enum.ANIMATION_SEQ then
		local success, activityID = self:SendViewModelSeq(tval, rate or 1, targ, fade or (data.transition and self2.Idle_Blend or self2.Idle_Smooth))
		return success, activityID, TFA.Enum.ANIMATION_SEQ
	end

	local success, activityID = self:SendViewModelAnim(tval, rate or 1, targ, fade or (data.transition and self2.Idle_Blend or self2.Idle_Smooth))
	return success, activityID, TFA.Enum.ANIMATION_ACT
end

--[[
Function Name:  Locomote
Syntax: self:Locomote( flip ironsights, new is, flip sprint, new sprint, flip walk, new walk).
Returns:
Notes:
Purpose:  Animation / Utility
]]
local tldata

function SWEP:Locomote(flipis, is, flipsp, spr, flipwalk, walk, flipcust, cust)
	local self2 = self:GetTable()
	if not (flipis or flipsp or flipwalk or flipcust) then return end
	if not (self:GetStatus() == TFA.Enum.STATUS_IDLE or (self:GetStatus() == TFA.Enum.STATUS_SHOOTING and self:CanInterruptShooting())) then return end
	tldata = nil

	if flipis then
		if is and self2.GetStatL(self, "IronAnimation.in") then
			tldata = self2.GetStatL(self, "IronAnimation.in", tldata)
		elseif self2.GetStatL(self, "IronAnimation.out") and not flipsp then
			tldata = self2.GetStatL(self, "IronAnimation.out", tldata)
		end
	end

	if flipsp then
		if spr and self2.GetStatL(self, "SprintAnimation.in") then
			tldata = self2.GetStatL(self, "SprintAnimation.in", tldata)
		elseif self2.GetStatL(self, "SprintAnimation.out") and not flipis and not spr then
			tldata = self2.GetStatL(self, "SprintAnimation.out", tldata)
		end
	end

	if flipwalk and not is then
		if walk and self2.GetStatL(self, "WalkAnimation.in") then
			tldata = self2.GetStatL(self, "WalkAnimation.in", tldata)
		elseif self2.GetStatL(self, "WalkAnimation.out") and (not flipis and not flipsp and not flipcust) and not walk then
			tldata = self2.GetStatL(self, "WalkAnimation.out", tldata)
		end
	end

	if flipcust then
		if cust and self2.GetStatL(self, "CustomizeAnimation.in") then
			tldata = self2.GetStatL(self, "CustomizeAnimation.in", tldata)
		elseif self2.GetStatL(self, "CustomizeAnimation.out") and (not flipis and not flipsp and not flipwalk) and not cust then
			tldata = self2.GetStatL(self, "CustomizeAnimation.out", tldata)
		end
	end

	if tldata then
		return self:PlayAnimation(tldata)
	end

	return false, -1, TFA.Enum.ANIMATION_SEQ
end

function SWEP:LocomoteOrIdle(...)
	local success, animID, animType = self:Locomote(...)

	if not success then
		return self:SetNextIdleAnim(-1)
	end

	return success, animID, animType
end

--[[
Function Name:  ChooseDrawAnim
Syntax: self:ChooseDrawAnim().
Returns:  Could we successfully find an animation?  Which action?
Notes:  Requires autodetection or otherwise the list of valid anims.
Purpose:  Animation / Utility
]]
SWEP.IsFirstDeploy = true

local function PlayChosenAnimation(self, typev, tanim, ...)
	local fnName = typev == TFA.Enum.ANIMATION_SEQ and "SendViewModelSeq" or "SendViewModelAnim"
	local a, b = self[fnName](self, tanim, ...)
	return a, b, typev
end

SWEP.PlayChosenAnimation = PlayChosenAnimation

local success, tanim, typev

local cv_firstdeploy = GetConVar("sv_tfa_first_draw_anim_enabled")

function SWEP:ChooseDrawAnim()
	local self2 = self:GetTable()
	if not self2.VMIV(self) then return false, 0 end
	--self:ResetEvents()
	tanim = ACT_VM_DRAW
	success = true

	local ct = CurTime()

	if self:GetIsFirstDeploy() and self:GetLastDeployAnim() >= 0 and ct > (self:GetLastDeployAnim() or ct) + 0.1 then
		self:SetIsFirstDeploy(false)
		self2.IsFirstDeploy = false
	end

	if self:GetActivityEnabled(ACT_VM_DRAW_EMPTY) and self:IsEmpty1() then
		typev, tanim = self:ChooseAnimation("draw_empty")
	elseif (self:GetActivityEnabled(ACT_VM_DRAW_DEPLOYED) or self2.GetStat(self, "FirstDeployEnabled", false)) and self:GetIsFirstDeploy() and cv_firstdeploy:GetBool() then
		typev, tanim = self:ChooseAnimation("draw_first")
	elseif self:GetActivityEnabled(ACT_VM_DRAW_SILENCED) and self2.GetSilenced(self) then
		typev, tanim = self:ChooseAnimation("draw_silenced")
	else
		typev, tanim = self:ChooseAnimation("draw")
	end

	self:SetLastDeployAnim(ct)
	self2.LastDeployAnim = ct

	return PlayChosenAnimation(self, typev, tanim)
end

function SWEP:ResetFirstDeploy()
	self.IsFirstDeploy = true
	self:SetIsFirstDeploy(true)

	self.LastDeployAnim = -1
	self:SetLastDeployAnim(-1)
end

--[[
Function Name:  ChooseInspectAnim
Syntax: self:ChooseInspectAnim().
Returns:  Could we successfully find an animation?  Which action?
Notes:  Requires autodetection or otherwise the list of valid anims.
Purpose:  Animation / Utility
]]
--

function SWEP:ChooseInspectAnim()
	local self2 = self:GetTable()
	if not self2.VMIV(self) then return false, 0 end

	if self:GetActivityEnabled(ACT_VM_FIDGET_SILENCED) and self2.GetSilenced(self) then
		typev, tanim = self:ChooseAnimation("inspect_silenced")
	elseif self:GetActivityEnabled(ACT_VM_FIDGET_EMPTY) and self:IsEmpty1() then
		typev, tanim = self:ChooseAnimation("inspect_empty")
	elseif self2.InspectionActions then
		tanim = self2.InspectionActions[self:SharedRandom(1, #self2.InspectionActions, "Inspect")]
	elseif self:GetActivityEnabled(ACT_VM_FIDGET) then
		typev, tanim = self:ChooseAnimation("inspect")
	else
		typev, tanim = self:ChooseAnimation("idle")
		success = false
	end

	return PlayChosenAnimation(self, typev, tanim)
end

--[[
Function Name:  ChooseHolsterAnim
Syntax: self:ChooseHolsterAnim().
Returns:  Could we successfully find an animation?  Which action?
Notes:  Requires autodetection or otherwise the list of valid anims.
Purpose:  Animation / Utility
]]
--
function SWEP:ChooseHolsterAnim()
	local self2 = self:GetTable()
	if not self2.VMIV(self) then return false, 0 end

	if self:GetActivityEnabled(ACT_VM_HOLSTER_SILENCED) and self2.GetSilenced(self) then
		typev, tanim = self:ChooseAnimation("holster_silenced")
	elseif self:GetActivityEnabled(ACT_VM_HOLSTER_EMPTY) and self:IsEmpty1() then
		typev, tanim = self:ChooseAnimation("holster_empty")
	elseif self:GetActivityEnabled(ACT_VM_HOLSTER) then
		typev, tanim = self:ChooseAnimation("holster")
	else
		return false, select(2, self:ChooseIdleAnim())
	end

	return PlayChosenAnimation(self, typev, tanim)
end

--[[
Function Name:  ChooseProceduralReloadAnim
Syntax: self:ChooseProceduralReloadAnim().
Returns:  Could we successfully find an animation?  Which action?
Notes:  Uses some holster code
Purpose:  Animation / Utility
]]
--
function SWEP:ChooseProceduralReloadAnim()
	local self2 = self:GetTable()
	if not self2.VMIV(self) then return false, 0 end

	if not self2.DisableIdleAnimations then
		self:SendViewModelAnim(ACT_VM_IDLE)
	end

	return true, ACT_VM_IDLE
end

--[[
Function Name:  ChooseReloadAnim
Syntax: self:ChooseReloadAnim().
Returns:  Could we successfully find an animation?  Which action?
Notes:  Requires autodetection or otherwise the list of valid anims.
Purpose:  Animation / Utility
]]
--
function SWEP:ChooseReloadAnim()
	local self2 = self:GetTable()
	if not self2.VMIV(self) then return false, 0 end
	if self2.GetStatL(self, "IsProceduralReloadBased") then return false, 0 end

	local ads = self:GetStatL("IronSightsReloadEnabled") and self:GetIronSightsDirect()

	if self:GetActivityEnabled(ACT_VM_RELOAD_SILENCED) and self2.GetSilenced(self) then
		typev, tanim = self:ChooseAnimation((ads and self:GetActivityEnabled(ACT_VM_RELOAD_SILENCED_ADS)) and "reload_silenced_is" or "reload_silenced")
	elseif self:GetActivityEnabled(ACT_VM_RELOAD_EMPTY) and (self:Clip1() == 0 or self:IsJammed()) and not self:GetStatL("LoopedReload") then
		typev, tanim = self:ChooseAnimation((ads and self:GetActivityEnabled(ACT_VM_RELOAD_EMPTY_ADS)) and "reload_empty_is" or "reload_empty")
	else
		typev, tanim = self:ChooseAnimation((ads and self:GetActivityEnabled(ACT_VM_RELOAD_ADS)) and "reload_is" or "reload")
	end

	local fac = 1

	if self:GetStatL("LoopedReload") and self:GetStatL("LoopedReloadInsertTime") then
		fac = self:GetStatL("LoopedReloadInsertTime")
	end

	return PlayChosenAnimation(self, typev, tanim, fac, fac ~= 1)
end

--[[
Function Name:  ChooseReloadAnim
Syntax: self:ChooseReloadAnim().
Returns:  Could we successfully find an animation?  Which action?
Notes:  Requires autodetection or otherwise the list of valid anims.
Purpose:  Animation / Utility
]]
--
function SWEP:ChooseShotgunReloadAnim()
	local self2 = self:GetTable()
	if not self2.VMIV(self) then return false, 0 end

	local ads = self:GetStatL("IronSightsReloadEnabled") and self:GetIronSightsDirect()

	if self:GetActivityEnabled(ACT_VM_RELOAD_SILENCED) and self2.GetSilenced(self) then
		typev, tanim = self:ChooseAnimation((ads and self:GetActivityEnabled(ACT_VM_RELOAD_SILENCED_ADS)) and "reload_silenced_is" or "reload_silenced")
	elseif self:GetActivityEnabled(ACT_VM_RELOAD_EMPTY) and self2.ShotgunEmptyAnim and (self:Clip1() == 0 or self:IsJammed()) then
		typev, tanim = self:ChooseAnimation((ads and self:GetActivityEnabled(ACT_VM_RELOAD_EMPTY_ADS)) and "reload_empty_is" or "reload_empty")
	elseif self:GetActivityEnabled(ACT_SHOTGUN_RELOAD_START) then
		typev, tanim = self:ChooseAnimation((ads and self:GetActivityEnabled(ACT_SHOTGUN_RELOAD_START_ADS)) and "reload_shotgun_start_is" or "reload_shotgun_start")
	else
		return false, select(2, self:ChooseIdleAnim())
	end

	return PlayChosenAnimation(self, typev, tanim)
end

function SWEP:ChooseShotgunPumpAnim()
	if not self:VMIV() then return false, 0 end

	typev, tanim = self:ChooseAnimation(
		(self:GetStatL("IronSightsReloadEnabled") and
		self:GetIronSightsDirect() and
		self:GetActivityEnabled(ACT_SHOTGUN_RELOAD_START_ADS)) and "reload_shotgun_finish_is" or "reload_shotgun_finish")

	return PlayChosenAnimation(self, typev, tanim)
end

--[[
Function Name:  ChooseIdleAnim
Syntax: self:ChooseIdleAnim().
Returns:  True,  Which action?
Notes:  Requires autodetection for full features.
Purpose:  Animation / Utility
]]
--
function SWEP:ChooseIdleAnim()
	local self2 = self:GetTable()
	if not self2.VMIV(self) then return false, 0 end
	--if self2.Idle_WithHeld then
	--  self2.Idle_WithHeld = nil
	--  return
	--end

	if TFA.Enum.ShootLoopingStatus[self:GetShootStatus()] and self:ShouldPlayLoopShootAnim() then
		return self:ChooseLoopShootAnim()
	end

	local idleMode = self2.GetStatL(self, "Idle_Mode")

	if idleMode ~= TFA.Enum.IDLE_BOTH and idleMode ~= TFA.Enum.IDLE_ANI then return end

	--self:ResetEvents()
	if self:GetIronSights() then
		local sightsMode = self2.GetStatL(self, "Sights_Mode")

		if sightsMode == TFA.Enum.LOCOMOTION_LUA then
			return self:ChooseFlatAnim()
		else
			return self:ChooseADSAnim()
		end
	elseif self:GetSprinting() and self2.GetStatL(self, "Sprint_Mode") ~= TFA.Enum.LOCOMOTION_LUA then
		return self:ChooseSprintAnim()
	elseif self:GetWalking() and self2.GetStatL(self, "Walk_Mode") ~= TFA.Enum.LOCOMOTION_LUA then
		return self:ChooseWalkAnim()
	elseif self:GetCustomizing() and self2.GetStatL(self, "Customize_Mode") ~= TFA.Enum.LOCOMOTION_LUA then
		return self:ChooseCustomizeAnim()
	end

	if self:GetActivityEnabled(ACT_VM_IDLE_SILENCED) and self2.GetSilenced(self) then
		typev, tanim = self:ChooseAnimation("idle_silenced")
	elseif self:IsEmpty1() then
		--self:GetActivityEnabled( ACT_VM_IDLE_EMPTY ) and (self:Clip1() == 0) then
		if self:GetActivityEnabled(ACT_VM_IDLE_EMPTY) then
			typev, tanim = self:ChooseAnimation("idle_empty")
		else --if not self:GetActivityEnabled( ACT_VM_PRIMARYATTACK_EMPTY ) then
			typev, tanim = self:ChooseAnimation("idle")
		end
	else
		typev, tanim = self:ChooseAnimation("idle")
	end

	--else
	--  return
	--end
	return PlayChosenAnimation(self, typev, tanim)
end

function SWEP:ChooseFlatAnim()
	local self2 = self:GetTable()
	if not self2.VMIV(self) then return false, 0 end
	--self:ResetEvents()
	typev, tanim = self:ChooseAnimation("idle")

	if self:GetActivityEnabled(ACT_VM_IDLE_SILENCED) and self2.GetSilenced(self) then
		typev, tanim = self:ChooseAnimation("idle_silenced")
	elseif self:GetActivityEnabled(ACT_VM_IDLE_EMPTY) and self:IsEmpty1() then
		typev, tanim = self:ChooseAnimation("idle_empty")
	end

	return PlayChosenAnimation(self, typev, tanim, 0.000001)
end

function SWEP:ChooseADSAnim()
	local self2 = self:GetTable()
	if not self2.VMIV(self) then return false, 0 end
	local a, b, c = self:PlayAnimation(self2.GetStatL(self, "IronAnimation.loop"))

	--self:SetNextIdleAnim(CurTime() + 1)
	if not a then
		local _
		_, b, c = self:ChooseFlatAnim()
		a = false
	end

	return a, b, c
end

function SWEP:ChooseSprintAnim()
	return self:PlayAnimation(self:GetStatL("SprintAnimation.loop"))
end

function SWEP:ChooseWalkAnim()
	return self:PlayAnimation(self:GetStatL("WalkAnimation.loop"))
end

function SWEP:ChooseLoopShootAnim()
	return self:PlayAnimation(self:GetStatL("ShootAnimation.loop"))
end

function SWEP:ChooseCustomizeAnim()
	return self:PlayAnimation(self:GetStatL("CustomizeAnimation.loop"))
end

--[[
Function Name:  ChooseShootAnim
Syntax: self:ChooseShootAnim().
Returns:  Could we successfully find an animation?  Which action?
Notes:  Requires autodetection or otherwise the list of valid anims.
Purpose:  Animation / Utility
]]
--
local shouldAnim, shouldBlowback
function SWEP:ChooseShootAnim(ifp)
	local self2 = self:GetTable()
	if ifp == nil then ifp = IsFirstTimePredicted() end
	if not self2.VMIV(self) then return false, 0 end

	if self2.GetStatL(self, "ShootAnimation.loop") and self2.ShouldPlayLoopShootAnim(self) then
		if self2.LuaShellEject and ifp then
			self:EventShell()
		end

		if TFA.Enum.ShootReadyStatus[self:GetShootStatus()] then
			self:SetShootStatus(TFA.Enum.SHOOT_START)

			local inan = self2.GetStatL(self, "ShootAnimation.in")

			if not inan then
				inan = self2.GetStatL(self, "ShootAnimation.loop")
			end

			return self:PlayAnimation(inan)
		end

		return
	end

	local sightsMode = self2.GetStatL(self, "Sights_Mode")

	if self:GetIronSights() and (sightsMode == TFA.Enum.LOCOMOTION_ANI or sightsMode == TFA.Enum.LOCOMOTION_HYBRID) and self2.GetStatL(self, "IronAnimation.shoot") then
		if self2.LuaShellEject and ifp then
			self:EventShell()
		end

		return self:PlayAnimation(self2.GetStatL(self, "IronAnimation.shoot"))
	end

	shouldBlowback = self2.GetStatL(self, "BlowbackEnabled") and (not self2.GetStatL(self, "Blowback_Only_Iron") or self:GetIronSights())
	shouldAnim = not shouldBlowback or self2.GetStatL(self, "BlowbackAllowAnimation")

	if shouldBlowback then
		if sp and SERVER then
			self:CallOnClient("BlowbackFull", "")
		end

		if ifp then
			self:BlowbackFull(ifp)
		end

		if self2.GetStatL(self, "Blowback_Shell_Enabled") and (ifp or sp) then
			self:EventShell()
		end
	end

	if shouldAnim then
		success = true

		if self2.LuaShellEject and (ifp or sp) then
			self:EventShell()
		end

		if self:GetActivityEnabled(ACT_VM_PRIMARYATTACK_SILENCED) and self2.GetSilenced(self) then
			typev, tanim = self:ChooseAnimation("shoot1_silenced")
		elseif self:Clip1() <= self2.Primary_TFA.AmmoConsumption and self:GetActivityEnabled(ACT_VM_PRIMARYATTACK_EMPTY) and self2.Primary_TFA.ClipSize >= 1 and not self2.ForceEmptyFireOff then
			typev, tanim = self:ChooseAnimation("shoot1_last")
		elseif self:Ammo1() <= self2.Primary_TFA.AmmoConsumption and self:GetActivityEnabled(ACT_VM_PRIMARYATTACK_EMPTY) and self2.Primary_TFA.ClipSize < 1 and not self2.ForceEmptyFireOff then
			typev, tanim = self:ChooseAnimation("shoot1_last")
		elseif self:Clip1() == 0 and self:GetActivityEnabled(ACT_VM_DRYFIRE) and not self2.ForceDryFireOff then
			typev, tanim = self:ChooseAnimation("shoot1_empty")
		elseif self2.GetStatL(self, "IsAkimbo") and self:GetActivityEnabled(ACT_VM_SECONDARYATTACK) and ((self:GetAnimCycle() == 0 and not self2.Akimbo_Inverted) or (self:GetAnimCycle() == 1 and self2.Akimbo_Inverted)) then
			typev, tanim = self:ChooseAnimation((self:GetIronSights() and self:GetActivityEnabled(ACT_VM_ISHOOT_M203)) and "shoot2_is" or "shoot2")
		elseif self:GetIronSights() and self:GetActivityEnabled(ACT_VM_PRIMARYATTACK_1) then
			typev, tanim = self:ChooseAnimation("shoot1_is")
		else
			typev, tanim = self:ChooseAnimation("shoot1")
		end

		return PlayChosenAnimation(self, typev, tanim)
	end

	self:SendViewModelAnim(ACT_VM_BLOWBACK)

	return true, ACT_VM_IDLE
end

SWEP.BlowbackRandomAngle = Angle(0, 0, 0) -- not cached, overwritten with each shot

SWEP.BlowbackRandomAngleMin = Angle(.1, -.5, -1)
SWEP.BlowbackRandomAngleMax = Angle(.2, .5, 1)

local minang, maxang

function SWEP:BlowbackFull()
	local self2 = self:GetTable()

	if IsValid(self) then
		self2.BlowbackCurrent = 1
		self2.BlowbackCurrentRoot = 1

		if CLIENT then
			minang, maxang = self2.GetStatL(self, "BlowbackRandomAngleMin"), self2.GetStatL(self, "BlowbackRandomAngleMax")

			self2.BlowbackRandomAngle = Angle(math.Rand(minang.p, maxang.p), math.Rand(minang.y, maxang.y), math.Rand(minang.r, maxang.r))
		end
	end
end

--[[
Function Name:  ChooseSilenceAnim
Syntax: self:ChooseSilenceAnim( true if we're silencing, false for detaching the silencer).
Returns:  Could we successfully find an animation?  Which action?
Notes:  Requires autodetection or otherwise the list of valid anims.  This is played when you silence or unsilence a gun.
Purpose:  Animation / Utility
]]
--
function SWEP:ChooseSilenceAnim(val)
	if not self:VMIV() then return false, 0 end
	--self:ResetEvents()
	typev, tanim = self:ChooseAnimation("idle_silenced")
	success = false

	if val then
		if self:GetActivityEnabled(ACT_VM_ATTACH_SILENCER) then
			typev, tanim = self:ChooseAnimation("silencer_attach")
			success = true
		end
	elseif self:GetActivityEnabled(ACT_VM_DETACH_SILENCER) then
		typev, tanim = self:ChooseAnimation("silencer_detach")
		success = true
	end

	if not success then
		return false, select(2, self:ChooseIdleAnim())
	end

	return PlayChosenAnimation(self, typev, tanim)
end

--[[
Function Name:  ChooseDryFireAnim
Syntax: self:ChooseDryFireAnim().
Returns:  Could we successfully find an animation?  Which action?
Notes:  Requires autodetection or otherwise the list of valid anims.  set SWEP.ForceDryFireOff to false to properly use.
Purpose:  Animation / Utility
]]
--
function SWEP:ChooseDryFireAnim()
	local self2 = self:GetTable()
	if not self2.VMIV(self) then return false, 0 end
	--self:ResetEvents()
	typev, tanim = self:ChooseAnimation("shoot1_empty")
	success = true

	if self:GetActivityEnabled(ACT_VM_DRYFIRE_SILENCED) and self2.GetSilenced(self) and not self2.ForceDryFireOff then
		typev, tanim = self:ChooseAnimation("shoot1_silenced_empty")
		--self:ChooseIdleAnim()
	else
		if self:GetActivityEnabled(ACT_VM_DRYFIRE) and not self2.ForceDryFireOff then
			typev, tanim = self:ChooseAnimation("shoot1_empty")
		else
			success = false
			local _
			_, tanim = nil, nil

			return success, tanim -- ???
		end
	end

	return PlayChosenAnimation(self, typev, tanim)
end

--[[
Function Name:  ChooseROFAnim
Syntax: self:ChooseROFAnim().
Returns:  Could we successfully find an animation?  Which action?
Notes:  Requires autodetection or otherwise the list of valid anims.  Called when we change the firemode.
Purpose:  Animation / Utility
]]
--
function SWEP:ChooseROFAnim()
	local self2 = self:GetTable()
	if not self2.VMIV(self) then return false, 0 end

	--self:ResetEvents()
	if self:GetIronSights() and self:GetActivityEnabled(ACT_VM_IFIREMODE) then
		typev, tanim = self2.ChooseAnimation(self, "rof_is")
		success = true
	elseif self:GetActivityEnabled(ACT_VM_FIREMODE) then
		typev, tanim = self2.ChooseAnimation(self, "rof")
		success = true
	else
		success = false
		local _
		_, tanim = nil, nil

		return success, tanim -- ???
	end

	return PlayChosenAnimation(self, typev, tanim)
end

--[[
Function Name:  ChooseBashAnim
Syntax: self:ChooseBashAnim().
Returns:  Could we successfully find an animation?  Which action?
Notes:  Requires autodetection or otherwise the list of valid anims.  Called when we bash.
Purpose:  Animation / Utility
]]
--
function SWEP:ChooseBashAnim()
	local self2 = self:GetTable()
	if not self2.VMIV(self) then return false, 0 end

	typev, tanim = nil, nil
	success = false

	local isempty = self2.GetStatL(self, "Primary.ClipSize") > 0 and self:Clip1() == 0

	if self2.GetSilenced(self) and self:GetActivityEnabled(ACT_VM_HITCENTER2) then
		if self:GetActivityEnabled(ACT_VM_MISSCENTER2) and isempty then
			typev, tanim = self:ChooseAnimation("bash_empty_silenced")
			success = true
		else
			typev, tanim = self:ChooseAnimation("bash_silenced")
			success = true
		end
	elseif self:GetActivityEnabled(ACT_VM_MISSCENTER) and isempty then
		typev, tanim = self:ChooseAnimation("bash_empty")
		success = true
	elseif self:GetActivityEnabled(ACT_VM_HITCENTER) then
		typev, tanim = self:ChooseAnimation("bash")
		success = true
	end

	if not success then
		return success, tanim
	end

	return PlayChosenAnimation(self, typev, tanim)
end

--[[THIRDPERSON]]
--These holdtypes are used in ironsights.  Syntax:  DefaultHoldType=NewHoldType
SWEP.IronSightHoldTypes = {
	pistol = "revolver",
	smg = "rpg",
	grenade = "melee",
	ar2 = "rpg",
	shotgun = "ar2",
	rpg = "rpg",
	physgun = "physgun",
	crossbow = "ar2",
	melee = "melee2",
	slam = "camera",
	normal = "fist",
	melee2 = "magic",
	knife = "fist",
	duel = "duel",
	camera = "camera",
	magic = "magic",
	revolver = "revolver"
}

--These holdtypes are used while sprinting.  Syntax:  DefaultHoldType=NewHoldType
SWEP.SprintHoldTypes = {
	pistol = "normal",
	smg = "passive",
	grenade = "normal",
	ar2 = "passive",
	shotgun = "passive",
	rpg = "passive",
	physgun = "normal",
	crossbow = "passive",
	melee = "normal",
	slam = "normal",
	normal = "normal",
	melee2 = "melee",
	knife = "fist",
	duel = "normal",
	camera = "slam",
	magic = "normal",
	revolver = "normal"
}

--These holdtypes are used in reloading.  Syntax:  DefaultHoldType=NewHoldType
SWEP.ReloadHoldTypes = {
	pistol = "pistol",
	smg = "smg",
	grenade = "melee",
	ar2 = "ar2",
	shotgun = "shotgun",
	rpg = "ar2",
	physgun = "physgun",
	crossbow = "crossbow",
	melee = "pistol",
	slam = "smg",
	normal = "pistol",
	melee2 = "pistol",
	knife = "pistol",
	duel = "duel",
	camera = "pistol",
	magic = "pistol",
	revolver = "revolver"
}

--These holdtypes are used in reloading.  Syntax:  DefaultHoldType=NewHoldType
SWEP.CrouchHoldTypes = {
	ar2 = "ar2",
	smg = "smg",
	rpg = "ar2"
}

SWEP.IronSightHoldTypeOverride = "" --This variable overrides the ironsights holdtype, choosing it instead of something from the above tables.  Change it to "" to disable.
SWEP.SprintHoldTypeOverride = "" --This variable overrides the sprint holdtype, choosing it instead of something from the above tables.  Change it to "" to disable.
SWEP.ReloadHoldTypeOverride = "" --This variable overrides the reload holdtype, choosing it instead of something from the above tables.  Change it to "" to disable.
local dynholdtypecvar = GetConVar("sv_tfa_holdtype_dynamic")
SWEP.mht_old = ""
local mht

function SWEP:IsOwnerCrouching()
	local ply = self:GetOwner()

	if not ply:IsPlayer() then return false end

	return (ply:Crouching() or self:KeyDown(IN_DUCK)) and ply:OnGround() and not ply:InVehicle()
end

function SWEP:ProcessHoldType()
	local self2 = self:GetTable()
	mht = self2.GetStatL(self, "HoldType", "ar2")

	if mht ~= self2.mht_old or not self2.DefaultHoldType then
		self2.DefaultHoldType = mht
		self2.SprintHoldType = nil
		self2.IronHoldType = nil
		self2.ReloadHoldType = nil
		self2.CrouchHoldType = nil
	end

	self2.mht_old = mht

	if not self2.SprintHoldType then
		self2.SprintHoldType = self2.SprintHoldTypes[self2.DefaultHoldType] or "passive"

		if self2.SprintHoldTypeOverride and self2.SprintHoldTypeOverride ~= "" then
			self2.SprintHoldType = self2.SprintHoldTypeOverride
		end
	end

	if not self2.IronHoldType then
		self2.IronHoldType = self2.IronSightHoldTypes[self2.DefaultHoldType] or "rpg"

		if self2.IronSightHoldTypeOverride and self2.IronSightHoldTypeOverride ~= "" then
			self2.IronHoldType = self2.IronSightHoldTypeOverride
		end
	end

	if not self2.ReloadHoldType then
		self2.ReloadHoldType = self2.ReloadHoldTypes[self2.DefaultHoldType] or "ar2"

		if self2.ReloadHoldTypeOverride and self2.ReloadHoldTypeOverride ~= "" then
			self2.ReloadHoldType = self2.ReloadHoldTypeOverride
		end
	end

	if not self2.SetCrouchHoldType then
		self2.SetCrouchHoldType = true
		self2.CrouchHoldType = self2.CrouchHoldTypes[self2.DefaultHoldType]

		if self2.CrouchHoldTypeOverride and self2.CrouchHoldTypeOverride ~= "" then
			self2.CrouchHoldType = self2.CrouchHoldTypeOverride
		end
	end

	local curhold, targhold, stat
	curhold = self:GetHoldType()
	targhold = self2.DefaultHoldType
	stat = self:GetStatus()

	if dynholdtypecvar:GetBool() then
		if self:OwnerIsValid() and self:IsOwnerCrouching() and self2.CrouchHoldType then
			targhold = self2.CrouchHoldType
		else
			if self:GetIronSights() then
				targhold = self2.IronHoldType
			end

			if TFA.Enum.ReloadStatus[stat] then
				targhold = self2.ReloadHoldType
			end
		end
	end

	if self:GetSprinting() or TFA.Enum.HolsterStatus[stat] or self:IsSafety() then
		targhold = self2.SprintHoldType
	end

	if targhold ~= curhold then
		self:SetHoldType(targhold)
	end
end
