Reporting and changing state

This is essentially a style question. Consider the following situation:

carry out blessing someone when the noun is cursed:
    now the noun is not cursed;

report blessing someone when the noun is cursed:
    say "You have saved [the noun]!";

Of course the report rule won’t work because the noun is no longer cursed at that point. So my question is, what is the “proper” way to do this? I could add an action variable to track a lifted curse, but that seems really ugly. I could do it all in an instead rule, but that seems the wrong place to use instead. It would be nice if inform allowed comparing pre-action state to post-action state.

I had to think about this because I barely use any report rules because of these kind of minor logic conundrums.

I reckon for normal people who aren’t me, what you want to do is first create conditions for the blessing action. In other words – stop the player blessing things that aren’t cursed. For a rulebook to reach the Carry Out stage, the action should be considered to be succeeding. And after that, the Report rule can safely talk about success.

Here’s a demonstration:

Church is a room.

a thing can be cursed.

Jane is a woman in church. Jane is cursed.

blessing is an action applying to one thing.

Understand "bless [someone]" as blessing.

Check blessing:
	unless the noun is cursed:
		instead say "[The noun] isn't cursed.";
		
Carry out blessing:
    now the noun is not cursed;

Report blessing:
	say "You have saved [the noun]!";

Test me with "bless jane/bless jane".

-Wade

3 Likes

Take a look at WWI 9.13 The past and perfect tenses.

carry out blessing someone when the noun is cursed:
    now the noun is not cursed;

report blessing someone when the noun was cursed: [probably also want a general report rule]
    say "You have saved [the noun]!";
1 Like

I had the same idea re has, but when I tested it on Borogrove it wouldn’t compile - the warning in the docs about using “was” with a variable appears to have turned into a prohibition at some point, it looks like (I don’t know enough about the action processing underpinnings to know whether the warning is right and the logic wouldn’t work even if it did compile):

Problem. You wrote ‘report blessing someone when the noun was cursed’ (line 10): but it is misleading to talk about the noun, the second noun or the person asked to do something in past tenses, because in the past, those were different things and people, or may have been nothing at all. Writing ‘if the noun has been unlocked’ tends not to do what we might hope because the value of ‘noun’ changes every turn. So such conditions are not allowed, although to get around this we can instead write ‘if we have unlocked the noun’, which uses a special mechanism to remember everything which has happened to every object.

The warning is usefully saving us from ourselves: “was” wouldn’t yield the desired result until after the update chronological records rule, which comes after action processing.

(previous description of turn sequence following the action)

2 Likes

Interesting. See also WWI 12.10 Action variables.

"Blessing"

Place is a room.

A person can be blessed.

Alice is a blessed woman in Place.

Bob is a man in Place.

Blessing is an action applying to one thing. Understand "bless [something]" as blessing. The blessing action has a thing called blessee. The blessing action has a truth state called newly saved.

Setting action variables for blessing:
    now the blessee is the noun;
    unless blessee is blessed:
	    now newly saved is true.

Carry out blessing something:
    now the blessee is blessed.

Report blessing when newly saved is true:
    say "You have saved [the blessee]!";
    rule succeeds. [halt report rulebook]

Report blessing:
    say "[The noun] stays blessed."

Test me with "bless alice / bless bob / bless bob".

But @severedhand’s solution is probably the better way to go.

1 Like

But this doesn’t seem to be what WII is warning us about:

Next is the past tense:

if X was Y …

holds if and only if “X is Y” was true at the start of the most recent action. This is convenient when trying to describe what has changed in the course of the action, but sometimes also when making the action itself happen. For instance:

if the lantern was switched on, now the lantern is switched off;
if the lantern was switched off, now the lantern is switched on;

I read “most recent action” as the ongoing action, if there is one, which seems to be implied by the lantern example.

But more confusing to me is the “don’t use noun in the past tense” passage:

Something we must watch out for is that variables might not have the same values in the past that they have now. As a result, writing conditions such as “if the noun has been open” is a bad idea, because in the past “the noun” very likely referred to something different. It is really only safe to talk in the past tense about definite, fixed things: “if the Great Gates of Kiev have been open” would be fine.

This seems strange to me, for two reasons:

  1. Shouldn’t noun stay constant during the course of action processing, once it has been assigned?
  2. Why wouldn’t the value of noun be resolved in the present tense rather than the past? I.e., even if noun had changed in the recent past, why aren’t we using the value of noun at the time a rule is invoked?
1 Like

This works unless you want blessing to work differently in different situations. I could use instead for that, but my understanding was that instead had drawbacks, such as not recording that the action in question had occurred.

Depending on how much variation you have where, you could maybe sort them into two actions.

A thing can be cursed or uncursed.
Cursed-blessing is an action applying to one thing.
Uncursed-blessing is an action applying to one thing.
Understand "bless [cursed thing]" as cursed-blessing.
Understand "bless [uncursed thing]" as uncursed-blessing.

The docs could be much clearer on this point. Consider this code, and this will confuse more than enlighten until you stare at it a while – sorry.

The lantern is an unlit switched off device.
The player carries the lantern.
understand "lamp" as the lantern.
carry out switching on the lantern: now the lantern is lit.
carry out switching off the lantern: now the lantern is unlit.

to carp (T - a text):
say "Turn [turn count]. [T] the lantern is [if lantern is unlit]un[end if]lit.";
say "Turn [turn count]. [T] the lantern was [if lantern was unlit]un[end if]lit."

before doing anything: carp "Before".

last report switching on: carp "Report".
last report switching off: carp "Report".

every turn: carp "Every".
foo is initially true.
After reading a command when foo is true, now foo is false.
Toggle is a recurring scene.
Toggle has a number called the tc.
Toggle begins when foo is false.
Toggle ends when turn count > tc of toggle.
When toggle begins: now tc of toggle is turn count; now foo is true; carp "first scene check".
When toggle ends: carp "second scene check".
test me with "turn on lamp / z / turn off lamp".

it would produce this session:

Turn 1. Before the lantern is unlit.
Turn 1. Before the lantern was unlit.
 
Lab
 
>test me
(Testing.)
 
>[1] turn on lamp
Turn 1. Before the lantern is unlit.
Turn 1. Before the lantern was unlit.
 
You switch the lantern on.
 
Turn 1. Report the lantern is lit.
Turn 1. Report the lantern was unlit.
 
Turn 1. first scene check the lantern is lit.
Turn 1. first scene check the lantern was unlit.
 
Turn 1. Every the lantern is lit.
Turn 1. Every the lantern was unlit.
 
Turn 2. second scene check the lantern is lit.
Turn 2. second scene check the lantern was lit.
 
>[2] z
Turn 2. Before the lantern is lit.
Turn 2. Before the lantern was lit.
 
Time passes.
 
Turn 2. first scene check the lantern is lit.
Turn 2. first scene check the lantern was lit.
 
Turn 2. Every the lantern is lit.
Turn 2. Every the lantern was lit.
 
Turn 3. second scene check the lantern is lit.
Turn 3. second scene check the lantern was lit.
 
>[3] turn off lamp
Turn 3. Before the lantern is lit.
Turn 3. Before the lantern was lit.
 
You switch the lantern off.
 
Turn 3. Report the lantern is unlit.
Turn 3. Report the lantern was lit.
 
Turn 3. first scene check the lantern is unlit.
Turn 3. first scene check the lantern was lit.
 
Turn 3. Every the lantern is unlit.
Turn 3. Every the lantern was lit.
 
Turn 4. second scene check the lantern is unlit.
Turn 4. second scene check the lantern was unlit.
 
> 

As I described above, the reckoning of “was” states happens in the update chronological records rule, which happens almost at the end of the turn sequence (right after the turn count is incremented) and before the second check for whether scenes begin or end. The update chronological records rule is also followed once at the start of the game before the initial command prompt. so if X was Y is really asking “Was X Y at the moment of the previous following of the update chronological records rule?”

Edited: I realized this would be more useful with rules tracing.

Rules-traced example Lab

Untitled

An Interactive Fiction

Release 1 / Serial number 220519 / Inform 7 v10.1.0 / D

Turn 1. Before the lantern is unlit.

Turn 1. Before the lantern was unlit.

Lab

test me

(Testing.)

[1] rules

Rules tracing now switched on. Type “rules off” to switch it off again, or “rules all” to include even rules which do not apply.

[Rule “parse command rule” applies.]

[2] turn on lamp

[Rule “declare everything initially unmentioned rule” applies.]
[Rule “generate action rule” applies.]
[Rule “announce items from multiple object lists rule” applies.]
[Rule “set pronouns from items from multiple object lists rule” applies.]
[Rule “before stage rule” applies.]
[Rule “before doing anything” applies.]
Turn 1. Before the lantern is unlit.

Turn 1. Before the lantern was unlit.

[Rule “basic visibility rule” applies.]
[Rule “basic accessibility rule” applies.]
[Rule “access through barriers rule” applies.]
[Rule “carrying requirements rule” applies.]
[Rule “instead stage rule” applies.]
[Rule “requested actions require persuasion rule” applies.]
[Rule “carry out requested actions rule” applies.]
[Rule “descend to specific action-processing rule” applies.]
[Rule “work out details of specific action rule” applies.]
[Rule “investigate player’s awareness before action rule” applies.]
[Rule “player aware of his own actions rule” applies.]
[Rule “check stage rule” applies.]
[Rule “can’t switch on unless switchable rule” applies.]
[Rule “can’t switch on what’s already on rule” applies.]
[Rule “carry out stage rule” applies.]
[Rule “carry out switching on the lantern” applies.]
[Rule “standard switching on rule” applies.]
[Rule “after stage rule” applies.]
[Rule “investigate player’s awareness after action rule” applies.]
[Rule “report stage rule” applies.]
[Rule “standard report switching on rule” applies.]
You switch the lantern on.

[Rule “last report switching on” applies.]
Turn 1. Report the lantern is lit.

Turn 1. Report the lantern was unlit.

[Rule “last specific action-processing rule” applies.]
[Rule “A first turn sequence rule” applies.]
[Rule “scene change machinery rule” applies.]
[Rule “scene description text rule” applies.]
[Rule “When toggle begins” applies.]
Turn 1. first scene check the lantern is lit.

Turn 1. first scene check the lantern was unlit.

[Rule “every turn stage rule” applies.]

[Rule “every turn stage rule” applies.]
[Rule “every turn” applies.]
Turn 1. Every the lantern is lit.

Turn 1. Every the lantern was unlit.

[Rule “timed events rule” applies.]
[Rule “advance time rule” applies.]
[Rule “update chronological records rule” applies.]
[Rule “A last turn sequence rule” applies.]
[Rule “scene change machinery rule” applies.]
[Rule “When toggle ends” applies.]
Turn 2. second scene check the lantern is lit.

Turn 2. second scene check the lantern was lit.

[Rule “adjust light rule” applies.]
[Rule “note object acquisitions rule” applies.]
[Rule “notify score changes rule” applies.]
[Rule “parse command rule” applies.]

[3] z

[Rule “After reading a command when foo is true” applies.]
[Rule “declare everything initially unmentioned rule” applies.]
[Rule “generate action rule” applies.]
[Rule “announce items from multiple object lists rule” applies.]
[Rule “set pronouns from items from multiple object lists rule” applies.]
[Rule “before stage rule” applies.]
[Rule “before doing anything” applies.]
Turn 2. Before the lantern is lit.

Turn 2. Before the lantern was lit.

[Rule “basic visibility rule” applies.]
[Rule “basic accessibility rule” applies.]
[Rule “carrying requirements rule” applies.]
[Rule “instead stage rule” applies.]
[Rule “requested actions require persuasion rule” applies.]
[Rule “carry out requested actions rule” applies.]
[Rule “descend to specific action-processing rule” applies.]
[Rule “work out details of specific action rule” applies.]
[Rule “investigate player’s awareness before action rule” applies.]
[Rule “player aware of his own actions rule” applies.]
[Rule “check stage rule” applies.]
[Rule “carry out stage rule” applies.]
[Rule “after stage rule” applies.]
[Rule “investigate player’s awareness after action rule” applies.]
[Rule “report stage rule” applies.]
[Rule “standard report waiting rule” applies.]
Time passes.

[Rule “last specific action-processing rule” applies.]
[Rule “A first turn sequence rule” applies.]
[Rule “scene change machinery rule” applies.]
[Rule “scene description text rule” applies.]
[Rule “When toggle begins” applies.]
Turn 2. first scene check the lantern is lit.

Turn 2. first scene check the lantern was lit.

[Rule “every turn stage rule” applies.]
[Rule “every turn” applies.]
Turn 2. Every the lantern is lit.

Turn 2. Every the lantern was lit.

[Rule “timed events rule” applies.]
[Rule “advance time rule” applies.]
[Rule “update chronological records rule” applies.]
[Rule “A last turn sequence rule” applies.]
[Rule “scene change machinery rule” applies.]
[Rule “When toggle ends” applies.]
Turn 3. second scene check the lantern is lit.

Turn 3. second scene check the lantern was lit.

[Rule “adjust light rule” applies.]
[Rule “note object acquisitions rule” applies.]
[Rule “notify score changes rule” applies.]
[Rule “parse command rule” applies.]

[4] turn off lamp

[Rule “After reading a command when foo is true” applies.]
[Rule “declare everything initially unmentioned rule” applies.]
[Rule “generate action rule” applies.]
[Rule “announce items from multiple object lists rule” applies.]
[Rule “set pronouns from items from multiple object lists rule” applies.]
[Rule “before stage rule” applies.]
[Rule “before doing anything” applies.]
Turn 3. Before the lantern is lit.

Turn 3. Before the lantern was lit.

[Rule “basic visibility rule” applies.]
[Rule “basic accessibility rule” applies.]
[Rule “access through barriers rule” applies.]
[Rule “carrying requirements rule” applies.]
[Rule “instead stage rule” applies.]
[Rule “requested actions require persuasion rule” applies.]
[Rule “carry out requested actions rule” applies.]
[Rule “descend to specific action-processing rule” applies.]
[Rule “work out details of specific action rule” applies.]
[Rule “investigate player’s awareness before action rule” applies.]
[Rule “player aware of his own actions rule” applies.]
[Rule “check stage rule” applies.]
[Rule “can’t switch off unless switchable rule” applies.]
[Rule “can’t switch off what’s already off rule” applies.]
[Rule “carry out stage rule” applies.]
[Rule “carry out switching off the lantern” applies.]
[Rule “standard switching off rule” applies.]
[Rule “after stage rule” applies.]
[Rule “investigate player’s awareness after action rule” applies.]
[Rule “report stage rule” applies.]
[Rule “standard report switching off rule” applies.]
You switch the lantern off.

[Rule “last report switching off” applies.]
Turn 3. Report the lantern is unlit.

Turn 3. Report the lantern was lit.

[Rule “last specific action-processing rule” applies.]
[Rule “A first turn sequence rule” applies.]
[Rule “scene change machinery rule” applies.]
[Rule “scene description text rule” applies.]
[Rule “When toggle begins” applies.]
Turn 3. first scene check the lantern is unlit.

Turn 3. first scene check the lantern was lit.

[Rule “every turn stage rule” applies.]
[Rule “every turn” applies.]
Turn 3. Every the lantern is unlit.

Turn 3. Every the lantern was lit.

[Rule “timed events rule” applies.]
[Rule “advance time rule” applies.]
[Rule “update chronological records rule” applies.]
[Rule “A last turn sequence rule” applies.]
[Rule “scene change machinery rule” applies.]
[Rule “When toggle ends” applies.]
Turn 4. second scene check the lantern is unlit.

Turn 4. second scene check the lantern was unlit.

[Rule “adjust light rule” applies.]
[Rule “note object acquisitions rule” applies.]
[Rule “notify score changes rule” applies.]
[Rule “parse command rule” applies.]

This looks correct.

Since you have a check rule that will fail blessing unless the noun is cursed, you have a carry out that removes the curse. The report rule won’t fire unless it’s gotten through the carry out phase, so you technically don’t need to know whether the item was cursed or not, since the action fails if it wasn’t.

bless father

Father Goodfellow isn’t cursed.

bless jane

You have saved Jane!

bless jane

Jane isn’t cursed.

The issue is with the way that the subsystem for handling past tenses works.

Specifically, the problem message is objecting to the use of the noun in the noun was not blessed.

To expand on Zed’s answer: Every time the update chronological records rule is run (at the end of the turn sequence rulebook by default), the truth states for the was condition are updated. The was condition in the report rule would basically just pull this truth state from storage; it would not look at the world state. (You can consider the storage of chronological records as being logged by condition ID. It would take a lot more storage to reflect the entire world state of the previous turn.) Were the compiler to accept the noun was blessed, there is the strong possibility of a mismatch between the value of the noun at two different times: when the chronological records are being updated and when the report rule is being evaluated for applicability.

The value of the noun may not be what you expect at the end of the turn sequence (i.e. when chronological records are updated). For example, if a missing noun was supplied, it will be dropped and returned to nothing after the action is processed. In that case the condition would evaluate true when the report rule is being processed, but it would not reflect the intended meaning, because the value stored would be based on whether or not nothing is not blessed was true when the record was last updated. Likewise, if the action applies to multiple objects, only the last object will be the noun at the end of the turn sequence. In that case, it would be a matter of happenstance whether the value of the noun were the same at both the point when the chronological record was updated and the point when the was condition was being evaluated.

Action variables (like temporary variables) are also prohibited from use in was conditions; they won’t be treated as in scope at the end of the turn sequence because action processing is already over.

1 Like

Okay, I can see what you’re all saying. I guess my gripe is that it feels like the noun variable shouldn’t be treated as part of the world model. If I were implementing an IF system in an object-oriented language like Java, for instance, the Action Processing subsystem would be entirely separate from the World Model, which would be entirely separate from the Parser subsystem, which would be separate from the Presentation Layer, etc.

But beggars can’t be choosers, and Inform 7 is great in so many other ways (for instance, I love its excellent type inference) that I can’t really complain.

It’s not really a question of separating subsystems. There’s a genuine linguistic ambiguity there. Like if you asked “How many times has the President of the US been assassinated?” the correct answer could be either “Four” or “Zero, he’s still alive!” If you ask the question one way and the listener hears it the other, you’ll both be deeply confused.

In this situation, it seems obvious how to interpret “the noun was blessed”, but in other cases the other way will be “obviously” correct.

However, like Otis said, the practicalities matter. You want the system to interpret “the noun” as Jane (its current value) and then interrogate the game history to determine whether “Jane is cursed” was ever true. But that would require the game to store its entire history forever, or at least the curse history of every game object. It just doesn’t do that. It can store counters and flags for a small list of named conditions.

3 Likes

It’s not (or I can’t think of how I could describe it as such). Noun is a variable. I7 doesn’t actually have much knowledge of the past in general. When your code contains “if the lantern was lit” anywhere, the I7 compiler notes it has to track lantern-lit-ness so it can answer the “was lantern lit” question wherever it comes up. It can’t answer questions about other things’ lit-ness-as-of-previous-turn unless it knew from the start that it was supposed to track it.

But as a special, not-well-documented case it does track whether a given action has ever succeeded with a given object, which you can test with if we have switched on the lamp and this becomes true immediately after action processing finishes: it’s true when the initial scene change check occurs.

4 Likes

Aha! Thanks. This is clearly what otis and zarf were talking about, in retrospect. I only need to be told things three times.

1 Like