Specific input loop

In your example, you’re still declaring the “outcome” variable inside a rule (the instead rule), so your after reading a command rule won’t recognize it. I think you’re going for something like this:

[code]Test Chamber is a room.

A man called Steve is in the Test Chamber.

The outcome is some text that varies.

Instead of asking Steve about something:
now outcome is “”;

After reading a command while outcome is “”:
now outcome is “[player’s command]”;
if outcome is “foo”:
say “FOO!”;
otherwise if outcome is “BAR”:
say “BAR!”;
otherwise:
say “ERROR!”;
reject the player’s command;
[/code]

That compiles, although I’m not 100% it will do what you want. A few observations:

  1. When you declare outcome as a text that varies, it will initially start out as an empty string (“”), which means that the very first command of the game will trigger your after reading a command rule. Unless that’s what you want to happen, you might want to set outcome initially to some arbitrary default value.

  2. Be aware that the “reading a command” rules are checked long before the instead rules are ever triggered. That means that when you try to talk to Steve, the game will first do nothing, then it will start the next turn, and THEN it will check the player’s input for “foo” or “bar”.

  3. When the after reading a command rules are finished, they allow the parser to proceed as normal unless you specify to “reject the player’s command.” Otherwise you’ll get output like this:

Which was why I wanted to make the outcome a local variable. I was hoping that by declaring the “After reading a command” rule inside the “Instead” rule, the “after reading” rule would be within scope to see that local variable.

But otherwise, thanks, that’s really helpful.

You can’t declare a rule inside another rule. Inform is assuming that when you declare the after reading a command rule, you’re starting a brand new rule, and it’s filing each of them away in their respective rulebooks where they belong.

Putting a rule inside a rule is somewhat like trying to define a function inside another function in C. Doesn’t work that way.

I’ve been toying with combining this approach with a scene, where the scene is effectively a conditional. The scene is triggered by talking to a character. While the scene is happening, enter an input loop.

The issue I’m having now is ending the scene. Is there a condition that goes “The scene ends when a command is read.” Or even “The scene ends when a command is read during the scene.”?

It sounds like you’re trying to have Inform interact with an external program that handles the input some of the time. This will require some non-standard kind of extension or interface. Maybe Vorple or something involving Unified Glulx Input (I’m not sure if the latest version is on zarf’s official sites, but here is a version that fixes a bug that popped up recently.) There was also something someone did that had Inform talking to Javascript but I can’t find it at the moment.

(It might in theory be possible to hack it up by manipulating the “For reading a command” activity and using external files, but I wouldn’t try this. That is to say, I did try this, and it hurt my head.)

One thing is that almost all the things we’ve suggested presuppose a normal input loop in which the player types something and the game processes it. You can’t do “The scene ends when a command is read”–a scene ends at the end of a turn, and the turn is going to be triggered by a command being entered and processed. (There can be exceptions, I guess, but they won’t help here.) The normal “For reading a command” rules also have the player type in something; using them, you can’t have the program go into a state where it awaits input and then run the “After reading a command” rules, because the way the program awaits input is by having the player type something.

Again, there are ways to have Inform talk to an external program, but it’s not something that you can make happen out of the box.

Sorry if I’ve misunderstood what you’re asking here, but insofar as you want Inform to be drawing inputs from an external program, that’s not something Inform routinely does.

The sending output and receiving input to an external program part I’ve already got sorted. I just need a tidy way to end the scene as soon as a valid command has been entered.

(I’ve also tried using a truth state that I set to true as soon as a valid command is received, but my “The scene ends when [truth state] is true” doesn’t seem to get triggered by the “now [truth state] is true”.)

Although I’ve just noticed that scenes only fire once? It won’t fire each time the player talks to a character. So maybe scenes aren’t the best way to do this.

OK, I think I misunderstood what you were using scenes for and what you meant by “a command is read.” Is this the current situation:

Sometimes you start a scene that activates your special input program.

The player interacts with an input program to eventually produce an output. (I’m picturing something like Ultimate Flirt-Off.)

Once the program produces an output, it gets sent to the Inform program.

Now you need a way to end the scene?

I’m not a scene expert, but this seems like something that should be doable. You can set a flag that determines whether the scene ends:

[code]Conversation happened is a truth state that varies. [note: The name of the variable is “conversation happenedd.” It’s like conversation_happened; the individual words don’t have a special role]

Talking to Steve is a scene. Talking to Steve begins when [your condition here]. Talking to Steve ends when conversation happened is true.

When talking to Steve begins: now conversation happened is false.[/code]

And the question is where to set the flag. You can set it at the beginning of the action-processing rules:

First before during Taking to Steve: now conversation happened is true.

…I was going to add something here about trying it during the After reading a command rules, but the scene-changing machinery doesn’t run until the end of a turn. so that won’t work. It might be possible to make the machinery run other times, but I’m not sure if that’ll work.

Here’s a sample of scene-changing machinery, without the cool external conversation mechanics of course:

[code]Lab is a room. The huge box is an enterable closed openable container in Lab. Steve is a man in the huge box.

Conversation happened is a truth state that varies.

Talking to Steve is a scene. Talking to Steve begins when Steve is visible. Talking to Steve ends when conversation happened is true.

When Talking to Steve begins: now conversation happened is false.

First before during Talking to Steve: now conversation happened is true.

When Talking to Steve ends: say “Conversation ended.”[/code]

This scene will only run once. If you want a scene that runs more than once, you have to declare it a “recurring” scene. (And while I was typing, I see that you’ve asked a question about this! Yes, recurring scenes are what you want.)

Hope this helps–let me know what I’ve misunderstood!

I may be missing something, but it sounds like just setting a global true/false variable would be simpler than setting up a scene, especially if it’s a state that can be triggered more-or-less arbitrarily whenever the player tries to talk to someone.

[code]Limited Input Mode is a truth state that varies. Limited Input Mode is initially false.

After reading a command while Limited Input Mode is true:
[do all the funky things you’re trying to do];[/code]

It may also help to get a sense of how the various rulebooks are ordered in the main gameplay loop, since it sounds like you’re trying to make decisions based on some fairly specific timing. This chart is very detailed but thorough (it’s also slightly out of date – it references “procedural rules”, which have been deprecated – but otherwise it’s still accurate).

Here you can see why a scene doesn’t necessarily stop or start the moment you change the condition it hinges on, and why a scene might not be the best way to handle your particular problem. Scene conditions aren’t checked until near the end of the turn sequence (they’re actually checked twice, once before and once after the every turn rules are checked), after the player’s input has been parsed and translated into an action. If you’re continually interrupting the turn sequence at the “reading a command” stage, which is at the very beginning, and not allowing the player’s input to be processed in the normal way, then the turn is never going to get to the point where it checks to see if the scene should end, and so the scene never will.

Thanks matt,

The issue I’m having is ending the scene. When the external program sends back its input, I need to handle that myself with a bunch of “if the player’s command includes X” clauses, and then I have to reject the player’s command so they don’t get a “that’s not a verb I recognise” message. But this means that the turn count doesn’t increase, which seems to prevent the scene from ending even if it’s end condition becomes true.

(I also tried making my scene a recurring scene, but it sent the game into a loop.)

It does sound like Mike’s suggestion might be the way to go–the scene machinery seems like it’s causing you trouble, so maybe the best way to do things is with a true-false variable.

You may be able to solve the issues by forcing the scene changing rules to run before you reject the player’s command:

[code]Jeopardy is a room.

Answer given is a truth state variable.

Quiz is a scene. Quiz begins when play begins. Quiz ends when answer given is true. When Quiz ends: say “Quiz ended.”

After reading a command:
if the player’s command includes “xyzzy”:
now answer given is true;
follow the scene changing rules;
reject the player’s command.[/code]

but I’d be chary of messing with internals in this way; sometimes it violates other assumptions that can mess things up in unforeseeable ways. It might not, but I don’t really understand the internals, so I’d be more comfortable using truth states.

(By the way, even if you didn’t reject the player’s command, parser errors like “That’s not a verb I recognize” don’t take turns, so you wouldn’t get a scene change anyway.)

Okay, it took me a little bit, but I got it working.

[global variable]
CurrentConversation is some text that varies.  CurrentConversation is "".

[global rule]
Last after reading a command while CurrentConversation is not "":
    if the player's input matches "[terminator character]":
        now CurrentConversation is "";
    reject the player's command.

[and then something like this goes inside the code for any room where a talkable character resides]

Instead of talking to the waiter:
    now CurrentConversation is "WaiterConversation";
    [send output to external application].

After reading a command while CurrentConversation is "WaiterConversation":
    if the player's command matches "[chicken option]":
        [serve the chicken];
    if the player's command matches "[fish option]":
        [serve the fish].

Thanks everyone for helping me out. I really appreciate it.

I’m very interested to see this project–it sounds cool!

By the way, you don’t necessarily have to make the current conversation a text string–you could make a kind of value for the current conversation, or you could make the current conversation partner a person (and set it to the player when no conversation is happening). But maybe the text string is the best way of passing it to your external program.

I hope it turns out that way!

I decided the text string was best because one of the things that might change about the world state is what conversations you can have with the characters. So depending on the player’s progress through the game, the waiter might offer them the fish and chicken, or maybe the beef and pasta, or maybe the monkey brains and live baby snakes. So the CurrentConversation might be “WaiterConversation1”, “WaiterConversation2”, etc.

One total aside - while I was trying to debug, I tried to store the player’s command so that I could look at it later. But I found when I wrote “now [text variable] is the player’s command”, the compiler interpreted it as a condition. And when I wrote “now [text variable] is “[the player’s command]””, this seemed to create a reference to wherever in memory the last command is stored, rather than storing the value of the then-current last command. Which meant that trying to recall the value in-game simply gave me back my most recent command, rather than the command from back when the “now [text variable] is “[the player’s command]”” code was executed.

(It’s possible that there’s a much better way of debugging, and seeing what values are in what variables, that I just don’t know of.)

For something like that, you want:

now the stored command is the substituted form of "[the player's command]"

See §20.7 of Writing with Inform. If you assign a text substitution like “[the player’s command]” to a text variable, it turns into a call by reference, as I think they’re called in other languages. Saying “the substituted form of…” freezes it to a call by value–that is, it’ll stay at whatever “[the player’s command]” is at that moment rather than continuing to change as that changes.

(This is a recent addition to Inform and still gets me a lot!)

Sorry for bumping an old thread!

I’m trying to do something very similar to this, but the choice is between 2 different verbs. Basicaly I’m trying to write:

Ordering from the menu is a scene. Before doing anything except buying the chicken or rejecting the chicken when ordering from the menu is happening: say "Sorry, that isn't a valid option."

But it doesn’t like it. It says “doing anything excpet buying the chicken” and “rejecting the chicken” are both okay, “but the combination was ambiguous, so I am unable to place this rule into any rulebook.”

To be clear, I can get it working as:

Ordering from the menu is a scene. Before doing anything except buying the chicken when ordering from the menu is happening: say "Sorry, that isn't a valid option."

(or equivalent with rejecting). It’s just having both with ‘or’ which messes it up. (I can’t find anything in the documentation about ‘or’, but I also can’t find anything anywhere about what I’m supposed to be using instead. Sorry I’m 1 day into Inform, I know nothing!)

(obviously in my example it’s not about buying or rejecting chicken…)

(also using the latest version of Inform 7 (or 10?), if that makes a difference.)

Buying the chicken is menu behavior.
Rejecting the chicken is menu behavior.
Instead of doing anything except menu behavior...
2 Likes

Thanks so much! Although it’s still not working and I have no idea why.

If I do:

Before doing anything except menu behaviour when ordering from the menu is happening: say "Sorry, that isn't a valid option."

That works, in that it adds “Sorry, that isn’t a valid option” to everything else that I try to do (save menu behaviour), before doing the other thing anyway. But when I try “Instead of” in place of “Before”, suddenly everything becomes permissable (but when I change ‘menu behaviour’ back to ‘buy the chicken’, ‘instead’ works fine and blocks anything other than buying chicken). I’m really sorry, I have 0 idea what could be wrong, each part works fine on its own but when I put it together it just mysteriously doesn’t?

(edit removed because the fix I thought I found didn’t actually work…)