Silverware Factory Control Room is a room.
The description is "You can SET DIAL TO fork, knife, or spoon.".
A DialSetting is a kind of value. The DialSettings are fork, knife, and spoon.
A dial is here. The dial has a DialSetting.
The block setting it to rule is not listed in the check setting it to rulebook.
Check setting the dial to a topic (this is the make sure it's a valid setting rule):
If the topic understood matches "[DialSetting]":
now the DialSetting of the dial is the DialSetting understood;
Otherwise:
Say "Oops! That's not a valid setting.";
say "You tried to set the dial to '[Topic understood]'." instead.
Carry out setting the dial to a topic:
say "Okay, you set the dial."
Test me with "set dial to spoon / set dial to spoon."
I get this output:
Silverware Factory Control Room
You can SET DIAL TO fork, knife, or spoon.
You can see a dial here.
>test me
(Testing.)
>[1] set dial to spoon
Okay, you set the dial.
>[2] set dial to spoon.
Oops! That's not a valid setting.
You tried to set the dial to "
*** Run-time problem P39: Attempt to say a snippet value which is currently invalid: words 0 to 2.
".
>
So, “set dial to spoon” (without a period) works. If the player types “set dial to spoon.” with a period, it causes a run-time error. And things go wrong even before the runtime error, actually–I want “set dial to spoon.” to be an acceptable way to setting the dial to spoon, but the check rule is deciding that it’s invalid.
Is there a better way for me to check whether the player entered a valid setting?
[Edit: I moved the single quotation mark inside the period in the “You tried to set the dial to…” string, but that shouldn’t affect the original problem.]
Well, I would have created a new action applying to one DialSetting, but your way of understanding a kov as a topic appears to work just fine. In fact, if you type in anything other than “fork, knife, or spoon” the game behaves as expected:
>set dial to blah
Oops! That’s not a valid setting.
You tried to set the dial to “blah.”
The issue you’re running into is the period at the end. Inform’s standard way of dealing with periods is to use them to separate multiple commands. This causes the snippet to be reset. The explanation of the RTP in the results tab explains it:
A snippet is a fragment of the player’s current command, but it does not record the actual text: instead, it notes only the word numbers. (Thus in TAKE ME TO THE RIVER, a snippet would be words 2 to 4 rather than the text ME TO THE.) Snippets go out of date as soon as a new command has come along, so shouldn’t be kept in longer-term storage. At any rate, the one you’ve just tried to say goes outside the range of the current command, so it can’t be right.
The part about snippets going out of date is what you’re seeing. You could try Emily Short’s “Punctuation Removal” extension if you’re concerned that players will actually try using periods at the ends of their commands.
I added a temporary variable called player-entered-topic to hold the topic understood. So the run-time error is gone. But I see the original problem is also a problem for multiple commands. If there’s another command after the first one, that entire thing is included in the “topic”.
So if the player types
set dial to spoon. set dial to fork.
The player-entered-topic becomes “spoon. set dial to fork.”
So maybe I need to detect the first period in the snippet and somehow discard that period along with everything that comes after it before trying to match it?
Although I understand there are other command separators besides periods, so maybe that’s not reliable.
Revised code with temporary variable:
Silverware Factory Control Room is a room.
The description is "You can SET DIAL TO fork, knife, or spoon.".
A DialSetting is a kind of value. The DialSettings are fork, knife, and spoon.
A dial is here. The dial has a DialSetting.
The block setting it to rule is not listed in the check setting it to rulebook.
Check setting the dial to a topic (this is the make sure it's a valid setting rule):
let player-entered-topic be the topic understood;
say "The player-entered-topic is '[player-entered-topic]'[paragraph break]";
If the player-entered-topic matches "[DialSetting]" or the player-entered-topic matches "[DialSetting]":
now the DialSetting of the dial is the DialSetting understood;
Otherwise:
Say "Oops! That's not a valid setting.";
say "You tried to set the dial to '[player-entered-topic]'[paragraph break]" instead.
Carry out setting the dial to a topic:
say "Okay, you set the dial."
Test me with "set dial to spoon / set dial to spoon. set dial to fork. / set dial to blah".
New output:
Silverware Factory Control Room
You can SET DIAL TO fork, knife, or spoon.
You can see a dial here.
>test me
(Testing.)
>[1] set dial to spoon
The player-entered-topic is "spoon"
Okay, you set the dial.
>[2] set dial to spoon. set dial to fork.
The player-entered-topic is "spoon. set dial to fork."
Oops! That's not a valid setting.
You tried to set the dial to "spoon. set dial to fork."
>[3] set dial to blah
The player-entered-topic is "blah"
Oops! That's not a valid setting.
You tried to set the dial to "blah"
>
(In the real project, I’m also using the extension Before Processing a Command by @Draconis, but it doesn’t seem like including that makes a difference to the results of this sample code.)
Silverware Factory Control Room is a room.
The description is "You can SET DIAL TO fork, knife, or spoon.".
A DialSetting is a kind of value. The DialSettings are fork, knife, and spoon.
A dial is here. The dial has a DialSetting.
The block setting it to rule is not listed in the check setting it to rulebook.
dial setting is an action applying to one thing and one dialsetting. Understand "set [dial] to [DialSetting]" as dial setting.
Carry out dial setting the dial:
say "Okay, you set the dial."
Test me with "set dial to spoon / set dial to spoon."
You can actually use an action applying to a DialSetting for the “real” action and rely on the standard action (applying to topics) to continue to catch the invalid entries in order to give helpful error messages. This seems to handle everything except an invalid DialSetting followed by a valid one in the same command, separated by a period.
Yeah, unfortunately topics in Inform are pretty fragile compared to other data types. I’m surprised topic parsing doesn’t end at a period or “then”, though (THEN*__WD); that strikes me as a bug.
It looks like what happens in this case is the second command gets ignored. Could be worse!
Also, I guess I should avoid quoting the invalid “topic” back to the player, in case it’s something silly like “forks. set the dial to spoon.”