Crowbar animation for the world model

I have a Crowbar SWEP that isn’t animating the “melee” hold type attack animation for the world model. What’s going on?

Code:



if SERVER then
	AddCSLuaFile()
	
		
	util.AddNetworkString("goml_crowbar_charge")

	SWEP.KnifeChargeConvar = CreateConVar("goml_crowbar_charge", 1, bit.bor(FCVAR_NOTIFY), "Should we use a charge bar on alt attack?" )
else
	killicon.AddFont("weapon_mu_crowbar", "HL2MPTypeDeath", "5", Color(0, 0, 255, 255))
	
	function SWEP:DrawWeaponSelection( x, y, w, h, alpha )
		local name = translate and translate.crowbar or "Crowbar"
		surface.SetFont("MersText1")
		local tw, th = surface.GetTextSize(name:sub(2))
		
		surface.SetFont("MersHead1")
		local twf, thf = surface.GetTextSize(name:sub(1, 1))
		tw = tw + twf + 1
		
		draw.DrawText(name:sub(2), "MersText1", x + w * 0.5 - tw / 2 + twf + 1, y + h * 0.51, Color(255, 150, 0, alpha), 0)
		draw.DrawText(name:sub(1, 1), "MersHead1", x + w * 0.5 - tw / 2 , y + h * 0.49, Color(255, 50, 50, alpha), 0)
	end
	
	function SWEP:DrawHUD()
		if self.ChargeStart then
			local charge = self:GetCharge()

			-- draw.DrawText("Charging" .. (math.Round(self:GetCharge() * 100) / 100),"MersHead1", sw * 0.5, sh * 0.5 + 30, color_white,1)

			local w = math.Round(ScrW() * 0.2)
			local h = ScrH() * 0.03
			local bord = math.Round(ScrW() * 0.08 * 0.03)
			local size = ScrW() * 0.08
			local x = size * 1.2
			
			surface.SetDrawColor(0, 0, 0, 255)
			surface.DrawRect(ScrW() / 2 - w / 2, ScrH() - h - size * 0.2, w, h)
			
			local ply = self.Owner
			local col = self.Owner:GetPlayerColor()
			col = Color(col.x * 255, col.y * 255, col.z * 255)
			surface.SetDrawColor(col, 255)
			surface.DrawRect(ScrW() / 2 - w / 2 + bord, ScrH() - h - size * 0.2 + bord, (w - bord * 2) * charge, h - bord * 2)
		end
	end  

	net.Receive("goml_crowbar_charge", function(len)
		local ent = net.ReadEntity()
		if not IsValid(ent) then return end
		
		local charging = net.ReadUInt(8) != 0
		if charging then
			ent.ChargeStart = net.ReadDouble()
		else
			ent.ChargeStart = nil
		end
	end)
end

SWEP.Base = "weapon_mers_base"
SWEP.Slot = 1
SWEP.SlotPos = 2
SWEP.DrawAmmo = false
SWEP.DrawCrosshair = false

--SWEP.ViewModel = "models/weapons/v_knife_t.mdl"
SWEP.ViewModel = "models/weapons/v_crowbar.mdl"
--SWEP.WorldModel = "models/weapons/w_knife_t.mdl"
SWEP.WorldModel = "models/weapons/w_crowbar.mdl"

SWEP.UseHands = false
SWEP.ViewModelFlip = false
SWEP.ViewModelFOV = 65

SWEP.HoldType = "melee"
SWEP.SequenceDraw = "draw"
SWEP.SequenceIdle = "idle"

SWEP.Primary.Sequence = {"misscenter1", "misscenter2"}
SWEP.Primary.Delay = 0.5
SWEP.Primary.Recoil = 3
SWEP.Primary.Damage = 66
SWEP.Primary.NumShots = 1	
SWEP.Primary.Cone = 0.04
SWEP.Primary.ClipSize = -1
SWEP.Primary.Force = 900
SWEP.Primary.DefaultClip = -1
SWEP.Primary.Automatic = true
SWEP.Primary.Ammo = "none"

local sound_single = Sound("Weapon_Crowbar.Single")

SWEP.PrintName = translate and translate.crowbar or "Crowbar"
function SWEP:Initialize()
	self.PrintName = translate and translate.crowbar or "Crowbar"
	self.BaseClass.Initialize(self)
end

function SWEP:SetupDataTables()
	self.BaseClass.SetupDataTables(self)
	self:NetworkVar("Float", 3, "FistHit")
end

function SWEP:Holster()
	if SERVER then
		if IsValid(self.Owner) then
			net.Start("goml_crowbar_charge")
			net.WriteEntity(self)
			net.WriteUInt(0, 8)
			net.Send(self.Owner)
		end
		
		self.ChargeStart = nil
	end
	return self.BaseClass.Holster(self)
end

function SWEP:PrimaryAttack()
   self.Weapon:SetNextPrimaryFire( CurTime() + self.Primary.Delay )

   if not IsValid(self.Owner) then return end

   if self.Owner.LagCompensation then
      self.Owner:LagCompensation(true)
   end

   local spos = self.Owner:GetShootPos()
   local sdest = spos + (self.Owner:GetAimVector() * 90)

   local tr_main = util.TraceLine({start=spos, endpos=sdest, filter=self.Owner, mask=MASK_SHOT_HULL})
   local hitEnt = tr_main.Entity

   self.Weapon:EmitSound(sound_single)

   if IsValid(hitEnt) or tr_main.HitWorld then
      self.Weapon:SendWeaponAnim( ACT_VM_HITCENTER )

      if not (CLIENT and (not IsFirstTimePredicted())) then
         local edata = EffectData()
         edata:SetStart(spos)
         edata:SetOrigin(tr_main.HitPos)
         edata:SetNormal(tr_main.Normal)
         edata:SetSurfaceProp(tr_main.SurfaceProps)
         edata:SetHitBox(tr_main.HitBox)
         edata:SetEntity(hitEnt)

         if hitEnt:IsPlayer() or hitEnt:GetClass() == "prop_ragdoll" then
            util.Effect("BloodImpact", edata)
            self.Owner:LagCompensation(false)
            self.Owner:FireBullets({Num=1, Src=spos, Dir=self.Owner:GetAimVector(), Spread=Vector(0,0,0), Tracer=0, Force=1, Damage=0})
         else
            util.Effect("Impact", edata)
         end
      end
   else
      self.Weapon:SendWeaponAnim( ACT_VM_MISSCENTER )
   end


   if SERVER then
      local tr_all = nil
      tr_all = util.TraceLine({start=spos, endpos=sdest, filter=self.Owner})
      
      self.Owner:SetAnimation( PLAYER_ATTACK1 )

      if hitEnt and hitEnt:IsValid() then

         local dmg = DamageInfo()
         dmg:SetDamage(self.Primary.Damage)
         dmg:SetAttacker(self.Owner)
         dmg:SetInflictor(self.Weapon)
         dmg:SetDamageForce(self.Owner:GetAimVector() * 1500)
         dmg:SetDamagePosition(self.Owner:GetPos())
         dmg:SetDamageType(DMG_CLUB)

         hitEnt:DispatchTraceAttack(dmg, spos + (self.Owner:GetAimVector() * 3), sdest)
      else
         if tr_all.Entity and tr_all.Entity:IsValid() then
            self:OpenEnt(tr_all.Entity)
         end
      end
   end

   if self.Owner.LagCompensation then
      self.Owner:LagCompensation(false)
   end
end


function SWEP:Think()
	if SERVER && self.ChargeStart then
		if !IsValid(self.Owner) || !self.Owner:KeyDown(IN_ATTACK2) then
			if IsValid(self.Owner) then
				self:ThrowKnife(self:GetCharge())
				net.Start("goml_crowbar_charge")
				net.WriteEntity(self)
				net.WriteUInt(0, 8)
				net.Send(self.Owner)
			end
			self.ChargeStart = nil
		end
	end
end

function SWEP:GetCharge()
	local start = CurTime() - (self.ChargeStart or 0)
	return math.Clamp((math.sin(start * 2 - 1) + 1) / 2, 0, 1)
end

function SWEP:ThrowKnife(force)
	if SERVER then self.Owner:EmitSound("weapons/slam/throw.wav", 100, 100) end
	local ent = ents.Create("mu_crowbar")
	ent:SetOwner(self.Owner)
	ent:SetPos(self.Owner:GetShootPos())
	local knife_ang = Angle(0,0,0) + self.Owner:EyeAngles()
	knife_ang:RotateAroundAxis(knife_ang:Right(), -90)
	ent:SetAngles(knife_ang)
	ent:Spawn()


	local phys = ent:GetPhysicsObject()
	phys:SetVelocity(self.Owner:GetAimVector() * (force * 1000 + 200))
	phys:AddAngleVelocity(Vector(0, 1500, 0))

	self:Remove()
	
	if self.Owner:IsPlayer() then
		self.Owner:SelectWeapon("weapon_mu_hands")
	end
end

function SWEP:SecondaryAttack()
	if !self:IsIdle() then return end

	if SERVER then
		if self.KnifeChargeConvar:GetBool() then
			self.ChargeStart = CurTime()
			net.Start("goml_crowbar_charge")
			net.WriteEntity(self)
			net.WriteUInt(1, 8)
			net.WriteDouble(self.ChargeStart)
			net.Send(self.Owner)
		else
			self:ThrowKnife(0.6)
		end
	end
end

function SWEP:Reload()
	if self.ChargeStart then
		self.ChargeStart = nil
		if SERVER then
			net.Start("goml_crowbar_charge")
			net.WriteEntity(self)
			net.WriteUInt(0, 8)
			net.Send(self.Owner)
		end
		return
	end
end


[editline]31st October 2016[/editline]

Here is the base class:



if ( SERVER ) then
	AddCSLuaFile()
	
	util.AddNetworkString("mers_base_holdtype")
	
	
	concommand.Add("mers_weapon_info", function (ply)
		local wep = ply:GetActiveWeapon()
		local vm = ply:GetViewModel()
		local ct = ChatText()
		for i = 0, vm:GetSequenceCount() - 1 do
			ct:Add(i .. "	" .. vm:GetSequenceName(i) .. "	" .. vm:SequenceDuration(i) .. "
")
		end
		
		for k, v in pairs(wep.Primary) do
			ct:Add(tostring(k) .. "	" .. tostring(v) .. "
")
		end
		ct:Send(ply)
	end)
else
	net.Receive("mers_base_holdtype", function (len)
		local wep = net.ReadEntity()
		if IsValid(wep) && wep:IsWeapon() && wep.SetWeaponHoldType then
			wep:SetWeaponHoldType(net.ReadString())
		end
	end)
end
SWEP.Base = "weapon_base"
SWEP.Weight			= 5
SWEP.AutoSwitchTo	= false
SWEP.AutoSwitchFrom	= false
SWEP.Spawnable		= true
SWEP.AdminSpawnable	= true
SWEP.UseHands = true

SWEP.Author			= "Mechanical Mind"
SWEP.Contact		= ""
SWEP.Purpose		= ""
SWEP.Instructions	= ""

SWEP.ViewModelFOV = 50
SWEP.HolsterHoldTime = 0.3

SWEP.Primary.ClipSize		= -1
SWEP.Primary.DefaultClip	= 0
SWEP.Primary.Automatic		= false
SWEP.Primary.Ammo			= "none"

SWEP.Secondary.ClipSize		= -1
SWEP.Secondary.DefaultClip	= 0
SWEP.Secondary.Automatic	= false
SWEP.Secondary.Ammo			= "none"

function SWEP:Initialize()
	self:SetWeaponState("holster")
	self:CalculateHoldType()
	self.HolsterPercent = 1
	self.IronsightsPercent = 0
end

function SWEP:SetNetHoldType(name)
	self:SetWeaponHoldType(name)
	if SERVER then
		net.Start("mers_base_holdtype")
		net.WriteEntity(self)
		net.WriteString(name)
		net.Broadcast()
	end
end

function SWEP:CalculateHoldType()
	local holdtype = self.HoldType
	// crouching in passive holdtype looks wierd, use smg instead
	if holdtype == "passive" && IsValid(self.Owner) && self.Owner:Crouching() then
		holdtype = self.HoldType or "smg"
	end
	if self.OldHoldType != holdtype then
		self.OldHoldType = holdtype
		self:SetNetHoldType(holdtype)
	end
end

function SWEP:SetupDataTables()
	self:NetworkVar("String", 0, "WeaponState")
	self:NetworkVar("Float", 0, "ReloadEnd")
	self:NetworkVar("Float", 1, "NextIdle")
	self:NetworkVar("Float", 2, "DrawEnd")
end

function SWEP:IsIdle()
	if self:GetReloadEnd() > 0 && self:GetReloadEnd() >= CurTime() then return false end
	if self:GetNextPrimaryFire() > 0 && self:GetNextPrimaryFire() >= CurTime() then return false end
	if self:GetDrawEnd() > 0 && self:GetDrawEnd() >= CurTime() then return false end
	return true
end

function SWEP:PrimaryAttack()
	if !self:IsIdle() then return end
	if self:GetMaxClip1() > 0 && self:Clip1() <= 0 then
		self:Reload()
		return
	end
	local vm = self.Owner:GetViewModel()
	if self.Primary.Sequence then
		local sequence = self.Primary.Sequence
		if type(sequence) == "table" then
			if IsFirstTimePredicted() then
				self.LastSequence = ((self.LastSequence or -1) + 1) % #sequence
			end
			sequence = sequence[self.LastSequence + 1]
		end
		vm:SendViewModelMatchingSequence(vm:LookupSequence(sequence))
	end
	
	self:SetNextPrimaryFire(CurTime() + (self.Primary.Delay or vm:SequenceDuration()))
	self:SetNextIdle(CurTime() + vm:SequenceDuration())
	self:TakePrimaryAmmo(1)
	
	if self.Primary.Sound then
		self:EmitSound(self.Primary.Sound)
	end
	self.Owner:SetAnimation(PLAYER_ATTACK1)
	
	local stats = {}
	stats.recoil = self.Primary.Recoil or 1
	stats.damage = self.Primary.Damage or 1
	stats.cone = self.Primary.Cone or 0.1
	if self.Primary.Recoil then
		stats.recoil = stats.recoil or 1
		if IsFirstTimePredicted() && CLIENT then
			local circle = Angle(0, math.Rand(0, 360), 0)
			local vec = circle:Forward() * math.Rand(stats.recoil * 0.8, stats.recoil) * 0.1
			vec.y = -math.abs(vec.y) - stats.recoil * 0.2
			if ViewPosition then ViewPosition:Recoil(vec) end
		end
	end
	hook.Run("CalculateWeaponPrimaryFireStats", self, self.Owner, stats)
	self:DoPrimaryAttackEffect(stats)
end

function SWEP:DoPrimaryAttackEffect(stats)
	local bullet = {}
	bullet.Num = self.Primary.NumShots or 1
	bullet.Src = self.Owner:GetShootPos()
	bullet.Dir = self.Owner:GetAimVector()
	bullet.Spread = Vector(stats.cone or 0, stats.cone or 0, 0)
	bullet.Tracer = self.Primary.Tracer or 1
	bullet.Force = self.Primary.Force or ((self.Primary.Damage or 1) * 3)
	bullet.Damage = stats.damage or 1
	self.Owner:FireBullets(bullet)
end

function SWEP:SecondaryAttack()
end

local function lerp(from, to, step)
	if from < to then
		return math.min(from + step, to)	
	end
	return math.max(from - step, to)
end

function SWEP:Think()
	self:CalculateHoldType()
	if self:GetReloadEnd() > 0 && self:GetReloadEnd() < CurTime() then
		self:SetReloadEnd(0)
		
		if self.Primary.InfiniteAmmo then
			self:SetClip1(self:GetMaxClip1())
		else
			local spare = self.Owner:GetAmmoCount(self:GetPrimaryAmmoType())
			local addAmmo = math.min(self:GetMaxClip1() - self:Clip1(), spare)
			self:SetClip1(self:Clip1() + addAmmo)
			self.Owner:SetAmmo(spare - addAmmo, self:GetPrimaryAmmoType())
		end
	end
	if self:GetNextIdle() > 0 && self:GetNextIdle() < CurTime() then
		self:SetNextIdle(0)
		
		local sequence = self.SequenceIdle
		local vm = self.Owner:GetViewModel()
		vm:SendViewModelMatchingSequence(vm:LookupSequence(sequence))
		if self.Primary.AutoReload then
			if self:GetMaxClip1() > 0 && self:Clip1() <= 0 then
				self:Reload()
			end
		end
	end
	
	if IsValid(self.Owner) then
		if !self.Owner:KeyDown(IN_RELOAD) then
			self.ReloadHoldStart = nil
		end
		self.UsingIronsights = false
		if self.Owner:KeyDown(IN_ATTACK2) && self:GetWeaponState() != "holster" then
			self.UsingIronsights = true
		end
	end
	
	self.IronsightsPercent = lerp(self.IronsightsPercent, self.UsingIronsights and 1 or 0, FrameTime() * 2.5)
end

function SWEP:Reload()
	if self:IsIdle() then
		if self:GetWeaponState() == "normal" && self:GetMaxClip1() > 0 && self:Clip1() < self:GetMaxClip1() then
			local spare = self.Owner:GetAmmoCount(self:GetPrimaryAmmoType())
			if spare > 0 || self.Primary.InfiniteAmmo then
				local vm = self.Owner:GetViewModel()
				vm:SendViewModelMatchingSequence(vm:LookupSequence(self.ReloadSequence))
				if self.ReloadSound then
					self:EmitSound(self.ReloadSound)
				end
				self.Owner:SetAnimation(PLAYER_RELOAD)
				self:SetReloadEnd(CurTime() + vm:SequenceDuration())
				self:SetNextIdle(CurTime() + vm:SequenceDuration())
			end
		end
	end
end

function SWEP:Deploy()
	self:SetWeaponState("normal")
	self:CalculateHoldType()
	local time = 1
	local vm = self.Owner:GetViewModel()
	if IsValid(vm) then
		if self.SequenceDraw then
			vm:SendViewModelMatchingSequence(vm:LookupSequence(self.SequenceDraw))
			time = vm:SequenceDuration()
		elseif self.SequenceDrawTime then
			time = self.SequenceDrawTime
		end
	end
	self:SetDrawEnd(CurTime() + 0)
	self:SetNextIdle(CurTime() + time)
	return true
end

function SWEP:Holster(newWep)
	return true
end

local function ease(t)
	if t<.5 then return 2*t*t else return -1+(4-2*t)*t end
end

local function addangle(ang,ang2)
	ang:RotateAroundAxis(ang:Up(),ang2.y) -- yaw
	ang:RotateAroundAxis(ang:Forward(),ang2.r) -- roll
	ang:RotateAroundAxis(ang:Right(),ang2.p) -- pitch
end

function SWEP:CalcViewModelView(vm, opos, oang, pos, ang)
	
	// iron sights
	local addpos, addang = Vector(0, 0, 0), Angle(0, 0, 0)
	if self.Ironsights then
		addpos = self.Ironsights.Pos or addpos
		addang = self.Ironsights.Angle or addang
	end
	local pos2 = addpos * ease(self.IronsightsPercent)
	addangle(ang, addang * ease(self.IronsightsPercent))
	pos2:Rotate(ang)
	return pos + pos2, ang
end

function SWEP:OnRemove()
end


Can’t see the whole code from my phone, but make sure you’re running Weapon:GetOwner():SetAnimation( PLAYER_ATTACK1 ) in the PrimaryAttack.

Ahh I’m an idiot, I put it in the server check and was expecting myself to see it. Oops.

[editline]31st October 2016[/editline]

I don’t want to make another post and spam the forum; how do I remove this prop when you holster? I deleted the previous code and forgot what you did.



function SWEP:Deploy()
	self.Owner:DrawWorldModel(false)
	
	local knife = ents.Create("prop_physics")
	knife:SetModel("models/weapons/w_knife_t.mdl")
	knife:SetLocalPos(Vector(self.Owner:GetPos().x, self.Owner:GetPos().y ,self.Owner:GetPos().z + 5))
	knife:SetLocalAngles(Angle(0,-90,0))
	self.Owner:DeleteOnRemove(knife)
	knife:SetParent(self.Owner)
	return true
end

function SWEP:Holster()

	return true
end


Attach the knife enthandle to a SWEP variable and remove it in Holster.

Hmm can’t figure it out, can you show me again? Sorry.


function SWEP:Deploy()
   local knife = ents.Create("blah")
   self.m_pKnife = knife
   -- etc
end

function SWEP:Holster()
   if ( self.m_pKnife ~= NULL ) then
      self.m_pKnife:Remove()
   end
end

I get:

[ERROR] addons/murder_187073946/gamemodes/murder/entities/weapons/weapon_mu_knife.lua:55: attempt to index field ‘m_pKnife’ (a nil value)

  1. unknown - addons/murder_187073946/gamemodes/murder/entities/weapons/weapon_mu_knife.lua:55

[editline]31st October 2016[/editline]

which is this line self.m_pKnife:Remove()

[editline]31st October 2016[/editline]

This is the code:



function SWEP:Deploy()
	self.Owner:DrawWorldModel(false)
	
	local knife = ents.Create("prop_physics")
	knife:SetModel("models/weapons/w_knife_t.mdl")
	knife:SetParent(self.Owner)
	knife:SetPos(Vector(self.Owner:GetPos().x , self.Owner:GetPos().y + 5, self.Owner:GetPos().z + 13))
	knife:SetAngles(Angle(self.Owner:GetAimVector().x,self.Owner:GetAimVector().y + 90,self.Owner:GetAimVector().z))
	self.Owner:DeleteOnRemove(knife)
	self.m_pKnife = knife
	return true
end

function SWEP:Holster()
	if ( self.m_pKnife != NULL ) then
		self.m_pKnife:Remove()
	end
	return true
end


Two things: wrap both in serverside statements and also check if m_pKnife is nil I guess.