So! As @DeusIrae shared, he had trouble opening a door in ‘course correction’:
> OPEN DOOR
There are way too many guards for that to have any chance of working.
The problem is, the door was already open! I admit to being slightly salty about this, as I felt like I had been promised that writing ‘check’ routines would avoid this sort of thing:
Check opening Garden Door:
say “There are way too many guards for that to have any chance of working.” instead.
And I blithely assumed that this meant I didn’t have to worry about ‘world model’ checks like ‘the door is already open’.
However, it makes sense in retrospect: they’re both ‘check’ routines, and in theory, any one of them could result in failure, so it doesn’t normally matter which one executes first.
But here, it clearly does. So. I could write:
Check opening Garden Door when the garden door is closed:
say “There are way too many guards for that to have any chance of working.” instead.
but that just means I have do add a ‘when’ clause for that and every other world-model check, which seems like the wrong approach.
But ISTR there’s a ‘list rule X before/after rule Y’ construct in I7? Is my vague memory correct, and could I use it here?
You could indeed! The default ordering is that more specific rules come first, and “this one door, whether or not it’s open” is considered more specific than “any door that’s open”.
But if you call it “last check” instead of just “check”, it will go after all the other checks, regardless of specificity. (You can also put it right after the rule you want, but that’s more fiddly and requires looking up specific rule names, and I’m lazy.)
Nice! Thank you. The phrase ‘last check’ doesn’t seem to appear in the I7 docs, but ‘first check’ does (though with no explanation; it’s just used in an example): I assume it does the same thing, in reverse?
And then if you have multiple first checks and last checks, they get executed in order of specificity again?
All ‘first check’ rules, in internal order of their specificity
All ‘check’ rules, in internal order of their specificity
All ‘last check’ rules, in internal order of their specificity
Does the standard library contain any first checks or last checks, or could one assume that they’re solely the domain of the author (/extension writer)?
I haven’t looked at your code so as not to spoil Course Correction, which I haven’t completed yet. However, based on the code in your post, you could just change the specificity of the rule in question by moving the condition from the header into the body:
Check an actor opening:
if the noun is Garden Door, say “There are way too many guards for that to have any chance of working.” instead.
Note that I used “an actor opening” which is the preamble used for the standard check rules for opening (can’t open unless openable rule, can’t open what’s locked rule, and can’t open what’s already open rule). This will cause the new rule to follow those because rules with names are followed before unnamed ones when the specificity in the preamble is the same.
Indeed, you can put “first” or “last” before any rulebook name to override the normal sorting. “First after printing the name of something”, “last when play begins”, and so on. I’ll look up the WI reference when I’m at my laptop.
Thanks for cleaning this up! Though I think my being blocked here was mostly just fuzzy-headedness from being sick when I played (sadly, this is also why I forgot to make a transcript).
Fun fact: when I was writing my first game, I ran into this same issue of needing to manipulate the order rule fired in, but also found the docs less than helpful in telling me how to do that. But I did notice an early bit saying that rules with more specific conditions have priority over more general ones, so I started larding my rules up with various always-true conditionals to arrange them into the order I wanted.
A last turn sequence rule: follow the scene changing rules. [3rd from last.]
The adjust light rule is listed last in the turn sequence rulebook. [2nd from last.]
The note object acquisitions rule is listed last in the turn sequence rulebook. [Penultimate.]
The notify score changes rule is listed last in the turn sequence rulebook. [Last.]
Note that this shows the true behavior of “Last” – a “last” rule is only last until another “last” rule after it in the code is declared last, making the previous “last” rule second-to-last, until… well see the code.
This is also true with “first,” as in this from the standard rules:
A first turn sequence rule (this is the every turn stage rule): follow the every turn rules. [5th.]
A first turn sequence rule: follow the scene changing rules. [4th.]
The generate action rule is listed first in the turn sequence rulebook. [3rd.]
The declare everything initially unmentioned rule is listed first in the turn sequence rulebook. [2nd.]
The parse command rule is listed first in the turn sequence rulebook. [1st.]
This is why I always name my rules, so I can explicitly place them if needed.
Pretty sure “order of source code” is determined solely by story.ni.
So, default library first (Basic Inform → Standard Rules → English Language → optional second language), then work through the story.ni, and any extension stuff is plopped in at the point it’s included.
First and last check aren’t separate rulebooks, just a rule for listing in the check rulebook. So, if some rule is explicitly list after a “last” rule, I’m pretty sure that rule will indeed be after that “last” rule.
The action rules in the Standard Rules don’t use preambles, so their order is just determined by order of appearance in the source. This is a good idea in that context that makes them much more readable.
When you’re adding a check rule of your own, you’ll definitely want to look at the existing rules and choose a specific place for it and use <new rule name> rule is listed after the <whatever> rule in the check <action name> rules. If you’re adding carry out or report rules, the same applies, though most actions have at most one of each so those cases tend to be much simpler (examining being one conspicuous exception with a lot of carry out rules).
Specificity only matters when rules have preambles. In the absence of preambles (or more explicit indications of placement), order of occurrence in the source becomes the determinant.
Wait, so are the Standard Rules not subject to the ‘rule of specificity’, but only to ‘order in the source’? Is it just extension/story.ni rules that get sorted that way?
I had been editing my entry to add what’s now it’s final paragraph before I saw your reply.
The compiler ignores the contents of rules’ code blocks for the purposes of quantifying specificity. Whatever conditionals occur there are irrelevant. Only preambles matter.
So it’s not that the compiler is special-casing the Standard Rules, it’s that the action rules in the Standard Rules have been written such that the compiler’s normal behavior results in their order being straightforwardly determined by order of occurrence in the source.
Check an actor dropping (this is the can't drop yourself rule):
Check an actor dropping something which is part of the actor (this is the
can't drop body parts rule):
The second one is more specific than the first, and indeed it is placed before the first for specificity reasons.
I read WI §19.7 The preamble of a rule to mean that everything before the colon is the preamble. So “Check an actor dropping” is the preamble. I think I would phrase it as “most of the preambles to action rules in the Standard Rules don’t contain additional specificity beyond the rulebook name,” although I admit that’s a bit of a mouthful.
Yeah, I wasn’t sure what was ‘pre’ about ‘preamble’ if it was supposed to mean the part after ‘check an X Ying’. ‘The entire bit before the colon’ at least makes sense in that regard.
All correct. I usually choose going into the weeds and expending lots more words over knowingly saying something imprecise. I really thought there was no payoff in this case, but apparently I chose incorrectly.
So I’ve learned my lesson and so my pedantry will be unrestrained, terrible, and merciless. This, I swear.