ID:157438
 
How do you get mobs to always move 2 squares ahead, instead of the default 1 square?
client/North()
movement(src.mob, NORTH)
proc/movement(mob/m, direction)
var/turf/t = get_step(m, direction)
m.Move(get_step(t, direction), direction)


Something like this should work. Getting the location of the location where the movable atom normally would have stepped, and then getting the further get_step() of that. You may have to fiddle around with it to get the desired effect. It may also cause bugs with certain things like void spaces.

proc/movement(mob/m, direction)
m.Move(get_step(get_step(m, direction),direction), direction)

That might also work.
Another way
atom/movable/multi_step(amount, dir)
var/movementSuccessful
for(var/i = 1 to amount)
// return 1 as long as any movement was successful
movementSuccessful |= step(src, dir)
return movementSuccessful

You could easily change that to return 1 only if all movement was successful by having it return on any step() failure instead of ORing it to the return value.

The easiest way to then implement this, if you don't mind skipping client/Move()
client/North()
mob.multi_step(2, NORTH)


(edit)
As Pop pointed out, you did not say anything about client-initiated movement, just mob movement in general.

This task is not quite the same, and the short answer is that you can't. As for the long answer...

mob/Move() does not make you step away from your current location to an adjacent one. mob/Move() (as inherited from movable/Move()) takes an argument specifying a location to move to, and that could be anywhere. There's no way to tell within mob/Move() whether the context of the move meant "walk in that direction" or if it meant another kind of movement, such as teleporting or whatever; even if the location is adjacent to your current location, it still doesn't necessarily mean you meant to walk a tile over.

There are a few ways you can do what you're looking for, and the implementation you use depends on the situation. (But of course, I could have just inserted that last sentence into 95% of posts)

You could start with something like the move_multi() I listed above, and use that anywhere you move a mob.

Another way would be to assume that movement to adjacent tiles means you're "walking." Then you could give Move() another parameter that makes it call recursively.
mob/Move(atom/newLoc, Dir=0, amount = 0)
// if an amount of movement was specified and you're "walking" to the adjacent tile
if(amount && amount > 0 && get_dist(loc, newLoc) == 1)
// can't trust Dir because it's not guarenteed to be get_dir(loc, newLoc)
var/D = get_dir(loc, newLoc)
// do normal first step, and if it succeeds...
if(..())
// ... then continue with the next step
.=..(get_step(src, D), Dir, amount-1)
// amount not specified, so do normal move
else
.=..()

I don't particularly like this way of doing it though. I think I would rather go with the multi_step() and just use that everywhere I wanted to move something.

Also note that the above recursive Move() will return 1 only if the entire movement succeeded, because it will return the success/failure of the last Move().

(edit2)
Also note that, if you use the recursive Move(), you have to call it in the first place with a specified amount for the extra parameter.
In response to Librarian
That's not very good. There's no need to define specifically for each client direction proc (nor did he say that it was only for clients), and the extra proc is completely unescesary.

mob/Move(atom/newloc, dir = 0)
// newloc is a default argument always supplied. We can
// use this to get the direction of movement.
var
direction = get_dir(src, newloc)
oldloc = src // We'll use this in a second.

newloc = get_step(get_step(src, direction), direction)

if(!newloc)
// If there isn't anything there (it's beyond the
// map's boundary) block movement.
return 0

// Otherwise, we have to do what is normally done by
// Move, since we're ovewriting it.
if(oldloc.Exit(src))
// Check and see if we can exit where we're at. If
// we can, check and see if we can enter where we're
// going.

if(newloc.Enter(src))
// If we can, then move us to the new location
// and change our direction either to the
// specified direction, or the direction we
// should be.

loc = newloc
src.dir = dir || direction

// Also call the Exited() and Entered() procs
// of the relevant turfs.
oldloc.Exited(src)
newloc.Entered(src, oldloc)

return 1 // Successfully entered the new location.

else
// If we can't enter, then call Bump() for
// whatever's blocking us.

if(newloc.density)
Bump(newloc)
else
for(var/atom/a in newloc)
if(a.density)
Bump(a)

return 0 // Failed to enter.


Now, this assumes you just pass through whatever's in between you and the next turf you're going to. If this isn't the case, it'd probably be easier just to call Move() twice.