Supplied missing noun forgotten by end of turn (so scene change fails)?

I ran into something strange: A supplied missing noun seems to stop being the noun after conclusion of the action processing rules. One significant side effect is that this can cause conditions using the noun (or a condition on the current action) in every turn or scene-changing rules to fail unexpectedly. Here’s a sample scenario:

"Lost the Noun"

Place is a room.

A cat is a kind of animal. Four cats are in Place.

Petting is an action applying to one thing. Understand "pet" or "pet [something]" as petting.

Report petting:
    say "You pet [the noun]."

Rule for supplying a missing noun while petting:
    now the noun is a random cat that can be seen by the player;
    if the noun is nothing:
	    say "Nothing to be pet here." instead.

Every turn:
    say "ca = [current action].";
    showme whether or not petting a cat.

Purring is a recurring scene.

Purring begins when petting a cat.

When Purring begins:
    say "Purring begins."

Purring ends when jumping.

When Purring ends:
    say "No more purring."

Test me with "scenes / actions / pet cat / jump / pet cat / jump / pet".

with a player-specified noun, output is:

[petting the cat]
You pet the cat.
[petting the cat - succeeded]

[Scene 'Purring' begins]
Purring begins.

ca = petting the cat.
"whether or not petting a cat" = truth state: true

but with a supplied noun, output is:

[petting the cat]
You pet the cat.
[petting the cat - succeeded]

ca = petting nothing.
"whether or not petting a cat" = truth state: false

What is the root cause here? Can it be fixed? (I couldn’t seem to find the point at which the assigned noun is forgotten.)


Looks like it happens here:

[ BeginAction a n s moi notrack  rv;

        @push action; @push noun; @push second; @push self; @push multiple_object_item;

        action = a; noun = n; second = s; self = noun; multiple_object_item = moi;
        if (action < 4096) rv = ActionPrimitive();

        @pull multiple_object_item; @pull self; @pull second; @pull noun; @pull action;

        if (notrack == false) TrackActions(true, meta);
        return rv;

ActionPrimitive is where the missing noun gets assigned to the noun variable. After we get back from ActionPrimitive, noun’s original null value is pulled from the stack.

This seems to be adequate to ameliorate it:

Include (-
Global emergency_backup_noun;
-) after "Definitions.i6t".

Emergency backup noun is an object that varies.
The emergency backup noun variable translates into I6 as "emergency_backup_noun".

Before trying doing anything (this is the backup noun rule): now the emergency backup noun is the noun.
First scene changing rule (this is the restore noun from backup rule): now the noun is the emergency backup noun.

Strictly, these lines look to be redundant? Or is there otherwise an issue with compiler sequencing?

That example doesn’t need an I6 variable at all, looks like.

1 Like

I don’t think it’s documented that the “original” action/noun/second-noun values persist through to the every-turn stage. They do in most cases, but there are other situations where you can’t rely on that. (The most obvious is TAKE LAMP, SWORD. With multiple objects, obviously, only the last one can still be held in noun.)

You can use declarations like “Purring ends when we have jumped” to avoid this uncertainty. I admit this gets tricky with recurring scenes. I haven’t found a better solution than setting a flag and clearing it in an every-turn rule.

1 Like

Or, say you decide to redirect some actions and write

Instead of touching the cat:
    try petting the cat.

This again leaves the end-of-turn variables in a state you might not handle correctly. Honestly, flags are safer.

On the contrary, it’s kind of documented that they in fact do not. In the section “Stored actions” of the chapter “Advanced Actions”:

[The current action] only makes sense if an action is currently going on, so it shouldn’t be used in “every turn” rules, for instance.

And the output of the ACTIONS command does say that petting the cat succeeded (i.e. is not going on anymore), so it checks out.


Yeah, the I6 variable was unnecessary, a vestige of a previous concept.

This is maybe a better approach:

The previous action is an action that varies.
Before trying doing anything, now the previous action is the current action.

Every turn (this is the previous action tracker rule):
    say "ca = [previous action].";
    showme whether or not the previous action is petting a cat.

Purring begins when the previous action is petting a cat.

I’m marking Zed’s answer as the solution (with a thank you) because it accomplishes what I wanted, but I also want to thank @zarf for the important point about this not being a reliable method in general and @Natrium729 for the citation of the documentation discouraging this approach.

1 Like