249 lines
6.4 KiB
Lua
249 lines
6.4 KiB
Lua
AddCSLuaFile()
|
|
|
|
SWEP.Base = "weapon_zs_zombie"
|
|
|
|
SWEP.PrintName = "Flesh Creeper"
|
|
|
|
SWEP.MeleeDelay = 0.5
|
|
SWEP.MeleeReach = 52
|
|
SWEP.MeleeDamage = 15
|
|
SWEP.MeleeForceScale = 1.25
|
|
SWEP.MeleeSize = 3
|
|
SWEP.MeleeDamageType = DMG_SLASH
|
|
SWEP.Primary.Delay = 0.75
|
|
|
|
SWEP.Secondary.Automatic = false
|
|
|
|
AccessorFuncDT(SWEP, "RightClickStart", "Float", 2)
|
|
AccessorFuncDT(SWEP, "AttackAnimTime", "Float", 3)
|
|
|
|
SWEP.NextDigSound = 0
|
|
SWEP.NextMessage = 0
|
|
|
|
function SWEP:Think()
|
|
self.BaseClass.Think(self)
|
|
|
|
if self:GetHoldingRightClick() and not self.Owner:KeyDown(IN_ATTACK2) then
|
|
self:SetRightClickStart(0)
|
|
|
|
if self.BuildSoundPlaying then
|
|
self.BuildSoundPlaying = false
|
|
self.BuildSound:ChangeVolume(0, 0.5)
|
|
end
|
|
elseif self:IsBuilding() then
|
|
if not self.BuildSoundPlaying then
|
|
self.BuildSoundPlaying = true
|
|
self.BuildSound:ChangeVolume(0.45, 0.5)
|
|
end
|
|
|
|
if SERVER then
|
|
self:BuildingThink()
|
|
end
|
|
end
|
|
|
|
self:NextThink(CurTime())
|
|
return true
|
|
end
|
|
|
|
function SWEP:SendMessage(msg, friendly)
|
|
if CurTime() >= self.NextMessage then
|
|
self.NextMessage = CurTime() + 2
|
|
self.Owner:CenterNotify(friendly and COLOR_GREEN or COLOR_RED, translate.ClientGet(self.Owner, msg))
|
|
end
|
|
end
|
|
|
|
function SWEP:Initialize()
|
|
self.BaseClass.Initialize(self)
|
|
|
|
self.BuildSound = CreateSound(self, "npc/antlion/charge_loop1.wav")
|
|
self.BuildSound:PlayEx(0, 100)
|
|
end
|
|
|
|
function SWEP:OnRemove()
|
|
self.BaseClass.OnRemove(self)
|
|
|
|
self.BuildSound:Stop()
|
|
end
|
|
|
|
function SWEP:BuildingThink()
|
|
local owner = self.Owner
|
|
local pos = owner:WorldSpaceCenter()
|
|
local ang = owner:EyeAngles()
|
|
ang.pitch = 0
|
|
ang.roll = 0
|
|
local forward = ang:Forward()
|
|
local right = ang:Right()
|
|
local endpos = pos + forward * 32
|
|
|
|
local tr = util.TraceLine({start = pos, endpos = endpos, filter = player.GetAll(), mask = MASK_PLAYERSOLID})
|
|
local trent = tr.Entity
|
|
|
|
if trent and trent:IsValid() and trent:GetClass() == "prop_creepernest" then
|
|
--[[if not trent:GetNestBuilt() and trent.LastBuilder and trent.LastBuild and trent.LastBuilder:IsValid() and trent.LastBuilder ~= owner and CurTime() < trent.LastBuild + 0.1 then
|
|
owner:ConCommand("-attack2")
|
|
self:SendMessage("nest_already_being_built")
|
|
return
|
|
end]]
|
|
|
|
self:BuildNest(trent)
|
|
|
|
return
|
|
end
|
|
|
|
if owner.NextNestSpawn and CurTime() < owner.NextNestSpawn then
|
|
if CurTime() >= self.NextMessage then
|
|
self.NextMessage = CurTime() + 2
|
|
owner:CenterNotify(COLOR_RED, translate.ClientFormat(owner, "wait_x_seconds_before_making_a_new_nest", math.ceil(owner.NextNestSpawn - CurTime())))
|
|
end
|
|
|
|
return
|
|
end
|
|
|
|
tr = util.TraceLine({start = endpos, endpos = endpos + Vector(0, 0, -48), mask = MASK_PLAYERSOLID})
|
|
local hitnormal = tr.HitNormal
|
|
local z = hitnormal.z
|
|
if not tr.HitWorld or tr.HitSky or z < 0.75 then
|
|
self:SendMessage("not_enough_room_for_a_nest")
|
|
return
|
|
end
|
|
|
|
local hitpos = tr.HitPos
|
|
|
|
for x = -20, 20, 20 do
|
|
for y = -20, 20, 20 do
|
|
local start = endpos + x * right + y * forward
|
|
tr = util.TraceLine({start = start, endpos = start + Vector(0, 0, -48), mask = MASK_PLAYERSOLID})
|
|
if not tr.HitWorld or tr.HitSky or math.abs(tr.HitNormal.z - z) >= 0.2 then
|
|
self:SendMessage("not_enough_room_for_a_nest")
|
|
return
|
|
end
|
|
end
|
|
end
|
|
|
|
for _, ent in pairs(team.GetValidSpawnPoint(TEAM_UNDEAD)) do
|
|
if ent.Disabled then continue end
|
|
|
|
if util.SkewedDistance(ent:GetPos(), hitpos, 2.5) < GAMEMODE.DynamicSpawnDistBuild then
|
|
self:SendMessage("too_close_to_a_spawn")
|
|
return
|
|
end
|
|
end
|
|
|
|
-- See if there's a nest nearby.
|
|
for _, ent in pairs(ents.FindByClass("prop_creepernest")) do
|
|
if util.SkewedDistance(ent:GetPos(), hitpos, 2.5) <= GAMEMODE.DynamicSpawnDistBuild then
|
|
self:SendMessage("too_close_to_another_nest")
|
|
return
|
|
end
|
|
end
|
|
|
|
for _, human in pairs(team.GetPlayers(TEAM_HUMAN)) do
|
|
if util.SkewedDistance(human:GetPos(), hitpos, 2.75) <= GAMEMODE.DynamicSpawnDistBuild then
|
|
self:SendMessage("too_close_to_a_human")
|
|
return
|
|
end
|
|
end
|
|
|
|
-- I didn't make this check where trigger_hurt entities are. Rather I made it check the time since the last time you were hit with a trigger_hurt.
|
|
-- I'm not sure if it's possible to check if a trigger_hurt is enabled or disabled through the Lua bindings.
|
|
if owner.LastHitWithTriggerHurt and CurTime() < owner.LastHitWithTriggerHurt + 2 then
|
|
return
|
|
end
|
|
|
|
local ent = ents.Create("prop_creepernest")
|
|
if ent:IsValid() then
|
|
nestang = hitnormal:Angle()
|
|
nestang:RotateAroundAxis(nestang:Right(), 270)
|
|
|
|
ent:SetPos(hitpos)
|
|
ent:SetAngles(nestang)
|
|
ent:Spawn()
|
|
|
|
ent:SetNestHealth(1)
|
|
ent:SetNestBuilt(false)
|
|
|
|
self:SendMessage("nest_created")
|
|
|
|
ent.Owner = owner
|
|
|
|
owner.NextNestSpawn = CurTime() + 10
|
|
end
|
|
end
|
|
|
|
function SWEP:BuildNest(ent)
|
|
ent:BuildUp()
|
|
|
|
ent.LastBuild = CurTime()
|
|
ent.LastBuilder = self.Owner
|
|
|
|
if not ent:GetNestBuilt() and ent:GetNestHealth() == ent:GetNestMaxHealth() then
|
|
ent:SetNestBuilt(true)
|
|
ent:EmitSound("physics/flesh/flesh_bloody_break.wav")
|
|
|
|
local name = self.Owner:Name()
|
|
for _, pl in pairs(team.GetPlayers(TEAM_UNDEAD)) do
|
|
pl:CenterNotify(COLOR_GREEN, translate.ClientFormat(pl, "nest_built_by_x", name))
|
|
end
|
|
end
|
|
end
|
|
|
|
function SWEP:PrimaryAttack()
|
|
if self:GetHoldingRightClick() or not self.Owner:OnGround() then return end
|
|
|
|
self.BaseClass.PrimaryAttack(self)
|
|
|
|
if self:IsSwinging() then
|
|
self:SetAttackAnimTime(CurTime() + self.Primary.Delay)
|
|
end
|
|
end
|
|
|
|
function SWEP:SecondaryAttack()
|
|
if self:IsSwinging() or self:IsInAttackAnim() or not self.Owner:OnGround() then return end
|
|
|
|
self:SetRightClickStart(CurTime())
|
|
end
|
|
|
|
function SWEP:GetHoldingRightClick()
|
|
return self:GetRightClickStart() > 0
|
|
end
|
|
|
|
function SWEP:IsBuilding()
|
|
return self:GetHoldingRightClick() and (CurTime() - self:GetRightClickStart()) >= 1
|
|
end
|
|
|
|
function SWEP:Reload()
|
|
self.BaseClass.SecondaryAttack(self)
|
|
end
|
|
|
|
function SWEP:IsMoaning()
|
|
return false
|
|
end
|
|
|
|
function SWEP:PlayAlertSound()
|
|
self.Owner:EmitSound("npc/barnacle/barnacle_pull"..math.random(4)..".wav", 70)
|
|
end
|
|
|
|
function SWEP:PlayIdleSound()
|
|
self.Owner:EmitSound("npc/barnacle/barnacle_pull"..math.random(4)..".wav", 70, 85)
|
|
end
|
|
|
|
function SWEP:PlayAttackSound()
|
|
end
|
|
|
|
function SWEP:PlayHitSound()
|
|
self.Owner:EmitSound("physics/body/body_medium_impact_hard"..math.random(6)..".wav", 70, math.random(110, 120))
|
|
end
|
|
|
|
function SWEP:PlayMissSound()
|
|
self.Owner:EmitSound("npc/zombie/claw_miss"..math.random(2)..".wav", 70, math.random(90, 100))
|
|
end
|
|
|
|
function SWEP:IsInAttackAnim()
|
|
return self:GetAttackAnimTime() > 0 and CurTime() < self:GetAttackAnimTime()
|
|
end
|
|
|
|
if not CLIENT then return end
|
|
|
|
function SWEP:PreDrawViewModel(vm)
|
|
return true
|
|
end
|