mirror of
https://github.com/lifestorm/wnsrc.git
synced 2025-12-17 13:53:45 +03:00
Upload
This commit is contained in:
923
lua/weapons/arccw_base/sh_firing.lua
Normal file
923
lua/weapons/arccw_base/sh_firing.lua
Normal file
@@ -0,0 +1,923 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
function SWEP:CanPrimaryAttack()
|
||||
local owner = self:GetOwner()
|
||||
|
||||
-- Should we not fire? But first.
|
||||
if self:GetBuff_Hook("Hook_ShouldNotFireFirst") then return end
|
||||
|
||||
-- We're holstering
|
||||
if IsValid(self:GetHolster_Entity()) then return end
|
||||
if self:GetHolster_Time() > 0 then return end
|
||||
|
||||
-- Disabled (currently used only by deploy)
|
||||
if self:GetState() == ArcCW.STATE_DISABLE then return end
|
||||
|
||||
-- Coostimzing
|
||||
if self:GetState() == ArcCW.STATE_CUSTOMIZE then
|
||||
if CLIENT and ArcCW.Inv_Hidden then
|
||||
ArcCW.Inv_Hidden = false
|
||||
gui.EnableScreenClicker(true)
|
||||
elseif game.SinglePlayer() then
|
||||
-- Kind of ugly hack: in SP this is only called serverside so we ask client to do the same check
|
||||
self:CallOnClient("CanPrimaryAttack")
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
-- A priority animation is playing (reloading, cycling, firemode etc)
|
||||
if self:GetPriorityAnim() then return end
|
||||
|
||||
-- Inoperable, but internally (burst resetting for example)
|
||||
if self:GetWeaponOpDelay() > CurTime() then return end
|
||||
|
||||
-- Safety's on, dipshit
|
||||
if self:GetCurrentFiremode().Mode == 0 then
|
||||
self:ChangeFiremode(false)
|
||||
self:SetNextPrimaryFire(CurTime())
|
||||
self.Primary.Automatic = false
|
||||
return
|
||||
end
|
||||
|
||||
-- If we are an NPC, do our own little methods
|
||||
if owner:IsNPC() then self:NPC_Shoot() return end
|
||||
|
||||
-- If we are in a UBGL, shoot the UBGL, not the gun
|
||||
if self:GetInUBGL() then self:ShootUBGL() return end
|
||||
|
||||
-- Too early, come back later.
|
||||
if self:GetNextPrimaryFire() >= CurTime() then return end
|
||||
|
||||
-- Gun is locked from heat.
|
||||
if self:GetHeatLocked() then return end
|
||||
|
||||
-- Attempting a bash
|
||||
if self:GetState() != ArcCW.STATE_SIGHTS and owner:KeyDown(IN_USE) or self.PrimaryBash then self:Bash() return end
|
||||
|
||||
-- Throwing weapon
|
||||
if self.Throwing then self:PreThrow() return end
|
||||
|
||||
-- Too close to a wall
|
||||
if self:BarrelHitWall() > 0 then return end
|
||||
|
||||
-- Can't shoot while sprinting
|
||||
if self:GetNWState() == ArcCW.STATE_SPRINT and !self:CanShootWhileSprint() then return end
|
||||
|
||||
-- Maximum burst shots
|
||||
if (self:GetBurstCount() or 0) >= self:GetBurstLength() then return end
|
||||
|
||||
-- We need to cycle
|
||||
if self:GetNeedCycle() then return end
|
||||
|
||||
-- If we have a trigger delay, make sure its progress is done
|
||||
if self:GetBuff_Override("Override_TriggerDelay", self.TriggerDelay) and ((!self:GetBuff_Override("Override_TriggerCharge", self.TriggerCharge) and self:GetTriggerDelta() < 1)
|
||||
or (self:GetBuff_Override("Override_TriggerCharge", self.TriggerCharge) and self:IsTriggerHeld())) then
|
||||
return
|
||||
end
|
||||
|
||||
-- Should we not fire?
|
||||
if self:GetBuff_Hook("Hook_ShouldNotFire") then return end
|
||||
|
||||
-- We made it
|
||||
return true
|
||||
end
|
||||
|
||||
function SWEP:TakePrimaryAmmo(num)
|
||||
if self:HasBottomlessClip() or self:Clip1() <= 0 then
|
||||
if self:Ammo1() <= 0 then return end
|
||||
if self:HasInfiniteAmmo() then return end
|
||||
self:GetOwner():RemoveAmmo(num, self:GetPrimaryAmmoType())
|
||||
return end
|
||||
self:SetClip1(self:Clip1() - num)
|
||||
end
|
||||
|
||||
function SWEP:ApplyRandomSpread(dir, spread)
|
||||
local radius = math.Rand(0, 1)
|
||||
local theta = math.Rand(0, math.rad(360))
|
||||
local bulletang = dir:Angle()
|
||||
local forward, right, up = bulletang:Forward(), bulletang:Right(), bulletang:Up()
|
||||
local x = radius * math.sin(theta)
|
||||
local y = radius * math.cos(theta)
|
||||
|
||||
dir:Set(dir + right * spread * x + up * spread * y)
|
||||
end
|
||||
|
||||
function SWEP:PrimaryAttack()
|
||||
local owner = self:GetOwner()
|
||||
|
||||
self.Primary.Automatic = true
|
||||
|
||||
if !self:CanPrimaryAttack() then return end
|
||||
|
||||
local clip = self:Clip1()
|
||||
local aps = self:GetBuff("AmmoPerShot")
|
||||
|
||||
if self:HasBottomlessClip() then
|
||||
clip = self:Ammo1()
|
||||
if self:HasInfiniteAmmo() then
|
||||
clip = math.huge
|
||||
end
|
||||
end
|
||||
|
||||
if clip < aps then
|
||||
self:SetBurstCount(0)
|
||||
self:DryFire()
|
||||
|
||||
self.Primary.Automatic = false
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
local dir = (owner:EyeAngles() + self:GetFreeAimOffset()):Forward() --owner:GetAimVector()
|
||||
local src = self:GetShootSrc()
|
||||
|
||||
if bit.band(util.PointContents(src), CONTENTS_WATER) == CONTENTS_WATER and !(self.CanFireUnderwater or self:GetBuff_Override("Override_CanFireUnderwater")) then
|
||||
self:DryFire()
|
||||
return
|
||||
end
|
||||
|
||||
if self:GetMalfunctionJam() then
|
||||
self:DryFire()
|
||||
return
|
||||
end
|
||||
|
||||
-- Try malfunctioning
|
||||
local mal = self:DoMalfunction(false)
|
||||
if mal == true then
|
||||
local anim = "fire_jammed"
|
||||
self:PlayAnimation(anim, 1, true, 0, true)
|
||||
return
|
||||
end
|
||||
|
||||
self:GetBuff_Hook("Hook_PreFireBullets")
|
||||
|
||||
local desync = ArcCW.ConVars["desync"]:GetBool()
|
||||
local desyncnum = (desync and math.random()) or 0
|
||||
math.randomseed(math.Round(util.SharedRandom(self:GetBurstCount(), -1337, 1337, !game.SinglePlayer() and self:GetOwner():GetCurrentCommand():CommandNumber() or CurTime()) * (self:EntIndex() % 30241)) + desyncnum)
|
||||
|
||||
self.Primary.Automatic = true
|
||||
|
||||
local spread = ArcCW.MOAToAcc * self:GetBuff("AccuracyMOA")
|
||||
local disp = self:GetDispersion() * ArcCW.MOAToAcc / 10
|
||||
|
||||
--dir:Rotate(Angle(0, ArcCW.StrafeTilt(self), 0))
|
||||
--dir = dir + VectorRand() * disp
|
||||
|
||||
self:ApplyRandomSpread(dir, disp)
|
||||
|
||||
if (CLIENT or game.SinglePlayer()) and ArcCW.ConVars["dev_shootinfo"]:GetInt() >= 3 and disp > 0 then
|
||||
local dev_tr = util.TraceLine({
|
||||
start = src,
|
||||
endpos = src + owner:GetAimVector() * 33000,
|
||||
mask = MASK_SHOT,
|
||||
filter = {self, self:GetOwner()}
|
||||
})
|
||||
local dist = (dev_tr.HitPos - src):Length()
|
||||
local r = dist / (1 / math.tan(disp)) -- had to google "trig cheat sheet to figure this one out"
|
||||
local a = owner:GetAimVector():Angle()
|
||||
local r_sqrt = r / math.sqrt(2)
|
||||
debugoverlay.Line(dev_tr.HitPos - a:Up() * r, dev_tr.HitPos + a:Up() * r, 5, color_white, true)
|
||||
debugoverlay.Line(dev_tr.HitPos - a:Right() * r, dev_tr.HitPos + a:Right() * r, 5, color_white, true)
|
||||
debugoverlay.Line(dev_tr.HitPos - a:Right() * r_sqrt - a:Up() * r_sqrt, dev_tr.HitPos + a:Right() * r_sqrt + a:Up() * r_sqrt, 5, color_white, true)
|
||||
debugoverlay.Line(dev_tr.HitPos - a:Right() * r_sqrt + a:Up() * r_sqrt, dev_tr.HitPos + a:Right() * r_sqrt - a:Up() * r_sqrt, 5, color_white, true)
|
||||
debugoverlay.Text(dev_tr.HitPos, math.Round(self:GetDispersion(), 1) .. "MOA (" .. math.Round(disp, 3) .. "°)", 5)
|
||||
end
|
||||
|
||||
local delay = self:GetFiringDelay()
|
||||
|
||||
local curtime = CurTime()
|
||||
local curatt = self:GetNextPrimaryFire()
|
||||
local diff = curtime - curatt
|
||||
|
||||
if diff > engine.TickInterval() or diff < 0 then
|
||||
curatt = curtime
|
||||
end
|
||||
|
||||
self:SetNextPrimaryFire(curatt + delay)
|
||||
self:SetNextPrimaryFireSlowdown(curatt + delay) -- shadow for ONLY fire time
|
||||
|
||||
local num = self:GetBuff("Num")
|
||||
|
||||
num = num + self:GetBuff_Add("Add_Num")
|
||||
|
||||
local tracer = self:GetBuff_Override("Override_Tracer", self.Tracer)
|
||||
local tracernum = self:GetBuff_Override("Override_TracerNum", self.TracerNum)
|
||||
local lastout = self:GetBuff_Override("Override_TracerFinalMag", self.TracerFinalMag)
|
||||
if lastout >= clip then
|
||||
tracernum = 1
|
||||
tracer = self:GetBuff_Override("Override_TracerFinal", self.TracerFinal) or self:GetBuff_Override("Override_Tracer", self.Tracer)
|
||||
end
|
||||
local dmgtable = self.BodyDamageMults
|
||||
dmgtable = self:GetBuff_Override("Override_BodyDamageMults") or dmgtable
|
||||
|
||||
-- drive by is cool
|
||||
src = ArcCW:GetVehicleFireTrace(self:GetOwner(), src, dir) or src
|
||||
|
||||
local bullet = {}
|
||||
bullet.Attacker = owner
|
||||
bullet.Dir = dir
|
||||
bullet.Src = src
|
||||
bullet.Spread = Vector(0, 0, 0) --Vector(spread, spread, spread)
|
||||
bullet.Damage = 0
|
||||
bullet.Num = num
|
||||
|
||||
local sglove = math.ceil(num / 3)
|
||||
bullet.Force = self:GetBuff("Force", true) or math.Clamp( ( (50 / sglove) / ( (self:GetBuff("Damage") + self:GetBuff("DamageMin")) / (self:GetBuff("Num") * 2) ) ) * sglove, 1, 3 )
|
||||
-- Overperforming weapons get the jerf, underperforming gets boost
|
||||
bullet.Distance = self:GetBuff("Distance", true) or 33300
|
||||
-- Setting AmmoType makes the engine look for the tracer effect on the ammo instead of TracerName!
|
||||
--bullet.AmmoType = self.Primary.Ammo
|
||||
bullet.HullSize = self:GetBuff("HullSize")
|
||||
bullet.Tracer = tracernum or 0
|
||||
bullet.TracerName = tracer
|
||||
bullet.Weapon = self
|
||||
bullet.Callback = function(att, tr, dmg)
|
||||
ArcCW:BulletCallback(att, tr, dmg, self)
|
||||
end
|
||||
|
||||
local shootent = self:GetBuff("ShootEntity", true) --self:GetBuff_Override("Override_ShootEntity", self.ShootEntity)
|
||||
local shpatt = self:GetBuff_Override("Override_ShotgunSpreadPattern", self.ShotgunSpreadPattern)
|
||||
local shpattov = self:GetBuff_Override("Override_ShotgunSpreadPatternOverrun", self.ShotgunSpreadPatternOverrun)
|
||||
|
||||
local extraspread = AngleRand() * self:GetDispersion() * ArcCW.MOAToAcc / 10
|
||||
|
||||
local projectiledata = {}
|
||||
|
||||
if shpatt or shpattov or shootent then
|
||||
if shootent then
|
||||
projectiledata.ent = shootent
|
||||
projectiledata.vel = self:GetBuff("MuzzleVelocity")
|
||||
end
|
||||
|
||||
bullet = self:GetBuff_Hook("Hook_FireBullets", bullet)
|
||||
|
||||
if !bullet then return end
|
||||
|
||||
local doent = shootent and num or bullet.Num
|
||||
local minnum = shootent and 1 or 0
|
||||
|
||||
if doent > minnum then
|
||||
for n = 1, bullet.Num do
|
||||
bullet.Num = 1
|
||||
|
||||
local dispers = self:GetBuff_Override("Override_ShotgunSpreadDispersion", self.ShotgunSpreadDispersion)
|
||||
local offset = self:GetShotgunSpreadOffset(n)
|
||||
local calcoff = dispers and (offset * self:GetDispersion() * ArcCW.MOAToAcc / 10) or offset
|
||||
|
||||
local ang = owner:EyeAngles() + self:GetFreeAimOffset()
|
||||
local ang2 = Angle(ang)
|
||||
ang2:RotateAroundAxis(ang:Right(), -1 * calcoff.p)
|
||||
ang2:RotateAroundAxis(ang:Up(), calcoff.y)
|
||||
ang2:RotateAroundAxis(ang:Forward(), calcoff.r)
|
||||
|
||||
if !self:GetBuff_Override("Override_NoRandSpread", self.NoRandSpread) then -- Needs testing
|
||||
ang2 = ang2 + AngleRand() * spread / 5
|
||||
end
|
||||
|
||||
if shootent then
|
||||
projectiledata.ang = ang2
|
||||
|
||||
self:DoPrimaryFire(true, projectiledata)
|
||||
else
|
||||
bullet.Dir = ang2:Forward()
|
||||
|
||||
self:DoPrimaryFire(false, bullet)
|
||||
end
|
||||
end
|
||||
elseif shootent then
|
||||
local ang = owner:EyeAngles() + self:GetFreeAimOffset()
|
||||
|
||||
if !self:GetBuff_Override("Override_NoRandSpread", self.NoRandSpread) then
|
||||
-- ang = (dir + VectorRand() * spread / 5):Angle()
|
||||
|
||||
local newdir = Vector(dir)
|
||||
self:ApplyRandomSpread(newdir, spread / 5)
|
||||
ang = newdir:Angle()
|
||||
end
|
||||
|
||||
projectiledata.ang = ang
|
||||
|
||||
self:DoPrimaryFire(true, projectiledata)
|
||||
end
|
||||
else
|
||||
if !bullet then return end
|
||||
|
||||
for n = 1, bullet.Num do
|
||||
bullet.Num = 1
|
||||
local dirry = Vector(dir.x, dir.y, dir.z)
|
||||
math.randomseed(math.Round(util.SharedRandom(n, -1337, 1337, !game.SinglePlayer() and self:GetOwner():GetCurrentCommand():CommandNumber() or CurTime()) * (self:EntIndex() % 30241)) + desyncnum)
|
||||
if !self:GetBuff_Override("Override_NoRandSpread", self.NoRandSpread) then
|
||||
self:ApplyRandomSpread(dirry, spread)
|
||||
bullet.Dir = dirry
|
||||
end
|
||||
bullet = self:GetBuff_Hook("Hook_FireBullets", bullet) or bullet
|
||||
|
||||
self:DoPrimaryFire(false, bullet)
|
||||
end
|
||||
end
|
||||
|
||||
self:DoRecoil()
|
||||
|
||||
self:SetNthShot(self:GetNthShot() + 1)
|
||||
|
||||
owner:DoAnimationEvent(self:GetBuff_Override("Override_AnimShoot") or self.AnimShoot)
|
||||
|
||||
local shouldsupp = SERVER and !game.SinglePlayer()
|
||||
|
||||
if shouldsupp then SuppressHostEvents(owner) end
|
||||
|
||||
self:DoEffects()
|
||||
|
||||
self:SetBurstCount(self:GetBurstCount() + 1)
|
||||
|
||||
self:TakePrimaryAmmo(aps)
|
||||
|
||||
self:DoShootSound()
|
||||
self:DoPrimaryAnim()
|
||||
|
||||
if self:GetCurrentFiremode().Mode < 0 and self:GetBurstCount() == self:GetBurstLength() then
|
||||
local postburst = (self:GetCurrentFiremode().PostBurstDelay or 0)
|
||||
self:SetWeaponOpDelay(CurTime() + postburst * self:GetBuff_Mult("Mult_PostBurstDelay") + self:GetBuff_Add("Add_PostBurstDelay"))
|
||||
end
|
||||
|
||||
if (self:GetIsManualAction()) and !(self.NoLastCycle and self:Clip1() == 0) then
|
||||
local fireanim = self:GetBuff_Hook("Hook_SelectFireAnimation") or self:SelectAnimation("fire")
|
||||
local firedelay = self.Animations[fireanim].MinProgress or 0
|
||||
self:SetNeedCycle(true)
|
||||
self:SetWeaponOpDelay(CurTime() + (firedelay * self:GetBuff_Mult("Mult_CycleTime")))
|
||||
self:SetNextPrimaryFire(CurTime() + 0.1)
|
||||
end
|
||||
|
||||
self:ApplyAttachmentShootDamage()
|
||||
|
||||
self:AddHeat(self:GetBuff("HeatGain"))
|
||||
|
||||
mal = self:DoMalfunction(true)
|
||||
if mal == true then
|
||||
local anim = "fire_jammed"
|
||||
self:PlayAnimation(anim, 1, true, 0, true)
|
||||
end
|
||||
|
||||
if self:GetCurrentFiremode().Mode == 1 then
|
||||
self.LastTriggerTime = -1 -- Cannot fire again until trigger released
|
||||
self.LastTriggerDuration = 0
|
||||
end
|
||||
|
||||
self:GetBuff_Hook("Hook_PostFireBullets")
|
||||
|
||||
if shouldsupp then SuppressHostEvents(nil) end
|
||||
end
|
||||
|
||||
function SWEP:TryBustDoor(ent, dmg)
|
||||
ArcCW.TryBustDoor(ent, dmg)
|
||||
end
|
||||
|
||||
function SWEP:DoShootSound(sndoverride, dsndoverride, voloverride, pitchoverride)
|
||||
local fsound = self.ShootSound
|
||||
local suppressed = self:GetBuff_Override("Silencer")
|
||||
|
||||
if suppressed then
|
||||
fsound = self.ShootSoundSilenced
|
||||
end
|
||||
|
||||
local firstsound = self.FirstShootSound
|
||||
|
||||
if self:GetBurstCount() == 1 and firstsound then
|
||||
fsound = firstsound
|
||||
|
||||
local firstsil = self.FirstShootSoundSilenced
|
||||
|
||||
if suppressed then
|
||||
fsound = firstsil and firstsil or self.ShootSoundSilenced
|
||||
end
|
||||
end
|
||||
|
||||
local lastsound = self.LastShootSound
|
||||
|
||||
local clip = self:Clip1()
|
||||
|
||||
if clip == 1 and lastsound then
|
||||
fsound = lastsound
|
||||
|
||||
local lastsil = self.LastShootSoundSilenced
|
||||
|
||||
if suppressed then
|
||||
fsound = lastsil and lastsil or self.ShootSoundSilenced
|
||||
end
|
||||
end
|
||||
|
||||
fsound = self:GetBuff_Hook("Hook_GetShootSound", fsound)
|
||||
|
||||
local distancesound = self.DistantShootSound
|
||||
|
||||
if suppressed then
|
||||
distancesound = self.DistantShootSoundSilenced
|
||||
end
|
||||
|
||||
distancesound = self:GetBuff_Hook("Hook_GetDistantShootSound", distancesound)
|
||||
|
||||
local spv = self.ShootPitchVariation
|
||||
local volume = self.ShootVol
|
||||
local pitch = self.ShootPitch * math.Rand(1 - spv, 1 + spv) * self:GetBuff_Mult("Mult_ShootPitch")
|
||||
|
||||
local v = ArcCW.ConVars["weakensounds"]:GetFloat()
|
||||
|
||||
volume = volume - v
|
||||
|
||||
volume = volume * self:GetBuff_Mult("Mult_ShootVol")
|
||||
|
||||
volume = math.Clamp(volume, 51, 149)
|
||||
pitch = math.Clamp(pitch, 0, 255)
|
||||
|
||||
if sndoverride then fsound = sndoverride end
|
||||
if dsndoverride then distancesound = dsndoverride end
|
||||
if voloverride then volume = voloverride end
|
||||
if pitchoverride then pitch = pitchoverride end
|
||||
|
||||
if distancesound then self:MyEmitSound(distancesound, 149, pitch, 0.5, CHAN_WEAPON + 1) end
|
||||
|
||||
if fsound then self:MyEmitSound(fsound, volume, pitch, 1, CHAN_WEAPON) end
|
||||
|
||||
local data = {
|
||||
sound = fsound,
|
||||
volume = volume,
|
||||
pitch = pitch,
|
||||
}
|
||||
|
||||
self:GetBuff_Hook("Hook_AddShootSound", data)
|
||||
end
|
||||
|
||||
function SWEP:GetMuzzleVelocity()
|
||||
local vel = self:GetBuff_Override("Override_PhysBulletMuzzleVelocity", self.PhysBulletMuzzleVelocity)
|
||||
|
||||
if !vel then
|
||||
vel = self:GetBuff("Range") * 3.5
|
||||
|
||||
if self:GetBuff("DamageMin") > self:GetBuff("Damage") then
|
||||
vel = vel * 2
|
||||
end
|
||||
vel = math.Clamp(vel, 200, 1000)
|
||||
end
|
||||
|
||||
vel = vel / ArcCW.HUToM
|
||||
|
||||
vel = vel * self:GetBuff_Mult("Mult_PhysBulletMuzzleVelocity")
|
||||
|
||||
vel = vel * ArcCW.ConVars["bullet_velocity"]:GetFloat()
|
||||
|
||||
return vel
|
||||
end
|
||||
|
||||
function SWEP:DoPrimaryFire(isent, data)
|
||||
local clip = self:Clip1()
|
||||
if self:HasBottomlessClip() then
|
||||
if !self:GetOwner():IsPlayer() then
|
||||
clip = math.huge
|
||||
else
|
||||
clip = self:Ammo1()
|
||||
end
|
||||
end
|
||||
local owner = self:GetOwner()
|
||||
|
||||
local shouldphysical = ArcCW.ConVars["bullet_enable"]:GetBool()
|
||||
|
||||
if self.AlwaysPhysBullet or self:GetBuff_Override("Override_AlwaysPhysBullet") then
|
||||
shouldphysical = true
|
||||
end
|
||||
|
||||
if self.NeverPhysBullet or self:GetBuff_Override("Override_NeverPhysBullet") then
|
||||
shouldphysical = false
|
||||
end
|
||||
|
||||
if isent then
|
||||
self:FireRocket(data.ent, data.vel, data.ang, self.PhysBulletDontInheritPlayerVelocity)
|
||||
else
|
||||
-- if !game.SinglePlayer() and !IsFirstTimePredicted() then return end
|
||||
if !IsFirstTimePredicted() then return end
|
||||
|
||||
if shouldphysical then
|
||||
local tracernum = data.Tracer or 1
|
||||
local phystracer = self:GetBuff_Override("Override_PhysTracerProfile", self.PhysTracerProfile)
|
||||
local lastout = self:GetBuff_Override("Override_TracerFinalMag", self.TracerFinalMag)
|
||||
if lastout >= self:Clip1() then
|
||||
phystracer = self:GetBuff_Override("Override_PhysTracerProfileFinal", self.PhysTracerProfileFinal) or phystracer
|
||||
elseif tracernum == 0 or clip % tracernum != 0 then
|
||||
phystracer = 7
|
||||
end
|
||||
|
||||
local vel = self:GetMuzzleVelocity()
|
||||
|
||||
vel = vel * data.Dir:GetNormalized()
|
||||
|
||||
ArcCW:ShootPhysBullet(self, data.Src, vel, phystracer or 0)
|
||||
else
|
||||
owner:FireBullets(data, true)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:DoPrimaryAnim()
|
||||
local anim = "fire"
|
||||
|
||||
local inbipod = self:InBipod()
|
||||
local iron = self:GetState() == ArcCW.STATE_SIGHTS
|
||||
|
||||
-- Needs testing
|
||||
if inbipod then
|
||||
anim = self:SelectAnimation("fire_bipod") or self:SelectAnimation("fire") or anim
|
||||
else
|
||||
anim = self:SelectAnimation("fire") or anim
|
||||
end
|
||||
|
||||
if (self.ProceduralIronFire and iron) or (self.ProceduralRegularFire and !iron) then anim = nil end
|
||||
|
||||
anim = self:GetBuff_Hook("Hook_SelectFireAnimation", anim) or anim
|
||||
|
||||
local time = self:GetBuff_Mult("Mult_FireAnimTime", anim) or 1
|
||||
|
||||
if anim then self:PlayAnimation(anim, time, true, 0, false) end
|
||||
end
|
||||
|
||||
function SWEP:DoPenetration(tr, penleft, alreadypenned)
|
||||
local bullet = {
|
||||
Damage = self:GetDamage((tr.HitPos - tr.StartPos):Length() * ArcCW.HUToM),
|
||||
DamageType = self:GetBuff_Override("Override_DamageType") or self.DamageType,
|
||||
Weapon = self,
|
||||
Penetration = self:GetBuff("Penetration"),
|
||||
Attacker = self:GetOwner(),
|
||||
Travelled = (tr.HitPos - tr.StartPos):Length()
|
||||
}
|
||||
|
||||
ArcCW:DoPenetration(tr, bullet.Damage, bullet, penleft, false, alreadypenned)
|
||||
end
|
||||
|
||||
function SWEP:GetFiringDelay()
|
||||
local delay = (self.Delay * (1 / self:GetBuff_Mult("Mult_RPM")))
|
||||
delay = self:GetBuff_Hook("Hook_ModifyRPM", delay) or delay
|
||||
|
||||
return delay
|
||||
end
|
||||
|
||||
function SWEP:GetShootSrc()
|
||||
local owner = self:GetOwner()
|
||||
|
||||
if !IsValid(owner) then return self:GetPos() end
|
||||
if owner:IsNPC() then return owner:GetShootPos() end
|
||||
|
||||
local dir = owner:EyeAngles()
|
||||
local offset = Vector(0, 0, 0)
|
||||
|
||||
if self:GetOwner():Crouching() then
|
||||
offset = self:GetBuff_Override("Override_BarrelOffsetCrouch") or self.BarrelOffsetCrouch or offset
|
||||
end
|
||||
|
||||
if self:GetNWState() == ArcCW.STATE_SIGHTS then
|
||||
offset = LerpVector(self:GetNWSightDelta(), offset, self:GetBuff_Override("Override_BarrelOffsetSighted", self.BarrelOffsetSighted) or offset)
|
||||
else
|
||||
offset = LerpVector(1 - self:GetNWSightDelta(), offset, self:GetBuff_Override("Override_BarrelOffsetHip", self.BarrelOffsetHip) or offset)
|
||||
end
|
||||
|
||||
local src = owner:EyePos()
|
||||
|
||||
|
||||
src = src + dir:Right() * offset[1]
|
||||
src = src + dir:Forward() * offset[2]
|
||||
src = src + dir:Up() * offset[3]
|
||||
|
||||
return src
|
||||
end
|
||||
|
||||
function SWEP:GetShotgunSpreadOffset(num)
|
||||
local rotate = Angle()
|
||||
local spreadpt = self:GetBuff_Override("Override_ShotgunSpreadPattern") or self.ShotgunSpreadPattern or {}
|
||||
local spreadov = self:GetBuff_Override("Override_ShotgunSpreadPatternOverrun") or self.ShotgunSpreadPatternOverrun or { Angle() }
|
||||
|
||||
if istable(spreadpt) and istable(spreadov) then
|
||||
spreadpt["BaseClass"] = nil
|
||||
spreadov["BaseClass"] = nil
|
||||
|
||||
if num > #spreadpt then
|
||||
if spo then
|
||||
num = num - #spreadpt
|
||||
num = math.fmod(num, #spreadov) + 1
|
||||
rotate = spreadov[num]
|
||||
else
|
||||
num = math.fmod(num, #spreadpt) + 1
|
||||
rotate = spreadpt[num]
|
||||
end
|
||||
else
|
||||
rotate = spreadpt[num]
|
||||
end
|
||||
end
|
||||
|
||||
local rottoang = {}
|
||||
rottoang.num = num
|
||||
rottoang.ang = rotate
|
||||
|
||||
rotate = self:GetBuff_Hook("Hook_ShotgunSpreadOffset", rottoang).ang
|
||||
|
||||
return rotate or Angle()
|
||||
end
|
||||
|
||||
function SWEP:GetDispersion()
|
||||
local owner = self:GetOwner()
|
||||
|
||||
if vrmod and vrmod.IsPlayerInVR(owner) then return 0 end
|
||||
|
||||
local hipdisp = self:GetBuff("HipDispersion")
|
||||
local sights = self:GetState() == ArcCW.STATE_SIGHTS
|
||||
|
||||
local hip = hipdisp
|
||||
|
||||
local sightdisp = self:GetBuff("SightsDispersion")
|
||||
if sights then hip = Lerp(self:GetNWSightDelta(), sightdisp, hipdisp) end
|
||||
|
||||
local speed = owner:GetAbsVelocity():Length()
|
||||
local maxspeed = owner:GetWalkSpeed() * self:GetBuff("SpeedMult")
|
||||
if sights then maxspeed = maxspeed * self:GetBuff("SightedSpeedMult") end
|
||||
speed = math.Clamp(speed / maxspeed, 0, 2)
|
||||
|
||||
if owner:OnGround() or owner:WaterLevel() > 0 and owner:GetMoveType() != MOVETYPE_NOCLIP then
|
||||
hip = hip + speed * self:GetBuff("MoveDispersion")
|
||||
elseif owner:GetMoveType() != MOVETYPE_NOCLIP then
|
||||
hip = hip + math.max(speed * self:GetBuff("MoveDispersion"), self:GetBuff("JumpDispersion"))
|
||||
end
|
||||
|
||||
if self:InBipod() then hip = hip * (self.BipodDispersion * self:GetBuff_Mult("Mult_BipodDispersion")) end
|
||||
|
||||
if ArcCW.ConVars["mult_crouchdisp"]:GetFloat() != 1 and owner:OnGround() and owner:Crouching() then
|
||||
hip = hip * ArcCW.ConVars["mult_crouchdisp"]:GetFloat()
|
||||
end
|
||||
|
||||
if ArcCW.ConVars["freeaim"]:GetInt() == 1 and !sights then
|
||||
hip = hip ^ 0.9
|
||||
end
|
||||
|
||||
--local t = hook.Run("ArcCW_ModDispersion", self, {dispersion = hip})
|
||||
--hip = t and t.dispersion or hip
|
||||
hip = self:GetBuff_Hook("Hook_ModDispersion", hip) or hip
|
||||
|
||||
return hip
|
||||
end
|
||||
|
||||
function SWEP:DoShellEject(atti)
|
||||
local eff = self:GetBuff_Override("Override_ShellEffect") or self.ShellEffect or "arccw_shelleffect"
|
||||
|
||||
if eff == "NONE" then return end
|
||||
|
||||
local owner = self:GetOwner()
|
||||
|
||||
if !IsValid(owner) then return end
|
||||
|
||||
local vm = self
|
||||
|
||||
if !owner:IsNPC() then owner:GetViewModel() end
|
||||
|
||||
local att = vm:GetAttachment(atti or self:GetBuff_Override("Override_CaseEffectAttachment") or self.CaseEffectAttachment or 2)
|
||||
|
||||
if !att then return end
|
||||
|
||||
local pos, ang = att.Pos, att.Ang
|
||||
|
||||
if pos and ang and self.ShellEjectPosCorrection then
|
||||
local up = ang:Up()
|
||||
local right = ang:Right()
|
||||
local forward = ang:Forward()
|
||||
pos = pos + up * self.ShellEjectPosCorrection.z + right * self.ShellEjectPosCorrection.x + forward * self.ShellEjectPosCorrection.y
|
||||
end
|
||||
|
||||
local ed = EffectData()
|
||||
ed:SetOrigin(pos)
|
||||
ed:SetAngles(ang)
|
||||
ed:SetAttachment(atti or self:GetBuff_Override("Override_CaseEffectAttachment") or self.CaseEffectAttachment or 2)
|
||||
ed:SetScale(1)
|
||||
ed:SetEntity(self)
|
||||
ed:SetNormal(ang:Forward())
|
||||
ed:SetMagnitude(100)
|
||||
|
||||
local efov = {}
|
||||
efov.eff = eff
|
||||
efov.fx = ed
|
||||
|
||||
if self:GetBuff_Hook("Hook_PreDoEffects", efov) == true then return end
|
||||
|
||||
util.Effect(eff, ed)
|
||||
end
|
||||
|
||||
function SWEP:DoEffects(att)
|
||||
if !game.SinglePlayer() and !IsFirstTimePredicted() then return end
|
||||
|
||||
local ed = EffectData()
|
||||
ed:SetStart(self:GetShootSrc())
|
||||
ed:SetOrigin(self:GetShootSrc())
|
||||
ed:SetScale(1)
|
||||
ed:SetEntity(self)
|
||||
ed:SetAttachment(att or self:GetBuff_Override("Override_MuzzleEffectAttachment") or self.MuzzleEffectAttachment or 1)
|
||||
|
||||
local efov = {}
|
||||
efov.eff = "arccw_muzzleeffect"
|
||||
efov.fx = ed
|
||||
|
||||
if self:GetBuff_Hook("Hook_PreDoEffects", efov) == true then return end
|
||||
|
||||
util.Effect("arccw_muzzleeffect", ed)
|
||||
end
|
||||
|
||||
function SWEP:DryFire()
|
||||
|
||||
if self.Animations.fire_dry then
|
||||
return self:PlayAnimation("fire_dry", 1, true, 0, true)
|
||||
end
|
||||
self:MyEmitSound(self.ShootDrySound or "weapons/arccw/dryfire.wav", 75, 100, 1, CHAN_ITEM)
|
||||
self:SetNextPrimaryFire(CurTime() + 0.25)
|
||||
end
|
||||
|
||||
function SWEP:DoRecoil()
|
||||
local single = game.SinglePlayer()
|
||||
|
||||
if !single and !IsFirstTimePredicted() then return end
|
||||
|
||||
if single and self:GetOwner():IsValid() and SERVER then self:CallOnClient("DoRecoil") end
|
||||
|
||||
-- math.randomseed(self:GetBurstLength() + (self.Recoil * 409) + (self.RecoilSide * 519))
|
||||
|
||||
local rec = {
|
||||
Recoil = 1,
|
||||
RecoilSide = 1,
|
||||
VisualRecoilMul = 1
|
||||
}
|
||||
rec = self:GetBuff_Hook("Hook_ModifyRecoil", rec) or rec
|
||||
|
||||
local recoil = rec.Recoil
|
||||
local side = rec.RecoilSide
|
||||
local visual = rec.VisualRecoilMul
|
||||
|
||||
local rmul = (recoil or 1) * self:GetBuff_Mult("Mult_Recoil")
|
||||
local recv = (visual or 1) * self:GetBuff_Mult("Mult_VisualRecoilMult")
|
||||
local recs = (side or 1) * self:GetBuff_Mult("Mult_RecoilSide")
|
||||
|
||||
-- local rrange = math.Rand(-recs, recs) * self.RecoilSide
|
||||
|
||||
-- local irec = math.Rand(rrange - 1, rrange + 1)
|
||||
-- local recu = math.Rand(0.5, 1)
|
||||
|
||||
local irec = math.Rand(-1, 1)
|
||||
local recu = 1
|
||||
|
||||
if self:InBipod() then
|
||||
local b = self.BipodRecoil * self:GetBuff_Mult("Mult_BipodRecoil")
|
||||
|
||||
rmul = rmul * b
|
||||
recs = recs * b
|
||||
recv = recv * b
|
||||
end
|
||||
|
||||
local recoiltbl = self:GetBuff_Override("Override_ShotRecoilTable") or self.ShotRecoilTable
|
||||
|
||||
if recoiltbl and recoiltbl[self:GetBurstCount()] then rmul = rmul * recoiltbl[self:GetBurstCount()] end
|
||||
|
||||
if ArcCW.ConVars["mult_crouchrecoil"]:GetFloat() != 1 and self:GetOwner():OnGround() and self:GetOwner():Crouching() then
|
||||
rmul = rmul * ArcCW.ConVars["mult_crouchrecoil"]:GetFloat()
|
||||
end
|
||||
|
||||
local punch = Angle()
|
||||
|
||||
punch = punch + (self:GetBuff_Override("Override_RecoilDirection", self.RecoilDirection) * math.max(self.Recoil, 0.25) * recu * recv * rmul)
|
||||
punch = punch + (self:GetBuff_Override("Override_RecoilDirectionSide", self.RecoilDirectionSide) * math.max(self.RecoilSide, 0.25) * irec * recv * rmul)
|
||||
punch = punch + Angle(0, 0, 90) * math.Rand(-1, 1) * math.Clamp(self.Recoil, 0.25, 1) * recv * rmul * 0.01
|
||||
punch = punch * (self.RecoilPunch or 1) * self:GetBuff_Mult("Mult_RecoilPunch")
|
||||
|
||||
self:SetFreeAimAngle(self:GetFreeAimAngle() - punch)
|
||||
|
||||
if CLIENT then self:OurViewPunch(punch) end
|
||||
|
||||
if CLIENT or single then
|
||||
recv = recv * self.VisualRecoilMult
|
||||
|
||||
self.RecoilAmount = self.RecoilAmount + (self.Recoil * rmul * recu)
|
||||
self.RecoilAmountSide = self.RecoilAmountSide + (self.RecoilSide * irec * recs * rmul)
|
||||
self.RecoilPunchBack = math.Clamp(self.RecoilAmount * recv * 5, 1, 5)
|
||||
|
||||
if self.MaxRecoilBlowback > 0 then
|
||||
self.RecoilPunchBack = math.Clamp(self.RecoilPunchBack, 0, self.MaxRecoilBlowback)
|
||||
end
|
||||
|
||||
self.RecoilPunchSide = self.RecoilSide * 0.1 * irec * recv * rmul
|
||||
self.RecoilPunchUp = self.RecoilRise * 0.1 * recu
|
||||
end
|
||||
|
||||
-- math.randomseed(CurTime() + (self:EntIndex() * 3))
|
||||
end
|
||||
|
||||
function SWEP:GetBurstLength()
|
||||
local clip = self:Clip1()
|
||||
if self:HasBottomlessClip() then
|
||||
clip = self:Ammo1()
|
||||
if self:HasInfiniteAmmo() then
|
||||
clip = math.huge
|
||||
end
|
||||
end
|
||||
--if clip == 0 then return 1 end
|
||||
|
||||
local len = self:GetCurrentFiremode().Mode
|
||||
|
||||
if !len then return self:GetBurstCount() + 10 end
|
||||
|
||||
local hookedlen = self:GetBuff_Hook("Hook_GetBurstLength", len)
|
||||
|
||||
if len == 1 then return 1 end
|
||||
if len >= 2 then return self:GetBurstCount() + 10 end
|
||||
|
||||
if hookedlen != len then return hookedlen end
|
||||
|
||||
if len < 0 then return -len end
|
||||
|
||||
return self:GetBurstCount() + 10
|
||||
end
|
||||
|
||||
function SWEP:FireAnimationEvent(pos, ang, event, options)
|
||||
return true
|
||||
end
|
||||
|
||||
function SWEP:IsRampupWeapon()
|
||||
local ovr = self:GetBuff_Override("Override_IsRampupWeapon")
|
||||
if ovr != nil then return ovr end
|
||||
return self:GetBuff("Damage") < self:GetBuff("DamageMin")
|
||||
end
|
||||
|
||||
function SWEP:GetMinMaxRange()
|
||||
local decrease = !self:IsRampupWeapon()
|
||||
|
||||
local min = self:GetBuff_Override("Override_RangeMin", self.RangeMin or 0)
|
||||
local max = self:GetBuff_Override("Override_Range", self.Range)
|
||||
local min_add = self:GetBuff_Add("Add_RangeMin")
|
||||
local max_add = self:GetBuff_Add("Add_Range")
|
||||
local min_mult = self:GetBuff_Mult("Mult_RangeMin")
|
||||
local max_mult = self:GetBuff_Mult("Mult_Range")
|
||||
|
||||
if decrease then
|
||||
-- MinRange is also affected by Mult_Range, this is intentional
|
||||
local total_min = math.max((min + min_add) * min_mult * max_mult, 0)
|
||||
return total_min, math.max((max + max_add) * max_mult, total_min)
|
||||
else
|
||||
-- For "rampup weapons" (dmgmin > dmg), range buffs *decrease* range, as it ramps up damage quicker
|
||||
-- After all, +Range is supposed to be a positive buff no matter the kind of gun
|
||||
local total_min = math.max((min - min_add) / min_mult / max_mult, 0)
|
||||
return total_min, math.max((max - max_add) / max_mult, total_min)
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:GetRangeFraction(range)
|
||||
local min, max = self:GetMinMaxRange()
|
||||
if range < min then
|
||||
return 0
|
||||
else
|
||||
return math.Clamp((range - min) / (max - min), 0, 1)
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:GetDamage(range, pellet)
|
||||
local ovr = self:GetBuff_Override("Override_Num")
|
||||
local add = self:GetBuff_Add("Add_Num")
|
||||
local mul = self:GetBuff_Mult("Mult_Num")
|
||||
|
||||
local num = self.Num
|
||||
local nbr = (ovr or num) * mul + add
|
||||
local factor = 1
|
||||
|
||||
-- Total damage should be unchanged regardless of whether the weapon originally fired 1 pellet or > 1
|
||||
-- If pellet is set, we return per-pellet damage instead of total damage
|
||||
if pellet and num == 1 then
|
||||
factor = 1 / ((ovr or 1) * mul + add)
|
||||
elseif num != nbr then
|
||||
factor = num / nbr
|
||||
end
|
||||
|
||||
--factor = ((pellet and num == 1) and (1 / ((ovr or 1) + add))) or ((num != nbr) and (num / nbr)) or 1
|
||||
|
||||
if !pellet then factor = factor * nbr end
|
||||
|
||||
local dmgmax = self:GetBuff("Damage") * factor
|
||||
local dmgmin = self:GetBuff("DamageMin") * factor
|
||||
local delta = self:GetRangeFraction(range)
|
||||
|
||||
local lerped = Lerp(delta, dmgmax, dmgmin)
|
||||
|
||||
return lerped
|
||||
end
|
||||
|
||||
function SWEP:SecondaryAttack()
|
||||
return self.Melee2 and self:Bash(true)
|
||||
end
|
||||
|
||||
function SWEP:CanShootWhileSprint()
|
||||
return ArcCW.ConVars["mult_shootwhilesprinting"]:GetBool() or self:GetBuff_Override("Override_ShootWhileSprint", self.ShootWhileSprint)
|
||||
end
|
||||
Reference in New Issue
Block a user