Files
wnsrc/lua/weapons/tfa_knife_base.lua
lifestorm 94063e4369 Upload
2024-08-04 22:55:00 +03:00

356 lines
9.9 KiB
Lua

--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
-- Copyright (c) 2018-2020 TFA Base Devs
-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this software and associated documentation files (the "Software"), to deal
-- in the Software without restriction, including without limitation the rights
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-- copies of the Software, and to permit persons to whom the Software is
-- furnished to do so, subject to the following conditions:
-- The above copyright notice and this permission notice shall be included in all
-- copies or substantial portions of the Software.
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-- SOFTWARE.
if SERVER then
AddCSLuaFile()
end
DEFINE_BASECLASS("tfa_gun_base")
SWEP.DrawCrosshair = true
SWEP.Primary.Automatic = true
SWEP.Secondary.Automatic = true
SWEP.Primary.RPM = 120 --Primary Slashs per minute
SWEP.Secondary.RPM = 60 --Secondary stabs per minute
SWEP.Primary.Delay = 0.15 --Delay for hull (primary)
SWEP.Secondary.Delay = 0.33 --Delay for hull (secondary)
SWEP.Primary.Length = 32
SWEP.Secondary.Length = 48
SWEP.Primary.Sound = Sound("Weapon_Knife.Slash") --Sounds
SWEP.KnifeShink = "Weapon_Knife.HitWall" --Sounds
SWEP.KnifeSlash = "Weapon_Knife.Hit" --Sounds
SWEP.KnifeStab = "Weapon_Knife.Slash" --Sounds
SWEP.SlashTable = {"midslash1", "midslash2"} --Table of possible hull sequences
SWEP.StabTable = {"stab"} --Table of possible hull sequences
SWEP.StabMissTable = {"stab_miss"} --Table of possible hull sequences
SWEP.DisableIdleAnimations = false --Enable idles
--[[ Don't Edit Below ]]
--
SWEP.DamageType = DMG_SLASH
SWEP.MuzzleFlashEffect = "" --No muzzle
SWEP.DoMuzzleFlash = false --No muzzle
SWEP.WeaponLength = 1 --No nearwall
SWEP.Primary.Ammo = "" -- pistol, 357, smg1, ar2, buckshot, slam, SniperPenetratedRound, AirboatGun
SWEP.Primary.ClipSize = 1 -- Size of a clip
SWEP.Primary.DefaultClip = 1 -- Bullets you start with
SWEP.data = {} --No ironsights
SWEP.Secondary.IronSightsEnabled = false --No ironsights
SWEP.Secondary.DisplaySpread = false
SWEP.IsMelee = true
SWEP.CrosshairConeRecoilOverride = .05
SWEP.HullData = {
hullMin = Vector(-16, -16, -16),
hullMax = Vector(16, 16, 16)
}
SWEP.Primary.DisplayFalloff = false
SWEP.SlashCounter = 1
SWEP.StabCounter = 1
function SWEP:Deploy()
return BaseClass.Deploy(self)
end
local lim_up_vec = Vector(1,1,0.1)
function SWEP:ApplyForce(ent, force, posv, now)
if not IsValid(ent) or not ent.GetPhysicsObjectNum then return end
if now then
if ent.GetRagdollEntity then
ent = ent:GetRagdollEntity() or ent
end
if not IsValid(ent) then return end
local phys = ent:GetPhysicsObjectNum(0)
if IsValid(phys) then
if ent:IsPlayer() or ent:IsNPC() then
ent:SetVelocity( force * 0.1 * lim_up_vec )
phys:SetVelocity(phys:GetVelocity() + force * 0.1 * lim_up_vec )
else
phys:ApplyForceOffset(force, posv)
end
end
else
timer.Simple(0, function()
if IsValid(self) and self:OwnerIsValid() and IsValid(ent) then
self:ApplyForce(ent, force, posv, true)
end
end)
end
end
function SWEP:SlashSound(tr)
if IsFirstTimePredicted() then
if tr.Hit then
if tr.MatType == MAT_FLESH or tr.MatType == MAT_ALIENFLESH then
self:EmitSound(self.KnifeSlash)
else
self:EmitSound(self.KnifeShink)
end
else
self:EmitSound(self.Primary_TFA.Sound)
end
end
end
function SWEP:GetSlashTrace(tbl, fwd)
local ow = self:GetOwner()
ow:LagCompensation(true)
local traceRes = util.TraceLine(tbl)
if (not traceRes.Hit) then
if not self.HullData.Radius then
self.HullData.Radius = self.HullData.hullMin:Distance(self.HullData.hullMax) / 2
end
local hd = self.HullData
tbl.mins = -hd.hullMin
tbl.maxs = hd.hullMax
tbl.endpos = tbl.endpos - fwd * hd.Radius
traceRes = util.TraceHull(tbl)
end
ow:LagCompensation(false)
return traceRes
end
function SWEP:SmackDamage(tr, fwd, primary)
if not tr.Entity:IsValid() then return end
local dmg, force
if primary then
dmg = self:GetStatL("Primary.Damage")
else
dmg = self:GetStatL("Secondary.Damage")
end
force = dmg * 25
local dmginfo = DamageInfo()
dmginfo:SetAttacker(self:GetOwner())
dmginfo:SetInflictor(self)
dmginfo:SetDamage(dmg)
dmginfo:SetDamageType(self.DamageType)
dmginfo:SetDamagePosition(tr.HitPos)
dmginfo:SetReportedPosition(tr.StartPos)
dmginfo:SetDamageForce(fwd * force)
tr.Entity:DispatchTraceAttack(dmginfo, tr, fwd)
self:ApplyForce( tr.Entity, dmginfo:GetDamageForce(), tr.HitPos )
end
function SWEP:SmackEffect(tr)
local vSrc = tr.StartPos
local bFirstTimePredicted = IsFirstTimePredicted()
local bHitWater = bit.band(util.PointContents(vSrc), MASK_WATER) ~= 0
local bEndNotWater = bit.band(util.PointContents(tr.HitPos), MASK_WATER) == 0
local trSplash = bHitWater and bEndNotWater and util.TraceLine({
start = tr.HitPos,
endpos = vSrc,
mask = MASK_WATER
}) or not (bHitWater or bEndNotWater) and util.TraceLine({
start = vSrc,
endpos = tr.HitPos,
mask = MASK_WATER
})
if (trSplash and bFirstTimePredicted) then
local data = EffectData()
data:SetOrigin(trSplash.HitPos)
data:SetScale(1)
if (bit.band(util.PointContents(trSplash.HitPos), CONTENTS_SLIME) ~= 0) then
data:SetFlags(1) --FX_WATER_IN_SLIME
end
util.Effect("watersplash", data)
end
self:DoImpactEffect(tr, self.DamageType)
if (tr.Hit and bFirstTimePredicted and not trSplash) then
local data = EffectData()
data:SetOrigin(tr.HitPos)
data:SetStart(vSrc)
data:SetSurfaceProp(tr.SurfaceProps)
data:SetDamageType(self.DamageType)
data:SetHitBox(tr.HitBox)
data:SetEntity(tr.Entity)
util.Effect("Impact", data)
end
end
local tracedata = {}
function SWEP:Slash(bPrimary)
local ow, gsp, ea, fw, tr, rpm, delay
if bPrimary == nil then
bPrimary = true
end
ow = self:GetOwner()
gsp = ow:GetShootPos()
ea = ow:EyeAngles()
fw = ea:Forward()
tracedata.start = gsp
tracedata.endpos = gsp + fw * (bPrimary and self.Primary_TFA.Length or self.Secondary_TFA.Length)
tracedata.filter = ow
tr = self:GetSlashTrace(tracedata, fw)
rpm = self:GetStatL("Primary.RPM")
delay = self:GetStatL("Primary.Delay")
self:SlashSound(tr)
self:SmackDamage(tr, fw, bPrimary)
self:SmackEffect(tr, fw, bPrimary)
self:ScheduleStatus(TFA.Enum.STATUS_SHOOTING, 60 / rpm - delay)
end
function SWEP:CanAttack()
if not TFA.Enum.ReadyStatus[self:GetStatus()] then return false end
if CurTime() < self:GetNextPrimaryFire() then return false end
return true
end
function SWEP:PrimaryAttack()
if not self:CanAttack() then return end
if self:GetNextPrimaryFire() < CurTime() and self:GetOwner():IsPlayer() and not self:GetOwner():KeyDown(IN_RELOAD) then
self.SlashCounter = self.SlashCounter + 1
if self.SlashCounter > #self.SlashTable then
self.SlashCounter = 1
end
self:SendViewModelSeq(self.SlashTable[self.SlashCounter])
self:GetOwner():SetAnimation(PLAYER_ATTACK1)
self:SetNextPrimaryFire(CurTime() + 1 / (self.Primary_TFA.RPM / 60))
self:SetNextSecondaryFire(CurTime() + 1 / (self.Primary_TFA.RPM / 60))
self:ScheduleStatus(TFA.Enum.STATUS_RELOADING, self.Primary_TFA.Delay)
end
end
function SWEP:SecondaryAttack()
if not self:CanAttack() then return end
local ow, gsp, ea, fw, tr
ow = self:GetOwner()
gsp = ow:GetShootPos()
ea = ow:EyeAngles()
fw = ea:Forward()
tracedata.start = gsp
tracedata.endpos = gsp + fw * self.Secondary_TFA.Length
tracedata.filter = ow
tr = self:GetSlashTrace(tracedata, fw)
if tr.Hit then
self.StabIndex = self.StabIndex or 0
self.StabIndex = self.StabIndex + 1
if self.StabIndex > #self.StabTable then
self.StabIndex = 1
end
self:SendViewModelSeq(self.StabTable[self.StabIndex])
else
self.StabMiss = self.StabMiss or 0
self.StabMiss = self.StabMiss + 1
if self.StabMiss > #self.StabMissTable then
self.StabMiss = 1
end
self:SendViewModelSeq(self.StabMissTable[self.StabMiss])
end
self:GetOwner():SetAnimation(PLAYER_ATTACK1)
self:SetNextPrimaryFire(CurTime() + 60 / self.Secondary_TFA.RPM)
self:SetNextSecondaryFire(CurTime() + 60 / self.Secondary_TFA.RPM )
self:ScheduleStatus(TFA.Enum.STATUS_SILENCER_TOGGLE, self.Secondary_TFA.Delay)
end
function SWEP:ThrowKnife()
if not IsFirstTimePredicted() then return end
self:EmitSound(self.Primary_TFA.Sound)
if SERVER then
local ent = ents.Create("tfa_thrown_blade")
if ent:IsValid() then
ent:SetPos(self:GetOwner():GetShootPos())
ent:SetAngles(self:GetOwner():EyeAngles())
ent:SetModel(self.Primary_TFA.ProjectileModel or self.WorldModel)
ent:SetOwner(self:GetOwner())
ent:SetPhysicsAttacker(self:GetOwner())
ent:Spawn()
ent:Activate()
ent:SetNW2String("ClassName", self:GetClass())
local phys = ent:GetPhysicsObject()
if IsValid(phys) then
phys:SetVelocity(self:GetOwner():GetAimVector() * 1250)
phys:AddAngleVelocity(Vector(0, 480, 0))
end
self:GetOwner():SetAnimation(PLAYER_ATTACK1)
self:GetOwner():StripWeapon(self:GetClass())
end
end
end
function SWEP:Reload()
if not self:OwnerIsValid() and self:GetOwner():KeyDown(IN_RELOAD) then return end
self:ThrowKnife()
end
function SWEP:Think2(...)
if self:GetStatus() == TFA.Enum.STATUS_SILENCER_TOGGLE and CurTime() > self:GetStatusEnd() then
self:Slash(false)
elseif self:GetStatus() == TFA.Enum.STATUS_RELOADING and CurTime() > self:GetStatusEnd() then
self:Slash(true)
end
BaseClass.Think2(self, ...)
end
SWEP.IsKnife = true
SWEP.WeaponLength = 8
TFA.FillMissingMetaValues(SWEP)