diff options
| author | Alexander Pickering <Alexander.Pickering@anondomain.site90.net> | 2016-01-02 22:10:06 -0500 |
|---|---|---|
| committer | Alexander Pickering <Alexander.Pickering@anondomain.site90.net> | 2016-01-02 22:10:06 -0500 |
| commit | f1e99d19a5aa6e5fa61518366235e3da09689d0b (patch) | |
| tree | 7ad13becc83a0c507c87ac2d543d285d73eebb0a /gamemode/npcsystem | |
| parent | 4dec7baa800e1bc73c659d04ad70edef2c0fc529 (diff) | |
| download | wintersurvival2-f1e99d19a5aa6e5fa61518366235e3da09689d0b.tar.gz wintersurvival2-f1e99d19a5aa6e5fa61518366235e3da09689d0b.tar.bz2 wintersurvival2-f1e99d19a5aa6e5fa61518366235e3da09689d0b.zip | |
Ai overhual now working
Diffstat (limited to 'gamemode/npcsystem')
| -rw-r--r-- | gamemode/npcsystem/aidirector.lua | 34 | ||||
| -rw-r--r-- | gamemode/npcsystem/npcs/base.lua | 14 | ||||
| -rw-r--r-- | gamemode/npcsystem/npcs/bird.lua | 124 | ||||
| -rw-r--r-- | gamemode/npcsystem/npcs/zombie.lua | 203 |
4 files changed, 234 insertions, 141 deletions
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()
|
