ID:2158429
 
(See the best response by Lummox JR.)
Problem description:
Completed my dream Ai, works perfectly, exactly as I so desired. Its set up to fight against another computer at speeds normally impossible, just for testing at this point, so I used a while loop to receive stimuli for it to react to whatever situation effectively. However, after some time passes in combat my cpu usage spikes up and starts lagging, fluctuating rapidly, especially when the Ai is doing chase attacks....Help meh pls!!!

Code:
mob
proc
SpecAi()
if(isplayer(src)) return
spawn() while(1)
if(src.npc==0) return
/*
if(src.transed==0)
if(src.PL<src.BasePL*0.1)
src.NPCPowerUP()
else
if(src.PL<src.tempmaxPL*0.1)
src.NPCPowerUP()
*/

if(src.skillactive==0 && src.knockback==0 && src.ingame==1)
if(src.state=="Searching")
spawn src.SearchAi()
else if(src.state=="Engaging")
if((!src.targets) || (src.targets==null))
src.state="Searching"
else
spawn src.CombatProcess(src.targets)
sleep(src.adelay)


CombatProcess(mob/M)
if(!src||src.skillactive==1)
return
if(!M) return
if(M.dead==1||!src.targets||src.targets==null)
src.state="Searching"
src.targets=null
return
if(src.state=="Engaging")
if((get_dist(src,M)>30)||M.dead==1||!src.targets||src.targets==null)
src.state="Searching"
src.targets=null
return
if(src.stuntime>0 || src.flinching==1)
return
src.dir=get_dir(src,M)
if(src.aura==1)
src.AuraToggle()
if(src.stance==0) src.Stance()


//reactions to knockback which seem to cause the lag starts here


if(M.knockback>=5)
if(prob(50)==1 && src.namekian==1)
if(src.LongGrab()!=0) view()<<"<b>[src]</b> : Come back here"
else if(prob(70)==1)
if(src.extending==0)
if(src.targets in oview(30))
src.Chase()
if(M.knockback>=7||((get_dist(src,M)>7) && (get_dist(src,M)<15)))
if(prob(30)==1)
if(src.rushuse==0)
if(src.Rush()!=0)
src.rushuse=1
spawn(60) src.rushuse=0
else
walk_towards(src,M)
if(src.imuse==0)
if(src.Im()!=0)
src.imuse=1
spawn(60) src.imuse=0
else
walk_towards(src,M)
else
walk_towards(src,M)


//reactions to knockback which seem to cause the lag ends here


if(get_dist(src,M)>1 && get_dist(src,M)<30)
walk_towards(src,M)
if(get_dist(src,M)<1)
if(src.fly==0)
src.N_Fly()
step_away(src,M)
if(get_dist(src,M)==1)
if(src.fly==0)
src.N_Fly()
walk(src,0)
if(prob(20)==1)
if(prob(25)==1 && src.countercool==0)
src<<""
if(src.Ccounter()!=0)
src.countercool=1
spawn(300)
src.countercool=0
/*else if(prob(10))
src.Block()
sleep(10)
if(src.blocking==1)
src.Block()*/

else
if(prob(10) && src.sfist==0)
if(src.SPunch()!=0)
src.sfist=1
spawn(600)
src.sfist=0
if(prob(80) && src.beamnpc==0)
src.dir=get_dir(src,M)
src.Beam()
src.beamnpc=1
spawn(100)
src.beamnpc=0
else if(src.cannonk==0)
src.KCannon()
else
var/randum=rand(1,4)
if(randum<>4)
src.LightAttack()
else
src.HeavyAttack()


SearchAi()
if(src.stance==1) src.Stance()
if(src.transed==1)
src.Revert()
if(src.aura==1)
src.AuraToggle()
//walk_rand(src)
if(istype(src,/mob/heronpc/Hero))
for(var/mob/M in world)
if(M.z==src.z)
if(istype(M,/mob/villainnpc/Villain))
if(src.aura==0)
src.AuraToggle()
if(src.fly==0)
src.N_Fly()
src.targets=M
break
else if(istype(src,/mob/villainnpc/Villain))
if(src.hitlist.len==0)
for(var/mob/M in world)
if(M.z==src.z)
if(M!=src)
src.hitlist+=M
if(istype(M,/mob/heronpc/Hero))
src.targets=M
if(!src.targets)
for(var/mob/M in src.hitlist)
src.targets=M
src.hitlist.Remove(M)
break
if(src.aura==0)
src.AuraToggle()
if(src.fly==0)
src.N_Fly()
src.targets<<"You feel a sudden chill run down your spine"
if(src.targets)
walk_towards(src,src.targets)
src.state="Pursuing"
return


Multiple problems here.

First off, you're abusing the crap out of spawn(), and that's probably why your CPU is spiking--you're basically piling up too many things happening at once, because your loop spawns something and then moves on.

You should never, ever use if(var==1) and if(var==0) to check if a var is true or false. Use if(var) and if(!var) instead.

if(!src) at the beginning of a proc is pointless.

The overuse of src.var and src.proc everywhere is murdering readability. Get rid of all the extra src.XXXX stuff.

Why is the var named "targets" when it's only ever one target?
In response to Lummox JR
"You should never, ever use if(var==1) and if(var==0) to check if a var is true or false. Use if(var) and if(!var) instead."

Out of mere interest: Why?

It seemed like an oddly emphatic observation for something that I -- personally -- would just consider a minor readability issue. Am I missing something? (or are my eyes awfully tolerant?)
Best response
Robustness, code size, and performance.

Code size: The if(var) and if(!var) versions are very straightforward, compiling to very few instructions. ==1 and ==0 means constants will have to be stored in the code and pushed to the stack, then comparisons have to be made.

Performance: The extra code is just going to make this run slower. It's only a smidge, but if this routine is called a lot, those smidges may eventually add up.

Robustness: This is the killer. If for any reason one of those vars is anything besides 0 or 1, suddenly those ==1 and ==0 checks will fail. Is that likely? Probably not, but it's a foolish risk when you can write the checks correctly and avoid the risk altogether. If a var is only ever meant to be true or false, treat it that way and never assume it will be a specific number, or even a number at all.
In response to Lummox JR
Thanks for the help, most of the lag came from other recursion based procs called by ai, but your advice also helped me alot. However, I don't think I quite understand what you meant by the below statement

Lummox JR wrote:
The overuse of src.var and src.proc everywhere is murdering readability. Get rid of all the extra src.XXXX stuff.

In response to Cheesy pants
You're using
src.var
everywhere, where it should just be
var

I.e
            if(state=="Engaging")
if((get_dist(src,M)>30)||M.dead||!targets||targets==null)
state="Searching"
targets=null
return
if(stuntime>0 || flinching)
return
dir=get_dir(src,M)
if(aura)
AuraToggle()
if(stance) Stance()
In response to GreatPirateEra
Thanks, I thought it was mandatory because I saw it in most of the examples in the dream maker directory, I recently started C++ and saw it wasn't used there, but I had just concluded that it was a simple difference between languages
In response to GreatPirateEra
I've been wondering though, does it make any large difference?
It makes no difference in the way the code runs, it simply makes the code more readable.
In response to Nadrew
Well then I'll sit out on that for now in that case