ID:1742330
 
(See the best response by Tko37.)
Code:
mob/NPC
Zombie
icon='Zombie.dmi'
Dead=1
var/tmp/Thinking="Wandering"
var/tmp/target
var/tmp/Lastloc
Bump(var/atom/movable/A)
sleep(src.Speed)
flick("attack",src)
if(istype(A,/obj/Corpse))
var/obj/Corpse/C=A
C.Health--
C.Destroy()
New()
Sight=rand(1,8)
Speed=rand(1,8)
ZombieAI()
proc
ZombieAI()
sleep(src.Speed)
if(!target) lookforhuman()
if(!target) lookforbody()
if(target)followtarget()
if(!target) AWander()
spawn() ZombieAI()
AWander()
Thinking="Wandering"
step_rand(src)
spawn(10) AWander()
followtarget()
if(!target)
src.Lastloc=null
return
if(get_dist(src,src.target)<=src.Sight)
if(istype(src.target,/obj/Corpse))
Thinking="Eating"
if(istype(src.target,/mob/NPC))
var/mob/NPC/A=src.target
Thinking="Hunting"
src.followers()
src.Lastloc=A.loc
step_to(src,src.target)
if(get_dist(src,src.target)>src.Sight)
src.Thinking="Searching"
step_to(src,src.Lastloc)
if(get_dist(src,src.Lastloc)<=2)
src.Lastloc=null
src.target=null
followers()
for(var/mob/NPC/Zombie/Z in viewers(src))
if(!Z.target)
Z.acquiretarget(src.target)
lookforbody()
for(var/obj/Corpse/A in oview(src.Sight,src))
src.acquiretarget(A)
break
lookforhuman()
for(var/mob/NPC/A in oview(src.Sight,src))
if(!A.Dead)
src.acquiretarget(A)
break
acquiretarget(mob/NPC/P)
if(!P) return
if(!target)
target=P
Lastloc=P.loc
return

Problem description:
I have been working on this coding for awhile and I have gotten stuck. I need help fixing this coding and making it run smoothly. Basically, When I run my game I get a massive amount of lag. I want to be able to have a large number of these npcs walking around on a map. How should I go about doing that without using up all the CPU? What within my coding is creating all this lag? I appreciate any advice given to me.


I'm not sure but it looks like AWander is compounding.
Scenario: no target
ZombieAI()
sleep() ...
call AWander()
AWander() spawns off another AWander() [which will forever keep itself alive] and returns
call ZombieAI()
ZombieAI() AWander()
sleep()
call AWander()
AWander() spawns off ANOTHER AWander() and returns
call ZombieAI()
ZombieAI() AWander() AWander() ....
In response to Tko37
Ah, yes it is, but even when I fixed it the game still uses a lot of the cpu. Besides what you mentioned, do you see any other way that I can re code this to be more efficient?
Best response
The main thing I can think of is to not actually have zombies active until someone / something of interest enters their vicinity.

I also realize that you seem to be using zombies to eat corpses, and if the zombies only move when humans are around, they will just leave the corpses sitting there until someone is near. To solve that, you can have the corpses "wake up" nearby zombies when they are created, and then put them back to sleep when they are eaten
//This is just to get the gist, don't implement it
//quite like this
obj
Corpse
var
list/Zombie/zombiesAfterMe
New()
//normal New() stuff
signal()
proc/signal()
for(var/mob/Zombie/A in /*choose a distance*/)
if(!zombiesAfterMe) zombiesAfterMe = list()
zombiesAfterMe.Add(A) //keep track of who we've awoken
A.wakeUp()
proc/callMeWhenEatenOrDeletedOrWhatever()
for(var/mob/Zombie/A in zombiesAfterMe)
A.calmDown()
mob
Zombie
var/howManyCorpsesWereTracking = 0 //Something that corpses would
//set off
var/playerCounter = 0 //Something that players could setoff
proc/wakeUp()
//Make sure zombieStuff()
//isn't called more than once if multiple
//corpses wake us up
if(!howManyCorpsesWereTracking)
zombieStuff()
howManyCorpsesWereTracking++

proc/calmDown()
//Make sure that
//once all of the corpses that woke this up
//are eaten, go back to sleep
//and make sure this isn't negative
howManyCorpsesWereTracking--
proc/zombieStuff()
while(howManyCorpsesWereTracking && playerCount)
//do stuff

If you do use counters just make sure that they are indeed getting incremented once and only once for each player / corpse setting them off, and that they are definitely getting decremented when a player / corpse is no longer being followed.


Finally, I notice theres two for loops for every iteration of ZombieAI. I find that more readable, and I'm not sure how cpu intensive they are, but you could compress them into 1 for loop and see how that helps.
Oh, really? That is good to know, thnx.
In response to Tko37
Tko37 wrote:
The main thing I can think of is to not actually have zombies active until someone / something of interest enters their vicinity.

I also realize that you seem to be using zombies to eat corpses, and if the zombies only move when humans are around, they will just leave the corpses sitting there until someone is near. To solve that, you can have the corpses "wake up" nearby zombies when they are created, and then put them back to sleep when they are eaten
> //This is just to get the gist, don't implement it
> //quite like this
> obj
> Corpse
> var
> list/Zombie/zombiesAfterMe
> New()
> //normal New() stuff
> signal()
> proc/signal()
> for(var/mob/Zombie/A in /*choose a distance*/)
> if(!zombiesAfterMe) zombiesAfterMe = list()
> zombiesAfterMe.Add(A) //keep track of who we've awoken
> A.wakeUp()
> proc/callMeWhenEatenOrDeletedOrWhatever()
> for(var/mob/Zombie/A in zombiesAfterMe)
> A.calmDown()
> mob
> Zombie
> var/howManyCorpsesWereTracking = 0 //Something that corpses would
> //set off
> var/playerCounter = 0 //Something that players could setoff
> proc/wakeUp()
> //Make sure zombieStuff()
> //isn't called more than once if multiple
> //corpses wake us up
> if(!howManyCorpsesWereTracking)
> zombieStuff()
> howManyCorpsesWereTracking++
>
> proc/calmDown()
> //Make sure that
> //once all of the corpses that woke this up
> //are eaten, go back to sleep
> //and make sure this isn't negative
> howManyCorpsesWereTracking--
> proc/zombieStuff()
> while(howManyCorpsesWereTracking && playerCount)
> //do stuff
>
>

If you do use counters just make sure that they are indeed getting incremented once and only once for each player / corpse setting them off, and that they are definitely getting decremented when a player / corpse is no longer being followed.


Finally, I notice theres two for loops for every iteration of ZombieAI. I find that more readable, and I'm not sure how cpu intensive they are, but you could compress them into 1 for loop and see how that helps.

I'ma try what you suggested right now, I think I got the gist of it. Thanks for helping me.