ID:1328767
 
Someone has asked me to help improve on an old game known as rise of heroes. The code for the AI for MOBs is known as Unique:

    proc/Unique(speed) //this is the main enemy logic
while(src) // while its alive
if (P in oview(5)) // if theres something in sight
if(hasspells==0) // if this enemy doesn't cast spells
step_towards(src,P) // step towards the player
if(Unique==1) // if its a unique
step_towards(src,P) // step twice
step_towards(src,P) // this causes uniques to attack twice and move faster
else // spell caster
var/V = rand(1,6) // 1 in 6 chance to do something
//if the enemy has all 6 of these spells, it wont attack regularly until it is out of MP
//if the enemy has 2 of these spells, it has a 1/6 chance to cast either of them and a 4/6 chance to attack
switch(V)
if(1)
if(fireboltlevel>0)
FIREbolt()
else
step_towards(src,P)
if(2)
if(iceboltlevel>0)
ICEbolt()
else
step_towards(src,P)
if(3)
if(lightningboltlevel>0)
LITbolt()
else
step_towards(src,P)
if(4)
if(feedbacklevel>0)
FEEDBACK()
else
step_towards(src,P)
if(5)
if(poisonlevel>0)
POISON()
else
step_towards(src,P)
if(6)
if(darklevel>0)
DARK()
else
step_towards(src,P)
else
sleep(speed) // pause based on speed
// step_rand(src) // then step randomly
for(P in view(src)) // if something comes nearby
break // break out to start taking fighting actions
sleep(speed) // pause based on speed
spawn(speed) // infinite loop based on speed before next calling
Unique(speed) // this is the call again



this proc is working but the way its called is inefficient. When running locally there is no lag, but when online, its really really bad.

Here is an example of how one mob calls this proc:

    //these are all the different enemies and their variables and actions...
slime
icon_state = "slime"
level = 1
Speed = 20
HP = 10
MAXHP = 10
MP = 5
MAXMP = 5
expgive = 2
goldgive = 2
Strength = 2
Intelligence = 1
firewk=20
New() //When this mob is created...
.=..()
spawn(1) //start and infinite loop
Unique(Speed)
Bump(mob/players/M) //When the mob bumps into another mob
if (istype(M,/mob/players)) //If the mob is a PC...
Attack(M)
proc/Attack(mob/players/M)
flick("slime_attack",src)
sleep(2) //This give the animation time to play, and sets the attack delay for this mob. Dont put this on PCs or evil little errors will keep popping up. I can make it different though so just ask me how to make a more advanced attack verb for PCs.
if (prob(M.tempevade))
view(src) << "[src] \red misses <font color = black>[M]"
else
HitPlayer(M)


Now there are close to 1000+ mobs on the map, and each one is spawning this unique 10 times a second, which is the source of the lag.


My approached solution was to remove:

            spawn(1)   //start and infinite loop
Unique(Speed)


from new()

and replace it with the first three lines within the Move() below:
    Move()
var/mob/enemies/M
if(M in oview(5)
M.Unique(M.Speed)
if(nomotion==0) // this is used so that you can't talk to shopkeepers a ton and then run around with their GUIs open
if(away != 0) // if you are away
away = 0 // now you aren't!
usr << "You are no longer marked as away"
if(poisonDMG<=0) // not poisoned anymore?
overlays = null // i guess we can take those poison things off your icon then
// problems with lag making me need to be sure that their hp and mp are within acceptable ranges
// so this lets them cast a few extra spells by spamming, but whatever...
if(HP>MAXHP)
HP=MAXHP
if(MP>MAXMP)
MP=MAXMP
if(MP<0)
MP=0
..() // oh yeah.. let them move too. do the default move() proc stuff
if(nomotion==1)
return // don't even think about moving, chump!


The problem is, The AI is dead and not working when i do this. I am assuming that once the Unique proc is fired once, it keeps itself alive untill the mob dies, and should only have to be called once. I am at a loss as to why its not running. The possible problems i can assume are either the M isn't calling the Unique proc, or the Unique proc isn't working right.

Thank you for reading and any/all feedback. someone gave me their source to work on, so i cant give out it all without their permission. However, if needed i can pull out the two .dm files where the code happens at and send them to someone for further diagnosis.
I've also tried:
in the Move()
        var/mob/enemies/M
if(M in oview(5))
if(M.isAlive == 0)
M.wakeUp(M)


Added this proc to /mob/enemies:

    proc/wakeUp(var/mob/enemies/M)
M.isAlive = 1
spawn(1)
M.Unique(Speed)




This just causes major lag and the ai still is dead.


I tried putting the wakeUp to the mob like this:

    slime
icon_state = "slime"
level = 1
Speed = 20
HP = 10
MAXHP = 10
MP = 5
MAXMP = 5
expgive = 2
goldgive = 2
Strength = 2
Intelligence = 1
firewk=20
New() //When this mob is created...
.=..()
proc/wakeUp(var/mob/enemies/M)
M.isAlive = 1
spawn(1)
M.Unique(Speed)
Bump(mob/players/M) //When the mob bumps into another mob
if (istype(M,/mob/players)) //If the mob is a PC...
Attack(M)
proc/Attack(mob/players/M)
flick("slime_attack",src)
sleep(2) //This give the animation time to play, and sets the attack delay for this mob. Dont put this on PCs or evil little errors will keep popping up. I can make it different though so just ask me how to make a more advanced attack verb for PCs.
if (prob(M.tempevade))
view(src) << "[src] \red misses <font color = black>[M]"
else
HitPlayer(M)


but when i try to compile i get this error;
Basics.dm:202:error: M.wakeUp: undefined proc
(which is referring to:)
    Move()
var/mob/enemies/M
if(M in oview(5))
if(M.isAlive == 0)
M.wakeUp(M)
if(nomotion==0) // this is used so that you can't talk to shopkeepers a ton and then run around with their GUIs open
if(away != 0) // if you are away
away = 0 // now you aren't!
usr << "You are no longer marked as away"
if(poisonDMG<=0) // not poisoned anymore?
overlays = null // i guess we can take those poison things off your icon then
// problems with lag making me need to be sure that their hp and mp are within acceptable ranges
// so this lets them cast a few extra spells by spamming, but whatever...
if(HP>MAXHP)
HP=MAXHP
if(MP>MAXMP)
MP=MAXMP
if(MP<0)
MP=0
..() // oh yeah.. let them move too. do the default move() proc stuff
if(nomotion==1)
return // don't even think about moving, chump!

That AI code makes my face hurt, try looking at forum_account's Enemy AI demo/guide. One of the very helpful things it does is teach you
" How to manage AI loops efficiently with thousands of mobs."

On to the problem though, you said online there is a bunch of lag? Does that have to do with player/mob count or just whenever it's hosted it lags? Try having a random value between speed-(a small tick) and speed+(a small tick) so that all of the AI with the same speed aren't on the same timer.

spawn(rand((Speed-3),(Speed + 3))) Unique(Speed)

Also try change things like

if(nomotion==1)

to
if(nomation)


and

if(M.isAlive == 0)

to
if(!M.isAlive)


better coding practice/readability makes everyone happy!
Ty Kenpachi12, I downloaded the AI this morning and when i get off work tonight i will go through all the samples and try to implament a completely new AI system.