PullTravelDir (adv3Lite)

…and now it’s time to implement a little red wagon. What I have discovered is that adv3Lite implements PushTravelDir, but there’s no PullTravelDir. Pushing a wagon would make no sense, so I need PullTravelDir.

I looked in thing.t, and there’s a fat wodge of stuff for handling PushTravelDir, much of which I don’t understand – stuff like PushTravelRevealItems().

Before I email Eric and make squeaking noises, I figured I should ask here whether anybody else has implemented a PullTravel action in adv3Lite, and if so whether you’d care to share your code.

Now, this is weird. It turns out the library is set up to let you either pull or push something – because functionally, in IF terms, it makes no difference. The only difference is in what the player types, and in how the library describes the resulting action. adv3Lite defines the property matchPullOnly, which if you read the DMsg code is supposed to result in “You pull the go-cart to the south” instead of “You push the go-cart to the south.” But it isn’t working. I’ve set matchPullOnly to true in my pullable object, and that changes nothing. I still get the library message saying I pushed it.

Specifically, this is the DMsg that’s being printed:

DMsg(push travel somewhere, '{I} <<if matchPullOnly>> pull{s/ed}
                <<else>> push{es/ed}<<end>> {the dobj} {1} {the iobj}. ', 
                 via.prep)

looks to me more of an oversight than a bug.

That one can push, but not pull a wagon or pull, but not push a rope makes sense, but there’s many items whose can be both pulled and pushed, like a cart/trolley.

With another flag, matchPushOnly, one can get a solid and consistent half-nybble truth table:

push      pull
  F         F      immovable (not pushable nor pullable)
  F         T      pullable only
  T         F      pushable only
  T         T      both pushable or pullable

Whose, at least in theory, makes sense in a solid world physics (of course, if the story has no magical nor supernatural elements…)

Best regards from Italy,
dott. Piergiorgio.

1 Like

It seems that, for commands involving a direction, like push cart north or pull cart north (not “through a door” or something else), the beforeMovePushable(connector, dir) method is called on the object being pushed and is responsible for outputting the message.

And in thing.t, we see that beforeMovePushable is implemented like this:

beforeMovePushable(connector, dir)
    {
        if(connector == nil || connector.ofKind(Room))
            DMsg(before push travel dir, '{I} push{es/ed} {the dobj} {1}. ',
                 dir.departureName);
        else
            describePushTravel(viaMode);      
        
    }

That is, the displayed message at least in this case is not “push travel somewhere”, but “before push travel dir”, which doesn’t contain the customization for matchPullOnly (this latter fact seems like a library bug, I’d say).

So, I think I’d override the beforeMovePushable(connector, dir) method on the object and just write “pull{s/ed}” in there, like this:

+ cart: Thing 'cart'
    "It's somehow asymmetrical in that it can only be pulled, not pushed. "
    canPushTravel = nil
    canPullTravel = true
    
    beforeMovePushable(connector, dir) {
        if(connector == nil || connector.ofKind(Room))
            DMsg(before push travel dir, '{I} pull{s/ed} {the dobj} {1}. ',
                 dir.departureName);
        else
            describePushTravel(viaMode);      
    }
;

Or, if you want to implement the correct response also for things which can be pushed as well as pulled, you could do it like this:

+ trolley: Thing 'trolley'
    "A small trolley which can be pushed and pulled. "
    canPushTravel = true
    
    beforeMovePushable(connector, dir) {
        if(connector == nil || connector.ofKind(Room))
            DMsg(before push travel dir, '{I} <<if matchPullOnly>> pull{s/ed} <<else>> push{es/ed}<<end>> {the dobj} {1}. ',
                 dir.departureName);
        else
            describePushTravel(viaMode);      
    }
;

When I tested this out in a small example project, it seemed to work well.

(When I alternatively experimented around with adding a CustomMessages object and customizing the messages there, I ran into problems where matchPullOnly as well as matchPushOnly were always nil, even though the library is supposed to set them. That probably has to do with the timing of the evaluation of embedded expressions (like <<if matchPullOnly>>) in single-quoted strings, I don’t know.
But with the method above, we should be able to circumvent those problems.)

3 Likes

Perfect, thanks!