PushDir

PushDir is a verb routine to support pushing objects in specific directions, or just to avoid the following:

> push boulder southwest
You haven’t encountered any “boulder southwest”. (If you’re sure you need to refer to that, try putting it another way.)

Don’t Call Me a Dummy, Dummy

Even if your game doesn’t support pushing objects from room to room, you might want to add some dummy grammar entries and a routine to properly parse >PUSH BOULDER SOUTHWEST. If you think someone might try that in your game, you’d want to add something like the following to your code:

! add to grammar
verb "push","pull","press","move"
    * object "to" xobject           DoPushDir
    * object "north"/ "n"/ "south"/ "s"/ "east"/ "e"/ "west"/ "w"/ \
    "southeast"/ "se"/ "southwest"/ "sw"/ "northwest"/ "nw"/ \
    "northeast"/ "ne"/ "up"/ "u"/ "down"/ "d"/ "in"/ "out"/ \
    "inside"/ "outside"             DoPushDir


routine DoPushDir
{
    "That would not help the present situation."
    return false ! let's not use up a turn
}

Your game will seem so smart!

Pushing In Earnest

Next, let’s code up a working example. As you saw in the code above, we had to specifically mention every direction for the PUSH command. The parser really hates if the object is directly next to the xobject since it has no way to distinguish what’s what without our help. Our code will turn >PUSH OBJECT DIRECTION into >PUSH OBJECT TO THE DIRECTION to get around that. We will also include code so that pushable objects can’t be pushing into every room.

verb "push","pull","press","move"
    * object "to" xobject           DoPushDirTo
    * object "north"/ "n"/ "south"/ "s"/ "east"/ "e"/ "west"/ "w"/ \
    "southeast"/ "se"/ "southwest"/ "sw"/ "northwest"/ "nw"/ \
    "northeast"/ "ne"/ "up"/ "u"/ "down"/ "d"/ "in"/ "out"/ \
    "inside"/ "outside"             DoPushDir


property outofbounds
property pushstart
property pushend

! This routine turns >PUSH OBJECT DIRECTION into >PUSH OBJECT TO DIRECTION
routine DoPushDir
{
    local a,m

    ! the for loop finds the last word before the direction
    ! which should be the object's noun
    for (a=2; ; a=a+1)
        {
        if ObjWord(word[a],object) = noun
            break
        }
    ! Let's add one to find the direction words
    a = a + 1

    ! Let's identify what we've got and point to the right direction object
    select word[a]
        case "north", "n":      m = n_obj
        case "south", "s":      m = s_obj
        case "east", "e":       m = e_obj
        case "west", "w":       m = w_obj
        case "northwest", "nw": m = nw_obj
        case "northeast", "ne": m = ne_obj
        case "southeast", "se": m = se_obj
        case "southwest", "sw": m = sw_obj
        case "up", "u":         m = u_obj
        case "down", "d":       m = d_obj
        case "in", "inside":    m = in_obj
        case "out", "outside":  m = out_obj

    ! Let's run it
    return Perform(&DoPushDirTo, object, m)
}

routine DoPushDirTo
{
    local moveto
    moveto = xobject

    if not (object is mobile and object is not clothing) ! if the item is not rollable, we'll just act
        return Perform(&DoMove, object)    ! like the player just tried to move it.
    elseif xobject.type ~= direction           ! since mobile = worn, we make sure the item is not
        {                                  ! clothing
        ! possibly, you might want to add code that checks to see
        ! if the xobject is a container and in such cases, interpreters
        ! >PUSH OBJECT INTO XOBJECT as DoPutIn. To avoid the checkheld headache
        ! that introduces, we will ignore that possiblity for now
        VMessage(&DoPushDirTo,1)
        return false
        }

    ! Let's check to see if we're pushing to a location
    ! we don't want the player pushing to
    local k
    k = location.(moveto.dir_to)
    if k > 1  ! means the direction we are moving in is a viable direction
        {
        ! is the direction a room we can walk to but can't push objects to?
        if k.outofbounds
            return false

        ! Let's print a success message before the move "You start pushing..."
        if not object.pushstart
            VMessage(&DoPushDirTo,2)
        }

    ! If DoGo works, then move the object to the location and print
    ! a followup success message.
    if Perform(&DoGo, xobject)
        {
        print ""
        move object to location
        VMessage(&DoPushDirto,3)
        return true
        }
}

replace NewVMessages(r, num, a, b)
{
        select r

    case &DoPushDirTo
    {
        ! Let's set default DoPushDirTo messages
        select num
        case 1:  print "Try pushing "; Art(object); " in a direction."
        case 2:  print CThe(player); MatchPlural(player, " pushes ", " push "); Art(object); " over to the..."
        case 3:  print CArt(object); " slows to a stop."
    }

        case else : return false

       return true ! this line is only reached if we replaced something
}

Note the addition of the extra properties. Here is some sample code that makes use of the above:

room STARTLOCATION "Start Location"
{
long_desc
       "This is the starting room description."
e_to EastRoom
cant_go
    {
    if object = s_obj
        "That wing is closed."
    else
        return false
    }
}

object onion "giant onion"
{
adjective "giant"
noun "onion"
article "the"
in STARTLOCATION
is mobile
pushstart
    "You roll the giant onion to the..."
pushend
    "The onion rolls to a stop."
}

room EastRoom "East Room"
{
w_to STARTLOCATION
u_to Stairs
}

room Stairs "Upstairs"
{
d_to EastRoom
outofbounds
    print "You can't push "; art(object); " up the stairs."
}

That gives us:

Start Location
The giant onion is here.

>push onion east
You roll the giant onion to the…

East Room
The onion rolls to a stop.

>push onion u
You can’t push the giant onion up the stairs.

Requirements

DoPushDirTo has been updated to require the mobile attribute, as that is a seldom used attribute somewhat meant for such things (it is also used for attachable objects, so if your game uses attachables, you may need to use something else). You also need to be mindful of your exit code, putting all “You can’t go that way.” messages in the cant_go property, like above.