Next Technological Steps?

This reminds me that I need to get back to that “issues I’ve had with the parser” post I have in draft. Maybe some quick things:
-understanding multiple things before the comma
-getting disambiguation to behave nicely
-interpreting ambiguous commands as referring multiply (so if the player types “x handle” in the presence of two handles they would examine both–all this would take is the ability to intercept a disambiguation request and automatically feed “all” to it)
-having disambiguation requests respond to the names of objects even when those names contain verbs (I almost got this to work with Ron Newcomb’s I7 version of the older parser, but I don’t have the I6 skills to do it for real)
-seriously, disambiguation is very hard to deal with and modify

Some non-parser issues:
-trying to get “a/an” to behave appropriately in front of any arbitrary string rather than be bound to the object itself. It’s sometimes hard to notice how many different IF locutions arise from working around the situations where English things get modified contextually–“a bag (empty)” rather than “an empty bag,” “You can also see a knife and a fork here” rather than “A knife and a fork are here also.” In the latter case, the capitalization and pluralization are pretty easy to take care of, but they sure weren’t solved by Infocom and Level 7! (Well, I guess they didn’t even have to worry about capitalization originally.)
-grouping issues; if anyone knows how to write the code for the printed name of a slice of bread so that it’s possible for Inform to print “You have two slices of bread and two slices of toast,” let me know.

There’s some other more blue-sky things I’d be interested to see in parsers, but those are all coding problems that I’ve actually had, which I think count as me bumping my head against the limits of the I7 parser more than me bumping my head against the limits of my coding ability.

There’s no reason why IF can’t have more polygons and higher resolutions too. Except money :slight_smile:

An IF game that has graphics just as good as other games is what I always wished. Sadly, after Legend stopped making graphical text adventures, this was never pursued again.

Kitchen is a room.

A bread slice is a kind of edible thing. There are four bread slices. Understand "of" as a bread slice. A bread slice can be toasted or untoasted. A bread slice is usually untoasted.  Understand "toast" as a bread slice when the item described is toasted. The printed name of a bread slice is "slice of [if toasted]toast[otherwise]bread[end if]".

Understand "slices" as the plural of a bread slice. The printed plural name of a bread slice is "slices of [if the item described is toasted]toast[otherwise]bread[end if]". The description of the bread slice is "[if untoasted]A bit crumbly[otherwise]Nicely toasted[end if]."

After jumping:
	let T be a random bread slice that is nowhere;
	if T is nothing, continue the action;
	now the player carries T;
	say "You jump, and a slice of bread materializes in your inventory."
	
After waving hands:
	let T be a random bread slice that is nowhere;
	if T is nothing, continue the action;
	now T is toasted;
	now the player carries T;
	say "You wave your hands, and a slice of toast materializes in your inventory."

After eating a bread slice:
	say "[We] [eat] [the noun][if actor is player]. Not bad[end if].";
	now the noun is untoasted;

Rule for printing a number of bread slices while taking inventory:
	let B be number of untoasted bread slices carried by the player;
	let T be number of toasted bread slices carried by the player;
	if B > 0, say "[if B is 1]a slice[else][B in words] slices[end if] of bread";
	if B > 0 and T > 0, say " and ";
	if T > 0, say "[if T is 1]a slice[else][T in words] slices[end if] of toast".

Test me with "wave / i / jump / i / wave / i / jump / i".

Printing a number of! Very clever! I had forgotten that that was even a thing.

I do think that there may still be some grouping issues that pop up occasionally.

There’s an extension that prints the number for you. :slight_smile:

Come to think about it, there IS something about the parser I never fully grasped. How well do I7 and TADS cope with giving NPCs multiple commands, via “NPC, this then that then those” format?

Touche. I guess I was thinking in terms of big changes and paradigm-changing improvements (like UNDO), and didn’t look at the small fiddly little niceties we take for granted and which are a big part of the solid systems we have. Mea culpa. Those are still being perfected, even in Inform 6 from what I see in the relevant board.

But that harkens back to what Dannii said, doesn’t it? :slight_smile: Not so much “what can we do that’s new”, but “how can we perfect what’s already here”.

Then again, that’s not so different from “more polygons” and “more light levels” - that stuff is just perfecting as well.

Argh. Brain hurts. Stopping now.

EDIT 2 - Is it possible to order more than one NPC around? Like “Donna and James, go north then hug” or something? Even if it is, though, isn’t it crazy specific and unlikely to be be of practical use? Then again, isn’t that true of EVERYTHING until someone actually makes it and then all of a sudden it turns out it really WAS necessary?

I7 handles this. Here’s a snippet of transcript from Example 188 (Generation X):

I should point out that this has been a thing since Enchanter, so it’s not surprising that it works.

With much hacking–that’s Daniel Stelzer’s Multiple Actors extension. It’s what I meant by “understanding multiple things before the comma.” But, you know, it took a lot of hacking and is not entirely smooth.

You’re breaking my heart, Peter! :wink: Arno von Borries did this in Dead Man’s Hill too.

Another big non-smoothness about ordering multiple NPCs around is that, even once you get the parser to resolve “Donna and James, go north then hug,” it’s going to turn into the action of Donna going north, then the action of James going north–which is fine–then the action of Donna hugging, then the action of James hugging, which is not so fine; we want Donna and James hugging to be a collective action, and there’s no such thing in the world model. (Actually the way Multiple Actors works it comes out worse–I think it gets resolved as Donna going north-Donna hugging-James going north-James hugging, which means that when the first hugging action gets resolved they’ll be in different rooms. Dunno–in Terminator I tried to disallow these completely, but that was because they could subvert the timed element rather than because of any particular problem with Multiple Actors, except insofar as I had to do some weird stuff to get the Every Turn rules to work properly with Multiple Actors.)

Anyway! The other big issue here, and one that goes beyond this admittedly rather specialized application (pending the upcoming boom in textual square-dance calling games), is that the actions will get processed as they get reported, in an entirely piecemeal fashion. So if you write “Donna, James, and Allie, go north” the default will look like this:

Which is ugly. But since the actions get processed separately in that order, and get reported as they get processed, it takes some hacking to get something different. And you get the same issue when the actions are triggered by the code rather than by a command. This makes it hard to have smooth prose when there are a bunch of autonomous NPCs around. Extensions like John Clemens’s Consolidated Multiple Actions are meant to take care of at least some of this (I think that only works for actions the player takes, though), but again, they require some pretty deep hacking.

I’ll go stand quietly in the corner and brush up on my parser knowledge, shall I. :wink:

(BTW, I knew the giving-people-more-than-one-order had been a thing since Enchanter, but it always puzzled me. I could never tell whether actions were queued, or whether the actor was performing more than one action in a single turn, and wasn’t this a puzzle element in Enchanter? Anyway, brain tired, and I’ve swallowed my feet often enough for one thread!)

They’re queued.

(Technically, it’s not the actions that are queued. The parser saves the unused part of the compound command and generates actions from it on demand each time the main game loop asks for the next action, reading new player input only when it runs out. See held_back_mode and sections A and K of the parser.)

I added an every turn rule to my previous example to illustrate this:

Yeah, the Enchanter thing was a puzzle element. That’s why I didn’t mention anything beyond the name. I’d have spoiler tagged even that, but what would I say to indicate who could safely read the spoiler?

So, in your example two turns pass and the PC is unable to do anything in the meantime? What about ordering a PC to two a bunch of actions and doing something WHILE they’re doing them?

Ha ha, no foot-swallowing here–it’s an obscure corner of parser experimentation that happens to be one I’m interested in.

I don’t know about Enchanter, but in I7 asking someone to try a queue of commands gets converted into a queue of requests, which get evaluated in turn. Example:

[code]Lab is a room.

Taylor is a person in Lab.

Persuasion rule when asking Taylor to try jumping or asking Taylor to try waving hands: persuasion succeeds.

Every turn: say “One turn has elapsed. Number of turns elapsed: [turn count].”

Test me with “actions/jump then wave then kiss taylor/taylor, jump then wave then kiss me/taylor, kiss me then wave then jump”.[/code]

output:

As you can see, the requests get processed in turn, and whether persuasion succeeds with one doesn’t affect whether the next one gets tried–it’s just as though you’d entered “Taylor, jump” and then “Taylor, wave” and then “Taylor, kiss me.” Each action seems to take one turn (on preview: as Vince points out), as with multiple queued actions you perform (which I’d forgotten about–I guess I had to hack queued commands out of Terminator because I’d already done something weird to prevent the Every Turn rules from running after every robot’s action, and I had the timer tied to the Every Turn rules rather than the turn count, so queued actions would’ve messed up the timer).

(By the way, the multiple-actors thing ultimately goes to a question someone had about Suspended, but Infocom’s solution there appears to have been something of a kludge.)

Oh! I forgot to add a particular piece of trivia about collective actions that may be of interest only to me. Spoilers for the third room in Faithful Companion (that’s after you get through the three-latch door):

One of the first things I coded in Inform was something for two people to move a couch together. I think this had something to do with a very early draft of Jim Aikin’s Inform handbook where he had some code for switching the PC near the beginning. Anyway, it turned out to be non-trivial to code this, because Inform’s world model is not that big on having an object that’s carried by two people at once. Then after I had the idea for the mimicking ghost in Faithful Companion, I thought it might be cool to have a puzzle where you and the ghost work together to move a heavy coffin lid, so I dropped that in… but instead of all the tricky stuff, I just had it check whether you and the ghost were trying to lift the lid on the same turn, and if you were the game put it in the right place for you.

Also, I meant to write a 10,000-word Lukascian rant on how the impossibility of collective action and collective report in these games is a reflection of our atomized bourgeois consciousness, which presents us always as individuals interacting with others as mere machines. Watch this space! (Don’t watch this space.)

I think that was always my confusion - I never really understood why it should be that way. Imagine if you could give an NPC a string of commands and, like in Lure of the Temptress, do stuff WHILE they were doing what we told them to!

I’m sure that in I7 this is codable, using tables and other wizardry… it’s just that it always seemed natural to me, but no game actually used it. That I know of. (cue matt w linking me to games that did it)

Nah, I’m going to do my other trick, which is to code it up quick-and-dirty. You have to catch when multiple commands are being issued in a turn, so you can execute the first one and intercept the rest for the queue, and then you have to empty the queue at the right time. Also I discovered a limitation in Inform’s model for queued commands: If your first command takes the NPC out of sight, then Inform won’t allow you to issue the second one, since it’s just as if you’d typed them one after the other.

[code]the living room is a room. the lower hallway is north of living room. the upper hallway is up from the lower hallway. the study is south of the upper hallway.

Taylor is a person in Living Room.

Taylor’s future actions is a list of stored actions that varies.
Caching action is a truth state that varies.
First action this turn is a truth state that varies.
Taylor commandable is a truth state that varies. [Tracks whether Taylor was in scope at the beginning of the queue of commands.]

After reading a command:
now first action this turn is true;
now caching action is false;
now Taylor commandable is false.

Every turn: now first action this turn is false. [This means that first action this turn will be false only when we’ve done or requested multiple actions in one turn]

Persuasion rule when first action this turn is true:
if the number of entries in Taylor’s future actions is greater than 0: [we’ve interrupted a previous sequence of commands]
say “Taylor says, ‘OK, never mind that stuff you said before.’”;
truncate Taylor’s future actions to 0 entries;
now Taylor commandable is true; [Taylor should remain commandable throughout these commands]
persuasion succeeds.

After deciding the scope of the player when Taylor commandable is true: place Taylor in scope.

Persuasion rule when first action this turn is false: [we’ve queued up multiple requests]
now caching action is true;
persuasion succeeds.

First before Taylor doing something when caching action is true: [so we are now executing one of the subsequent requested action on the turn when multiple requests were made–that means we add it to the queue and then stop it completely]
add the current action to Taylor’s future actions;
rule succeeds.

Every turn when the number of entries in Taylor’s future actions is greater than 0 and caching action is false: [if it’s true, then we added actions to Taylor’s queue this turn, and we don’t want to empty it again]
try entry 1 in Taylor’s future actions;
remove entry 1 from Taylor’s future actions.

A clock is a door. It is up from the Living Room and down from the Study.
After going when the door gone through is the clock:
say “You slip through the secret passage in the clock and go [noun] to [the room gone to].”

Last report Taylor going to the Study when the Study encloses the player and the Upper Hallway is unvisited:
say “‘Oh! I didn’t expect you here!’ [if the clock is open]Taylor looks at the open clock. ‘Ah, I see.’ [otherwise]Taylor says. [end if][paragraph break]”.

Test me with “Taylor, jump then wave then jump/z/Taylor, go north then go up then go south/open clock/up”.[/code]

Correct. The parser is set up to produce the next action (actor, action, noun, second noun) each time that the game’s main loop calls it, not to manage per-actor action queues.

Today, you would have to implement simultaneous action at the game level. For example, you could say “Professor Plum, go to the library” and have the parser produce a single action that sets some state in Plum that he’s now in the process of going to the library. Then, each turn a rule (“every turn when plum is traveling:”) would note that he’s going to the library, figure out the next step on the path, and execute a going action. Since this would be a rule-generated action (“try going east”) rather than a parser-generated action, by default it would be part of the current turn, simultaneous with the player’s action for that turn.

It’s an interesting area for experimentation. I can see a couple of approaches:

  • The parser views the entire compound command as a speech action and sends it as an order to the NPC. The burden is then on the NPC to parse it and act on it over time.
  • The parser produces a set of actions each time it’s called rather than a single action, and the game loop maintains queues for each actor. The problem here is that the parser disambiguates commands based on the current state of the world. So if we say “Bob, A. B. C.”, B and C may be interpreted differently after A has happened. I think that this is why the parser holds off on consuming input and generating actions from it until a new action is needed. Generating actions for A, B, and C immediately so that they can be shipped off to the game loop and queued would interfere with this disambiguation and possibly result in a different and less sensible set of actions (although one could argue that Bob would interpret them based on the world as it was when the command was issued).

I’ve just checked, and this is featured in Melbourne House’s classic Tolkien IF works “Lord Of the Rings” and “The Hobbit” (this last one, incidentally, launched the year before Enchanter)

In the beginning of the Hobbit you can, for example (testing it right now in a Spectrum emulator):

DROP MAP
SAY TO THORIN “GET MAP,GO EAST,DROP MAP,GO WEST”

and if Thorin agrees (beeing the hard headed guy he is, there is a high chance that he’ll refuse :laughing: ) he will use a turn for every order and you’ll be able to do any action in between.

Hey thanks everyone for the responses. Zarf I think you really summed things up perfectly :smiley:

Quick addition: Matt W, here’s a bit of code to fix the scope issue (from here):

The most recent actor is an object that varies.
After reading a command (this is the reset distant actor before multiple-command rule):
    now the most recent actor is nothing. [This ensures we don't leave the actor in scope for multiple command-entries, only when multiple commands are entered on the same line.]
First persuasion (this is the reset most recent actor rule):
    now the most recent actor is the person asked.
After deciding the scope of the player while parsing for persuasion (this is the multiple commands to a distant actor rule):
    if the most recent actor is not nothing:
        place the most recent actor in scope, but not its contents.

Story of my life.

Where’s the +1 buttons on this thing?

I think from a story-telling perspective, we’re probably okay for awhile. I think there’s still a lot of work on the UI side of things, especially where the web is concerned. But that would entail getting web designers more involved in IF, something with which I think we’ve struggled.

I think people should just focus on writing good stories and worry less about the technology though.