Hi. I’m trying to find out what is causing a HUGE delay in attacking with the SWEP. The SWEP is not mine, I am using a modified version of the one created by CmndrFello, Modified by RisingDarkness. Is is a addon for TTT that adds a T weapon that is Genjis’ Katana. When attacking, there is a .3-.4 second delay between when the animation plays, and when damage occurs. This makes it impossible to kill moving targets as the hitbox for damage is quite small. Here is the code.
AddCSLuaFile()
resource.AddFile("sound/weapons/genji/genjidraw.wav")
resource.AddFile("sound/weapons/genji/genjiyell.wav")
resource.AddFile("sound/weapons/genji/genjiyelltwo.wav")
resource.AddFile("sound/weapons/katana/katana_swing_miss.wav")
resource.AddFile("sound/weapons/katana/katana_impact_world1.wav")
SWEP.PrintName = "Genji's Katana"
SWEP.Author = "Rising Darkness"
SWEP.Instructions = "You know the drill"
SWEP.Category = "Overwatch"
SWEP.Spawnable= true
SWEP.AdminSpawnable= true
SWEP.AdminOnly = false
SWEP.Base = "weapon_tttbase"
SWEP.Kind = WEAPON_EQUIP1
SWEP.AutoSpawnable = false
SWEP.AmmoEnt = ""
SWEP.InLoadoutFor = nil
SWEP.AllowDrop = true
SWEP.IsSilent = false
SWEP.NoSights = false
SWEP.CanBuy = { ROLE_TRAITOR }
SWEP.Icon = "entities/genji_melee"
SWEP.EquipMenuData = {
type = "Weapon",
desc = [[You know the drill]]
};
SWEP.ViewModelFOV = 70
SWEP.ViewModelFlip = false
SWEP.ViewModel = "models/weapons/melee/v_katana.mdl"
SWEP.WorldModel = "models/weapons/w_crowbar.mdl"
SWEP.ShowViewModel = true
SWEP.ShowWorldModel = false
SWEP.ViewModelBoneMods = {
["ValveBiped.base"] = { scale = Vector(0.009, 0.009, 0.009), pos = Vector(0, -0.86, -0.005), angle = Angle(0, 0, 0) },
["ValveBiped.Bip01_L_UpperArm"] = { scale = Vector(1, 1, 1), pos = Vector(-1.859, -1.543, -2.842), angle = Angle(0, 0, 0) },
["ValveBiped.Bip01_L_Hand"] = { scale = Vector(1, 1, 1), pos = Vector(-0.389, 0, 0), angle = Angle(-8.622, -51.949, 0) }
}
SWEP.Slot = 7
SWEP.UseHands = true
SWEP.HoldType = "melee2"
SWEP.FiresUnderwater = true
SWEP.DrawCrosshair = true
SWEP.DrawAmmo = true
SWEP.ReloadSound = Sound("weapons/pistol_reload_scout.wav")
SWEP.CSMuzzleFlashes = true
SWEP.Primary.Sound = Sound("weapons/doom_sniper_smg.wav")
SWEP.Primary.Damage = 10
SWEP.Primary.TakeAmmo = 1
SWEP.Primary.ClipSize = -1
SWEP.Primary.Ammo = "no"
SWEP.Primary.DefaultClip = -1
SWEP.Primary.Spread = 0
SWEP.Primary.NumberofShots = 1
SWEP.Primary.Automatic = true
SWEP.Primary.Recoil = 0
SWEP.Primary.Delay = 0.6
SWEP.Primary.Force = 5
SWEP.Secondary.ClipSize = 0
SWEP.Secondary.DefaultClip = 0
SWEP.Secondary.Automatic = false
SWEP.Secondary.Ammo = "none"
SWEP.WElements = {
["sword"] = { type = "Model", model = "models/weapons/melee/w_katana.mdl", bone = "ValveBiped.Bip01_R_Hand", rel = "", pos = Vector(3.719, 1.939, -1.162), angle = Angle(180, 180, 0), size = Vector(1.016, 1.016, 1.016), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} }
}
function SWEP:Initialize()
// other initialize code goes here
self:SetHoldType("melee2")
if CLIENT then
// Create a new table for every weapon instance
self.VElements = table.FullCopy( self.VElements )
self.WElements = table.FullCopy( self.WElements )
self.ViewModelBoneMods = table.FullCopy( self.ViewModelBoneMods )
self:CreateModels(self.VElements) // create viewmodels
self:CreateModels(self.WElements) // create worldmodels
// init view model bone build function
if IsValid(self.Owner) then
local vm = self.Owner:GetViewModel()
if IsValid(vm) then
self:ResetBonePositions(vm)
// Init viewmodel visibility
if (self.ShowViewModel == nil or self.ShowViewModel) then
vm:SetColor(Color(255,255,255,255))
else
// we set the alpha to 1 instead of 0 because else ViewModelDrawn stops being called
vm:SetColor(Color(255,255,255,1))
// ^ stopped working in GMod 13 because you have to do Entity:SetRenderMode(1) for translucency to kick in
// however for some reason the view model resets to render mode 0 every frame so we just apply a debug material to prevent it from drawing
vm:SetMaterial("Debug/hsv")
end
end
end
end
end
function SWEP:Deploy()
self.Weapon:SendWeaponAnim(ACT_VM_DRAW)
self.Owner:EmitSound(Sound("weapons/genji/genjidraw.wav"))
end
function SWEP:PrimaryAttack()
if !IsValid(self) or !IsValid(self.Owner) then return end
self.Weapon:SetNextPrimaryFire( CurTime() + self.Primary.Delay )
self.Weapon:EmitSound("weapons/katana/katana_swing_miss.wav")--slash in the wind sound here
self.Weapon:SendWeaponAnim(ACT_VM_HITCENTER)
timer.Simple(0.2, function()
if IsValid(self) then
self:Slash()
end
end)
self.Weapon:SendWeaponAnim( ACT_VM_MISSCENTER )
self.Owner:SetAnimation( PLAYER_ATTACK1 )
end
function SWEP:Slash()
if !IsValid(self) or !IsValid(self.Owner) then return end
pos = self.Owner:GetShootPos()
ang = self.Owner:GetAimVector()
damagedice = math.Rand(6,10)
pain = self.Primary.Damage * damagedice
if SERVER and IsValid(self.Owner) then
local slash = {}
slash.start = pos
slash.endpos = pos + (ang * 70)
slash.filter = self.Owner
slash.mins = Vector(-5, -5, 0)
slash.maxs = Vector(5, 5, 5)
local slashtrace = util.TraceHull(slash)
if slashtrace.Hit then
targ = slashtrace.Entity
if targ:IsPlayer() or targ:IsNPC() then
self.Owner:EmitSound("weapons/katana/katana_impact_world1.wav")
paininfo = DamageInfo()
paininfo:SetDamage(pain)
paininfo:SetDamageType(DMG_SLASH)
paininfo:SetAttacker(self.Owner)
paininfo:SetInflictor(self.Weapon)
local RandomForce = math.random(1000,20000)
paininfo:SetDamageForce(slashtrace.Normal * RandomForce)
if targ:IsPlayer() then
targ:ViewPunch( Angle( -10, -20, 0 ) )
end
if SERVER then
local blood = targ:GetBloodColor()
local fleshimpact = EffectData()
fleshimpact:SetEntity(self.Weapon)
fleshimpact:SetOrigin(slashtrace.HitPos)
fleshimpact:SetNormal(slashtrace.HitPos)
if blood >= 0 then
fleshimpact:SetColor(blood)
util.Effect("BloodImpact", fleshimpact)
end
end
if SERVER then targ:TakeDamageInfo(paininfo) end
else
look = self.Owner:GetEyeTrace()
util.Decal("ManhackCut", look.HitPos + look.HitNormal, look.HitPos - look.HitNormal )
end
end
end
end
function SWEP:SecondaryAttack()
end
function SWEP:Reload()
end
function SWEP:Holster()
if CLIENT and IsValid(self.Owner) then
local vm = self.Owner:GetViewModel()
if IsValid(vm) then
self:ResetBonePositions(vm)
end
end
return true
end
function SWEP:OnRemove()
if CLIENT and IsValid(self.Owner) and self.Owner == LocalPlayer() and self.Owner:Alive() then
RunConsoleCommand("lastinv")
end
end
if CLIENT then
SWEP.vRenderOrder = nil
function SWEP:ViewModelDrawn()
local vm = self.Owner:GetViewModel()
if !IsValid(vm) then return end
if (!self.VElements) then return end
self:UpdateBonePositions(vm)
if (!self.vRenderOrder) then
// we build a render order because sprites need to be drawn after models
self.vRenderOrder = {}
for k, v in pairs( self.VElements ) do
if (v.type == "Model") then
table.insert(self.vRenderOrder, 1, k)
elseif (v.type == "Sprite" or v.type == "Quad") then
table.insert(self.vRenderOrder, k)
end
end
end
for k, name in ipairs( self.vRenderOrder ) do
local v = self.VElements[name]
if (!v) then self.vRenderOrder = nil break end
if (v.hide) then continue end
local model = v.modelEnt
local sprite = v.spriteMaterial
if (!v.bone) then continue end
local pos, ang = self:GetBoneOrientation( self.VElements, v, vm )
if (!pos) then continue end
if (v.type == "Model" and IsValid(model)) then
model:SetPos(pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z )
ang:RotateAroundAxis(ang:Up(), v.angle.y)
ang:RotateAroundAxis(ang:Right(), v.angle.p)
ang:RotateAroundAxis(ang:Forward(), v.angle.r)
model:SetAngles(ang)
//model:SetModelScale(v.size)
local matrix = Matrix()
matrix:Scale(v.size)
model:EnableMatrix( "RenderMultiply", matrix )
if (v.material == "") then
model:SetMaterial("")
elseif (model:GetMaterial() != v.material) then
model:SetMaterial( v.material )
end
if (v.skin and v.skin != model:GetSkin()) then
model:SetSkin(v.skin)
end
if (v.bodygroup) then
for k, v in pairs( v.bodygroup ) do
if (model:GetBodygroup(k) != v) then
model:SetBodygroup(k, v)
end
end
end
if (v.surpresslightning) then
render.SuppressEngineLighting(true)
end
render.SetColorModulation(v.color.r/255, v.color.g/255, v.color.b/255)
render.SetBlend(v.color.a/255)
model:DrawModel()
render.SetBlend(1)
render.SetColorModulation(1, 1, 1)
if (v.surpresslightning) then
render.SuppressEngineLighting(false)
end
elseif (v.type == "Sprite" and sprite) then
local drawpos = pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z
render.SetMaterial(sprite)
render.DrawSprite(drawpos, v.size.x, v.size.y, v.color)
elseif (v.type == "Quad" and v.draw_func) then
local drawpos = pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z
ang:RotateAroundAxis(ang:Up(), v.angle.y)
ang:RotateAroundAxis(ang:Right(), v.angle.p)
ang:RotateAroundAxis(ang:Forward(), v.angle.r)
cam.Start3D2D(drawpos, ang, v.size)
v.draw_func( self )
cam.End3D2D()
end
end
end
SWEP.wRenderOrder = nil
function SWEP:DrawWorldModel()
if (self.ShowWorldModel == nil or self.ShowWorldModel) then
self:DrawModel()
end
if (!self.WElements) then return end
if (!self.wRenderOrder) then
self.wRenderOrder = {}
for k, v in pairs( self.WElements ) do
if (v.type == "Model") then
table.insert(self.wRenderOrder, 1, k)
elseif (v.type == "Sprite" or v.type == "Quad") then
table.insert(self.wRenderOrder, k)
end
end
end
if (IsValid(self.Owner)) then
bone_ent = self.Owner
else
// when the weapon is dropped
bone_ent = self
end
for k, name in pairs( self.wRenderOrder ) do
local v = self.WElements[name]
if (!v) then self.wRenderOrder = nil break end
if (v.hide) then continue end
local pos, ang
if (v.bone) then
pos, ang = self:GetBoneOrientation( self.WElements, v, bone_ent )
else
pos, ang = self:GetBoneOrientation( self.WElements, v, bone_ent, "ValveBiped.Bip01_R_Hand" )
end
if (!pos) then continue end
local model = v.modelEnt
local sprite = v.spriteMaterial
if (v.type == "Model" and IsValid(model)) then
model:SetPos(pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z )
ang:RotateAroundAxis(ang:Up(), v.angle.y)
ang:RotateAroundAxis(ang:Right(), v.angle.p)
ang:RotateAroundAxis(ang:Forward(), v.angle.r)
model:SetAngles(ang)
//model:SetModelScale(v.size)
local matrix = Matrix()
matrix:Scale(v.size)
model:EnableMatrix( "RenderMultiply", matrix )
if (v.material == "") then
model:SetMaterial("")
elseif (model:GetMaterial() != v.material) then
model:SetMaterial( v.material )
end
if (v.skin and v.skin != model:GetSkin()) then
model:SetSkin(v.skin)
end
if (v.bodygroup) then
for k, v in pairs( v.bodygroup ) do
if (model:GetBodygroup(k) != v) then
model:SetBodygroup(k, v)
end
end
end
if (v.surpresslightning) then
render.SuppressEngineLighting(true)
end
render.SetColorModulation(v.color.r/255, v.color.g/255, v.color.b/255)
render.SetBlend(v.color.a/255)
model:DrawModel()
render.SetBlend(1)
render.SetColorModulation(1, 1, 1)
if (v.surpresslightning) then
render.SuppressEngineLighting(false)
end
elseif (v.type == "Sprite" and sprite) then
local drawpos = pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z
render.SetMaterial(sprite)
render.DrawSprite(drawpos, v.size.x, v.size.y, v.color)
elseif (v.type == "Quad" and v.draw_func) then
local drawpos = pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z
ang:RotateAroundAxis(ang:Up(), v.angle.y)
ang:RotateAroundAxis(ang:Right(), v.angle.p)
ang:RotateAroundAxis(ang:Forward(), v.angle.r)
cam.Start3D2D(drawpos, ang, v.size)
v.draw_func( self )
cam.End3D2D()
end
end
end
function SWEP:GetBoneOrientation( basetab, tab, ent, bone_override )
local bone, pos, ang
if (tab.rel and tab.rel != "") then
local v = basetab[tab.rel]
if (!v) then return end
// Technically, if there exists an element with the same name as a bone
// you can get in an infinite loop. Let's just hope nobody's that stupid.
pos, ang = self:GetBoneOrientation( basetab, v, ent )
if (!pos) then return end
pos = pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z
ang:RotateAroundAxis(ang:Up(), v.angle.y)
ang:RotateAroundAxis(ang:Right(), v.angle.p)
ang:RotateAroundAxis(ang:Forward(), v.angle.r)
else
bone = ent:LookupBone(bone_override or tab.bone)
if (!bone) then return end
pos, ang = Vector(0,0,0), Angle(0,0,0)
local m = ent:GetBoneMatrix(bone)
if (m) then
pos, ang = m:GetTranslation(), m:GetAngles()
end
if (IsValid(self.Owner) and self.Owner:IsPlayer() and
ent == self.Owner:GetViewModel() and self.ViewModelFlip) then
ang.r = -ang.r // Fixes mirrored models
end
end
return pos, ang
end
function SWEP:CreateModels( tab )
if (!tab) then return end
// Create the clientside models here because Garry says we can't do it in the render hook
for k, v in pairs( tab ) do
if (v.type == "Model" and v.model and v.model != "" and (!IsValid(v.modelEnt) or v.createdModel != v.model) and
string.find(v.model, ".mdl") and file.Exists (v.model, "GAME") ) then
v.modelEnt = ClientsideModel(v.model, RENDER_GROUP_VIEW_MODEL_OPAQUE)
if (IsValid(v.modelEnt)) then
v.modelEnt:SetPos(self:GetPos())
v.modelEnt:SetAngles(self:GetAngles())
v.modelEnt:SetParent(self)
v.modelEnt:SetNoDraw(true)
v.createdModel = v.model
else
v.modelEnt = nil
end
elseif (v.type == "Sprite" and v.sprite and v.sprite != "" and (!v.spriteMaterial or v.createdSprite != v.sprite)
and file.Exists ("materials/"..v.sprite..".vmt", "GAME")) then
local name = v.sprite.."-"
local params = { ["$basetexture"] = v.sprite }
// make sure we create a unique name based on the selected options
local tocheck = { "nocull", "additive", "vertexalpha", "vertexcolor", "ignorez" }
for i, j in pairs( tocheck ) do
if (v[j]) then
params["$"..j] = 1
name = name.."1"
else
name = name.."0"
end
end
v.createdSprite = v.sprite
v.spriteMaterial = CreateMaterial(name,"UnlitGeneric",params)
end
end
end
local allbones
local hasGarryFixedBoneScalingYet = false
function SWEP:UpdateBonePositions(vm)
if self.ViewModelBoneMods then
if (!vm:GetBoneCount()) then return end
// !! WORKAROUND !! //
// We need to check all model names :/
local loopthrough = self.ViewModelBoneMods
if (!hasGarryFixedBoneScalingYet) then
allbones = {}
for i=0, vm:GetBoneCount() do
local bonename = vm:GetBoneName(i)
if (self.ViewModelBoneMods[bonename]) then
allbones[bonename] = self.ViewModelBoneMods[bonename]
else
allbones[bonename] = {
scale = Vector(1,1,1),
pos = Vector(0,0,0),
angle = Angle(0,0,0)
}
end
end
loopthrough = allbones
end
// !! ----------- !! //
for k, v in pairs( loopthrough ) do
local bone = vm:LookupBone(k)
if (!bone) then continue end
// !! WORKAROUND !! //
local s = Vector(v.scale.x,v.scale.y,v.scale.z)
local p = Vector(v.pos.x,v.pos.y,v.pos.z)
local ms = Vector(1,1,1)
if (!hasGarryFixedBoneScalingYet) then
local cur = vm:GetBoneParent(bone)
while(cur >= 0) do
local pscale = loopthrough[vm:GetBoneName(cur)].scale
ms = ms * pscale
cur = vm:GetBoneParent(cur)
end
end
s = s * ms
// !! ----------- !! //
if vm:GetManipulateBoneScale(bone) != s then
vm:ManipulateBoneScale( bone, s )
end
if vm:GetManipulateBoneAngles(bone) != v.angle then
vm:ManipulateBoneAngles( bone, v.angle )
end
if vm:GetManipulateBonePosition(bone) != p then
vm:ManipulateBonePosition( bone, p )
end
end
else
self:ResetBonePositions(vm)
end
end
function SWEP:ResetBonePositions(vm)
if (!vm:GetBoneCount()) then return end
for i=0, vm:GetBoneCount() do
vm:ManipulateBoneScale( i, Vector(1, 1, 1) )
vm:ManipulateBoneAngles( i, Angle(0, 0, 0) )
vm:ManipulateBonePosition( i, Vector(0, 0, 0) )
end
end
/**************************
Global utility code
**************************/
// Fully copies the table, meaning all tables inside this table are copied too and so on (normal table.Copy copies only their reference).
// Does not copy entities of course, only copies their reference.
// WARNING: do not use on tables that contain themselves somewhere down the line or you'll get an infinite loop
function table.FullCopy( tab )
if (!tab) then return nil end
local res = {}
for k, v in pairs( tab ) do
if (type(v) == "table") then
res[k] = table.FullCopy(v) // recursion ho!
elseif (type(v) == "Vector") then
res[k] = Vector(v.x, v.y, v.z)
elseif (type(v) == "Angle") then
res[k] = Angle(v.p, v.y, v.r)
else
res[k] = v
end
end
return res
end
end
hook.Add("TTTPlayerSpeed", "genjikatanaspeed" , function(ply)
local wep=ply:GetActiveWeapon()
if wep and IsValid(wep) and wep:GetClass()=="genji_melee" and !ply.RandomatSuperSpeed then
return 1.5
end
end )
Any clue what is causing this huge delay? Thanks in advance.