I6: Should an after rule for Take ever abort the main action?

If I type WEAR SWEATER in a game built with the Inform 6 library v6/12, and I’m not holding the sweater, an implicit take action is triggered. If the sweater has an after rule which returns true, the Wear action never happens.

Is this behaviour correct?

I’m thinking that after rules are there to print a different message or add some side-effect, but not to abort the action, and then it doesn’t make sense to abort the wear action in this scenario either.

Here’s one scenario wherein an after rule for TAKE causes an abort.

> LOOK

You're at your campfire.  A rock of unusual colouration is in the middle of the blaze.

> PUT ROCK IN BASKET
(Taking the rock)
Not surprisingly, the rock is too hot to touch.  You painfully jerk your hand back.

>INVENTORY

You are empty-handed.

> LOOK

You're at your campfire.  A rock of unusual colouration is in the middle of the blaze.

How does your game look when WEAR SWEATER is done with the sweater’s after rule returning true and then false?

No, that would have to be an Instead rule, not an After rule.

Instead rules are to prevent the action, After rules are to succeed the action but with a different message output (overruling the Report rulebook).

But indeed when I try it, using an After rule does not prevent the action:

Campfire is a room.  "You're at your campfire."
A rock of unusual colouration is in Campfire.  "A rock of unusual colouration is in the middle of the blaze."

The player carries a basket.  The basket is a container.

After taking the rock, say "Not surprisingly, the rock is too hot to touch.  You painfully jerk your hand back." instead.

Test me with "put rock in basket / i / l"

Try changing After to Instead of or commenting out the rule entirely and see how things change.

Regarding the original scenario, that’s working as expected for me (in 6M62, at least) as well:

There is a room.  In it is a sweater.  The sweater is wearable.

After taking the sweater, say "It's strangely musty." instead.

Test me with "wear sweater / i".
>[1] wear sweater
(first taking the sweater)
It's strangely musty.

You put on the sweater.

>[2] i
You are carrying:
  a sweater (being worn)

Though an interesting side-effect is that for implicit takes, the Report rules are normally not run, so these After rules result in printing extra text rather than replacing standard text (though they still do replace the standard text if you take sweater explicitly). There are ways to detect these cases and suppress the extra message for an implicit take (or only print it for the first take), when more appropriate.


Edit: Sorry, I just noticed this was tagged as I6 rather than I7. But still, perhaps this will provide some insight.

For an I6-based answer, it looks like the After routine is supposed to rtrue when it’s reporting a failure and rfalse when it’s reporting an alternative success message.

Assuming I’m reading the library code correctly (I don’t have I6 myself to test this out at present), in the latter case by default it will still print the default taking message. But you should be able to add before_implicit 1 to the object to suppress that, then you can rfalse from your after taking handler.

I’m not sure if that may have other undesirable effects. You may need to make it a routine so that you can check conditions such as the current action.


Actually, on more careful reading, I don’t think it invokes After taking for an implicit take at all. It can invoke “after ##LetGo” on the container that the object is in (not on the object itself), but that’s still after the take succeeds.

So I think you might need to provide some code that demonstrates the problem you’re seeing.

This is purely an Inform 6 question. And I’m not searching for ways to make my code behave a certain way. I’m saying that the library causes the main action to be aborted if the noun returns true for the implicit ##Take action, and I wonder if this is the way it should work. To me, it’s a surprising behaviour.

The after-routine for an object is called after the action has been performed but before the library has printed a message. Returning false means that the library should go on and print the standard message, while returning true means that the library should not print the standard message. None of these return values mean that the action has failed.

AFAIK, the idea behind after-routines is not to have actions fail (then you would just do it in a before-routine instead), but to either add some side-effect like setting a flag, starting or stopping a daemon/timer etc, or to print an alternate message. Of course, that alternate message could be alarming (“You pick up the pair of boots, noticing that they are full of scorpions!”). That doesn’t mean the take action has failed though.

Example:

Object Sweater “sweater”
has clothing
with
after [;
Take:
if(self hasnt general) {
give self general;
“As you pick it up, you notice there’s a small tag in the back of the neck.”;
}
];

2 Likes

Yes, it’s correct. Returning true to the library always means “job done”. In this case the implicit take has the wear action “wrapped around” it, so returning true from the “inner” Take action returns true from the “outer” Wear action, IYSWIM.

Imagine the player is in a shop, and the sweater is protected by an alarm, wired to Before Take on the sweater. You absolutely want the

“Feeling the warning tingle of electricity you jerk your hand back.”

message to return true and stop the action, otherwise wearing the sweater directly “off the peg” would introduce a bug.

Edited to remove my misleading misrememberings. :crazy_face:

Nope, you got it wrong.

Before an action happens, react_before is called for all objects in scope. That’s how they get a chance to react before an action has taken place.

And if the action isn’t stopped by any of the react_before or before-routines, or by the checks in the action sub, the action is performed and then the react_after routine of all objects in scope is called, and then the after routine for the noun. (Also, the location’s before and after are called, as well as the game’s global Pre and Post routines, but that’s not important for what we’re discussing.)

The golem guardian is exactly the kind of thing you use react_before for.

And if the Take fails, no after routines or react_after routines whatsoever will be called. Not for the noun, not for the room, not for anything in scope.

2 Likes

Ah well. Serves me right for trying to remember what I was doing ten years ago. But the answer to your question is still yes: returning true from an implicit take should stop the action.

This is how the 6/11 library worked.

I7 takes a different approach. It only interrupts the eating action if the implicit take fails to move the item to the player’s inventory. The success/failure of the implicit take action is ignored.

2 Likes