In the Missing Tools discussion some time ago, one of the things people mentioned wanting more of in IF was procedural text generation, which here is meant specifically as the ability to have the computer describe complex world model states or story events without having to hand-author every possible variation.
This is an area where there’s a lot to learn from work going on in academic research, but as far as I’m aware there’s relatively little communication. As I mentioned in my ICIDS writeup, James Ryan at UCSC and Dr. Boyang Li at Georgia Tech’s Entertainment Intelligence Lab are doing work on a) how to better represent a richly complicated world model and b) how to procedurally alter narrative features such as the tone of narration. One of the things we particularly don’t seem to do in hobbyist IF, perhaps for lack of resources, is experiment with large word databases such as WordNet or crowd-sourced work in particular areas like that used on Scheherazade.
Speaking for myself, I’ve also tended to stumble towards solutions in this space based on trial and error and the needs of my own projects, rather than having a strong grounding in the relevant academic work. Most of what we’ve needed — and most of what we’ve done — is pretty much work in the shallowest end of this pool.
And, of course, text generation for parser IF comes with special additional challenges, in that the player usually expects to be able to refer to any generated noun or noun phrase element; therefore if we generate a description of a thing as “blue”, the system also needs to remember how we described that object and accept the input “blue” to refer to it.
Here are the things I’m currently aware of. Unfortunately, I’m inevitably more aware of the internals of my own libraries and games than I am of other people’s work, so if I left out something cool that you did, please by all means say something in the comments: I am eager to know about it. In particular, there may be a lot I don’t know about under the hood in Kerkerkruip.
Substituting text based on a variable and/or world model information. Pretty much all the major systems are capable of this. Inform also allows syntax such as “understand the color property as describing a brick” also to affect parsing to make this easier to parse.
Choosing randomly from multiple text options. Inform’s [one of]…[at random], [one of]…[as decreasingly likely options], [one of]…[sticky random], and similar features; TADS and Twine also provide this functionality. Most of the time it’s used to handle randomized atmosphere messages and NPC idles, or to diversify the responses to player behavior instead of using just one default message all the time. Counterfeit Monkey uses some randomness and cycling in default messages in order to make the narrator character Alex seem more personable and less like a computer.
Recording and reusing user-supplied strings. Probably the most common application of this is to ask for the player’s preferred name, as exemplified in the example Identity Theft in Inform; all the major systems that I know of have some way of doing this, since it’s just collecting text and then subsequently using that variable for generation.
Ultimate Quest kind of went to extremes with this by allowing people to rename objects however they wanted, permitting them to assign their own synonyms or nicknames to things. This occasionally had an in-game value but often was used to do things like rename villain characters to JERKFACE. (The code obviously needed a few checks to make sure that players weren’t naming objects the same as some other existing object.)
Selecting singular and plural forms, or generating them. Inform and TADS both deal with this to create plurals of nouns and to make verbs agree properly; the systems have over time gotten more and more elaborate, and tied in with
Revising person, number, and tense of narration. Curveship got here first; the TADS libraries adv3 and adv3lite, and Inform’s 2014 builds all supply ways to do this as well. (And before the 2014 build, there were more clumsy ways of doing this with library message replacement libraries such as Custom Library Messages.) Because this applies to verb forms and not to nouns, it doesn’t tend to raise the same parsing challenges.
This can be useful to shift the descriptions of an entire game; Shelter From the Storm rather dramatically lets you choose your own person and tense of narration as you like. It also turns up in flashback sequences in only part of a game; I think All Hope Abandon does this, and I know Dial C for Cupcakes does. (It’s also possible to find first person, third person, and past tense games on IFDB using tags. I checked for future tense games and didn’t find any, which may reflect a genuine absence thereof.)
Selecting and ordering information to be narrated. The Inform libraries Complex Listing and Room Description Control; Inform’s writing a paragraph about and locale activities.
Room Description Control is the most systematic of these, and is designed to allow the author to
- write her own rules about what room description information should be mentioned at all, which means one can write rules like “anything marked as invisible should not be mentioned” or “things on high shelves should not be mentioned” or “open objects should be mentioned”; then
- once a list of information to report has been established, write rules controlling the order of that that report, e.g. “people should be mentioned last”; then
- using the “write a paragraph about” activity, provide more or less specialized templates for describing particular sets of facts or objects. This means one can, say, provide a special override for the case that the statue bust is on a pedestal vs. in any other location.
One of the major points about “write a paragraph about”, both as used by RDC and in its use in vanilla Inform, is that it’s not necessarily trying to assemble a human-sounding paragraph from scratch (though Tailored Room Description does provide some attempts at that for generic cases). Instead, it’s matching an author-generated paragraph to the particular selection of salient information it needs to report, and falling back to default descriptions if it can’t find any such paragraphs available.
This is closer to the approach taken by the Prom Week engineers and James Ryan’s current work, though in practice IF often needs to rely on mix of both methods.
RDC demands a lot from the author, so it has a companion extension Tailored Room Description that exemplifies how much of the heavy listing is done (and can be used as an out of box solution, though I imagine the only reason someone would go to the trouble of using it would be if they wanted to make some major changes).
See also this article on generating physical descriptions for characters on a MUD.
Talking naturally about lists and quantifiers. The aim here is to avoid clumsy reports of world state concerning sequentially related model data, such as “The left drawer is open. The middle drawer is closed. The right drawer is closed.” The rather vaguely-named extension Assorted Text Generation mostly does one task: write phrases identifying members of a group, such as “Both of the doors are open” or “All but the white door are closed”. It includes a number of minor variations on these, and also has some ways of talking imprecisely about large numbers.
Building on this, the Automated Drawers extension is basically an excuse to use this functionality; to the best of my knowledge it has wisely been avoided by other authors, though I did use it in Counterfeit Monkey. Its function is to allow the author to say that a given desk has N drawers and that they’re vertically or horizontally arranged, and then autogenerate and auto-understand input such as “open the top drawer” or “the top drawer is open”.
Combining clauses into paragraphs. The challenge here is to take a sequence of single-clause sentence texts such as “Mary enters the room. Paul enters the room. Paul sits on the bed. A dog is on the bed.”, generated by world model information, into a more natural-sounding paragraph, using strategies such as combining sentences with shared information, but avoiding erroneous over-combination:
“Mary and Paul enter the room. Paul sits on the bed.”
“Mary enters the room. Paul enters the room and sits on the bed.”
* “Mary and Paul enter the room and sit on the bed.”
Savoir-Faire does this with its object-throwing-and-landing code: things can be thrown at other things, and the target objects might break, roll away, fall, spill, etc. In theory, liquid can pour out of a broken vase, or a marble fall out of a glass box and then roll off the shelf the box was sitting on: the possible ramifications are numerous. SF also provides mechanisms for reporting less-vital “color” information like what sound is made when one object strikes another. So to report all this, it needs to
- assemble a list of clauses describing all the different things that happen, labeling them as instant (things that could happen at the same time as other things) or sequential (things that in themselves take time)
- choose which if any clauses it can eliminate (if there’s lots of important stuff to report, color information may be omitted; if not, it will leave that information in to keep the report interesting)
- generate output sentences by stitching clauses together in a way that respects their temporal information as well as trying to minimize redundancy
It’s actually even a bit more ridiculous than that, because each verb that can be the main verb of a clause was implemented as an object with special rules about how to print itself, including making alternate short, medium, or long instantiations of those clauses in order to produce stylistic variation, and doing some stuff to automatically create verb plurals where needed, and so on.
Honestly I am not sure that players noticed or cared about most of this; the point was mostly that I was enjoying the mad science of it all.
The I7 extension Approaches, meanwhile, deals with traversing large amounts of territory and putting together descriptions of all the rooms the player passes through.
Most rigorously of all, a generalized combination of reports of player actions are built into TADS 3 in order to present. I’m not an expert in how this works, however, since TADS 3 has not been my main language of choice. Games like Return to Ditch Day demonstrate the effects, though.
Adjective selection for complex objects. The last category slightly gets into this one: sometimes we want to apply identifying vocabulary to a particular object based on multiple aspects of the world model; an NPC doesn’t just have the property “angry”, for instance, but can be described as “apoplectic” if she has both the mood angry and the personality profile domineering.
Noisy Cricket is an Inform example that constructs a name for an alcoholic beverage depending on the mix of liquids included in that beverage; otherwise I don’t know of a large number of things that do this much in practice. In that case, it’s assumed that player actions will directly prompt changes in the object name, which may not always be the case. If it’s necessary to respond to world model changes that might be happening for multiple reasons, one might calculate and reassign descriptors to objects each turn in order to keep them up to date with the world model.
Filtering output to add verbal tics and similar features. These are filters that are added after the fact once the text is already fully composed in order to add surface-level effects or defects. Versu has a drunkenness filter built in which automatically slurs text output by a character that registers as drunk. Curveship’s examples include an um-inserter to make characters seem to hesitate.
Other obvious examples I’m not thinking of?