From 4dec7baa800e1bc73c659d04ad70edef2c0fc529 Mon Sep 17 00:00:00 2001 From: Alexander Pickering Date: Sat, 2 Jan 2016 13:30:26 -0500 Subject: Added zombie code --- gamemode/npcsystem/npcs/zombie.lua | 100 +++++++++++++++++++++++++++++++++---- 1 file changed, 90 insertions(+), 10 deletions(-) diff --git a/gamemode/npcsystem/npcs/zombie.lua b/gamemode/npcsystem/npcs/zombie.lua index 0980cdc..d9232a7 100644 --- a/gamemode/npcsystem/npcs/zombie.lua +++ b/gamemode/npcsystem/npcs/zombie.lua @@ -1,26 +1,106 @@ -NPC.Name = "Zombie" -NPC.Desc = "Ahh! The Undead!!" -NPC.Class = "Other" --Ambient, Agressive, Boss -NPC.Model = "models/props_combine/breenlight.mdl" +NPC.Name = "Bird" +NPC.Desc = "A flappy little guy" +NPC.Class = "Ambient" --Ambient, Agressive, Boss +NPC.Model = "models/pigeon.mdl" NPC.Icon = Material("wintersurvival2/hud/ws1_icons/icon_rock") -NPC.Vitality = 100 +NPC.Social = "Pack" --Solo, Pack + +NPC.Vitality = 10 NPC.Speed = 100 --Drops should be formated as [index]={["item name"], percent_drop} where percent_drop is a number from 0 to 100 -NPC.Drops = nil +NPC.Drops = { + [0] = {"Meat",100},--Birds will drop at least 1 meat, and have a 50% chance of dropping 2 + [1] = {"Meat",50}, + [2] = {"Feather",50}, +} ---Attacks should be formated as [range]={index = function doattack(target)} ---Where range is the range of the target, and doattack(target) is the function called to attack +--Attacks should be formated as [i]={function (return bool) canattack(ply) = function doattack(ply)} NPC.Attacks = nil --A function that takes a position and returns true if this is an acceptable place to spawn -NPC.SpawnLocations = function(pos) return true end +NPC.SpawnLocations = nil ---The entity that is this npc's current target, if it has one +--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 = nil + +--What to replace the ENT:BehaveAct with +function NPC:Act() +end + +--What to replace ENT:OnStuck with +function NPC:Stuck() + +end + +--What to replace ENT:RunBehaviour with +function NPC:Behave() + print("Going into antlion's custom behaviour") + while ( true ) do + self:StartActivity( ACT_IDLE ) -- walk anims + self:PlaySequenceAndWait( "Idle01" ) -- Sit on the floor + --Check if there are any players nearby + local players = ents.FindByClass("Player") + local playernearby = false + for k,v in pairs(players) do + local fardist = 800 + local closedist = 300 + local removedist = 2000 + local iscrouched = v:Crouching() + local dist = v:GetPos():Distance(self:GetPos()) + --Remove ourselves if there's noone nearby + if(dist > 2000) then + playernearby = true + end + --Keep flying away as long as we're being chased + while((dist < fardist and not iscrouched) or (dist < closedist)) do -- We found a player! + if(dist < 100) then -- We're in attack range! + local target = v; + local targetpos = v:GetPos() + self:StartActivity(ACT_MELEE_ATTACK1) + --Antlion has 6 attack animations + local attackanim = math.Round(math.Rand(1,6)) + self:PlaySequenceAndWait("attack" .. attackanim) + --If the player is still in front of us after the animation, they didn't dodge apply dammage! + if(v:GetPos():Distance(targetps) < 100) then + v:TakeDamage(20) + end + else + self:StartActivity(ACT_WALK) + self:PlaySequenceAndWait( "walk_all" ) + + --Find a position in roughly the oposite direction of the player + local tpos = self:GetPos() + local ppos = v:GetPos() + local direction = Vector(ppos.x - tpos.x, ppos.y - tpos.y, ppos.z - tpos.z) + direction:Normalize() + local addition = direction * 1000 + local topos = self:GetPos() + addition + + local navarea = navmesh.GetNavArea(self:GetPos(), 100) + + if navarea:IsValid() then + self:MoveToPos(topos) + else + self:BecomeRagdoll(DamageInfo()) + end + + --Check to see if we're being chased + iscrouched = v:Crouching() + dist = v:GetPos():Distance(self:GetPos()) + end + end + end + if not playernearby then + self:BecomeRagdoll(DamageInfo()) + end + end + coroutine.yield() +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() -- cgit v1.2.3-70-g09d2 From f1e99d19a5aa6e5fa61518366235e3da09689d0b Mon Sep 17 00:00:00 2001 From: Alexander Pickering Date: Sat, 2 Jan 2016 22:10:06 -0500 Subject: Ai overhual now working --- entities/entities/ws_npc_ambient/init.lua | 5 + entities/entities/ws_npc_ambient/shared.lua | 75 +++++++++- gamemode/npcsystem/aidirector.lua | 34 +++-- gamemode/npcsystem/npcs/base.lua | 14 +- gamemode/npcsystem/npcs/bird.lua | 124 ++++++++--------- gamemode/npcsystem/npcs/zombie.lua | 203 +++++++++++++++++++--------- 6 files changed, 313 insertions(+), 142 deletions(-) diff --git a/entities/entities/ws_npc_ambient/init.lua b/entities/entities/ws_npc_ambient/init.lua index 485b6c9..a0497dd 100644 --- a/entities/entities/ws_npc_ambient/init.lua +++ b/entities/entities/ws_npc_ambient/init.lua @@ -8,6 +8,11 @@ function ENT:Initialize() --print("NPC spawned!") if(self.Model) then self:SetModel(self.Model) else print("NPC created without model, this might be a bug!") end + if(self.Stats["Vitality"]) then self.Vitality = self.Stats["Vitality"] + else print("NPC created with no stat for vitality, this might be a bug!")end + if(self.Stats["Accel"]) then self.loco:SetAcceleration(self.Stats["Accel"])end + if(self.Stats["Decel"]) then self.loco:SetDeceleration(self.Stats["Decel"]) end + if(self.Stats["Step"]) then self.loco:SetJumpHeight(self.Stats["Step"]) end --self:SetModel( "models/Humans/Group01/Female_01.mdl" ) --[[ self:SetHullType( HULL_HUMAN ); diff --git a/entities/entities/ws_npc_ambient/shared.lua b/entities/entities/ws_npc_ambient/shared.lua index ba65e2b..7fa3661 100644 --- a/entities/entities/ws_npc_ambient/shared.lua +++ b/entities/entities/ws_npc_ambient/shared.lua @@ -17,6 +17,79 @@ ENT.Act = nil function ENT:OnRemove() end +function ENT:DefaultBehaviour() + while ( true ) do + --Main loop for ai + + --Update aware enemies + local players = ents.FindByClass("Player") + for k,v in pairs(players) do + if(v:IsPigeon()) then continue end + local dist = v:GetPos():Distance(self:GetPos()) + if( dist < self.Stats["AwareDist"]) then + table.insert(self.AwareEnemies,v) + end + end + + --Find the enemy with the highest priority + local maxpriority = -1 + local maxprioritytarget = nil + for k,v in pairs(self.AwareEnemies) do + local priority = self:AttackPriority(v) + if(priority > maxpriority) then + maxpriority = priority + maxprioritytarget = v + end + end + self.Target = maxprioritytarget + + --If we can't find anyone to attack, just stay idle + if(self.Target == nil) then + print("Couldn't find anyone to attack!") + --Play an idle sequence + local randanim = math.Round(math.Rand(0,#self.IdleSequences)) + self:PlaySequenceAndWait( self.IdleSequences[randanim] ) + self:StartActivity( ACT_IDLE ) + --If there's noone within 4000 units, just remove ourselves to save server resources + local closest = 5000 + for k,v in pairs(player.GetAll()) do + local thisdist = self:GetPos():Distance(v:GetPos()) + if(thisdist > closest) then + closest = thisdist + end + end + if(closest > 4000) then self:BecomeRagdoll(DamageInfo()) end + else + --We have a target to attack! + + --Find which attack will do the most dammage + local maxdammage = -1 + local maxdammagefunc = nil + for k,v in pairs(self.Attacks) do + local dammagefunc = nil + local attackfunc = nil + for i,j in pairs(v) do + dammagefunc = i + attackfunc = j + end + local dammage = dammagefunc(self, self.Target) + if(dammage > maxdammage) then + maxdammage = dammage + maxdammagefunc = attackfunc + end + end + + --Do that attack + if(maxdammagefunc) then + maxdammagefunc(self, self.Target) + end + end + coroutine.yield() + end + + coroutine.yield() +end + function ENT:BehaveAct() if(self.Act) then self:Act() @@ -29,6 +102,6 @@ function ENT:RunBehaviour() if(self.Behave) then self:Behave() else - print("NPC spawned without a Behave function, this might be an error!") + self:DefaultBehaviour() end end diff --git a/gamemode/npcsystem/aidirector.lua b/gamemode/npcsystem/aidirector.lua index 073eea7..4051204 100644 --- a/gamemode/npcsystem/aidirector.lua +++ b/gamemode/npcsystem/aidirector.lua @@ -11,18 +11,16 @@ end) function SpawnNpcByName(name, position) if(CLIENT) then return end entdata = GetNpcByName(name) + if not entdata then + print("Could not find npc data for name " .. name) + return + end ent = ents.Create("ws_npc_ambient") ent:SetPos(position) - if(entdata.Speed) then - ent.Speed = entdata.Speed - end if(entdata.Model) then ent.Model = entdata.Model end - if(entdata.vitality) then - ent:SetHealth(entdata.vitality) - end if(entdata.Drops) then ent.Drops = entdata.Drops end @@ -35,6 +33,21 @@ function SpawnNpcByName(name, position) if(entdata.Act) then ent.Act = entdata.Act end + if(entdata.Stats) then + ent.Stats = entdata.Stats + end + if(entdata.IdleSequences) then + ent.IdleSequences = entdata.IdleSequences + end + if(entdata.Attacks) then + ent.Attacks = entdata.Attacks + end + if(entdata.AttackPriority) then + ent.AttackPriority = entdata.AttackPriority + end + if(entdata.AwareEnemies) then + ent.AwareEnemies = entdata.AwareEnemies + end ent:Spawn() end @@ -43,7 +56,11 @@ local traceline = util.TraceLine local contents = util.PointContents local Up = Vector(0,0,1) ---Randomly spawn bird npc's around? +--Randomly spawn npc's around? +local ambientnpcs = { + [0] = "Bird", + [1] = "Zombie" +} local Tick = CurTime() hook.Add("Tick","SpawnAmbient",function() if(CLIENT) then return end @@ -75,7 +92,8 @@ hook.Add("Tick","SpawnAmbient",function() if (C != CONTENTS_WATER and C != CONTENTS_WATER+CONTENTS_TRANSLUCENT) then --print("Appropriate place found, spawning bird)") - SpawnNpcByName("Bird",Pos) + local randnpcnum = math.Round(math.Rand(0, #ambientnpcs)) + SpawnNpcByName(ambientnpcs[randnpcnum],Pos) break end end diff --git a/gamemode/npcsystem/npcs/base.lua b/gamemode/npcsystem/npcs/base.lua index 7afb4fe..670c476 100644 --- a/gamemode/npcsystem/npcs/base.lua +++ b/gamemode/npcsystem/npcs/base.lua @@ -6,14 +6,24 @@ NPC.Icon = Material("wintersurvival2/hud/ws1_icons/icon_rock") NPC.Social = "Pack" --Solo, Pack -NPC.Vitality = 0 -NPC.Speed = 0 +NPC.Stats = { + ["Vitality"] = 100, + ["Speed"] = 50, + ["AwareDist"] = 1000, +} + +--Some npc's like birds have diffent names for their idle sequence +NPC.IdleSequence = "Idle" + --Drops should be formated as [index]={["item name"], percent_drop} where percent_drop is a number from 0 to 100 NPC.Drops = nil --Attacks should be formated as [i]={function attackpriority() = function doattack()} NPC.Attacks = nil +--Attack priority should be formated as [i] = func tion(return int priority) attackpriority +NPC.AttackPriority = nil + --A function that takes a position and returns true if this is an acceptable place to spawn NPC.SpawnLocations = nil diff --git a/gamemode/npcsystem/npcs/bird.lua b/gamemode/npcsystem/npcs/bird.lua index fa3ad8d..0b05e62 100644 --- a/gamemode/npcsystem/npcs/bird.lua +++ b/gamemode/npcsystem/npcs/bird.lua @@ -6,17 +6,58 @@ NPC.Icon = Material("wintersurvival2/hud/ws1_icons/icon_rock") NPC.Social = "Pack" --Solo, Pack -NPC.Vitality = 10 -NPC.Speed = 100 +NPC.Stats = { + ["Vitality"] = 10, + ["Speed"] = 50, + ["AwareDist"] = 800, +} + +--Some npc's like birds have diffent names for their idle sequences +NPC.IdleSequences = { + [0] = "Idle01", + [1] = "Eat_A", +} + --Drops should be formated as [index]={["item name"], percent_drop} where percent_drop is a number from 0 to 100 NPC.Drops = { - [0] = {"Meat",100},--Birds will drop at least 1 meat, and have a 50% chance of dropping 2 - [1] = {"Meat",50}, - [2] = {"Feather",50}, + [0] = {"Meat",100}, + [1] = {"Meat",100}, + [2] = {"Meat",100}, + [3] = {"Meat",100}, + [4] = {"Meat",80}, + [5] = {"Meat",40}, + [6] = {"Meat",10}, } --Attacks should be formated as [i]={function attackpriority() = function doattack()} -NPC.Attacks = nil +local checkrun = function(self,ply) + --If we're awayre of any enemies, run away! + return 1 +end +local dorun = function(self,ply) + self:StartActivity(ACT_FLY) + self:PlaySequenceAndWait( "Fly01" ) + + --Find a position in roughly the oposite direction of the player + local tpos = self:GetPos() + local ppos = ply:GetPos() + local direction = Vector(tpos.x - ppos.x, tpos.y - ppos.y, tpos.z - ppos.z) + direction:Normalize() + local addition = direction * 1000 + local topos = self:GetPos() + addition + local navarea = navmesh.GetNavArea(self:GetPos(), 100) + if navarea:IsValid() then + self:MoveToPos(topos) + else + print("Suicideing a bird to prevent server crash!") + self:BecomeRagdoll(DamageInfo()) + end +end +NPC.Attacks = { + [1] = {--run away from the player + [checkrun] = dorun + }, +} --A function that takes a position and returns true if this is an acceptable place to spawn NPC.SpawnLocations = nil @@ -25,7 +66,13 @@ NPC.SpawnLocations = nil NPC.Target = nil --All enemies that this NPC is aware of -NPC.AwareEnemies = nil +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) + local dist = ply:GetPos():Distance(self:GetPos()) + return self.Stats["AwareDist"] - dist +end --What to replace the ENT:BehaveAct with function NPC:Act() @@ -36,69 +83,6 @@ function NPC:Stuck() end ---What to replace ENT:RunBehaviour with -function NPC:Behave() - --print("Going into bird's custom behaviour") - while ( true ) do - self:StartActivity( ACT_IDLE ) -- walk anims - self:PlaySequenceAndWait( "Idle01" ) -- Sit on the floor - --Check if there are any players nearby - local players = ents.FindByClass("Player") - local playernearby = false - for k,v in pairs(players) do - local fardist = 800 - local closedist = 300 - local removedist = 2000 - local iscrouched = v:Crouching() - local dist = v:GetPos():Distance(self:GetPos()) - --Remove ourselves if there's noone nearby - if(dist > 2000) then - playernearby = true - end - --Keep flying away as long as we're being chased - while((dist < fardist and not iscrouched) or (dist < closedist)) do - self:StartActivity(ACT_FLY) - self:PlaySequenceAndWait( "Fly01" ) - - --Find a position in roughly the oposite direction of the player - local tpos = self:GetPos() - local ppos = v:GetPos() - local direction = Vector(tpos.x - ppos.x, tpos.y - ppos.y, tpos.z - ppos.z) - direction:Normalize() - local addition = direction * 1000 - local topos = self:GetPos() + addition - - --Check to make sure we can make it somewhere, so we don't crash - --[[ - if not self.loco:IsAreaTraversable(navmesh.GetNavArea(self:GetPos(),100)) then - print("No way to go forward!") - break - end - --]] - local navarea = navmesh.GetNavArea(self:GetPos(), 100) - - if navarea:IsValid() then - --print("Looks like nav area is valid") - self:MoveToPos(topos) - else - --print("Looks like nav area is invalid") - self:BecomeRagdoll(DamageInfo()) - end - - - - --Check to see if we're being chased - iscrouched = v:Crouching() - dist = v:GetPos():Distance(self:GetPos()) - end - end - if not playernearby then - self:BecomeRagdoll(DamageInfo()) - end - end - coroutine.yield() -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() diff --git a/gamemode/npcsystem/npcs/zombie.lua b/gamemode/npcsystem/npcs/zombie.lua index d9232a7..7c598fd 100644 --- a/gamemode/npcsystem/npcs/zombie.lua +++ b/gamemode/npcsystem/npcs/zombie.lua @@ -1,13 +1,21 @@ -NPC.Name = "Bird" -NPC.Desc = "A flappy little guy" +NPC.Name = "Zombie" +NPC.Desc = "A fearsome monster!" NPC.Class = "Ambient" --Ambient, Agressive, Boss -NPC.Model = "models/pigeon.mdl" +NPC.Model = "models/Zombie/Classic.mdl" NPC.Icon = Material("wintersurvival2/hud/ws1_icons/icon_rock") -NPC.Social = "Pack" --Solo, Pack +NPC.Social = "Solo" --Solo, Pack + +NPC.Stats = { + ["Vitality"] = 100, + ["Speed"] = 50, + ["AwareDist"] = 1000, + ["Accel"] = 100, + ["Decel"] = 200, + ["Step"] = 20, --Step height + ["Hull"] = HULL_HUMAN +} -NPC.Vitality = 10 -NPC.Speed = 100 --Drops should be formated as [index]={["item name"], percent_drop} where percent_drop is a number from 0 to 100 NPC.Drops = { [0] = {"Meat",100},--Birds will drop at least 1 meat, and have a 50% chance of dropping 2 @@ -15,8 +23,70 @@ NPC.Drops = { [2] = {"Feather",50}, } ---Attacks should be formated as [i]={function (return bool) canattack(ply) = function doattack(ply)} -NPC.Attacks = nil +--Some npc's like birds have diffent names for their idle sequences +NPC.IdleSequences = { + [0] = "Idle", +} + +--Distance to be made aware of players + +--Attacks should be formated as [i]={function (return int dammage) canattack(ply) = function doattack(ply)} +--NPC will do the most dammage possible per attack +local checkmele = function(self, ply) + if(ply:GetPos():Distance(self:GetPos()) < 100) then return 20 end + return -1 +end + +local domele = function(self, ply) + self:StartActivity(ACT_MELEE_ATTACK1) + --Antlion has 6 attack animations + local attackanim = math.Round(math.Rand(1,6)) + coroutine.wait(0.75) + --If the player is still in front of us after the animation, they didn't dodge! apply dammage! + if(ply:GetPos():Distance(self:GetPos()) < 100) then + ply:TakeDamage(20) + end + --Finish up the animation + coroutine.wait(0.25) +end + +local checkrun = function(self, ply) return 0 end + +local dorun = function(self, ply) + local navarea = navmesh.GetNavArea(self:GetPos(), 100) + self.loco:SetDesiredSpeed( 50 ) + if navarea:IsValid() then + local moveop = {} + moveop.tolerance = 50 + moveop.repath = 2 + moveop.lookahead = 3 + moveop.draw = true + self:StartActivity(ACT_WALK) + self:MoveToPos(ply:GetPos(),moveop) + else + print("Could not find valid navmesh, suicideing to prevent server crash!") + self:BecomeRagdoll(DamageInfo()) + end +end + +NPC.Attacks = { + [1] = { --A mele attack + [checkmele] = domele + }, + + [2] = {--Move to the player + [checkrun] = dorun + + }, + + +} + +--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) + local dist = ply:GetPos():Distance(self:GetPos()) + return self.Stats["AwareDist"] - dist +end --A function that takes a position and returns true if this is an acceptable place to spawn NPC.SpawnLocations = nil @@ -25,7 +95,7 @@ NPC.SpawnLocations = nil NPC.Target = nil --All enemies that this NPC is aware of -NPC.AwareEnemies = nil +NPC.AwareEnemies = {} --What to replace the ENT:BehaveAct with function NPC:Act() @@ -33,74 +103,85 @@ end --What to replace ENT:OnStuck with function NPC:Stuck() - + --If we're stuck, jump backwards end --What to replace ENT:RunBehaviour with +--[[ function NPC:Behave() + --[[ print("Going into antlion's custom behaviour") while ( true ) do - self:StartActivity( ACT_IDLE ) -- walk anims - self:PlaySequenceAndWait( "Idle01" ) -- Sit on the floor - --Check if there are any players nearby + --self:PlaySequenceAndWait( "Idle" ) + + --Main loop for ai + + --Update aware enemies local players = ents.FindByClass("Player") - local playernearby = false for k,v in pairs(players) do - local fardist = 800 - local closedist = 300 - local removedist = 2000 - local iscrouched = v:Crouching() + if(v:IsPigeon()) then continue end local dist = v:GetPos():Distance(self:GetPos()) - --Remove ourselves if there's noone nearby - if(dist > 2000) then - playernearby = true + if( dist < self.Stats["AwareDist"]) then + table.insert(self.AwareEnemies,v) end - --Keep flying away as long as we're being chased - while((dist < fardist and not iscrouched) or (dist < closedist)) do -- We found a player! - if(dist < 100) then -- We're in attack range! - local target = v; - local targetpos = v:GetPos() - self:StartActivity(ACT_MELEE_ATTACK1) - --Antlion has 6 attack animations - local attackanim = math.Round(math.Rand(1,6)) - self:PlaySequenceAndWait("attack" .. attackanim) - --If the player is still in front of us after the animation, they didn't dodge apply dammage! - if(v:GetPos():Distance(targetps) < 100) then - v:TakeDamage(20) - end - else - self:StartActivity(ACT_WALK) - self:PlaySequenceAndWait( "walk_all" ) - - --Find a position in roughly the oposite direction of the player - local tpos = self:GetPos() - local ppos = v:GetPos() - local direction = Vector(ppos.x - tpos.x, ppos.y - tpos.y, ppos.z - tpos.z) - direction:Normalize() - local addition = direction * 1000 - local topos = self:GetPos() + addition - - local navarea = navmesh.GetNavArea(self:GetPos(), 100) - - if navarea:IsValid() then - self:MoveToPos(topos) - else - self:BecomeRagdoll(DamageInfo()) - end - - --Check to see if we're being chased - iscrouched = v:Crouching() - dist = v:GetPos():Distance(self:GetPos()) - end + end + + --Find the enemy with the highest priority + local maxpriority = -1 + local maxprioritytarget = nil + for k,v in pairs(self.AwareEnemies) do + local priority = self:AttackPriority(v) + if(priority > maxpriority) then + maxpriority = priority + maxprioritytarget = v end end - if not playernearby then - self:BecomeRagdoll(DamageInfo()) + self.Target = maxprioritytarget + + --If we can't find anyone to attack, just stay idle + if(self.Target == nil) then + print("Couldn't find anyone to attack!") + --Play an idle sequence + local randanim = math.Round(math.Rand(0,#self.IdleSequences)) + self:PlaySequenceAndWait( self.IdleSequences[randanim] ) + self:StartActivity( ACT_IDLE ) + else + --We have a target to attack! + print("We found something to attack!") + --Find which attack will do the most dammage + local maxdammage = -1 + local maxdammagefunc = nil + for k,v in pairs(self.Attacks) do + local dammagefunc = nil + local attackfunc = nil + for i,j in pairs(v) do + dammagefunc = i + attackfunc = j + end + print("Using damagefunc:") + print(dammagefunc) + local dammage = dammagefunc(self, self.Target) + print("dammage is ") + print(dammage) + if(dammage > maxdammage) then + maxdammage = dammage + maxdammagefunc = attackfunc + end + end + + --Do that attack + if(maxdammagefunc) then + maxdammagefunc(self, self.Target) + else + print("It looked like we could attack, but we can't!") + end end + --coroutine.yield() end + coroutine.yield() 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() -- cgit v1.2.3-70-g09d2 From a7a1e3a2d23e4aa10d874ad1b663d2116c1f62cb Mon Sep 17 00:00:00 2001 From: Alexander Pickering Date: Sat, 2 Jan 2016 22:23:17 -0500 Subject: More work on ai overhaul --- gamemode/npcsystem/aidirector.lua | 2 ++ gamemode/npcsystem/npcs/bird.lua | 4 +++- gamemode/npcsystem/npcs/zombie.lua | 4 +++- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/gamemode/npcsystem/aidirector.lua b/gamemode/npcsystem/aidirector.lua index 4051204..f5cf2b4 100644 --- a/gamemode/npcsystem/aidirector.lua +++ b/gamemode/npcsystem/aidirector.lua @@ -93,6 +93,8 @@ hook.Add("Tick","SpawnAmbient",function() if (C != CONTENTS_WATER and C != CONTENTS_WATER+CONTENTS_TRANSLUCENT) then --print("Appropriate place found, spawning bird)") local randnpcnum = math.Round(math.Rand(0, #ambientnpcs)) + local npc = GetNpcByName(ambientnpcs[randnpcnum]) + if(npc:) SpawnNpcByName(ambientnpcs[randnpcnum],Pos) break end diff --git a/gamemode/npcsystem/npcs/bird.lua b/gamemode/npcsystem/npcs/bird.lua index 0b05e62..463b8bd 100644 --- a/gamemode/npcsystem/npcs/bird.lua +++ b/gamemode/npcsystem/npcs/bird.lua @@ -60,7 +60,9 @@ NPC.Attacks = { } --A function that takes a position and returns true if this is an acceptable place to spawn -NPC.SpawnLocations = nil +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 diff --git a/gamemode/npcsystem/npcs/zombie.lua b/gamemode/npcsystem/npcs/zombie.lua index 7c598fd..216ca43 100644 --- a/gamemode/npcsystem/npcs/zombie.lua +++ b/gamemode/npcsystem/npcs/zombie.lua @@ -89,7 +89,9 @@ function NPC:AttackPriority(ply) end --A function that takes a position and returns true if this is an acceptable place to spawn -NPC.SpawnLocations = nil +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 -- cgit v1.2.3-70-g09d2 From b94ae1f187c46f1f775575daadc893a35890b6c3 Mon Sep 17 00:00:00 2001 From: Alexander Pickering Date: Sat, 2 Jan 2016 22:24:46 -0500 Subject: Introduced npc-determined spawn position --- gamemode/npcsystem/aidirector.lua | 5 ++- gamemode/npcsystem/npcs/zombie.lua | 76 -------------------------------------- 2 files changed, 3 insertions(+), 78 deletions(-) diff --git a/gamemode/npcsystem/aidirector.lua b/gamemode/npcsystem/aidirector.lua index f5cf2b4..a78e41e 100644 --- a/gamemode/npcsystem/aidirector.lua +++ b/gamemode/npcsystem/aidirector.lua @@ -94,8 +94,9 @@ hook.Add("Tick","SpawnAmbient",function() --print("Appropriate place found, spawning bird)") local randnpcnum = math.Round(math.Rand(0, #ambientnpcs)) local npc = GetNpcByName(ambientnpcs[randnpcnum]) - if(npc:) - SpawnNpcByName(ambientnpcs[randnpcnum],Pos) + if(npc:SpawnLocations(Pos)) then + SpawnNpcByName(ambientnpcs[randnpcnum],Pos) + end break end end diff --git a/gamemode/npcsystem/npcs/zombie.lua b/gamemode/npcsystem/npcs/zombie.lua index 216ca43..a725a04 100644 --- a/gamemode/npcsystem/npcs/zombie.lua +++ b/gamemode/npcsystem/npcs/zombie.lua @@ -108,82 +108,6 @@ function NPC:Stuck() --If we're stuck, jump backwards end ---What to replace ENT:RunBehaviour with ---[[ -function NPC:Behave() - --[[ - print("Going into antlion's custom behaviour") - while ( true ) do - --self:PlaySequenceAndWait( "Idle" ) - - --Main loop for ai - - --Update aware enemies - local players = ents.FindByClass("Player") - for k,v in pairs(players) do - if(v:IsPigeon()) then continue end - local dist = v:GetPos():Distance(self:GetPos()) - if( dist < self.Stats["AwareDist"]) then - table.insert(self.AwareEnemies,v) - end - end - - --Find the enemy with the highest priority - local maxpriority = -1 - local maxprioritytarget = nil - for k,v in pairs(self.AwareEnemies) do - local priority = self:AttackPriority(v) - if(priority > maxpriority) then - maxpriority = priority - maxprioritytarget = v - end - end - self.Target = maxprioritytarget - - --If we can't find anyone to attack, just stay idle - if(self.Target == nil) then - print("Couldn't find anyone to attack!") - --Play an idle sequence - local randanim = math.Round(math.Rand(0,#self.IdleSequences)) - self:PlaySequenceAndWait( self.IdleSequences[randanim] ) - self:StartActivity( ACT_IDLE ) - else - --We have a target to attack! - print("We found something to attack!") - --Find which attack will do the most dammage - local maxdammage = -1 - local maxdammagefunc = nil - for k,v in pairs(self.Attacks) do - local dammagefunc = nil - local attackfunc = nil - for i,j in pairs(v) do - dammagefunc = i - attackfunc = j - end - print("Using damagefunc:") - print(dammagefunc) - local dammage = dammagefunc(self, self.Target) - print("dammage is ") - print(dammage) - if(dammage > maxdammage) then - maxdammage = dammage - maxdammagefunc = attackfunc - end - end - - --Do that attack - if(maxdammagefunc) then - maxdammagefunc(self, self.Target) - else - print("It looked like we could attack, but we can't!") - end - end - --coroutine.yield() - end - - coroutine.yield() -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() -- cgit v1.2.3-70-g09d2 From f11d53ab5eca356b2eadb0e75b7c1ae94870e033 Mon Sep 17 00:00:00 2001 From: Alexander Pickering Date: Sat, 2 Jan 2016 22:31:14 -0500 Subject: Fixed mixup between bird and zombie drops --- gamemode/npcsystem/npcs/base.lua | 10 +++++++--- gamemode/npcsystem/npcs/bird.lua | 21 +++++++++++---------- gamemode/npcsystem/npcs/zombie.lua | 10 +++++++--- 3 files changed, 25 insertions(+), 16 deletions(-) diff --git a/gamemode/npcsystem/npcs/base.lua b/gamemode/npcsystem/npcs/base.lua index 670c476..0e8ea53 100644 --- a/gamemode/npcsystem/npcs/base.lua +++ b/gamemode/npcsystem/npcs/base.lua @@ -7,9 +7,13 @@ NPC.Icon = Material("wintersurvival2/hud/ws1_icons/icon_rock") NPC.Social = "Pack" --Solo, Pack NPC.Stats = { - ["Vitality"] = 100, - ["Speed"] = 50, - ["AwareDist"] = 1000, + ["Vitality"] = 1, + ["Speed"] = 1, + ["AwareDist"] = 1, + ["Accel"] = 1, + ["Decel"] = 1, + ["Step"] = 1, --Step height + ["Hull"] = HULL_HUMAN } --Some npc's like birds have diffent names for their idle sequence diff --git a/gamemode/npcsystem/npcs/bird.lua b/gamemode/npcsystem/npcs/bird.lua index 463b8bd..14eef6a 100644 --- a/gamemode/npcsystem/npcs/bird.lua +++ b/gamemode/npcsystem/npcs/bird.lua @@ -7,9 +7,13 @@ NPC.Icon = Material("wintersurvival2/hud/ws1_icons/icon_rock") NPC.Social = "Pack" --Solo, Pack NPC.Stats = { - ["Vitality"] = 10, - ["Speed"] = 50, - ["AwareDist"] = 800, + ["Vitality"] = 100, + ["Speed"] = 400, + ["AwareDist"] = 1000, + ["Accel"] = 200, + ["Decel"] = 200, + ["Step"] = 20, --Step height + ["Hull"] = HULL_TINY } --Some npc's like birds have diffent names for their idle sequences @@ -19,14 +23,11 @@ NPC.IdleSequences = { } --Drops should be formated as [index]={["item name"], percent_drop} where percent_drop is a number from 0 to 100 + NPC.Drops = { - [0] = {"Meat",100}, - [1] = {"Meat",100}, - [2] = {"Meat",100}, - [3] = {"Meat",100}, - [4] = {"Meat",80}, - [5] = {"Meat",40}, - [6] = {"Meat",10}, + [0] = {"Meat",100},--Birds will drop at least 1 meat, and have a 50% chance of dropping 2 + [1] = {"Meat",50}, + [2] = {"Feather",50}, } --Attacks should be formated as [i]={function attackpriority() = function doattack()} diff --git a/gamemode/npcsystem/npcs/zombie.lua b/gamemode/npcsystem/npcs/zombie.lua index a725a04..f07bd5a 100644 --- a/gamemode/npcsystem/npcs/zombie.lua +++ b/gamemode/npcsystem/npcs/zombie.lua @@ -18,9 +18,13 @@ NPC.Stats = { --Drops should be formated as [index]={["item name"], percent_drop} where percent_drop is a number from 0 to 100 NPC.Drops = { - [0] = {"Meat",100},--Birds will drop at least 1 meat, and have a 50% chance of dropping 2 - [1] = {"Meat",50}, - [2] = {"Feather",50}, + [0] = {"Meat",100}, + [1] = {"Meat",100}, + [2] = {"Meat",100}, + [3] = {"Meat",100}, + [4] = {"Meat",80}, + [5] = {"Meat",40}, + [6] = {"Meat",10}, } --Some npc's like birds have diffent names for their idle sequences -- cgit v1.2.3-70-g09d2 From 958ccc93f9339a232cc761f0842a85d14e2865b8 Mon Sep 17 00:00:00 2001 From: Alexander Pickering Date: Sat, 2 Jan 2016 22:35:29 -0500 Subject: Added more documentation on ai overhaul --- gamemode/npcsystem/npcs/base.lua | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/gamemode/npcsystem/npcs/base.lua b/gamemode/npcsystem/npcs/base.lua index 0e8ea53..880e4a5 100644 --- a/gamemode/npcsystem/npcs/base.lua +++ b/gamemode/npcsystem/npcs/base.lua @@ -17,7 +17,9 @@ NPC.Stats = { } --Some npc's like birds have diffent names for their idle sequence -NPC.IdleSequence = "Idle" +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 = nil @@ -25,11 +27,16 @@ NPC.Drops = nil --Attacks should be formated as [i]={function attackpriority() = function doattack()} NPC.Attacks = nil ---Attack priority should be formated as [i] = func tion(return int priority) attackpriority -NPC.AttackPriority = nil +--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) + local dist = ply:GetPos():Distance(self:GetPos()) + return self.Stats["AwareDist"] - dist +end --A function that takes a position and returns true if this is an acceptable place to spawn -NPC.SpawnLocations = nil +function NPC:SpawnLocations(pos) + return true +end --The entity that is this npc's current target, if it has one NPC.Target = nil -- cgit v1.2.3-70-g09d2 From 60755b6e0f24770117c39e0faddfcfaca5bf9afb Mon Sep 17 00:00:00 2001 From: Alexander Pickering Date: Sat, 2 Jan 2016 22:41:57 -0500 Subject: Allow arrows to be picked up again --- entities/entities/ws_arrow/init.lua | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/entities/entities/ws_arrow/init.lua b/entities/entities/ws_arrow/init.lua index e27dda9..db5adb6 100644 --- a/entities/entities/ws_arrow/init.lua +++ b/entities/entities/ws_arrow/init.lua @@ -13,9 +13,9 @@ function ENT:Initialize() self:SetCollisionGroup(COLLISION_GROUP_INTERACTIVE) self:PhysWake() self:SetUseType(SIMPLE_USE) - + util.SpriteTrail( self, 0, Ab, true, 1, 0, 1, 1, "sprites/smoke_trail.vmt" ) - + self:NextThink(CurTime()+10) end @@ -24,4 +24,8 @@ function ENT:Think() return true end - +function ENT:Use(activator, caller, usetype, value) + if caller:IsPigeon() then return end + caller:AddItem("Arrow",1) + self:Remove() +end -- cgit v1.2.3-70-g09d2 From 8e0e1e34108c1ba8909b186772596f8b1aae9f03 Mon Sep 17 00:00:00 2001 From: Alexander Pickering Date: Sat, 2 Jan 2016 23:29:30 -0500 Subject: Fixed up more bugs with the ai overhaul --- entities/entities/ws_arrow/init.lua | 8 ++++ entities/entities/ws_npc_ambient/init.lua | 57 ++++++++++++++++++----------- entities/entities/ws_npc_ambient/shared.lua | 1 - gamemode/npcsystem/npcs/bird.lua | 2 +- 4 files changed, 45 insertions(+), 23 deletions(-) diff --git a/entities/entities/ws_arrow/init.lua b/entities/entities/ws_arrow/init.lua index db5adb6..d87924a 100644 --- a/entities/entities/ws_arrow/init.lua +++ b/entities/entities/ws_arrow/init.lua @@ -24,8 +24,16 @@ function ENT:Think() return true end +function ENT:PhysicsCollide(data, phys) + if phys:GetEntity():IsPlayer() or phys:GetEntity():IsNPC() then + print("We hit a player!") + else + end +end + function ENT:Use(activator, caller, usetype, value) if caller:IsPigeon() then return end + print("Trying to pick up an arrow!") caller:AddItem("Arrow",1) self:Remove() end diff --git a/entities/entities/ws_npc_ambient/init.lua b/entities/entities/ws_npc_ambient/init.lua index a0497dd..6df03a0 100644 --- a/entities/entities/ws_npc_ambient/init.lua +++ b/entities/entities/ws_npc_ambient/init.lua @@ -6,9 +6,15 @@ include('shared.lua') function ENT:Initialize() --print("NPC spawned!") + self:SetMoveType(MOVETYPE_STEP) + self:SetSolid(SOLID_OBB) + self:SetCollisionGroup(COLLISION_GROUP_INTERACTIVE) + if(self.Model) then self:SetModel(self.Model) else print("NPC created without model, this might be a bug!") end - if(self.Stats["Vitality"]) then self.Vitality = self.Stats["Vitality"] + if(self.Stats["Vitality"]) then + self:SetHealth(self.Stats["Vitality"]) + print("Helath set to " .. self.Stats["Vitality"]) else print("NPC created with no stat for vitality, this might be a bug!")end if(self.Stats["Accel"]) then self.loco:SetAcceleration(self.Stats["Accel"])end if(self.Stats["Decel"]) then self.loco:SetDeceleration(self.Stats["Decel"]) end @@ -30,27 +36,36 @@ end function ENT:OnInjured(dmg) --print("Taking some dammage") local itempos = self:GetPos() - self:SetHealth(self:Health() - dmg:GetDamage()) + print("Takeing " .. dmg:GetDamage() .. " health from our " .. self:Health()) + --self:SetHealth(self:Health() - dmg:GetDamage()) + print("Health is now" .. self:Health()) if self.OnDammage != nil then self:OnDammage(dmg) end - if self:Health() <= 0 then //run on death - if(CLIENT) then return end - if not self.Drops then return end - --print("Looks like we have some drops") +end + +function ENT:OnContact(ent) + if(ent:GetClass() == "ws_arrow") then + self:TakeDamage(30) + ent:SetParent(self) + end +end + +function ENT:OnKilled(dmg) + if(CLIENT) then return end + if not self.Drops then return end + --print("Looks like we have some drops") + for k,v in pairs(self.Drops) do local rng = math.random(0,100) - for k,v in pairs(self.Drops) do - local itemname = self.Drops[k][1] - local itemchance = self.Drops[k][2] - local heightoffset = 10 - if rng < itemchance then - --print("Createing a " .. itemname) - local drop = ents.Create("ws_item") - drop.Item = GetItemByName(itemname) - drop:SetModel(drop.Item.Model) - drop:SetPos(itempos + (self:GetUp()*heightoffset)) - drop:Spawn() - heightoffset = heightoffset + 10 - end + local itemname = self.Drops[k][1] + local itemchance = self.Drops[k][2] + local heightoffset = 10 + if rng < itemchance then + local drop = ents.Create("ws_item") + drop.Item = GetItemByName(itemname) + drop:SetModel(drop.Item.Model) + drop:SetPos(self:GetPos() + (self:GetUp()*heightoffset)) + drop:Spawn() + heightoffset = heightoffset + 10 end - --self:SetSchedule( SCHED_FALL_TO_GROUND ) - end + end + self:BecomeRagdoll( dmg ) end diff --git a/entities/entities/ws_npc_ambient/shared.lua b/entities/entities/ws_npc_ambient/shared.lua index 7fa3661..c84245c 100644 --- a/entities/entities/ws_npc_ambient/shared.lua +++ b/entities/entities/ws_npc_ambient/shared.lua @@ -3,7 +3,6 @@ ENT.Base = "base_nextbot" //WS stuff ENT.Drops = nil ENT.OnDammage = nil -ENT.Vitality = 1 ENT.Speed = 0 ENT.Model = nil diff --git a/gamemode/npcsystem/npcs/bird.lua b/gamemode/npcsystem/npcs/bird.lua index 14eef6a..ff4c2f2 100644 --- a/gamemode/npcsystem/npcs/bird.lua +++ b/gamemode/npcsystem/npcs/bird.lua @@ -7,7 +7,7 @@ NPC.Icon = Material("wintersurvival2/hud/ws1_icons/icon_rock") NPC.Social = "Pack" --Solo, Pack NPC.Stats = { - ["Vitality"] = 100, + ["Vitality"] = 10, ["Speed"] = 400, ["AwareDist"] = 1000, ["Accel"] = 200, -- cgit v1.2.3-70-g09d2 From f462f49f123f094b1799ee269a67c533a436f56b Mon Sep 17 00:00:00 2001 From: Alexander Pickering Date: Sat, 2 Jan 2016 23:30:50 -0500 Subject: More stuff added from the air overhaul --- entities/entities/ws_npc_ambient/init.lua | 6 +++--- gamemode/npcsystem/npcs/zombie.lua | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/entities/entities/ws_npc_ambient/init.lua b/entities/entities/ws_npc_ambient/init.lua index 6df03a0..b896726 100644 --- a/entities/entities/ws_npc_ambient/init.lua +++ b/entities/entities/ws_npc_ambient/init.lua @@ -6,9 +6,9 @@ include('shared.lua') function ENT:Initialize() --print("NPC spawned!") - self:SetMoveType(MOVETYPE_STEP) - self:SetSolid(SOLID_OBB) - self:SetCollisionGroup(COLLISION_GROUP_INTERACTIVE) + --self:SetMoveType(MOVETYPE_STEP) + --self:SetSolid(SOLID_OBB) + --self:SetCollisionGroup(COLLISION_GROUP_INTERACTIVE) if(self.Model) then self:SetModel(self.Model) else print("NPC created without model, this might be a bug!") end diff --git a/gamemode/npcsystem/npcs/zombie.lua b/gamemode/npcsystem/npcs/zombie.lua index f07bd5a..422080a 100644 --- a/gamemode/npcsystem/npcs/zombie.lua +++ b/gamemode/npcsystem/npcs/zombie.lua @@ -7,7 +7,7 @@ NPC.Icon = Material("wintersurvival2/hud/ws1_icons/icon_rock") NPC.Social = "Solo" --Solo, Pack NPC.Stats = { - ["Vitality"] = 100, + ["Vitality"] = 200, ["Speed"] = 50, ["AwareDist"] = 1000, ["Accel"] = 100, -- cgit v1.2.3-70-g09d2 From d55c70375be34c740cee4a8a86dc3a81249d42f1 Mon Sep 17 00:00:00 2001 From: Alexander Pickering Date: Sun, 3 Jan 2016 22:48:10 -0500 Subject: spelling fix in zombie.lua --- gamemode/npcsystem/npcs/bird.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gamemode/npcsystem/npcs/bird.lua b/gamemode/npcsystem/npcs/bird.lua index ff4c2f2..7b19457 100644 --- a/gamemode/npcsystem/npcs/bird.lua +++ b/gamemode/npcsystem/npcs/bird.lua @@ -32,7 +32,7 @@ NPC.Drops = { --Attacks should be formated as [i]={function attackpriority() = function doattack()} local checkrun = function(self,ply) - --If we're awayre of any enemies, run away! + --If we're aware of any enemies, run away! return 1 end local dorun = function(self,ply) -- cgit v1.2.3-70-g09d2 From 97c511eb32ab1edd85391b027ecbdcb38c61eaa9 Mon Sep 17 00:00:00 2001 From: Alexander Pickering Date: Sun, 3 Jan 2016 23:03:11 -0500 Subject: Added first kind of antlion --- .../wintersurvival2/hud/ws2_icons/icon_chitin.png | Bin 0 -> 9905 bytes gamemode/itemsystem/items/chitin.lua | 5 + gamemode/npcsystem/npcs/antlion1.lua | 137 +++++++++++++++++++++ gamemode/npcsystem/npcs/zombie.lua | 2 +- 4 files changed, 143 insertions(+), 1 deletion(-) create mode 100644 content/materials/wintersurvival2/hud/ws2_icons/icon_chitin.png create mode 100644 gamemode/itemsystem/items/chitin.lua create mode 100644 gamemode/npcsystem/npcs/antlion1.lua diff --git a/content/materials/wintersurvival2/hud/ws2_icons/icon_chitin.png b/content/materials/wintersurvival2/hud/ws2_icons/icon_chitin.png new file mode 100644 index 0000000..a8a05a6 Binary files /dev/null and b/content/materials/wintersurvival2/hud/ws2_icons/icon_chitin.png differ diff --git a/gamemode/itemsystem/items/chitin.lua b/gamemode/itemsystem/items/chitin.lua new file mode 100644 index 0000000..3ae082e --- /dev/null +++ b/gamemode/itemsystem/items/chitin.lua @@ -0,0 +1,5 @@ +ITEM.Name = "Chitin" +ITEM.Class = "resource" +ITEM.Desc = "Some hard outer-skeleton" +ITEM.Model = "models/props_junk/Rock001a.mdl" +ITEM.Icon = Material("wintersurvival2/hud/ws2_icons/icon_chitin.png") diff --git a/gamemode/npcsystem/npcs/antlion1.lua b/gamemode/npcsystem/npcs/antlion1.lua new file mode 100644 index 0000000..255799a --- /dev/null +++ b/gamemode/npcsystem/npcs/antlion1.lua @@ -0,0 +1,137 @@ +NPC.Name = "Antlion Scout" +NPC.Desc = "A fearsome monster!" +NPC.Class = "Agressive" --Ambient, Agressive, Boss +NPC.Model = "models/antlion.mdl" +NPC.Icon = Material("wintersurvival2/hud/ws1_icons/icon_rock") + +NPC.Social = "Solo" --Solo, Pack + +NPC.Stats = { + ["Vitality"] = 150, + ["Speed"] = 200, + ["AwareDist"] = 1000, + ["Accel"] = 400, + ["Decel"] = 400, + ["Step"] = 20, --Step height + ["Hull"] = HULL_MEDIUM +} + +--Drops should be formated as [index]={["item name"], percent_drop} where percent_drop is a number from 0 to 100 +NPC.Drops = { + [0] = {"Meat",100}, + [1] = {"Meat",100}, + [2] = {"Meat",80}, + [3] = {"Meat",50}, + [4] = {"Chitin",80}, + [5] = {"Chitin",50}, +} + +--Some npc's like birds have diffent names for their idle sequences +NPC.IdleSequences = { + [0] = "Idle", +} + +--Distance to be made aware of players + +--Attacks should be formated as [i]={function (return int dammage) canattack(ply) = function doattack(ply)} +--NPC will do the most dammage possible per attack +local checkmele = function(self, ply) + if(ply:GetPos():Distance(self:GetPos()) < 100) then return 20 end + return -1 +end + +local domele = function(self, ply) + self:StartActivity(ACT_MELEE_ATTACK1) + --Antlion has 6 attack animations + local attackanim = math.Round(math.Rand(1,6)) + coroutine.wait(0.75) + --If the player is still in front of us after the animation, they didn't dodge! apply dammage! + if(ply:GetPos():Distance(self:GetPos()) < 100) then + ply:TakeDamage(20) + end + --Finish up the animation + coroutine.wait(0.25) +end + +local checkrun = function(self, ply) return 0 end + +local dorun = function(self, ply) + local navarea = navmesh.GetNavArea(self:GetPos(), 100) + self.loco:SetDesiredSpeed( 50 ) + if navarea:IsValid() then + local moveop = {} + moveop.tolerance = 50 + moveop.repath = 2 + moveop.lookahead = 3 + moveop.draw = true + self:StartActivity(ACT_WALK) + self:MoveToPos(ply:GetPos(),moveop) + else + print("Could not find valid navmesh, suicideing to prevent server crash!") + self:BecomeRagdoll(DamageInfo()) + end +end + +NPC.Attacks = { + [1] = { --A mele attack + [checkmele] = domele + }, + + [2] = {--Move to the player + [checkrun] = dorun + + }, + + +} + +--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) + local dist = ply:GetPos():Distance(self:GetPos()) + return self.Stats["AwareDist"] - dist +end + +--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 = {} + +--What to replace the ENT:BehaveAct with +function NPC:Act() +end + +--What to replace ENT:OnStuck with +function NPC:Stuck() + --If we're stuck, jump backwards +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() +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 +*/ diff --git a/gamemode/npcsystem/npcs/zombie.lua b/gamemode/npcsystem/npcs/zombie.lua index 422080a..5914c04 100644 --- a/gamemode/npcsystem/npcs/zombie.lua +++ b/gamemode/npcsystem/npcs/zombie.lua @@ -1,6 +1,6 @@ NPC.Name = "Zombie" NPC.Desc = "A fearsome monster!" -NPC.Class = "Ambient" --Ambient, Agressive, Boss +NPC.Class = "Agressive" --Ambient, Agressive, Boss NPC.Model = "models/Zombie/Classic.mdl" NPC.Icon = Material("wintersurvival2/hud/ws1_icons/icon_rock") -- cgit v1.2.3-70-g09d2 From cc2f78ca9fc6cd2e3bc8225b62fff87cc5034926 Mon Sep 17 00:00:00 2001 From: Alexander Pickering Date: Sun, 3 Jan 2016 23:26:08 -0500 Subject: Added 2 antlion types --- gamemode/npcsystem/aidirector.lua | 14 +++- gamemode/npcsystem/npcs/antlion1.lua | 4 +- gamemode/npcsystem/npcs/antlion2.lua | 154 +++++++++++++++++++++++++++++++++++ 3 files changed, 169 insertions(+), 3 deletions(-) create mode 100644 gamemode/npcsystem/npcs/antlion2.lua diff --git a/gamemode/npcsystem/aidirector.lua b/gamemode/npcsystem/aidirector.lua index a78e41e..f9f7203 100644 --- a/gamemode/npcsystem/aidirector.lua +++ b/gamemode/npcsystem/aidirector.lua @@ -8,6 +8,16 @@ concommand.Add("ws_spawnbird",function(ply,cmd,args) SpawnNpcByName("Bird",ply:GetPos()) end) +concommand.Add("ws_spawnnpc",function(ply,cmd,args) + if(!args[1]) then print("You must enter the name of an npc") + return end + + local npc = GetNpcByName(args[1]) + if(npc == nil) then print("Not a valid name!") + return end + SpawnNpcByName(args[1],ply:GetPos()) +end) + function SpawnNpcByName(name, position) if(CLIENT) then return end entdata = GetNpcByName(name) @@ -59,7 +69,9 @@ local Up = Vector(0,0,1) --Randomly spawn npc's around? local ambientnpcs = { [0] = "Bird", - [1] = "Zombie" + [1] = "Zombie", + [2] = "Antlion Scout", + [3] = "Antlion Pouncer" } local Tick = CurTime() hook.Add("Tick","SpawnAmbient",function() diff --git a/gamemode/npcsystem/npcs/antlion1.lua b/gamemode/npcsystem/npcs/antlion1.lua index 255799a..5c5ccab 100644 --- a/gamemode/npcsystem/npcs/antlion1.lua +++ b/gamemode/npcsystem/npcs/antlion1.lua @@ -8,7 +8,7 @@ NPC.Social = "Solo" --Solo, Pack NPC.Stats = { ["Vitality"] = 150, - ["Speed"] = 200, + ["Speed"] = 800, ["AwareDist"] = 1000, ["Accel"] = 400, ["Decel"] = 400, @@ -44,7 +44,7 @@ local domele = function(self, ply) self:StartActivity(ACT_MELEE_ATTACK1) --Antlion has 6 attack animations local attackanim = math.Round(math.Rand(1,6)) - coroutine.wait(0.75) + coroutine.wait(0.5) --If the player is still in front of us after the animation, they didn't dodge! apply dammage! if(ply:GetPos():Distance(self:GetPos()) < 100) then ply:TakeDamage(20) diff --git a/gamemode/npcsystem/npcs/antlion2.lua b/gamemode/npcsystem/npcs/antlion2.lua new file mode 100644 index 0000000..c232b22 --- /dev/null +++ b/gamemode/npcsystem/npcs/antlion2.lua @@ -0,0 +1,154 @@ +NPC.Name = "Antlion Pouncer" +NPC.Desc = "A fearsome monster!" +NPC.Class = "Agressive" --Ambient, Agressive, Boss +NPC.Model = "models/antlion.mdl" +NPC.Icon = Material("wintersurvival2/hud/ws1_icons/icon_rock") + +NPC.Social = "Solo" --Solo, Pack + +NPC.Stats = { + ["Vitality"] = 150, + ["Speed"] = 800, + ["AwareDist"] = 1000, + ["Accel"] = 400, + ["Decel"] = 400, + ["Step"] = 20, --Step height + ["Hull"] = HULL_MEDIUM +} + +--Drops should be formated as [index]={["item name"], percent_drop} where percent_drop is a number from 0 to 100 +NPC.Drops = { + [0] = {"Meat",100}, + [1] = {"Meat",100}, + [2] = {"Meat",80}, + [3] = {"Meat",50}, + [4] = {"Chitin",80}, + [5] = {"Chitin",50}, +} + +--Some npc's like birds have diffent names for their idle sequences +NPC.IdleSequences = { + [0] = "Idle", +} + +--Distance to be made aware of players + +--Attacks should be formated as [i]={function (return int dammage) canattack(ply) = function doattack(ply)} +--NPC will do the most dammage possible per attack +local checkmele = function(self, ply) + if(ply:GetPos():Distance(self:GetPos()) < 100) then return 20 end + return -1 +end + +local domele = function(self, ply) + self:StartActivity(ACT_MELEE_ATTACK1) + --Antlion has 6 attack animations + local attackanim = math.Round(math.Rand(1,6)) + coroutine.wait(0.5) + --If the player is still in front of us after the animation, they didn't dodge! apply dammage! + if(ply:GetPos():Distance(self:GetPos()) < 100) then + ply:TakeDamage(20) + end + --Finish up the animation + coroutine.wait(0.25) +end + +local checkpounce = function(self, ply) + if(ply:GetPos():Distance(self:GetPos())) < 200 then return 15 end + return -1 +end + +local dopounce = function(self,ply) + self:StartActivity(ACT_MELEE_ATTACK2) + coroutine.wait(0.5) + if(ply:GetPos():Distance(self:GetPos()) < 200) then + ply:TakeDamage(15) + end + coroutine.wait(0.25) +end + +local checkrun = function(self, ply) return 0 end + +local dorun = function(self, ply) + local navarea = navmesh.GetNavArea(self:GetPos(), 100) + self.loco:SetDesiredSpeed( 50 ) + if navarea:IsValid() then + local moveop = {} + moveop.tolerance = 50 + moveop.repath = 2 + moveop.lookahead = 3 + moveop.draw = true + self:StartActivity(ACT_WALK) + self:MoveToPos(ply:GetPos(),moveop) + else + print("Could not find valid navmesh, suicideing to prevent server crash!") + self:BecomeRagdoll(DamageInfo()) + end +end + +NPC.Attacks = { + [1] = { --A mele attack + [checkmele] = domele + }, + + [2] = {--Move to the player + [checkrun] = dorun + + }, + + [3] = { + [checkpounce] = dopounce + }, + +} + +--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) + local dist = ply:GetPos():Distance(self:GetPos()) + return self.Stats["AwareDist"] - dist +end + +--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 = {} + +--What to replace the ENT:BehaveAct with +function NPC:Act() +end + +--What to replace ENT:OnStuck with +function NPC:Stuck() + --If we're stuck, jump backwards +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() +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 +*/ -- cgit v1.2.3-70-g09d2 From 9f68b88436d7514df847486163433fb87e06f770 Mon Sep 17 00:00:00 2001 From: Alexander Pickering Date: Sun, 3 Jan 2016 23:56:18 -0500 Subject: Adjustements to antlion pouncer --- entities/entities/ws_npc_ambient/init.lua | 3 ++- gamemode/npcsystem/aidirector.lua | 3 +++ gamemode/npcsystem/npcs/antlion1.lua | 2 +- gamemode/npcsystem/npcs/antlion2.lua | 18 ++++++++++++++---- 4 files changed, 20 insertions(+), 6 deletions(-) diff --git a/entities/entities/ws_npc_ambient/init.lua b/entities/entities/ws_npc_ambient/init.lua index b896726..523333c 100644 --- a/entities/entities/ws_npc_ambient/init.lua +++ b/entities/entities/ws_npc_ambient/init.lua @@ -7,7 +7,7 @@ include('shared.lua') function ENT:Initialize() --print("NPC spawned!") --self:SetMoveType(MOVETYPE_STEP) - --self:SetSolid(SOLID_OBB) + self:SetSolid(SOLID_NONE) --self:SetCollisionGroup(COLLISION_GROUP_INTERACTIVE) if(self.Model) then self:SetModel(self.Model) @@ -19,6 +19,7 @@ function ENT:Initialize() if(self.Stats["Accel"]) then self.loco:SetAcceleration(self.Stats["Accel"])end if(self.Stats["Decel"]) then self.loco:SetDeceleration(self.Stats["Decel"]) end if(self.Stats["Step"]) then self.loco:SetJumpHeight(self.Stats["Step"]) end + if(self.OnSpawn) then self:OnSpawn() end --self:SetModel( "models/Humans/Group01/Female_01.mdl" ) --[[ self:SetHullType( HULL_HUMAN ); diff --git a/gamemode/npcsystem/aidirector.lua b/gamemode/npcsystem/aidirector.lua index f9f7203..04e645d 100644 --- a/gamemode/npcsystem/aidirector.lua +++ b/gamemode/npcsystem/aidirector.lua @@ -58,6 +58,9 @@ function SpawnNpcByName(name, position) if(entdata.AwareEnemies) then ent.AwareEnemies = entdata.AwareEnemies end + if(entdata.OnSpawn) then + ent.OnSpawn = entdata.OnSpawn + end ent:Spawn() end diff --git a/gamemode/npcsystem/npcs/antlion1.lua b/gamemode/npcsystem/npcs/antlion1.lua index 5c5ccab..1b0a38f 100644 --- a/gamemode/npcsystem/npcs/antlion1.lua +++ b/gamemode/npcsystem/npcs/antlion1.lua @@ -57,7 +57,7 @@ local checkrun = function(self, ply) return 0 end local dorun = function(self, ply) local navarea = navmesh.GetNavArea(self:GetPos(), 100) - self.loco:SetDesiredSpeed( 50 ) + self.loco:SetDesiredSpeed(self.Stats["Speed"] ) if navarea:IsValid() then local moveop = {} moveop.tolerance = 50 diff --git a/gamemode/npcsystem/npcs/antlion2.lua b/gamemode/npcsystem/npcs/antlion2.lua index c232b22..738bb7e 100644 --- a/gamemode/npcsystem/npcs/antlion2.lua +++ b/gamemode/npcsystem/npcs/antlion2.lua @@ -59,19 +59,24 @@ local checkpounce = function(self, ply) end local dopounce = function(self,ply) - self:StartActivity(ACT_MELEE_ATTACK2) - coroutine.wait(0.5) + local randanim = math.Round(math.Rand(0,1)) + if(randanim) then + self:SetSequence("pounce") + else + self:SetSequence("pounce2") + end + coroutine.wait(0.23) if(ply:GetPos():Distance(self:GetPos()) < 200) then ply:TakeDamage(15) end - coroutine.wait(0.25) + coroutine.wait(0.15) end local checkrun = function(self, ply) return 0 end local dorun = function(self, ply) local navarea = navmesh.GetNavArea(self:GetPos(), 100) - self.loco:SetDesiredSpeed( 50 ) + self.loco:SetDesiredSpeed(self.Stats["Speed"]) if navarea:IsValid() then local moveop = {} moveop.tolerance = 50 @@ -129,6 +134,11 @@ function NPC:Stuck() 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:SetSkin(2) +end + /* function NPC:OnSpawn() end -- cgit v1.2.3-70-g09d2 From 5f9616bc0d398721e1e459cd836c89906b6e4fd1 Mon Sep 17 00:00:00 2001 From: Alexander Pickering Date: Sun, 3 Jan 2016 23:57:57 -0500 Subject: Simple change to arrow --- entities/entities/ws_arrow/init.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/entities/entities/ws_arrow/init.lua b/entities/entities/ws_arrow/init.lua index d87924a..63bfa6e 100644 --- a/entities/entities/ws_arrow/init.lua +++ b/entities/entities/ws_arrow/init.lua @@ -26,7 +26,7 @@ end function ENT:PhysicsCollide(data, phys) if phys:GetEntity():IsPlayer() or phys:GetEntity():IsNPC() then - print("We hit a player!") + print("We hit something!") else end end -- cgit v1.2.3-70-g09d2