ID:264767
 
Code:
Follow(mob/leader)
while(src.status=="follow")
step_to(src,leader,1)
sleep(leader.movespeed) //movespeed==1 usually


Problem description:
Simple enough proc, and looks harmless enough. But with it looping through 3-15 mobs every tick, it actually generates an abhorrent amount of CPU lag; what was 0 becomes 5 when I host locally, with just myself.

Is there a better way to tell a bunch of MOBs to follow you until told otherwise?
I am not sure how to exactly go about programming it, BUT, logic wise:

if (check distance between mobs, if you even need to step)
while(status == follow)
sleep(leader.movespeed)
step_to(src,leader,1)


Also, exactly how often do you need to call the Follow verb?

Have you thought of just having a list of followers too?

mob/var/list/followers

mob/Move()
var/mob/M
if(M in followers)
for(M in followers)
if( the mob can follow, and is not already right next to them)
..()
//Make each mob in the list do the step_to


Here is Nandrews' distance detection system: http://www.byond.com/developer/Nadrew/rangedetection
In response to Darkjohn66
Wow! Your Move() idea solved the CPU issue 110%!! :)
Unfortunately it created a new issue:
If you're a but too nimble/youre making your way through tricky obstacles - you can end up ages away from the followers.
EDIT:
Also, just realised the idea isn't feasible for my project.
Players need to be able to call these mobs over to them whether they move or not
step_to can be a CPU hog but it doesn't seem like there should be that much CPU usage for only 3-15 mobs. If you can use step_towards instead, even only some of the time, you'll get rid of most of the CPU usage. If the mobs are close to you or have a clear path to you, you don't need to use step_to, step_towards would work.
In response to Forum_account
Thanks, that did assist to an adequate level... I guess.
Would be nice to get it lower but meh; I'll consider that one solved.
i have a trickier problem now :|
    FollowersAttack()
var/mob/t=src.target; var/m=src.movespeed; if(m<1) m=1
while(get_dist(t,src)<17&&!t.dead&&src.status=="attack")
t=src.target
if(!t) break
if(t.decoy) t=t.decoy
if(get_dist(t,src)<=10)
if(get_dist(t,src)<=1)// this criteria is the focus
if(get_dir(src,t)==src.dir)
if(src.HitCheck(t))Punch(t)
else t<<"You dodged [src]'s attack"
sleep(src.atkspeed)
else
step_towards(src,t)
sleep(1)
else
step_to(src,t)
sleep(m)
else sleep(m+3)


Tested @ 300-600 mobs on my comp, and gave out avg CPU readings of 30-50 respectively; which causes noticable lag.
I know 300 - 600 seems high, but I want each player to be able to use 8-15 if them at a time; I concluded that 300-600 would be a fair test of 50 people using 6-12 all at once.

NOTE: CPU reading is @ 0, very occasionally its 1 prior to using the proc
In response to Saucepan Man
If the delay between iteration of the follower's loop is lower after using the proc the CPU usage should increase some. Replace step_to with step_towards to see how low you can get the CPU usage to go. That'll give you an idea of how much lag comes from the number of mobs and how much comes from step_to.

You could switch to using step_to only when step_towards fails. That way if you're in an open area the followers will never need to use step_to.
In response to Forum_account
if(!step_towards(ref,trg)) step_to(ref,trg)

Like that?
In response to Forum_account
Oh yeah, sorry! Forgot to update:
        while(get_dist(t,src)<17&&!t.dead&&src.status=="attack")
t=src.target
if(!t) break
if(t.decoy) t=t.decoy
if(get_dist(t,src)<=10)
if(get_dist(t,src)<=1)
if(t in get_step(src,src.dir))
if(src.HitCheck(t))Punch(t)
else t <<"You dodged [src]'s attack"
sleep(src.atkspeed)
else
step_towards(src,t)
sleep(1)


That loop there, where atkspeed = 3 and Punch(t) is called each time, causes a lot of yucky lag. :\
In response to Saucepan Man
Saucepan Man wrote:
> if(!step_towards(ref,trg)) step_to(ref,trg)
>

Like that?

Sure.

There are some cases where that won't work:

########
#
F# O
######


If F is following O, step_towards will fail so you'll call step_to and F will move left. The next iteration will try step_towards and succeed, moving F to the right.

When step_towards fails you might want to set a counter telling the routine to use step_to for the next 3 or 4 iterations.

The reason why step_to is inefficient is mostly because it has to compute the full path just to find what the first step of the path would be. To get around this, when step_towards fails you could use a pathfinding algorithm to find a path, then have the mob follow that. Their destination is moving, but it's not likely that the player will move so much that the entire path is invalid each iteration and needs to be recomputed. If you only need to recompute the path every 3rd move you can support three times as many mobs.
Using numerical constants for the status variable, rather than text strings, should improve performance slightly. So, instead you'd have:

var/const/status_follow = 1
var/const/status_attack = 2

Follow(mob/leader)
while(src.status == status_follow)
//...


Also less prone to errors on your part.

(thinking about it now, it might actually only improve performance when it comes to actually changing status... but it's still better practice anyway)
In response to Garthor
Thanks for that, always interested in learning proper procedure and reducing lag in any way