sninctbur / ba2 Goto Github PK
View Code? Open in Web Editor NEWBio-Annihilation II: the zombie mod to end all zombie mods. Distributed under CC-BY 3.0 https://steamcommunity.com/sharedfiles/filedetails/?id=2416750969
License: Other
Bio-Annihilation II: the zombie mod to end all zombie mods. Distributed under CC-BY 3.0 https://steamcommunity.com/sharedfiles/filedetails/?id=2416750969
License: Other
hi :D, I would like the complete source code because I would like to create a virus mod for me and my friends but I'm not a programmer :( can you help me? thanks
anyway i love this mod i'm sorry i can't put it in all maps
hi: D, I would like the complete source code because I would like to create a virus mod for me and my friends but I'm not a programmer :( can you help me? thanks
Hello! I noticed a bug when trying to do self:SetPos()
on an infected given a certain situation, it simply makes them invincible, which itself creates LookupBone
errors because of that. Shooting them infinitely only causes them to stagger, nothing else. I did it by replacing every case of self:Remove()
with self:SetPos()
, here in the nb_ba2_infected
file:
AddCSLuaFile()
ENT.PrintName = "Infected"
ENT.Base = "base_nextbot"
ENT.Spawnable = false
include("autorun/ba2_shared.lua")
if SERVER then
include("autorun/server/ba2_master_init.lua")
end
-- Initialization
function ENT:Initialize()
self:SetModel("models/ba2/infected/ba2_handfix.mdl")
self:AddFlags(FL_OBJECT)
self.BA2_Attacking = false
self.BA2_Stunned = false
self.BA2_LArmDamage = 0
self.BA2_RArmDamage = 0
self.BA2_LLegDamage = 0
self.BA2_RLegDamage = 0
self.BA2_SpeedMult = math.random(90,100) / 100
self.BA2_TimeToNextScan = 0
self.BA2_CreationTime = CurTime()
--self.InfBody = "models/Humans/Group01/male_02.mdl"
if SERVER then
self.SearchRadius = GetConVar("ba2_zom_range"):GetInt() or 10000
self.HullType = HULL_HUMAN
local hp = GetConVar("ba2_zom_health"):GetInt()
self:SetMaxHealth(hp)
self:SetHealth(hp)
self:SetCollisionBounds(self:OBBMins(),self:OBBMaxs())
self:SetSolid(SOLID_BBOX)
self:PhysicsInitBox(self:OBBMins(),self:OBBMaxs())
--self:SetMoveType(MOVETYPE_STEP)
self:SetCollisionGroup(COLLISION_GROUP_NPC)
self:PhysicsInitStatic(SOLID_BBOX)
self:SetSolidMask(MASK_NPCSOLID)
self:SetFriction(0)
self.loco:SetStepHeight(36)
self.loco:SetJumpHeight(80)
for i,npc in pairs(ents.FindByClass("npc_*")) do
if npc:IsNPC() then
if npc.IsVJBaseSNPC then
table.insert(npc.VJ_AddCertainEntityAsEnemy,z)
table.insert(npc.CurrentPossibleEnemies,z)
end
npc:AddEntityRelationship(self,D_HT,1)
end
end
-- Credit to GammaWhiskey for this block of code
-- if GetConVar("ba2_misc_isnpc"):GetBool() and not BA2_CustomMetaTable then
-- BA2_CustomMetaTable = table.Copy(getmetatable(self))
-- BA2_CustomMetaTable.IsNPC = function() return true end
-- debug.setmetatable(self, BA2_CustomMetaTable)
-- end
timer.Simple(0,function()
if not IsValid(self) then return end
self:GetPhysicsObject():SetMass(90)
-- if BA2_GetMaggotMode() then
-- self:SetModel("models/player/soldier.mdl")
-- self.InfBody = "models/player/soldier.mdl"
-- self.InfVoice = 3
-- self.InfSkin = math.random(4,5)
-- self.ColorOverride = Color(255,255,255)
-- end
-- If you'd like to be chased by a horde of T-posing Soldiers this May, be my guest!
if #navmesh.GetAllNavAreas() == 0 then
for i,v in pairs(player.GetAll()) do
v:PrintMessage(HUD_PRINTCENTER,"This map doesn't have a navmesh!")
end
print("BA2: There is no navmesh! Despawning...")
self:SetPos(self:GetPos()+Vector(50,0,0))
end
if self.InfBody == "CUSTOM" or self.InfBody == "CUSTOM_ARM" then
local tbl1,tbl2 = BA2_GetCustomInfs()
if #tbl1 == 0 or #tbl2 == 0 then
tbl1,tbl2 = BA2_ReloadCustoms()
end
if self.InfBody == "CUSTOM" then
self.InfBody = tbl1[math.random(#tbl1)]
else
self.InfBody = tbl2[math.random(#tbl2)]
end
if !GetConVar("ba2_cos_tint"):GetBool() then
self.ColorOverride = Color(255,255,255)
end
end
if self.InfBody ~= nil then
local model
if self.cheapleEgg and math.random(1,100) <= 1 then
model = "models/Humans/Group01/Male_Cheaple.mdl"
elseif istable(self.InfBody) then
model = self.InfBody[math.random(1,#self.InfBody)]
else
model = self.InfBody
end
self.InfBody = ents.Create("ba2_infbody")
self.InfBody:SetPos(self:GetPos())
self.InfBody:SetModel(model)
self.InfBody:SetOwner(self)
self.InfBody:SetParent(self,0)
self.InfBody:Spawn()
self.InfBody:Activate()
if self.InfBodyGroups and #self.InfBodyGroups > 0 then
for i = 1,#self.InfBodyGroups do
self.InfBody:SetBodygroup(i,self.InfBodyGroups[i])
end
else
for i = 1,#self.InfBody:GetBodyGroups() do
self.InfBody:SetBodygroup(i,math.random(0,self.InfBody:GetBodygroupCount(i-1)))
end
end
self.InfBody:SetSkin(self.InfSkin or math.random(0,self.InfBody:SkinCount()-1))
self:SetNoDraw(true)
self.InfBody:AddEffects(EF_BONEMERGE)
self.InfBody:SetColor(self.ColorOverride or BA2_GetDefaultColor())
if BA2_GetMaggotMode() then
self.InfVoice = 1
elseif self.InfVoice == nil then
if BA2_FemaleModels[model] or string.find(model,"female") ~= nil then
self.InfVoice = 1
elseif string.find(model,"combine") ~= nil or string.find(model,"police") ~= nil then
self.InfVoice = 1
else
self.InfVoice = 1
end
end
-- if BA2_GetMaggotMode() then
-- local eff = ents.Create("prop_dynamic")
-- eff:SetModel("models/player/items/soldier/soldier_zombie.mdl")
-- eff:SetPos(self:GetPos())
-- eff:SetParent(self.InfBody,0)
-- eff:SetSkin(self.InfSkin - 4)
-- eff:Spawn()
-- eff:AddEffects(EF_BONEMERGE)
-- end
if self.BA2_ArmoredZom then
self.BA2_SpeedMult = self.BA2_SpeedMult * .9
end
else
print("BA2: Zombie spawned with no model! Despawning...")
self:SetPos(self:GetPos()+Vector(50,0,0))
end
end)
end
end
-- Getters and setters
function ENT:SetEnemy( ent )
self.Enemy = ent
end
function ENT:GetEnemy()
return self.Enemy
end
function ENT:IsValidEnemy(e)
local ent = e or self:GetEnemy()
return IsValid(ent) and ent:GetNoDraw() == false and ((ent:IsNPC())
or (not GetConVar("ai_ignoreplayers"):GetBool() and ent:IsPlayer() and ent:Alive())
or (ent:IsNextBot() and !string.StartWith(ent:GetClass(),"nb_ba2_infected")))
end
function ENT:GetAllEnemies()
local list = {}
for i,ent in pairs(ents.FindInSphere(self:GetPos(),self.SearchRadius or 10000)) do
if self:IsValidEnemy(ent) and ent:GetMaterialType() ~= MAT_METAL then
table.insert(list,ent)
end
end
return list
end
function ENT:GetAttacking()
return self.BA2_Attacking
end
function ENT:SetAttacking(a)
self.BA2_Attacking = a
end
function ENT:GetStunned()
return self.BA2_Stunned
end
function ENT:SetStunned(a)
self.BA2_Stunned = a
end
function ENT:GetHullType()
return self.HullType
end
function ENT:SetHullType(a)
self.HullType = a
end
-- function ENT:IsNPC()
-- return GetConVar("ba2_zom_isnpc"):GetBool()
-- end
-- AI
function ENT:ZombieNav(path)
return path:Compute(self,self.NavTarget,function( area, fromArea, ladder, elevator, length ) -- Mod of the default function because writing a pathfinding algorithm is the most horrific thing a programmer can do
if ( !IsValid( fromArea ) ) then
-- first area in path, no cost
return 0
else
if ( !self.loco:IsAreaTraversable( area ) ) then
-- our locomotor says we can't move here
return -1
end
-- compute distance traveled along path so far
local dist = 0
if ( IsValid( ladder ) ) then
dist = ladder:GetLength()
elseif ( length > 0 ) then
-- optimization to avoid recomputing length
dist = length
else
dist = ( area:GetCenter() - fromArea:GetCenter() ):GetLength()
end
local cost = dist + fromArea:GetCostSoFar()
-- check height change
local deltaZ = fromArea:ComputeAdjacentConnectionHeightChange( area )
if ( deltaZ >= self.loco:GetStepHeight() ) then
if ( deltaZ >= self.loco:GetMaxJumpHeight() ) then
-- too high to reach
return -1
end
-- jumping is slower than flat ground
local jumpPenalty = 5
cost = cost + jumpPenalty * dist
elseif ( deltaZ < -self.loco:GetDeathDropHeight() ) then
-- too far to drop
return -1
end
if area:IsUnderwater() and (self.Enemy == nil or self.Enemy:WaterLevel() < 2) then
-- only kill ourselves in water as a last resort
cost = cost * 2
end
return cost
end
end )
end
function ENT:RunBehaviour() -- IT'S BEHAVIOUR NOT BEHAVIOR YOU DUMBASS
--self:EmitSound("groan")
if !self.noRise and self:WaterLevel() ~= 3 then
self:EmitSound("npc/zombie/foot_slide"..math.random(1,3)..".wav")
timer.Simple(2.25,function()
if IsValid(self) then
self:EmitSound("npc/zombie/foot_slide"..math.random(1,3)..".wav")
end
end)
self:PlaySequenceAndWait("Infectionrise")
end
local path = Path( "Follow" )
path:SetMinLookAheadDistance(100)
path:SetGoalTolerance(15)
local pathComplete = nil
local traceEnts = {
["prop_door_rotating"] = true,
["func_door"] = true,
["func_door_rotating"] = true,
["func_breakable"] = true,
["func_breakable_surf"] = true,
["prop_physics"] = true
}
while true do
if GetConVar("ai_disabled"):GetBool() then
self:SwitchActivity( ACT_IDLE )
-- n o t h i n g
elseif self:WaterLevel() == 3 then
--self:SetSequence("Choked_Barnacle")
self:ResetSequenceInfo()
self:ResetSequence("fall_0"..math.random(1,9))
self.loco:SetVelocity(Vector(0,0,-5))
local dmgVal = math.random(15,25)
if self:Health() <= dmgVal then
self:EmitSound("player/pl_drown1.wav")
else
self:EmitSound("player/pl_drown"..math.random(2,3)..".wav")
end
local dmg = DamageInfo()
dmg:SetDamage(dmgVal)
dmg:SetDamageType(DMG_DROWN)
dmg:SetInflictor(game.GetWorld())
self:TakeDamageInfo(dmg)
coroutine.wait(1)
-- elseif self.loco:IsClimbingOrJumping() then
-- self:SwitchActivity(ACT_IDLE)
-- self:SetSequence("fall_0"..math.random(1,9))
elseif not self:GetAttacking() and not self:GetStunned() then
-- Todo: End attacking animation if it's still going
if self:IsValidEnemy() or IsValid(self:SearchForEnemy()) then -- Pursuit
self:PursuitSpeed()
--self:ChaseEnemy()
self.NavTarget = self:GetEnemy():GetPos() -- + (self:GetEnemy():GetVelocity() - (self:GetPos() - self:EyePos())) still working on this vector math
elseif self:GetEnemy() ~= nil and !self:IsValidEnemy() then
self:SetEnemy(nil)
self.NavTarget = self:GetPos() + Vector( math.Rand( -1, 1 ), math.Rand( -1, 1 ), 0 ) * 200
elseif IsValid(self:SearchForCorpse()) then -- Move to corpse
local corpse = self:SearchForCorpse()
local corpsePos = corpse:GetPos()
if self:GetPos():DistToSqr(corpsePos) <= 2500 then
self:ZombieEat(corpse)
else
self:SwitchActivity( ACT_WALK ) -- Walk anmimation
self.loco:SetDesiredSpeed( 40 ) -- Walk speed
self.loco:SetAcceleration(400)
self.NavTarget = corpsePos
end
else -- Pacing
self:SwitchActivity( ACT_WALK ) -- Walk anmimation
self.loco:SetDesiredSpeed( 35 * self.BA2_SpeedMult ) -- Walk speed
self.loco:SetAcceleration(400)
--self:EmitSound("groan")
if self.NavTarget == nil or self:GetPos():Distance(self.NavTarget) <= 20 then
self:SwitchActivity( ACT_IDLE )
coroutine.wait(math.Rand(25,200) / 100)
self.NavTarget = self:GetPos() + Vector( math.Rand( -1, 1 ), math.Rand( -1, 1 ), 0 ) * 200
pathComplete = nil
end
end
if self.NavTarget ~= nil then -- ChaseEnemy code robbed shamelessly from the wiki, because fuck reinventing the wheel
--self.loco:FaceTowards(self.NavTarget)
local distToTarget = self:GetPos():Distance(self.NavTarget)
if path:GetAge() > math.Clamp(distToTarget / 1000,3,10) then
pathComplete = self:ZombieNav(path) -- Compute the path towards the enemies position
end
--print(pathComplete)
if pathComplete then
if path:GetAge() > 0.5 and (distToTarget < 1000) then -- Remake the path sooner if it's successful to keep up the chase
pathComplete = self:ZombieNav(path) -- Compute the path towards the enemy's position again
end -- This function moves the bot along the path
elseif self:IsValidEnemy() then
--print(self:EntIndex(),"BA2: Pathfinding failed")
--self:HandleStuck()
local tr = util.TraceLine({
start = self:EyePos(),
endpos = self:GetEnemy():GetPos(),
mask = MASK_BLOCKLOS
})
if tr.Hit and !traceEnts[tr.Entity] then
self:SetEnemy(self:SearchForEnemy()) -- Pick a new enemy if we can't get to the current one
self:HandleStuck()
end
end
path:Update( self )
if self.loco:IsStuck() then
--print(self:EntIndex(),"BA2: Pathfinding stuck")
-- if (path:GetPositionOnPath(path:GetCursorPosition() + 25) - path:GetCursorData().pos).z > 0 then
-- self.loco:JumpAcrossGap(path:GetCursorData().pos,path:GetPositionOnPath(path:GetCursorPosition() + 25))
-- else
self:HandleStuck()
-- end
end
if self:IsValidEnemy() then
local tr = nil
local tr2 = nil
if GetConVar("ba2_zom_breakobjects"):GetBool() and !(self.BA2_LArmDown and self.BA2_RArmDown) then
tr = util.TraceHull({
start = self:EyePos(),
endpos = self:EyePos() + self:GetForward() * 25,
maxs = Vector(8,8,16),
mins = Vector(-8,-8,-16),
filter = self
})
tr2 = util.TraceLine({
start = self:EyePos(),
endpos = self:GetEnemy():GetPos(),
mask = MASK_NPCSOLID
})
debugoverlay.Line(tr.StartPos,tr.HitPos,.1)
end
if GetConVar("ba2_zom_breakobjects"):GetBool() and tr ~= nil and tr.Hit and tr2.Hit and !traceEnts[tr2.Hit] and !self:VisibleVec(self:GetEnemy():GetPos()) and (tr.Entity:IsVehicle() or traceEnts[tr.Entity:GetClass()]) then
self:ZombieSmash(tr.Entity)
elseif self:GetEnemy():GetPos():Distance(self:GetPos()) < 40 and self:VisibleVec(self:GetEnemy():GetPos()) and !(self:GetEnemy():IsPlayer() and self:GetEnemy():InVehicle()) then
if GetConVar("ba2_zom_attackmode"):GetBool() then
self:ZombieAttackAlt(self:GetEnemy())
else
self:ZombieAttack()
end
end
end
if GetConVar("ba2_zom_retargeting"):GetBool() and CurTime() >= self.BA2_TimeToNextScan then
self:SearchForEnemy()
end
end
end
self.SearchRadius = GetConVar("ba2_zom_range"):GetInt()
coroutine.yield()
end
end
function ENT:PursuitSpeed()
local PursuitConfig = GetConVar("ba2_zom_pursuitspeed"):GetInt()
if self.BA2_Crippled then
self:SwitchActivity(ACT_WALK)
self.loco:SetDesiredSpeed(45 * self.BA2_SpeedMult)
self.loco:SetAcceleration(400)
elseif PursuitConfig == 1 then
self:SwitchActivity(ACT_RUN)
self.loco:SetDesiredSpeed(120 * self.BA2_SpeedMult)
self.loco:SetAcceleration(1600)
elseif PursuitConfig == 2 then
self:SwitchActivity(ACT_SPRINT)
self.loco:SetDesiredSpeed(300 * self.BA2_SpeedMult)
self.loco:SetAcceleration(3200)
else
self:SwitchActivity(ACT_WALK)
self.loco:SetDesiredSpeed(45 * self.BA2_SpeedMult)
self.loco:SetAcceleration(400)
end
end
function ENT:SearchForEnemy()
-- Don't bother looking for enemies if there are no enemies in the first place
self.BA2_TimeToNextScan = CurTime() + math.random(10,20) / 10
if #ents.FindByClass("npc_*") == 0 then
if GetConVar("ai_ignoreplayers"):GetBool() then return
else
local foundPly = false
for i,p in pairs(player.GetAll()) do
if p:Alive() then
foundPly = true
break
end
end
if !foundPly then return end
end
end
local minEnt = nil
local minDist = math.huge
for i,ent in pairs(self:GetAllEnemies()) do
local dist = ent:GetPos():Distance(self:GetPos())
if dist < minDist then
minEnt = ent
minDist = dist
end
end
if minEnt then
self:SetEnemy(minEnt)
end
return minEnt
end
function ENT:SearchForCorpse()
if #ents.FindByClass("prop_ragdoll") == 0 then return end
local minEnt = nil
local minDist = math.huge
if self.SearchRadius == nil then
self.SearchRadius = 10000
end
for i,ent in pairs(ents.FindInSphere(self:GetPos(),self.SearchRadius / 4)) do
if ent:GetClass() == "prop_ragdoll" and ent:GetNoDraw() == false and ent:GetMaterialType() ~= MAT_METAL and !ent.BA2_ZomCorpse then
local dist = ent:GetPos():Distance(self:GetPos())
if dist < minDist then
minEnt = ent
minDist = dist
end
end
end
if minEnt then
self:SetEnemy(minEnt)
end
return minEnt
end
function ENT:HandleStuck()
--print(self:EntIndex(),"BA2: Handling stuck")
self.loco:ClearStuck()
if self.BA2_AutoSpawned and self.BA2_CreationTime < CurTime() - 2 then
self:SetPos(self:GetPos()+Vector(50,0,0))
return
end
if self:IsValidEnemy() then
self:PursuitSpeed()
else
self:SwitchActivity( ACT_WALK ) -- Walk anmimation
self.loco:SetDesiredSpeed( 35 * self.BA2_SpeedMult ) -- Walk speed
self.loco:SetAcceleration(400)
end
-- if (self.NavTarget - self:GetPos()).z > 0 then
-- self.loco:Jump()
-- else
-- self.NavTarget = self:GetPos() + Vector( math.Rand( -1, 1 ), math.Rand( -1, 1 ), 0 ) * 200
-- end -- Jump behavior is temporarily disabled on account of being garbo
self.NavTarget = self:GetPos() + Vector( math.Rand( -1, 1 ), math.Rand( -1, 1 ), 0 ) * 200
--self:MoveToPos(self:GetPos() + Vector( math.Rand( -1, 1 ), math.Rand( -1, 1 ), 0 ) * 200,{maxage = 3}) -- Unoptimized, apparently
for i = 1,125 do
self.loco:FaceTowards(self.NavTarget)
self.loco:Approach(self.NavTarget,1)
-- if !self.loco:IsOnGround() then
-- self.loco:SetVelocity(self:GetForward() * 6)
-- end
if self:GetPos():Distance(self.NavTarget) <= 20 then
break
end
coroutine.yield()
end
end
-- function ENT:OnUnStuck()
-- print(self:EntIndex(),"BA2: Stuck handled!")
-- end
function ENT:ZombieAttack()
self:SetAttacking(true)
if self.BA2_Crippled then
self:SetSequence("crawlgrabloop")
else
self:SetSequence("nz_boardtear_blend_horizontal_m_hold")
end
local enemy = self:GetEnemy()
local dmgMult = GetConVar("ba2_zom_dmgmult"):GetFloat()
local attackMode = GetConVar("ba2_zom_attackmode"):GetInt()
if !(self.BA2_LArmDown and self.BA2_RArmDown) then
self:EmitSound("physics/flesh/flesh_impact_hard"..math.random(1,6)..".wav")
BA2_ZombieGrab(self,enemy)
end
local breakDist = 60
if self.BA2_LArmDown or self.BA2_RArmDown then
breakDist = 40
end
while self:IsValidEnemy() and self:GetAttacking() do
coroutine.wait(.5)
if not self:IsValidEnemy() or not self:GetAttacking() then break end
if enemy:GetPos():Distance(self:GetPos()) > breakDist then break end
self.loco:FaceTowards(enemy:GetPos())
BA2_AddInfection(enemy,math.random(1,7) * GetConVar("ba2_zom_infectionmult"):GetFloat())
local dmg = DamageInfo()
dmg:SetDamage(math.random(7,9) * dmgMult)
dmg:SetDamageType(DMG_SLASH)
dmg:SetDamageCustom(DMG_BIOVIRUS)
dmg:SetAttacker(self)
dmg:SetInflictor(BA2_InfectionManager())
if self.BA2_LArmDown then
dmg:SetDamage(dmg:GetDamage() * 0.5)
end
if self.BA2_RArmDown then
dmg:SetDamage(dmg:GetDamage() * 0.5)
end
enemy:TakeDamageInfo(dmg)
if enemy:IsPlayer() then
enemy:ViewPunch(AngleRand(-1,1) * 5)
end
self:EmitSound("ba2_fleshtear") -- Nom
end
self:SetAttacking(false)
if self:IsValidEnemy() and enemy:GetPos():Distance(self:GetPos()) > breakDist then
self:EmitSound("physics/body/body_medium_impact_soft"..math.random(1,7)..".wav")
self:ZombieStun()
end
end
function ENT:ZombieAttackAlt(ent)
self.loco:FaceTowards(ent:GetPos())
self:SetAttacking(true)
local attackAnims = {
"nz_attack_stand_ad_2-2",
"nz_attack_stand_ad_2-3"
}
timer.Simple(.28,function()
if IsValid(self) and not self:GetStunned() and IsValid(ent) then
local tr = util.TraceHull({
start = self:EyePos(),
endpos = self:EyePos() + self:GetForward() * 25,
maxs = Vector(16,16,16),
mins = Vector(-16,-16,-16),
filter = self
})
debugoverlay.Box(self:EyePos() + self:GetForward() * 25,Vector(16,16,16),Vector(-16,-16,-16),2)
if tr.Entity == ent then
BA2_AddInfection(ent,math.random(1,7) * GetConVar("ba2_zom_infectionmult"):GetFloat())
local dmg = DamageInfo()
dmg:SetDamage(math.random(10,15) * GetConVar("ba2_zom_dmgmult"):GetFloat())
dmg:SetDamageType(DMG_SLASH)
dmg:SetDamageCustom(DMG_BIOVIRUS)
dmg:SetAttacker(self)
dmg:SetInflictor(BA2_InfectionManager())
if self.BA2_LArmDown then
dmg:SetDamage(dmg:GetDamage() * 0.5)
end
if self.BA2_RArmDown then
dmg:SetDamage(dmg:GetDamage() * 0.5)
end
ent:TakeDamageInfo(dmg)
if ent:IsPlayer() then
ent:ViewPunch(AngleRand(-5,5) * 5)
end
self:EmitSound("ba2_fleshtear")
else
self:EmitSound("npc/zombie/claw_miss1.wav")
end
end
end)
self:EmitSound("npc/zombie/foot_slide"..math.random(1,3)..".wav")
if self.BA2_Crippled then
self:PlaySequenceAndWait("crawlgrabmiss",1.75)
else
self:PlaySequenceAndWait(attackAnims[math.random(2)],1.75)
end
self:SetAttacking(false)
end
function ENT:ZombieStun()
if self:GetStunned() or self:WaterLevel() == 3 then return end
self:ZombieVox("hurt")
self:SwitchActivity(ACT_IDLE)
self:ResetSequenceInfo()
self:SetAttacking(false)
self:SetStunned(true)
if self.BA2_Crippled then
self:ResetSequence("Crawlgrabshove")
self:SetPlaybackRate(.5)
else
self:ResetSequence("ShoveReact")
end
local timerName = self:EntIndex().."-stun"
timer.Create(timerName,self:SequenceDuration(self:LookupSequence("ShoveReact")),1,function()
if IsValid(self) then
self:SetStunned(false)
end
end)
timer.Start(timerName)
end
function ENT:ZombieSmash(ent)
self:SetAttacking(true)
local attackAnims = {
"nz_attack_stand_ad_2-2",
"nz_attack_stand_ad_2-3"
}
timer.Simple(0.6,function()
if IsValid(self) and not self:GetStunned() and IsValid(ent) then
local class = ent:GetClass()
local tr = util.TraceHull({
start = self:EyePos(),
endpos = self:EyePos() + self:GetForward() * 75,
maxs = Vector(8,8,16),
mins = Vector(-8,-8,-16),
filter = self
})
if tr.Hit or string.StartWith(class,"func_breakable") then
local propDmg = math.random(10,20) * GetConVar("ba2_zom_propdmgmult"):GetFloat()
if self.BA2_LArmDown or self.BA2_RArmDown then
propDmg = propDmg * 0.5
end
if ent:GetClass() == "prop_door_rotating" or ent:GetClass() == "func_door_rotating" then
if ent.BA2_DoorHealth == nil then
ent.BA2_DoorHealth = 200 - propDmg
elseif ent.BA2_DoorHealth <= 0 then
self:EmitSound("npc/zombie/claw_miss1.wav")
return -- Prevent magic door duplication
else
ent.BA2_DoorHealth = ent.BA2_DoorHealth - propDmg
end
if ent.BA2_DoorHealth <= 0 then
ent:EmitSound("ambient/materials/door_hit1.wav")
if ent:GetClass() == "prop_door_rotating" then
local prop = ents.Create("prop_physics")
prop:SetModel(ent:GetModel())
prop:SetSkin(ent:GetSkin())
prop:SetBodygroup(0,ent:GetBodygroup(0))
prop:SetPos(ent:GetPos())
prop:SetAngles(ent:GetAngles())
prop:SetCollisionGroup(COLLISION_GROUP_DEBRIS)
prop:SetSolid(SOLID_NONE)
prop:Spawn()
prop:Activate()
prop:GetPhysicsObject():ApplyForceCenter(self:GetForward() * 5000)
if IsValid(ent) then
ent:SetNoDraw(true)
ent:SetSolid(SOLID_NONE)
end
local doorRespawn = GetConVar("ba2_zom_doorrespawn"):GetFloat()
if doorRespawn > 0 then
timer.Simple(doorRespawn,function()
if IsValid(ent) then
ent:SetNoDraw(false)
ent:SetCollisionGroup(COLLISION_GROUP_NONE)
ent:SetSolid(SOLID_OBB)
ent.BA2_DoorHealth = 200
end
SafeRemoveEntity(prop)
end)
end
else
ent:Fire("SetSpeed",ent:GetInternalVariable("Speed") * 2.5)
ent:Fire("Open")
ent:Fire("SetSpeed",ent:GetInternalVariable("Speed"))
ent.BA2_DoorHealth = 200
end
elseif math.random(1,100) >= ent.BA2_DoorHealth then
ent:EmitSound("physics/wood/wood_strain"..math.random(2,4)..".wav")
end
else
local dmg = DamageInfo()
dmg:SetDamage(propDmg)
dmg:SetAttacker(self)
dmg:SetInflictor(self)
dmg:SetDamageType(DMG_SLASH)
if self.BA2_LArmDown or self.BA2_RArmDown then
dmg:SetDamage(dmg:GetDamage() * 0.5)
end
ent:TakeDamageInfo(dmg)
end
if GetConVar("ba2_zom_breakphys"):GetBool() and #constraint.GetTable(ent) > 0 then
constraint.RemoveAll(ent)
ent:EmitSound("physics/metal/sawblade_stick"..math.random(1,3)..".wav")
end
local phys = ent:GetPhysicsObject()
if IsValid(phys) then
phys:ApplyForceCenter(self:GetForward() * 5000)
if GetConVar("ba2_zom_breakphys"):GetBool() then
phys:EnableMotion(true)
end
end
if ent:GetClass() == "prop_physics" then
ent:EmitSound("npc/zombie/zombie_pound_door.wav")
elseif ent:GetClass() ~= "func_breakable_surf" then
ent:EmitSound("physics/wood/wood_crate_impact_hard"..math.random(2,3)..".wav",75,math.random(80,110))
end
else
self:EmitSound("npc/zombie/claw_miss1.wav")
end
end
end)
if self.BA2_Crippled then
self:PlaySequenceAndWait("crawlgrabmiss")
else
self:PlaySequenceAndWait(attackAnims[math.random(2)])
end
self:SetAttacking(false)
end
function ENT:ZombieEat(corpse)
self:SwitchActivity( ACT_IDLE )
timer.Simple(.6,function()
if IsValid(self) and not self:GetStunned() and IsValid(corpse) then
self:EmitSound("ba2_corpsechomp",75,75,100)
local mat = corpse:GetMaterialType()
if mat == MAT_ANTLION or mat == MAT_ALIENFLESH then
util.Decal("YellowBlood",self:EyePos(),corpse:GetPos(),self)
elseif mat == MAT_CONCRETE or mat == MAT_FLESH or mat == MAT_BLOODYFLESH then -- You tell me why human corpses have the concrete material
util.Decal("Blood",self:EyePos(),corpse:GetPos(),self)
end
end
end)
if self.BA2_Crippled then
self:PlaySequenceAndWait("crawlgrabloop")
else
self:PlaySequenceAndWait("choke_eat")
end
end
-- Damage/death handling
function ENT:BreakLArm(dmginfo)
self.BA2_LArmDown = true
self:EmitSound("npc/barnacle/barnacle_crunch"..math.random(2,3)..".wav",75)
self:DeflateBones({
"ValveBiped.Bip01_L_Forearm",
"ValveBiped.Bip01_L_Hand",
"ValveBiped.Bip01_L_Finger0",
"ValveBiped.Bip01_L_Finger1",
"ValveBiped.Bip01_L_Finger2",
"ValveBiped.Bip01_L_Finger3",
"ValveBiped.Bip01_L_Finger4",
})
self:CreateGib(self.InfBody:GetBonePosition(self.InfBody:LookupBone("ValveBiped.Bip01_L_Forearm")),"models/ba2/gibs/armlowerl.mdl",dmginfo:GetDamageForce():GetNormalized() * 100)
self:CreateGib(self.InfBody:GetBonePosition(self.InfBody:LookupBone("ValveBiped.Bip01_L_Hand") or self.InfBody:LookupBone("ValveBiped.Bip01_L_Forearm")),"models/ba2/gibs/handl.mdl",dmginfo:GetDamageForce():GetNormalized() * 100)
local eff = EffectData()
eff:SetFlags(6)
eff:SetColor(0)
eff:SetScale(2)
eff:SetEntity(self)
local timer1 = self:EntIndex().."-larmshot"
timer.Create(timer1,0.2,math.random(8,10),function()
if IsValid(self) then
eff:SetOrigin(self:GetBonePosition(self:LookupBone("ValveBiped.Bip01_L_Forearm")))
util.Effect("BloodImpact",eff)
else
timer.Destroy(timer1)
end
end)
timer.Start(timer1)
end
function ENT:BreakRArm(dmginfo)
self.BA2_RArmDown = true
self:EmitSound("npc/barnacle/barnacle_crunch"..math.random(2,3)..".wav",75)
self:DeflateBones({
"ValveBiped.Bip01_R_Forearm",
"ValveBiped.Bip01_R_Hand",
"ValveBiped.Bip01_R_Finger0",
"ValveBiped.Bip01_R_Finger1",
"ValveBiped.Bip01_R_Finger2",
"ValveBiped.Bip01_R_Finger3",
"ValveBiped.Bip01_R_Finger4",
})
self:CreateGib(self.InfBody:GetBonePosition(self.InfBody:LookupBone("ValveBiped.Bip01_R_Forearm")),"models/ba2/gibs/armlowerr2.mdl",dmginfo:GetDamageForce():GetNormalized() * 100)
self:CreateGib(self.InfBody:GetBonePosition(self.InfBody:LookupBone("ValveBiped.Bip01_R_Hand") or self.InfBody:LookupBone("ValveBiped.Bip01_R_Forearm")),"models/ba2/gibs/handr.mdl",dmginfo:GetDamageForce():GetNormalized() * 100)
local eff = EffectData()
eff:SetFlags(6)
eff:SetColor(0)
eff:SetScale(2)
eff:SetEntity(self)
local timer1 = self:EntIndex().."-rarmshot"
timer.Create(timer1,0.2,math.random(8,10),function()
if IsValid(self) then
eff:SetOrigin(self:GetBonePosition(self:LookupBone("ValveBiped.Bip01_R_Forearm")))
util.Effect("BloodImpact",eff)
else
timer.Destroy(timer1)
end
end)
timer.Start(timer1)
end
function ENT:BreakLLeg(dmginfo)
self.BA2_LLegDown = true
self.BA2_Crippled = true
self.HullType = HULL_TINY
self:EmitSound("npc/barnacle/barnacle_crunch"..math.random(2,3)..".wav",75)
self:DeflateBones({
"ValveBiped.Bip01_L_Calf",
"ValveBiped.Bip01_L_Foot",
"ValveBiped.Bip01_L_Toe0",
})
self:CreateGib(self.InfBody:GetBonePosition(self.InfBody:LookupBone("ValveBiped.Bip01_L_Calf")),"models/ba2/gibs/legupperleft.mdl",dmginfo:GetDamageForce():GetNormalized() * 100)
self:CreateGib(self.InfBody:GetBonePosition(self.InfBody:LookupBone("ValveBiped.Bip01_L_Foot")),"models/ba2/gibs/leglowerleft.mdl",dmginfo:GetDamageForce():GetNormalized() * 100)
local eff = EffectData()
eff:SetFlags(6)
eff:SetColor(0)
eff:SetScale(2)
eff:SetEntity(self)
local timer1 = self:EntIndex().."-llegshot"
timer.Create(timer1,0.2,math.random(8,10),function()
if IsValid(self) then
eff:SetOrigin(self:GetBonePosition(self:LookupBone("ValveBiped.Bip01_L_Calf")))
util.Effect("BloodImpact",eff)
else
timer.Destroy(timer1)
end
end)
timer.Start(timer1)
end
function ENT:BreakRLeg(dmginfo)
self.BA2_RLegDown = true
self.BA2_Crippled = true
self.HullType = HULL_TINY
self:EmitSound("npc/barnacle/barnacle_crunch"..math.random(2,3)..".wav",75)
self:DeflateBones({
"ValveBiped.Bip01_R_Calf",
"ValveBiped.Bip01_R_Foot",
"ValveBiped.Bip01_R_Toe0",
})
self:CreateGib(self.InfBody:GetBonePosition(self.InfBody:LookupBone("ValveBiped.Bip01_R_Calf")),"models/ba2/gibs/legupperright.mdl",dmginfo:GetDamageForce():GetNormalized() * 100)
self:CreateGib(self.InfBody:GetBonePosition(self.InfBody:LookupBone("ValveBiped.Bip01_R_Foot")),"models/ba2/gibs/leglowerright.mdl",dmginfo:GetDamageForce():GetNormalized() * 100)
local eff = EffectData()
eff:SetFlags(6)
eff:SetColor(0)
eff:SetScale(2)
eff:SetEntity(self)
local timer1 = self:EntIndex().."-rlegshot"
timer.Create(timer1,0.2,math.random(8,10),function()
if IsValid(self) then
eff:SetOrigin(self:GetBonePosition(self:LookupBone("ValveBiped.Bip01_R_Calf")))
util.Effect("BloodImpact",eff)
else
timer.Destroy(timer1)
end
end)
timer.Start(timer1)
end
function ENT:OnTraceAttack(dmginfo,dir,trace)
if self.BA2_ArmoredZom and (trace.HitGroup == HITGROUP_HEAD or trace.HitGroup == HITGROUP_CHEST or trace.HitGroup == HITGROUP_STOMACH) then
dmginfo:SetDamage(dmginfo:GetDamage() * GetConVar("ba2_zom_armordamagemult"):GetFloat())
local eff = EffectData()
eff:SetOrigin(trace.HitPos)
util.Effect("StunstickImpact",eff)
self:EmitSound("physics/metal/metal_sheet_impact_bullet2.wav",80,math.random(90,110))
end
if trace.HitGroup == HITGROUP_HEAD then
dmginfo:SetDamage(dmginfo:GetDamage() * 3)
if dmginfo:IsDamageType(DMG_BUCKSHOT) and dmginfo:GetDamage() > self:Health() then
dmginfo:SetDamage(dmginfo:GetDamage() * 2)
end
if BA2_GetMaggotMode() then
self:EmitSound("player/crit_hit"..math.random(2,6)..".wav",95)
end
if GetConVar("ba2_misc_headshoteff"):GetBool() and self:Health() - dmginfo:GetDamage() <= math.random(-60,-30) then
self.BA2_HeadshotEffect = true
end
end
if trace.HitGroup == HITGROUP_LEFTARM and self.BA2_LArmDown == nil then
self.BA2_LArmDamage = self.BA2_LArmDamage + dmginfo:GetDamage()
if GetConVar("ba2_zom_armdamage"):GetBool() and self.BA2_LArmDamage >= self:GetMaxHealth() * .5 then
self:BreakLArm(dmginfo)
end
dmginfo:SetDamage(dmginfo:GetDamage() * GetConVar("ba2_zom_limbdamagemult"):GetFloat())
elseif trace.HitGroup == HITGROUP_RIGHTARM and self.BA2_RArmDown == nil then
self.BA2_RArmDamage = self.BA2_RArmDamage + dmginfo:GetDamage()
if GetConVar("ba2_zom_armdamage"):GetBool() and self.BA2_RArmDamage >= self:GetMaxHealth() * .5 then
self:BreakRArm(dmginfo)
end
dmginfo:SetDamage(dmginfo:GetDamage() * GetConVar("ba2_zom_limbdamagemult"):GetFloat())
end
if trace.HitGroup == HITGROUP_LEFTLEG and self.BA2_LLegDown == nil then
self.BA2_LLegDamage = self.BA2_LLegDamage + dmginfo:GetDamage()
if GetConVar("ba2_zom_legdamage"):GetBool() and self.BA2_LLegDamage >= self:GetMaxHealth() * .75 then
self:BreakLLeg(dmginfo)
end
dmginfo:SetDamage(dmginfo:GetDamage() * GetConVar("ba2_zom_limbdamagemult"):GetFloat())
elseif trace.HitGroup == HITGROUP_RIGHTLEG and self.BA2_RLegDown == nil then
self.BA2_RLegDamage = self.BA2_RLegDamage + dmginfo:GetDamage()
if GetConVar("ba2_zom_legdamage"):GetBool() and self.BA2_RLegDamage >= self:GetMaxHealth() * .75 then
self:BreakRLeg(dmginfo)
end
dmginfo:SetDamage(dmginfo:GetDamage() * GetConVar("ba2_zom_limbdamagemult"):GetFloat())
end
if trace.HitGroup ~= HITGROUP_HEAD then
dmginfo:SetDamage(dmginfo:GetDamage() * GetConVar("ba2_zom_nonheadshotmult"):GetFloat())
end
if self.BA2_Crippled and self:GetActivity() == ACT_IDLE then
self:SetSequence("crawlidle")
end
end
function ENT:OnInjured(dmginfo)
if dmginfo:IsExplosionDamage() and math.random(1,100) <= dmginfo:GetDamage() then
if math.random(self:GetMaxHealth()) <= dmginfo:GetDamage() then
local randNum
if self:Health() <= dmginfo:GetDamage() then
randNum = math.random(5)
else
randNum = math.random(4)
end
if randNum == 1 then
self:BreakLArm(dmginfo)
elseif randNum == 2 then
self:BreakRArm(dmginfo)
elseif randNum == 3 then
self:BreakLLeg(dmginfo)
elseif randNum == 4 then
self:BreakRLeg(dmginfo)
else
self.BA2_HeadshotEffect = true
end
end
end
if (self:GetAttacking() and (dmginfo:IsDamageType(DMG_SLASH) or dmginfo:IsDamageType(DMG_CRUSH) or dmginfo:IsDamageType(DMG_CLUB) or dmginfo:IsExplosionDamage()))
or (GetConVar("ba2_zom_damagestun"):GetBool() and dmginfo:GetDamage() > self:Health() / 2) then
self:ZombieStun()
end
end
function ENT:OnKilled(dmginfo)
if engine.ActiveGamemode() == "horde" then
gamemode.Call("OnNPCKilled",self,dmginfo:GetAttacker(),dmginfo:GetInflictor()) -- Hardcode to fix horde
end
net.Start("BA2ZomDeathNotice")
net.WriteEntity(dmginfo:GetAttacker())
net.WriteEntity(dmginfo:GetInflictor())
net.Broadcast()
if not IsValid(self.InfBody) then self:SetPos(self:GetPos()+Vector(50,0,0)) return end
self:ZombieVox("hurt")
if string.find(self.InfBody:GetModel(),"group03m") and math.random(1,100) <= GetConVar("ba2_zom_medicdropchance"):GetInt() then
local vial = ents.Create("item_healthvial")
vial:SetPos(self:GetPos() + Vector(0,0,40))
vial:SetVelocity(VectorRand() * 2)
vial:Spawn()
vial:Activate()
end
local body = ents.Create( "prop_ragdoll" )
body:SetPos(self:GetPos())
body:SetModel(self.InfBody:GetModel())
body:SetColor(self.InfBody:GetColor())
body:SetSkin(self.InfBody:GetSkin())
for i = 1,#self.InfBody:GetBodyGroups() do
body:SetBodygroup(i-1,self.InfBody:GetBodygroup(i-1))
end
body:SetCollisionGroup(COLLISION_GROUP_DEBRIS)
body.BA2_ZomCorpse = true
body:Spawn()
for id = 1,body:GetPhysicsObjectCount() do
local bone = body:GetPhysicsObjectNum(id - 1)
if IsValid(bone) then
local pos,angle = self:GetBonePosition(body:TranslatePhysBoneToBone(id - 1))
if pos ~= nil then
bone:SetPos(pos)
end
if angle ~= nil then
bone:SetAngles(angle)
end
bone:AddVelocity(self:GetVelocity())
--body:ManipulateBoneScale(id - 1,self.InfBody:GetManipulateBoneScale(id - 1))
end
end
if self.BA2_LArmDown then
self:DeflateBones({
"ValveBiped.Bip01_L_Forearm",
"ValveBiped.Bip01_L_Hand",
"ValveBiped.Bip01_L_Finger0",
"ValveBiped.Bip01_L_Finger1",
"ValveBiped.Bip01_L_Finger2",
"ValveBiped.Bip01_L_Finger3",
"ValveBiped.Bip01_L_Finger4",
},body)
end
if self.BA2_RArmDown then
self:DeflateBones({
"ValveBiped.Bip01_R_Forearm",
"ValveBiped.Bip01_R_Hand",
"ValveBiped.Bip01_R_Finger0",
"ValveBiped.Bip01_R_Finger1",
"ValveBiped.Bip01_R_Finger2",
"ValveBiped.Bip01_R_Finger3",
"ValveBiped.Bip01_R_Finger4",
},body)
end
if self.BA2_LLegDown then
self:DeflateBones({
"ValveBiped.Bip01_L_Calf",
"ValveBiped.Bip01_L_Foot",
"ValveBiped.Bip01_L_Toe0",
},body)
end
if self.BA2_RLegDown then
self:DeflateBones({
"ValveBiped.Bip01_R_Calf",
"ValveBiped.Bip01_R_Foot",
"ValveBiped.Bip01_R_Toe0",
},body)
end
if self.BA2_HeadshotEffect then
self:KillSounds()
self:EmitSound("npc/barnacle/barnacle_crunch"..math.random(2,3)..".wav",85)
local headBone = body:LookupBone("ValveBiped.Bip01_Head1")
if headBone ~= nil then
body:EmitSound("ba2_headlessbleed")
self:DeflateBones({
"ValveBiped.Bip01_Head1",
},body)
local headPos = body:GetBonePosition(headBone)
local gibs = {
"models/ba2/gibs/eyel.mdl",
"models/ba2/gibs/eyer.mdl",
"models/ba2/gibs/headbackl.mdl",
"models/ba2/gibs/headbackr.mdl",
"models/ba2/gibs/headfrontl.mdl",
"models/ba2/gibs/headfrontr.mdl",
"models/ba2/gibs/headtop.mdl",
"models/ba2/gibs/jaw.mdl"
}
for i,mdl in pairs(gibs) do
self:CreateGib(headPos,mdl,dmginfo:GetDamageForce():GetNormalized() * 250)
end
local eff = EffectData()
eff:SetFlags(6)
eff:SetColor(0)
eff:SetScale(10)
eff:SetEntity(body)
eff:SetAttachment(6)
local timer1 = body:EntIndex().."-headshot1"
timer.Create(timer1,0.1,math.random(17,20),function()
local headBone = body:LookupBone("ValveBiped.Bip01_Head1")
if IsValid(body) and headBone ~= nil then
eff:SetOrigin(body:GetBonePosition(headBone))
util.Effect("BloodImpact",eff)
else
timer.Destroy(timer1)
end
end)
timer.Start(timer1)
end
end
local phys = body:GetPhysicsObject()
if IsValid(phys) then
phys:ApplyForceCenter(dmginfo:GetDamageForce())
end
local corpseLife = GetConVar("ba2_misc_corpselife"):GetFloat()
if corpseLife >= 0 then
body:Fire("FadeAndRemove",0.5,corpseLife)
end
-- if BA2_GetMaggotMode() then
-- local eff2 = ents.Create("prop_dynamic")
-- eff2:SetModel("models/player/items/soldier/soldier_zombie.mdl")
-- eff2:SetPos(body:GetPos())
-- eff2:SetParent(body,0)
-- eff2:SetOwner(body)
-- eff2:SetSkin(self.InfSkin - 4)
-- eff2:Spawn()
-- eff2:AddEffects(EF_BONEMERGE)
-- body:AddEffects(EF_BONEMERGE)
-- if corpseLife >= 0 then
-- timer.Simple(corpseLife,function()
-- if IsValid(eff2) then
-- eff2:Fire("FadeAndRemove",0.5)
-- end
-- end)
-- end
-- end
if GetConVar("ba2_misc_addscore"):GetBool() then
local att = dmginfo:GetAttacker()
if IsValid(att) and att:IsPlayer() then
att:AddFrags(1)
end
end
self:SetPos(self:GetPos()+Vector(50,0,0))
end
-- Pretty stuff
function ENT:KillSounds() -- Dev note: Might still murder performance
if self.InfVoice == 0 then
self:StopSound("ba2_inf_m_groan")
self:StopSound("ba2_inf_m_hurt")
elseif self.InfVoice == 1 then
self:StopSound("ba2_inf_f_groan")
self:StopSound("ba2_inf_f_hurt")
elseif self.InfVoice == 2 then
self:StopSound("ba2_inf_c_groan")
self:StopSound("ba2_inf_c_hurt")
else
self:StopSound("ba2_inf_s_groan")
self:StopSound("ba2_inf_s_hurt")
end
end
-- function ENT:OnLandOnGround()
-- end
-- function ENT:OnRemove()
-- end
function ENT:ZombieVox(sound)
if self:WaterLevel() == 3 then return end
if self.BA2_HeadshotEffect then return end
if SERVER then
--self:KillSounds()
if sound == "groan" then
if self.InfVoice == 1 then
self:EmitSound("ba2_inf_f_groan")
elseif self.InfVoice == 2 then
self:EmitSound("ba2_inf_c_groan")
elseif self.InfVoice == 3 then
self:EmitSound("ba2_inf_s_groan")
else
self:EmitSound("ba2_inf_m_groan")
end
elseif sound == "hurt" then
if self.InfVoice == 1 then
self:EmitSound("ba2_inf_f_hurt")
elseif self.InfVoice == 2 then
self:EmitSound("ba2_inf_c_hurt")
elseif self.InfVoice == 3 then
self:EmitSound("ba2_inf_s_hurt")
else
self:EmitSound("ba2_inf_m_hurt")
end
else
error("Invalid zombie vox")
end
end
end
function ENT:SwitchActivity(act)
if self.loco:GetVelocity():LengthSqr() < 20 and self:GetActivity() ~= ACT_IDLE then
self:StartActivity(ACT_IDLE)
elseif self:GetActivity() ~= act then
self.NextStepTime = nil
if act ~= ACT_IDLE and self.loco:GetVelocity():LengthSqr() > 20 then
self:EmitSound("npc/zombie/foot_slide"..math.random(1,3)..".wav")
end
self:StartActivity(act)
if self.BA2_Crippled then
if act == ACT_IDLE then
self:SetSequence("crawlidle")
else
self:SetSequence("crawl")
end
end
end
end
function ENT:CreateGib(pos,mdl,force)
force = force or Vector(0,0,0)
local gib = ents.Create("ba2_gib")
gib:SetPos(pos + VectorRand() * 0.5)
gib:SetModel(mdl)
gib:Spawn()
gib:Initialize()
gib:GetPhysicsObject():SetVelocity(force + VectorRand() * 125)
end
function ENT:DeflateBones(tbl,ent)
ent = ent or self.InfBody
if !IsValid(ent) then return end
for i,b in pairs(tbl) do
if ent:LookupBone(b) then
ent:ManipulateBoneScale(ent:LookupBone(b),Vector(0,0,0))
end
end
end
function ENT:Think()
if SERVER then
if self.NextSoundTime == nil or self.NextSoundTime < CurTime() + .001 then
self:ZombieVox("groan")
self.NextSoundTime = CurTime() + math.random(4,8)
end
if self.NextStepTime == nil then
local act = self:GetActivity()
if act == ACT_WALK then
self.NextStepTime = CurTime() + .8 / self.BA2_SpeedMult
elseif act == ACT_RUN then
self.NextStepTime = CurTime() + .33 / self.BA2_SpeedMult
elseif act == ACT_SPRINT then
self.NextStepTime = CurTime() + .27 / self.BA2_SpeedMult
end
elseif self:IsOnGround() and self.NextStepTime < CurTime() then
if self.loco:GetVelocity():LengthSqr() >= 20 then
if self.BA2_Crippled then
self:EmitSound("npc/zombie/foot_slide"..math.random(1,3)..".wav")
else
self:EmitSound("npc/zombie/foot"..math.random(1,3)..".wav")
end
end
self.NextStepTime = nil
end
end
end
function ENT:OnContact(ent)
local class = ent:GetClass()
local IsVehicle = ent:IsVehicle()
if IsVehicle or class == "prop_physics" then
local dmg = DamageInfo()
dmg:SetDamageType(DMG_BLAST + DMG_CRUSH)
if IsVehicle then
dmg:SetDamage(math.max((ent:GetVelocity():Length() - 200) * ent:GetPhysicsObject():GetMass() / 5000,0))
else
dmg:SetDamage(math.max((ent:GetVelocity():Length() - 200) * ent:GetPhysicsObject():GetMass() / 100,0))
end
--dmg:SetDamageForce(ent:GetVelocity() * ent:GetPhysicsObject():GetMass() * 0.75)
if IsVehicle then
if IsValid(ent:GetDriver()) then
dmg:SetAttacker(ent:GetDriver())
else
dmg:SetAttacker(ent)
end
else
dmg:SetAttacker(ent)
ent:TakeDamage(dmg:GetDamage(),ent,ent)
end
dmg:SetInflictor(ent)
if dmg:GetDamage() > 0 then
self:TakeDamageInfo(dmg)
end
elseif class == "prop_combine_ball" then
local dmg = DamageInfo()
dmg:SetDamageType(DMG_DISSOLVE)
dmg:SetDamage(self:Health())
self:TakeDamageInfo(dmg)
end
end
-- Error handling
function ENT:GetActiveWeapon()
return NULL
end
function ENT:Disposition(ent)
return D_HT
end
function ENT:AddEntityRelationship(t,d,p)
end
-- Credit to GammaWhiskey for going through the trouble of adding these dummy functions
function ENT:AddRelationship(relationstring)
end
function ENT:AlertSound()
end
function ENT:AutoMovement(interval, target)
end
function ENT:CapabilitiesAdd(capabilities)
end
function ENT:CapabilitiesClear()
end
function ENT:CapabilitiesGet()
return 0
end
function ENT:CapabilitiesRemove(capabilities)
end
function ENT:Classify()
return 0
end
function ENT:GetNPCState()
return 0
end
function ENT:SetNPCState(state)
end
function ENT:SetCondition(condition)
end
function ENT:ClearCondition(condition)
end
function ENT:HasCondition(condition)
return false
end
-- Hello from the past -Sninctbur
--[[ Animations to delete:
Ad11
Ad7
Ad8
Au5
]]```
Is there something wrong? Maybe something I overlooked? Thanks in advance!
Hello. I wanted to ask what timer.simple function should I remove for it to never delay removing a stuck zombie (I want it to remove a zombie right when it cannot move towards my direction). I browsed the FP wiki a lot, know some functions, and actively browsed all the files and code of your addon (mainly ba2_hordespawner.lua and nb_ba2_infected.lua), tried removing the timer from the function that reads "ba2_hs_notargetclean", and also tried to remove every timer that has to do with HandleStuck(), even replaced every instance of HandleStuck() with OnStuck(), then Remove(), still nothing helped... and the delay is still there, and sometimes even a bug occurs when they don't get removed but get removed immediately when they get killed.
Any help would be amazingly appareciated!^^
I wanted to let you know that the JMod compatibility has fallen out of date.
Jack, switched from JMod_
to JMod.
a while ago for organizational reasons and so the biological resistance method has changed names.
Here's how it would probably work now:
BA2_JMod = istable(JMod) and JMod.GetArmorBiologicalResistance
if BA2_JMod and ent:IsPlayer() and JMod.GetArmorBiologicalResistance(ent, DMG_NERVEGAS) > 0 then
I could write the required code changes if you want me to.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.