188 lines
5.3 KiB
Lua
188 lines
5.3 KiB
Lua
function SWEP:NPC_PrimaryAttack()
|
|
if !IsValid(self:GetOwner()) then return end
|
|
|
|
local enemy = self:GetOwner():GetEnemy()
|
|
|
|
local aps = self:GetValue("AmmoPerShot")
|
|
|
|
if self:Clip1() < aps then
|
|
if !IsValid(enemy) or !IsValid(enemy:GetActiveWeapon()) or table.HasValue({"weapon_crowbar", "weapon_stunstick"}, enemy:GetActiveWeapon():GetClass()) then
|
|
// do not attempt to find cover if enemy does not have a ranged weapon
|
|
self:GetOwner():SetSchedule(SCHED_RELOAD)
|
|
else
|
|
self:GetOwner():SetSchedule(SCHED_HIDE_AND_RELOAD)
|
|
end
|
|
return
|
|
end
|
|
|
|
self:SetBaseSettings()
|
|
self:SetShouldHoldType()
|
|
|
|
self.Primary.Automatic = true
|
|
|
|
local pvar = self:GetValue("ShootPitchVariance")
|
|
|
|
local sshoot = self:GetValue("Sound_Shoot")
|
|
|
|
if self:GetValue("Silencer") then
|
|
sshoot = self:GetValue("Sound_Shoot_Silenced")
|
|
end
|
|
|
|
if istable(sshoot) then
|
|
sshoot = table.Random(sshoot)
|
|
end
|
|
|
|
self:EmitSound(sshoot, self:GetValue("Vol_Shoot"), self:GetValue("Pitch_Shoot") + math.Rand(-pvar, pvar), 1, CHAN_WEAPON)
|
|
|
|
self:SetClip1(self:Clip1() - aps)
|
|
|
|
local delay = 60 / self:GetValue("RPM")
|
|
self:SetNextPrimaryFire(CurTime() + delay)
|
|
if delay < 0.1 then
|
|
self:GetOwner():NextThink(CurTime() + delay) // they will only attempt to fire once per think
|
|
end
|
|
|
|
local spread = self:GetNPCSpread()
|
|
|
|
local dir = self:GetOwner():GetAimVector()
|
|
|
|
if self:GetValue("ShootEnt") then
|
|
if IsValid(enemy) then
|
|
dir = (enemy:WorldSpaceCenter() - self:GetOwner():GetShootPos()):GetNormalized():Angle()
|
|
dir = dir + ((spread + (0.1 / self:GetOwner():GetCurrentWeaponProficiency())) * AngleRand() / 3.6)
|
|
end
|
|
self:ShootRocket(dir)
|
|
else
|
|
self:GetOwner():FireBullets({
|
|
Damage = self:GetValue("Damage_Max"),
|
|
Force = 8,
|
|
TracerName = "tacrp_tracer",
|
|
Tracer = self:GetValue("TracerNum"),
|
|
Num = self:GetValue("Num"),
|
|
Dir = dir,
|
|
Src = self:GetOwner():GetShootPos(),
|
|
Spread = Vector(spread, spread, spread),
|
|
Callback = function(att, btr, dmg)
|
|
local range = (btr.HitPos - btr.StartPos):Length()
|
|
|
|
self:AfterShotFunction(btr, dmg, range, 0, {}) // self:GetValue("Penetration")
|
|
|
|
if TacRP.Developer() then
|
|
if SERVER then
|
|
debugoverlay.Cross(btr.HitPos, 4, 5, Color(255, 0, 0), false)
|
|
else
|
|
debugoverlay.Cross(btr.HitPos, 4, 5, Color(255, 255, 255), false)
|
|
end
|
|
end
|
|
end
|
|
})
|
|
end
|
|
|
|
self:DoEffects()
|
|
self:DoEject()
|
|
end
|
|
|
|
function SWEP:GetNPCBulletSpread(prof)
|
|
local mode = self:GetCurrentFiremode()
|
|
|
|
if mode < 0 then
|
|
return 10 / (prof + 1)
|
|
elseif mode == 1 then
|
|
if math.Rand(0, 100) < (prof + 5) * 5 then
|
|
return 2 / (prof + 1)
|
|
else
|
|
return 20 / (prof + 1)
|
|
end
|
|
elseif mode > 1 then
|
|
if math.Rand(0, 100) < (prof + 5) * 2 then
|
|
return 5 / (prof + 1)
|
|
else
|
|
return 30 / (prof + 1)
|
|
end
|
|
|
|
end
|
|
|
|
return 15
|
|
end
|
|
|
|
function SWEP:GetNPCSpread()
|
|
return self:GetValue("Spread")
|
|
end
|
|
|
|
function SWEP:GetNPCBurstSettings()
|
|
local mode = self:GetCurrentFiremode()
|
|
|
|
local delay = 60 / self:GetValue("RPM")
|
|
|
|
if !mode then return 1, 1, delay end
|
|
|
|
if mode < 0 then
|
|
return -mode, -mode, delay
|
|
elseif mode == 0 then
|
|
return 0, 0, delay
|
|
elseif mode == 1 then
|
|
local c = self:GetCapacity()
|
|
return math.ceil(c * 0.075), math.max(1, math.floor(c * math.Rand(0.15, 0.3))), delay + math.Rand(0.1, 0.2)
|
|
elseif mode >= 2 then
|
|
return math.min(self:Clip1(), 1 + math.floor(0.5 / delay)), math.min(self:Clip1(), 1 + math.floor(2 / delay)), delay
|
|
end
|
|
end
|
|
|
|
function SWEP:GetNPCRestTimes()
|
|
local mode = self:GetCurrentFiremode()
|
|
local postburst = self:GetValue("PostBurstDelay") or 0
|
|
local m = self:GetValue("RecoilKick")
|
|
local delay = 60 / self:GetValue("RPM")
|
|
|
|
if !mode then return delay + 0.3, delay + 0.6 end
|
|
|
|
local o = m > 1 and math.sqrt(m) or m
|
|
if delay <= 60 / 90 then
|
|
return delay + 0.1 * o, delay + 0.2 * o
|
|
elseif mode < 0 then
|
|
o = delay + o * 0.5 + postburst
|
|
end
|
|
|
|
return delay + 0.4 * o, delay + 0.6 * o
|
|
end
|
|
|
|
function SWEP:CanBePickedUpByNPCs()
|
|
return self.NPCUsable
|
|
end
|
|
|
|
function SWEP:NPC_Reload()
|
|
self:DropMagazine()
|
|
end
|
|
|
|
function SWEP:NPC_Initialize()
|
|
if CLIENT then return end
|
|
// auto attachment
|
|
|
|
if TacRP.ConVars["npc_atts"]:GetBool() then
|
|
for i, slot in pairs(self.Attachments) do
|
|
local atts = TacRP.GetAttsForCats(slot.Category or "", self)
|
|
|
|
local ind = math.random(0, #atts)
|
|
|
|
if ind > 0 and math.random() <= 0.75 then
|
|
slot.Installed = atts[ind]
|
|
end
|
|
end
|
|
|
|
self:InvalidateCache()
|
|
end
|
|
|
|
timer.Simple(0.25, function()
|
|
if !IsValid(self) then return end
|
|
self:NetworkWeapon()
|
|
end)
|
|
|
|
self:SetBaseSettings()
|
|
|
|
self:SetClip1(self:GetCapacity())
|
|
|
|
if math.random() <= 0.5 then
|
|
self:SetFiremode(math.random(1, self:GetFiremodeAmount()))
|
|
end
|
|
end
|