local n = nrequire("sv_npcsystem.lua") local ncom = nrequire("sv_common.lua") local NPC = {} NPC.Name = "Zombie" NPC.Desc = "The living dead, argh!" NPC.Class = "Ambient" --Ambient, Agressive, Boss NPC.Model = "models/Zombie/Classic.mdl" --[[ models/Zombie/Fast.mdl models/Zombie/Poison.mdl models/Humans/corpse1.mdl models/Humans/Charple01.mdl models/fallout/tunneler.mdl models/fallout/streettrog.mdl models/fallout/deathclaw.mdl models/fallout/deathclaw_alphamale.mdl models/fallout/deathclaw_baby.mdl models/fallout/deathclaw_mother.mdl models/fallout/gecko.mdl models/fallout/giantrat.mdl models/fallout/sporecarrier.mdl ]] NPC.Stats = { ["Vitality"] = 400, ["Speed"] = 40, ["AwareDist"] = 1000, ["Accel"] = 25, ["Decel"] = 40, ["Step"] = 20, --Step height ["Hull"] = HULL_HUMAN } --Some npc's like birds have diffent names for their idle sequences NPC.IdleSequences = { [0] = "idle", } --Drops should be formated as [index]={["item name"], percent_drop} where percent_drop is a number from 0 to 100 NPC.Drops = { [0] = {"Rat Meat",100},--Rats will drop at least 1 meat, and have a 50% chance of dropping 2 [1] = {"Rat Meat",50}, } local checkattack = function(self,ply) print("Checking attack") if not ply or not self then return -1 end local pp,sp = ply:GetPos(),self:GetPos() local isnear = (pp:Distance(sp) < 100) and (math.abs(pp.z - sp.z) < 20) local canattack = CurTime() - self.lastattack > 2 if isnear and canattack then local tr = util.TraceLine({ start = self:GetPos() + Vector(0,0,50), endpos = ply:GetPos() + Vector(0,0,50), filter = self, }) if tr.Hit and tr.Entity == ply then return 2 else return 0 end else return 0 end end local doattack = function(self,ply) print("Doing attack") self.lastattack = CurTime() self:StartActivity(ACT_MELEE_ATTACK1) timer.Simple(1,function() --It looks like you're hit about 1/2s after animation start if (not IsValid(self)) or( not IsValid(ply)) then return end --Make sure we're both still alive! local sp,pp = self:GetPos(),ply:GetPos() local cross = sp:Cross(pp) local fppj = cross:GetNormalized():Dot(self:GetForward()) if math.abs(fppj) < 0.1 and sp:Distance(pp) < 75 then --If the player is still in front of us, do a trace local tr = util.TraceLine({ start = sp + Vector(0,0,50), endpos = pp + Vector(0,0,50), filter = self, }) if tr.Hit and tr.Entity == ply then ply:TakeDamage(20,self,self) else print("tr.hit was",tr.Hit,"entity was",tr.Entity) end else print('Player was not in front, or distance too great') print(fppj) print(sp:Distance(pp)) end end) end --At least 1 check function must return greater than -1 local checkrun = function(self,ply) local isnearby = (1000 - ply:GetPos():Distance(self:GetPos()))/1000 --Zombies work on smell or something, idk, line of sight is hard to do cheaply --But we want attack priority to override this, so only return a max of 1 return isnearby end local dorun = function(self,ply) if CurTime() - self.lastwalk > 3 then self:StartActivity( ACT_WALK ) self.lastwalk = CurTime() end if not ply or not ply:IsValid() then return end local ppos = ply:GetPos() self.TargetPos = ppos if self.TargetPos ~= nil then self.loco:Approach(self.TargetPos,1) end end NPC.Attacks = { [1] = {--attack the player if they're in front of us [checkattack] = doattack }, [2] = {--Run at the player [checkrun] = dorun } } --A function that takes a position and returns true if this is an acceptable place to spawn function NPC:SpawnLocations(pos) return true end --The entity that is this npc's current target, if it has one. Nil otherwise NPC.Target = nil --All enemies that this NPC is aware of NPC.AwareEnemies = {} --Attack priority is a fucntion that takes a player, and returns an int describing it's prority to attack (higher = more important) NPC will always attack the player with the highest priority function NPC:AttackPriority(ply) if not ply then return 0 end local plypos = ply:GetPos() local mypos = self:GetPos() if not plypos then return 0 end local dist = plypos:Distance(mypos) return self.Stats["AwareDist"] - dist end --What to replace the ENT:RunBehaviour with function NPC:Act(deltat) end --What to replace ENT:OnStuck with function NPC:Stuck() --Find out what we're stuck on local tr = util.TraceLine({ start = self:GetPos() + Vector(0,0,50), --Start at about waist height endpos =( self:GetForward()*50) + self:GetPos() + Vector(0,0,50), filter = self }) end --These are just here to tell the editors/develoeprs what functions are available.. dont un-comment them out, as this could affect all the items. function NPC:OnSpawn() self.lastattack = CurTime() self.lastwalk = CurTime() end /* --If we need to do more than just reduce health on dammage function NPC:OnDammage(ammount) end --If we need to do more than just drop items on death function NPC:OnDeath() end --A particular spell was cast on this npc by player function NPC:OnSpell(spell, player) end function NPC:OnFindEnemy(enemy) end --Called when the npc is attacking anything with any attack function NPC:OnAttack(target) end */ n.RegisterNPC(NPC)