ID:2108660
 
(See the best response by Kaiochao.)
Code:
mob
var
tmp
move_delay = 0.4
next_move = 0
Move(NewLoc, Dir, step_x, step_y, force=0)
if(force)
if(src.loc)
src.loc.Exited(src)
if(src.loc.loc)
src.loc.loc.Exited(src)
src.loc = NewLoc
src.loc.Entered(src)
src.loc.loc.Entered(src)
return 1
if(src.shopping || src.next_move > world.time)
return 0
..()
src.next_move = world.time+src.move_delay


mob
Read(var/savefile/s)
..()
src.Move(locate(s["save_x"],s["save_y"],s["save_z"]),SOUTH,0,0,1)


Problem description:
postimage

If I change the move_delay to 0, I do not get that obscene amount of Move() calls. It becomes normal (like 3 or whatever). But 0.4 makes it horrendous. Not sure what's going on, or how something like a small number can mean that much of a difference.

The second bit of code is what's calling the Move() proc and that's it. All I'm doing is loading a mob and the Read() proc places that mob onto the map where it was saved last. I'm not doing anything else. Move() is being called once here and it's generating a huge amount of Move() calls for no reason.
Not sure why but changing the following...
..()
src.next_move = world.time+src.move_delay

...in Move() to...
if(..())
src.next_move = world.time+src.move_delay

...fixed it. Strange because the code being executed shouldn'tve ever hit that far into Move() since force was set to 1 and returns after setting the location directly.
Best response
You should always return a value when overriding procs that are meant to return a value. Instead of if(..()), you should do this (in Move()):
. = ..()
if(.)
src.next_move = // etc.

. is a variable, local to all procs (like usr and src), that is returned when a proc ends or "return" isn't given a value afterwards. It's syntactic sugar (equivalent) to:
var success = ..()
if(success)
src.next_move = // etc.
return success

The difference between checking and not checking the value given by ..() comes from the fact that, by default, Move() returns a value depending on the success of the movement. By not checking if the movement failed, you were delaying the next movement even if no movement occurred.

Of course, this is all only relevant to when you're not forcing the move, so...

Oh, I almost forgot. Part of the default behavior of /mob/Login() is to, if the mob isn't on the map, place it on the map. It does this by calling Move() starting at (1, 1, 1), scanning rightwards and wrapping around on the next y, until the mob is on the map. When these calls to Move() occur, they're not "forced" calls. What this means is, if you have a sea of dense turfs along the bottom of a really wide map (which might be common to platformers or islands surrounded by water), you'll have a lot of calls to Move() on Login(). The solution here is to either avoid calling the default behavior (this requires careful attention to ..() calls in all your Login() overrides), or make sure the mob is on the map before calling the default behavior.
In response to Kaiochao
That was very informative. Thank you. I now understand why there was an obscene amount of Move calls. I never really got into using the . or .=..() method for whatever reason. Maybe when I first learned DM, I never knew about the . and what it meant in such procs, so I just stuck with the "normal programming" (using C#/C++/Java/etc) way of doing things and manually returning a value.

Is it flat out incorrect practice to use if(..()) instead of . = ..(); if(.) because it seems to do the same thing in my eyes.
In response to Demonking2002
If you call ..() without storing its return value in a variable, the return value is lost, same as any other function.
In response to Kaiochao
Oh okay. I gotcha now. Thank you.