MovePlayer

MovePlayer is a routine specifically written for moving the player to another location, saving us the trouble of updating the [location global, among other things. For instance, it also checks to checks that the new location has a light source and runs DarkWarning, if necessary. Let’s break it down: The first argument (loc or dir) is either the location object we are moving the player to or a direction object (n_to, e_to, etc.). If it’s the latter, MovePlayer only moves the player if it’s a valid direction.

The second argument (silent) determines whether DescribePlace should be executed after we move the player, giving the name and description of the new location. The last argument (ignore) determines whether we want to run any player.before or player.after code. Imagine a game where moving the player (such as the wand or >XYZZY in Adventure) gives him an odd feeling:

player_character you "you"
{
    before
        {
        actor MovePlayer
            {
            "Your whole body tingles."
            return false ! so the player still is moved by MovePlayer
            }
        }
    after
        {
        actor MovePlayer
            {
            "The odd tingling subsides."
            return true
            }
        }
}

Having an ignore value would skip both of those statements. Ta-da!

the code

For the sake of browsing, here is the routine itself:

!----------------------------------------------------------------------------
! MovePlayer(location[, silent])
! moves the player to the object <location>, with no description if <silent>
! is true
!
! MovePlayer(direction[, silent[, ignore]])
! moves player in <direction>, where <direction> is a direction object.
! If <ignore> is true, before/after routines relating to the move are
! not checked.
!
! MovePlayer calls DarkWarning when there is no light source in the new
! location; replace it with a new DarkWarning routine for a more elaborate
! response, such as the possible demise of the player

routine MovePlayer(loc, silent, ignore)
{
    local v, obj, xobj, act, ret

#ifclear NO_OBJLIB
    if loc.type = direction
    {
        local l
        l = location.(loc.dir_to)
        if l > 1                ! since a message always returns 1
            loc = l
        else
            return
    }
#endif

#ifset USE_ATTACHABLES
    if ObjectisAttached(player, location, loc)
        return
#endif

    ! Check if there's a before routine for MovePlayer in the new
    ! location.  Note that the (potential) new location and the old
    ! location are stored in object and xobject, respectively.
    !
    v = verbroutine
    obj = object
    xobj = xobject
    act = actor
    verbroutine = &MovePlayer
    object = loc
    xobject = location
    actor = player
    if not ignore
    {
        ret = player.before
        if ret:  jump LeaveMovePlayer
        ret = location.before
        if ret:  jump LeaveMovePlayer
        ret = loc.before
        if ret:  jump LeaveMovePlayer
    }

    move player to loc
    old_location = location
    if parent(loc) = 0              ! if it's likely a room object
        location = loc
    else                            ! if it's an enterable object
        location = parent(loc)  ! (noting that the object must be
                    ! in a room, not inside another
                    ! non-room object)

#ifset USE_ATTACHABLES
    MoveAllAttachables(player, old_location, location)
#endif

    PrintStatusline

:LeaveMovePlayer

    if not ret
    {
        if not FindLight(location)
            DarkWarning
        elseif not silent
        {
            DescribePlace(location)
            event_flag = true
            location is visited
        }

    ! Check if there's an after routine for MovePlayer in the new
    ! location:
    !
        if not ignore
        {
            ret = player.after
            if not ret
                ret = location.after
        }
    }

    verbroutine = v
    object = obj
    xobject = xobj
    actor = act

    return ret
}