Impulsing: #devtober Day 2

No fancy graphics today.

I spent the evening getting the “Owen” node hooked up to the higher-level “Owen” component. I decided to have this split from the beginning between the underlying graph nodes and the higher-level UI/game components. It has served me well so far, especially since a serialized Godot component is a huge mess. It’s amazing how much “stuff” it writes out.

Once I got the node hooked up and loading from the palette, I found some issues I had to fix, but it all went smoothly.

I have a Trello board with next steps. I need to add some more, as I know there is more than three things left to do. One will be to create some new levels with this component and make sure it serialized properly. I haven’t tried that yet. At least I have a plan for tomorrow. (Saturday! Yay!)

Hey, look! There was a graphic after all. That’s the editor component palette so far.

Impulsing: #devtober Day 1

I decided to give the #devtober game jam on itch.io a try this year. It popped into my inbox, and it sounded like it might be a good experience. You can read more about it here: https://itch.io/jam/devtober-2020. Basically, you just work on your game each day of October and blog about it. Then in the end you write a post-mortem. I have been working on it almost every day anyway, but this makes me write about it, too, and maybe some people will read along.

This is day 1.

A month to go.

Given that this is the first real Impulsing posting, I probably should give a little information about it. I would love to post images, talk all about it, and get everyone excited (or bored) by what I’m doing. However, part of the game is figuring out what it all means, and talking about it too much could spoil that sense of discovery. So I need to be a bit guarded.

Impulsing is a puzzle game I have been creating off and on for over two years. Probably closer to three now. Part of that length of time is that I’ve been working only on it in my spare time. Another part of it is that I have been working on another project as well at the same time that has been taking priority. Another part is that I actually gave up on it for a while before a mental “eureka” moment happened, which provided a breakthrough to a tough design problem and got me back into it with real energy.

It went through a number of (crude horrible) prototypes in HTML and JavaScript before I began to cause my CPU usage to go through the roof. Time to get more real.

I dabbled in Unity for a while before my struggles to do simple things put me off it. I am now using Godot, and I’m much happier with it, though it too has quirks that drive me bonkers at times. (One example: I’m using resources to read and write levels, and there have been times where the game crashing has trashed the current level resource file. And the Godot editor/system seems to still have it open – if I restore it from git, it just overwrites it again whenever I do anything. I have to shut down the Godot editor before I can restore the file.) However, there is a lot I really like about Godot, like its nested scene/component model.

The game started off life in 2D, and I sent around a small prototype to some people I know. For various reasons, I decided to move to 3D.

One reason I did is that I’m “better” at making 3D art than 2D, even though I was using Inkscape to create SVGs. I enjoy using Blender, I can produce some nice (if simple) assets, and I want to get better at it. Also, the 2D game was top-down, and it was just too limiting to try to make things look good and interesting looking straight down. Now with 3D (really 2.5D), I can have more depth and make things easier to understand. And lots of interesting 3D assets to use, if desired.

Original 2D game:

Current 3D look:

Another reason I switched to 3D is just to experience using 3D. I don’t know if this game will ever amount to anything, so I’m really using it just to learn about a wide variety of things.

That’s a brief overview. That’s all I’ll say for now. What did I do today?

I’m working on a new component called “Owen”. All right, that’s not what it’s really called. That’s just its code name. I just made it up.

This is what it looks like, so far. It feels too bulky, but… get it working first. tweak later.

I have made a point of using TDD to drive at least the complex parts of the game, like the graph and nodes. I’m using GUT in Godot for my unit tests. Today was working test by test to drive the component’s code. As often happens with TDD, suddenly it was just working. And I had the tests as a testbed to show me it working, outside of the complexities of the game. Faster turn around. Faster development. A bit more code in the end, but probably less typing. And I know, at least for the test cases I have so far, it works.

Time to step back from the screen before heading off to bed.

I say. You say. We say.

Here is the way this project has gone so far, largely:

  1. “Yes! I’ve made enough progress with the code that I can actually start to add real content now!”
  2. “Hmm… well I tried adding some content, and some things work, but something I hadn’t considered has come up that isn’t right.”
  3. “Sigh… I could try to work around it, but I think I should make this work properly.”
  4. “Ok. The feature has been implemented or fixed, and a small amount of content has been added.”
  5. Go to 1

Yes! Hmm…. Sigh… Ok.

Yes! Hmm…. Sigh… Ok.

Yes! Hmm…. Sigh… Ok.

It just goes to show that you can’t create software in a vacuum. You have to actually use it in real world situations to evolve the design.

My latest “Hmm…” moment has just arrived. I have the beginnings of a scene where I hope to exercise (and, if lucky, actually prove viable) the response/topic/action design I’ve been working all this time to create. The scene has a few characters, who will all at some point engage in conversation.

The room has an opening paragraph. Just to start off simple, the bartender has a response that asks if the player would like a drink, and the loudmouth seated at the bar will make a political comment. When I enter the room, I get the following output:

<room opening paragraph>  The bartender says in your direction, “Can I get you something to drink?” “I tell you, the mayor is an idiot and a buffoon. I could do his job better than he does.”

Hmm…

The code is working as designed, but not as desired, in an ideal world. The problem arises from how normal prose is written, especially dialogue. Generally, when the the topic changes or when the speaker changes, a new paragraph is created. (In my mind, a speaker speaking is actually a strong prod toward “topic changes”, unless there is something binding the dialogue to the existing content.)

What I would want is more like this:

<room opening paragraph>

The bartender says in your direction, “Can I get you something to drink?”

“I tell you, the mayor is an idiot and a buffoon. I could do his job better than he does.”

( I do realize, by the way, that the second bit of dialogue needs something around it to identify the speaker. This is not the greatest content so far, but it is early days and first stabs.)

What the text output needs is context. (I have an entire blog post planned – and even started – touching on that subject.) The text outputting code needs to know both what has been output and what will be output in order to make intelligent formatting decisions connecting the two. The context is key. The text itself, at least in these cases, is largely irrelevant. But there are two key pieces of information necessary:

  1. What kind of output it is. In particular, in this case, we need to know if the output is dialogue or not. That implies at least two kinds of output. There may well be more.
  2. What character the output corresponds to. In this case, it would be which character is speaking the dialogue, but it’s also useful in terms of binding dialogue output to non-dialogue output for the same character.

We already have a mechanism in ResponsIF for associating content with characters – responses belong to responders, and responses are what “say” text. So if the content is authored in a reasonable way, where responders handle their own dialogue sequences, then we should generally who we’re talking about – or who is doing the talking. The responder is a key part of the context.

We also already have a mechanism for saying what a response “is”, which can be used to group responses for output.  This can be used for things like hints or other special text that lives alongside but separated from the main text. (My first thought was that that could work to separate the content. The problem is that these are actions across multiple responders, each being processed separately. As they are not processed together, the code does not know how to partition them since it never sees them all at once. In other words, it has no context.) Whether this existing mechanism is the one to use for this purpose remains to be seen. But either way, we need to attach metadata to the output.

A solution would be to have the output handler be aware of what has been output and what is being output, using the output type and character to nicely separate things. And the code to do that shouldn’t be that hard to write. What I often run into, though, is whether it makes sense to build such “business logic” into general purpose code. This will take more review, but I’m leaning in that direction. The more “smarts” that can be in ResponsIF out-of-the-box, the more people will enjoy and want to use it.

One way this can be implemented is via some sort of layer between the response processors and the output formatter. This layer would have the smarts to know what to do to the text to make it look correct. In theory, that layer could be swapped out, but what I hope to do instead is to expand it even more, allowing it to take part in the actual writing of the content in future situations.

In a game I was working on before, I had such a piece of code. I called it StoryText, a name I still like. (Of course, the vaporware cat is out of the bag here, and someone could easily steal that name.) In order to implement StoryText, we need to associate metadata with content, like the content “kind” mentioned above. And then write some code. In a reasonable way.

How exactly to slot this into place requires some thought.

Sigh…

Association

ResponsIF supports associations among topics, which is something I consider important. What does this mean? Let’s give an example from real life.

Say it’s morning, and you go out for a walk with the dog. The sky is gray, but your mind is pondering the day ahead of you. There’s a problem you’ve been assigned to solve, and it’s important that it be done soon. You walk absently, your mind exploring possibilities.

As you approach the corner shop, the sight triggers a memory – you need bread. For a moment, your thoughts of the problem at work have been displaced. You think about when you might be able to get some bread as you continue on, and soon that thought fades. Re-gathering, you return to your original pressing thought.

Waiting to cross the road, your thoughts are displaced again by the need to be aware of the traffic and the proximity to your dog. An old fashioned car cruises by, and you’re reminded of that film that you saw when you were younger, about the car that could fly.You think about the actor who was in it, and of how you used to like to watch his TV show. It was quite an old-fashioned TV show, black and white, but your parents liked to have it on in the evenings in the living room.

That living room was what you entered when you were done playing with your friends outside. You remember the cool evening air when you used to ride your bike and play ball. You remember the time you went off that insanely high jump on your bike, and that time you fell. You also remember that time you feel off your skateboard and fractured a rib.You can almost feel the pain, and how you almost couldn’t breathe.

You register that the traffic has cleared, and you head across, alert to any oncoming cars you may not have seen coming or that may be coming quickly.

Having crossed the road, you follow a path beside the grass. There are flowers growing there, and delicate purple ones remind you of – you almost can’t even bear the name, you miss the person so. Suddenly, you feel the loss all over again. You can’t help but recall images of the last time you were together, of the words spoken, of the tears shed. The heartbreak has faded to a dull ache, but it doesn’t take much to flare it up.

An elderly man approaches you along the path. He smiles and waves as he passes. He told you his name once, but it didn’t stick.

For a moment, you’re in tune with what’s going on around you. You hear birds chatting in the trees. You hear cars drifting by. You smell the remnants of last night’s rain, which you remember made the windows shake and the dog jump. It was impossible sleeping during the downpour, but it was ok, because you like the sound of rain.

The smell of fresh, hot food greets you as you approach a small shop. You remember you need bread. You’re not sure when you’ll be able to get it, because of the time pressure at work…

And you’re back to  your original thoughts.

I’m not sure if that seems familiar or not, but it certainly is for me. I find my head is an ongoing stream of thoughts, steered left and right and up and down by ongoing associations, either to other thoughts or to external stimuli.

Assuming that is how a human mind works, on some level, the obvious question is whether or not you’d actually want that going in your NPC’s “minds”. The interesting thing about what happened above is that there was no external indication of what was happening. There was no speaking or obvious signs of emotion. It was all internal. Does it make sense for NPCs to have an inner life? Traditionally, IF has been about what the character does: what it says, where it moves, whether it attacks you , etc. The invisible inner workings have taken a back seat or not been bothered with at all. After all, does the player care?

I can only say that I’m interested in giving it a try. The reason why is that the inner state influences the outer. Let’s say that someone were to approach you along your walk and attempt to engage you in conversation. The response you give might well be determined to some extent by what’s happening inside. If you’re thinking about what you have to do and how you have no time and how you don’t know what to do and how you really have to work out the problem, your response might be annoyance at any intrusion. If you are forced to respond while you’re contemplating your lost love, the response might be considerably different.

Having this sort of NPC inner turmoil (or at least ongoing inner state fluctuations) could help provide a more varied response during game play, depending on what’s happening or has happened in the past.

One thing you may have noticed in the narrative above was the continual return to thinking about the pressing long term goal. Little distractions came in, some even causing ripples that lasted a while, but eventually, when the water calmed again, the long-term goal came to the fore again. This points to several key things:

  1. Long vs short term topics. Short-term topics have a short lifespan. They are the introduction of topics into the thought stream that cause ripples or even a splash, but they have no sustaining energy. They’re fleeting, disappearing as quickly as they come, replaced by either their own descendants or simply fading away unless sustained. Long-term goals, on the other hand, are constantly there, although perhaps at a lower level.
  2. Higher and lower priorities to topics. Thoughts of work took precedence over thoughts of buying bread, ultimately. But external stimuli were able to temporarily overpower long-term thinking. Responses occurred or not depending on which topics had current weight, and those weights changed over time.
  3. The internal topic patterns oscillated or could oscillate. This is a powerful concept for me, one I’d like to explore further in a separate blog post.

Without delving too deeply into it, there are two primary mechanisms ResponsIF uses to associate topics. First, a response can trigger via multiple topics. This allows topics to be grouped in terms of the effect they have. Second, topics can trigger responses which can then add possibly different (but related) topics either back into the responder or out to other responders via suggestions. And the topics can be weighted appropriately. So, for example, the topic “family” might introduce topics for “mother”, “father”, and “Sarah” with relative strong weights, but it might also introduce the topic “farm” and “Pine Valley” with lesser, but still existent, weights. And if the discussion just prior also had weights for one of those lesser topics, it might be enough to push it up enough in priority to cause a response.

Topics are the glue that link response together. Responses tell you what happens in a riff. Topics tell you what the riff is all about.

Design Goals and Uber Philosophy

I have some fairly specific design goals I intend to explore in my IF “adventures”. Some of them can be seen in my first (and, so far, only) game spondre. That game not only gave me my first experience trying to realize these, it showed me some problems that need to be addressed. Not all of them are easily solvable. But you have to start somewhere!

If you don’t fail at least 90 percent of the time, you’re not aiming high enough. – Alan Kay

First, and not surprisingly, I want the game to be responsive. I don’t mean that just in the sense that you will get a response to your input. That goes without saying. What I mean is that the game should respond dynamically to not only what you are doing but to what you have done in the past. (Wouldn’t it be something if it could respond as well to what you might be about to do in the future?)

Now that’s not unheard of in games, even IF games, but it’s also not unheard of in IF games where, if you provide the same input, even after having advanced the game, you get the same response. To me, that just feels robotic.

Ideally, the game should respond as if it were someone there with you. This isn’t going to be Turing Test stuff, but the responses should make it feel that the game is in some form a conversation with you.

To that extent, I see a certain amount of AI involved in this, not just as far as any in-game characters are concerned but the overall game experience as well. All the text you see should have some sort of intelligence behind (with “intelligence” in quotes, of course) as much as possible and necessary.

I guess what I mean is, I want there to be a unified experience. Just as each of our brain cells is a part of a larger brain, and just as each of us in turn is part of a larger realization which is the collective activity of all of us together, all the elements of a game – rooms (if any), characters, plot, events, etc – are just parts of the combined, collective game. In other words, the game itself could be a considered a collective “non-player character”, working both with and against you to create a resulting story unique to you, using components of itself along the way.

A single “mind” instead of a disparate group of individual ones.

Hopefully, when I read this again in a month or two, it won’t seem like gibberish!

 

50-50

I’ve been learning about and experimenting a bit of late with fuzzy logic. In fact, I decided to implement a variant of it in ResponsIF. For those who don’t know, unlike in “crisp” logic where you have only two values (“true” or “false”), in fuzzy logic you have a continuum of values ranging from 0 (“false”) to 1 (“true”). A value represents a level of certainty or degree of something. For example, if you’re happy, your “happy” value might be 1. If you’re almost perfectly happy, but not quite, your “happy” value might be only 0.85. If you’re only a little bit happy, you might be down to 0.1.

Such variability comes in handy for attributes that don’t have hard edges. A person who is six feet tall would be considered tall, but how about someone only five-nine? And how about down to five-seven or five-five? As you can see, there is no clear line for “tall”, where you can say everyone above this value is tall and those below are not. There is not “you must be this tall” in life. The “tallness” attribute tapers of as height decreases. As it decreases, there is less certainty. Things become iffy. Things become fuzzy.

This blog entry came to be because I happened upon something interesting in relation to that.

In normal logic, you have certain tautologies. One of them is that “A and not A” is always false. This is so because “A” and “not A” can never both be true at the same time, and “and” requires both arguments to be true for it to be true. Similarly, “B or not B” is always true, as either “B” or “not B” will always be true, which makes the “or” true as well.

In fuzzy logic, things aren’t quite so simple.

Fuzzy logic uses “min” for “and” and “max” for “or”. That is, to compute “A and B”, you take the smaller value of “A” and “B”. To compute “A or B”, you take the larger value of “A” and “B”. These fuzzy operations happen to have the same behavior as the standard logic ones when “A” and “B” have extreme values (0 or 1). Check out the numerous truth tables on the web if you’re unsure.

In between the extremes, things aren’t so clear.

I came to think about this because, in ResponsIF, a “need” was initially considered met if the final value evaluated to 0.5 or greater. I began to think about the 0.5 case. Should 0.5 be considered met or not?

First, it occurred to me that “A and not A” when A is 0.5 evaluates to 0.5 So that means that an expression like that would actually satisfy the need at 0.5. That seemed wrong to me. “A and not A” is always false! (Or should be.)

But then I thought of “A or not A” when A is 0.5, and I realized it too is 0.5. Hmm. But “A or not A” should always be a true value. Or should it?

So when A is 0.5, both “A and not A” and “A or not A” have the same middling value.

I had a choice to make: do I consider 0.5 satisfying a need or not? I was getting no help from “and” and “or”. They were both ambiguous at 0.5. And that’s what led to my final decision: 0.5 does not satisfy a need. That’s the 50-50 case, the “it could be or it couldn’t be”. It’s just shy of a preponderance of the evidence. It isn’t anything definite.

I made the change. It might seem a bit strange to someone reading this that I pondered such a small thing at all, or for any length of time, but such tiny decisions are what go into designs like this. You have to work out the minutiae. You have to make the little decisions that sometimes end up to having large ramifications.

Sometimes pondering this level of things brings unexpected thoughts: if 0.5 is on that edge between false and true, if it’s a no-mans land, perhaps it becomes a coin toss. Perhaps when evaluating a need, if it’s 0.5, then it generates a random 50-50 result, sometimes true, sometimes false. That has some interesting ramifications which I might explore someday. In particular, I began thinking perhaps it should always be evaluated that way, as a chance. Not an “above or below this limit” but a random coin toss, where the coin is weighted by the need expression result. For example, if it evaluates to 0.8, you’d have an 80% chance of the need being considered met. Similarly, 0.1 would only give you a 10% chance. The extremes would still work as expected.

I don’t know if that makes sense at all. But it is fun to think about. It did have the result of making me start to consider whether “needs” should stop being a crisp choice at all, whether the “needs” value should just be an additional weight. That goes against its original emphasis, which is that a response allows you to configure it in both crisp and fuzzy ways. But I have to have these design crises on occasion to make sure I’m doing the right thing. Sometimes “the right thing” only becomes clear after doing something else for a while.

Like having 0.5 satisfy a need. It did and now it doesn’t.

Though sometimes I wonder if I made the right choice. It could have gone either way, really…

Oh, I don’t know.

Response-based IF

This will be a quick overview of what I’m calling “response-based” IF, which is what the ResponsIF engine is designed to do. It won’t get too in-depth into the nuances of the engine itself but will strive more to give the overall design considerations.

In general terms, a “response” is a unit of behavior. A response can output text (or other elements), change variables in the world state, move objects around, invoke other responses, etc. or any combination of the above. Anything that occurs in the course of interaction is done through some sort of response.

Responses are triggered by “topics”. A topic is anything you can think of. Nouns, verbs, ideas, emotions, pretty much anything you can think of can be a topic. If you can express it, then it can be a topic. A topic is “called” to generate responses.

Responses do not exist on their own. Rather, responses are provided by “responders”. A responder provides one type of context for when a response can be triggered – a response can only trigger when its responder is part of the active scene. (There are other sorts of context for responses as well, including the topic(s) to match and any necessary world state conditions.)

Let’s give a simple example of a response: the ubiquitous “Hello world” response.

.responses player
    .response START
        .does .says Hello, world!
.end

The key elements are here. The first line (“.responses player”) states that we are defining the responses for the “player” responder. The “player” responder is the only built-in responder in ResponsIF, and it is active in any response context. It is meant to correspond to the person playing (or reading or whatever) the current IF piece.

The next line (“.response START”) begins a definition for a response, responding to the topic “START”. The “START” topic is called by default when a ResponsIF piece begins.

The subsequent line defines what the response does: it outputs the string “Hello, world!”

Finally, “.end” terminates the set of responses for the player.

This is just a single response, and it doesn’t do much. But it should give an idea about how a ResponsIF game or work (termed a “riff”) is structured. An entire riff contains statements to set up the game world along with a collection of responders and their responses which will occur when various topics are called. Responders can be arranged in a hierarchical structure (parent/child) to establish the necessary contexts or even model “world” structures like rooms, hallways, caverns, etc.

How are topics called? Sometimes they’re called internally, as the “START” example shows. They can also be called by other responses. The vast majority of topics will be called due to player action, typically through UI elements such as buttons, hyper-links and textual input.

For example, the following rather pointless example shows how hyper-links can be created to call topics.

.responses player
    .response START
        .does .says Once upon a time, there was a {!princess!} who lived in a tall {!tower!}.
    .response princess
        .does .says She had long luxurious hair.
    .response tower
        .does .says The tower had smooth, stone walls that not even ivy could scale.
.end

The notation “{!princess!}” is called “link markup”. It creates a link that will call the specified topic (“princess”) when clicked.

The exact ResponsIF details are not terribly relevant here, beyond showing the basic concepts. (More details can be found at the ResponsIF github site: https://github.com/jaynabonne/responsif.)

A key part of ResponsIF is its use of HTML, CSS and JavaScript, which provides great freedom in how a work looks and feels. Due to this, ResponsIF can be used to create a large number of possible works. As a general-purpose engine, it is not restricted to any particular form of IF. Of course, being a general-purpose engine, it’s also not specialized for any particular form of IF, which means it may make more sense to use other tools more dedicated to a particular form, depending on what end result is desired. As always, choose the tool that best matches the task at hand!

In upcoming posts, I will go over my own personal goals and design choices for my IF work(s).

Conversations

(These are a series of postings I made in the textadventures.com (Quest) forums almost three years ago. The ideas put forth here eventually led to my Quest “Response Library”, which was then rewritten in JavaScript as ResponsIF. Not everything in it is still relevant for me, but I’m including here because it has some nascent ideas I think are worth preserving as well as including in this sequence of blog posts. I’m concatenating the posts together, as they’re all related.)

(Intro)

I wanted to start a dialogue (no pun intended) about conversations. Part of this is philosophical/theoretical, which can be fun on its own, but I also wanted to possibly work toward the creation of something new – a Quest conversation engine.

First, the idea bantering phase… So, what exactly do I mean by a conversation?

Part of that should be fairly obvious: the player having communication with other characters (also known as “non-player characters” or “NPCs”). There is already code in Quest – plus an extended such library written by The Pixie in the “Libraries and Code Samples” forum – which supports basic “ask” and “tell”. This takes the form of something like “ask Mary about George” or “tell janitor about fire”. You have a target character and what’s known as a “topic”. Typically, this basic implementation responds with a fixed response (e.g. look up string “topic” in character’s “ask” string table), with an occasional implementation of selecting randomly from a set of fixed responses.

But we usually want more…

There have always been questions, wishes, requests for NPCs to be more interactive. Now, this is black art at this point, and I don’t propose to have a definitive answer (maybe we can move toward that through this), but the point is, game author’s want more dynamic responses, based on any number of variables including previous topics, the time of day, what has occurred in the game, the state of play, and possibly even the emotional state of the character.

My own (limited) game design and wishes took me further.

Consider related desires. It has often come up that author’s want, say, room descriptions to change based on, well, more or less the same things listed above (though emotions come into it less). Similar design choices could be made for object descriptions, NPC descriptions, etc.

I had this revelation one day, as I began to see patterns in this. It finally occurred to me:

In a text adventure (or “interactive fiction”), everything is a conversation.

Let’s list some examples.

1) NPC conversation. The player wishes to ask characters in the game about things, requesting responses to topics. The character responds with information (or some non-committal shrugs or “I don’t know”, if not).
2) Room descriptions. The player makes queries to the game about the room. We ask the room, “Tell me about yourself,” and it responds. This extends as well to scenery. We often will put scenery objects into a room just to hang descriptions off of. These are not interactive objects as such – they exist in the game framework just so the user can type something like “x carpeting” and get a response. In the mindset of conversations, this could be thought of as asking the room about its carpeting. (In other words, the room is the character we’re conversing with, and the “carpeting” is the topic.)
3) Object descriptions. Similarly, when we “x” an object, we are asking it to describe itself.
4) NPC descriptions. Sort of like object descriptions but with a different feel.
5) Hints. Hints are really a bit of a one-way conversation, a running commentary by the game on what you’re doing. Certainly, there could be a “hint” command that forces a response, but there is also the system whereby hints are offered unbidden at the appropriate times. This, in a real sense, is the game conversing with you based on the state of play.

So you might be wondering why I’m trying to lump everything into conversation. The reason why was mentioned before: because we want all of the above things to have a certain dynamic to them, and that dynamic is common across them. We want them to not be static. We want them to change over time, not only randomly but in response to the game world. In a very real sense, as we are playing a game, we are in a conversation with the game itself, and we want this conversation to be alive and engaging.

Currently in Quest, the above areas are handled separately. Room, character and object descriptions (well, rooms and NPCs are objects, after all) are handled via a “description” attribute, which can be a string or a script. Ask/tell are handled via string dictionaries. And hints are basically “roll your own.” Which means that if you wanted to add dynamic responses for all of them, you’d need to implement separate code in separate places.

I’d like to change that. I know in my games (largely contemplated and only minimally implemented, mainly due to wanting too much), I have made stabs at implementing the above pieces.

One example: I wanted my rooms to have “directional descriptions”. By that, I mean that you would get a different description depending on which way you came into a room (or “area”). As an example, let’s say you’re outside in a clearing and you see a path to the north, so you type “n”. A stock description once you get there would be “You’re on a path. To the north, you can see a pond. A clearing lies to the south.” That bugged me a bit. Of course a clearing lies to the south – I was just there. I have walked north. In my head, I’m facing north.

What I wanted was that if you came north onto the path, it would say something like, “The path continues north. You can see a pond in the distance.” Whereas, if you came onto the path from the north, heading south, it would say, “The path winds further south, leading to a clearing.” Now, we can get into debates about where the full set of exits is listed. My option was to have a ubiquitous “exits” command that would dump the out (e.g. “You can go north and south.”) There are other ways to do it. But the point is: the game responds in context. To me, that is much more immersive than “push level B and get response Q”.

Now even if directional descriptions don’t make sense to you, other things undoubtedly will. For example, if you have a game that spans days within the same environment, you might want the descriptions to change based time of day or what the weather is. A whole host of possibilities come up. The same might be true even of NPC descriptions: in the beginning, the sidekick is immaculately dressed in blue. After the flight from the enemy agents, her top is torn and her hair is askew. The next day, having changed, she’s in black jeans, and she has donned a graying wig and wrinkled skin prosthetics like in “Mission Impossible.”

How would you do all that? Lots of “if” statements? I must confess – I love writing code, but it makes my skin crawl to write lots of special-case code, because it’s incredibly brittle and requires all sorts of mental gymnastics to keep straight. I’d rather write some nice general, data-driven code that seemingly by magic does the right thing.

So now we’re down to the proposal part – I’d like to begin working on a community Quest “conversation” engine. Not a library. Not “ask/tell”. I mean a full-on, topic-based, evolving over time sort of engine that anyone can use and enjoy. To that end, I’d like to get any thoughts that people have on the subject, any design considerations, possibly even any code designs that you’ve tried yourself. For anyone who’s interested, let’s put our heads together (and chickens are welcome as well as pigs – if you don’t know what that means, either skip it or look it up).

There are different approaches to NPC conversation, but I want this engine to be something that can be used universally in a game as well as (on some level) for all those things listed above. Perhaps that’s too big an ask, but I want to set the bar high going in. Then we can see where we get to.

I’m going to follow this post up with some of my own (soon), but I wanted to get this started.

(First of several parts)

What we will call “conversing” (I’m going to stick with that, as perhaps it will someday become more like that) is in reality selecting text to display to the user – choosing something for a character to “say” – either in response to a query (direct trigger) or based on conditions (indirect trigger).The trigger might have a topic or topics associated with it (e.g. a query about a topic), or the trigger might be neutral (e.g. a hint engine that runs on each turn searching for phrases to present, or a particularly chatty NPC who offers up information in his/her own when the time is right).

How do you select what to say? For things like object/room/character descriptions, the standard is either a hard-coded string or some code which typically selects and assembles the output based on whatever specific logic is programmed in. For something like ask/tell, the implementation is a string lookup in a dictionary.

That is the current state-of-the-art in Quest. There’s any number of ways to go as far as how we can implement string selection. I’ll cover a couple of directions I have explored.

Boolean Logic

The most straightforward is to implement some sort of hard “yes or no” selection. That is, we look through the available phrases and see which ones match. Either a phrase matches or it doesn’t. What to do if more than one matches depends on the situation (and so complicates things a little bit). For interactions with an NPC, you’d probably want it to spit out a phrase at a time in response. You could randomly select one, for example. Another possibility is to show all matching phrases.

The latter is what I did in my room description implementation. Each room could have various “topics”. A topic would then have conditions. Standard topics included “base” (the base description), “first” (text to show the first time), “later” (text to show when not the first time), “north”/”south”/”west”, etc (text to show based on arrival direction), etc. Custom topics could also be added, depending on conditions and needs.

A sample room might have text like:

<baseDescription>"This is the second floor landing."</baseDescription>
<westDescription>"Further to the west you can see an archway leading to another hallway. A broad staircase leads up and down."</westDescription>
<eastDescription>"The hallway continues east. A broad staircase leads up and down."</eastDescription>
<upDescription>"The stairs continue up. A hallway heads off to the east, and through an archway to the west, you can see another hallway."</upDescription>
<downDescription>"The stairs continue down. A hallway heads off to the east, and through an archway to the west, you can see another hallway."</downDescription>

The description would be a combination of the base description and any directional ones. So, for example, if you move west to get the landing it will show:

This is the second floor landing. Further to the west you can see an archway leading to another hallway. A broad staircase leads up and down.

which is a combination of the “base” and “west” descriptions. (The fact that strings are surrounded by quotes is due to the fact that I would “eval” the attribute to get its real value. This allowed me to put expressions in the strings.)

Here are some of the conditions (in the base room type) that trigger the various pieces:

<baseCondition>true</baseCondition>
<northCondition>lastdir="northdir"</northCondition>
<northwestCondition>lastdir="northwestdir"</northwestCondition>
<westCondition>lastdir="westdir"</westCondition>
<firstCondition>not GetBoolean(room, "visited")</firstCondition>
<laterCondition>GetBoolean(room, "visited")</laterCondition>

Now, this is all well and good and works fine for rooms. The conditions can vary, and the text shown will vary accordingly. But it is very static. What it’s missing is any sense of history, any inclusion of what has been shown (to some extent, what has been “discussed”). For NPC interactions, I wanted more.

Fuzzy Logic

Moving beyond the yes/no, hot/cold, show/don’t show of binary, Boolean logic, we arrive at another alternative – that of fuzzy logic. I have only toyed with a test implementation of this; with no real world uses, it might end up needing some more design to make it all work properly. I’ll describe what I have considered so far.

The basic idea behind this is the notion of a current “conversation context”. This context holds information about the current set of topics. This set of topics changes over time as different topics are explored.

Each NPC would have its own conversation context. Each possible phrase would also have related topics. Triggering a phrase will update the conversation context, which will then influence subsequent phrase selection. Let’s see how this might work with an example.

Here are the phrases. The first part is the string. After that is a list of topic weights associated with that phrase. Weights range from 0 to 100. (There might be a use for negative weights as well.) I hope this isn’t too contrived…

[id=1] “My father was a farmer.”, father=100, farming=100, family=50, history=80
[id=2] “I grew up on a farm.”, farming=100,history=80,home=100
[id=3] “My brother’s name is John”, brother=100, family=50, john=100

Let’s look at these a bit. For the first one (“My father was a farmer.”), we have the topics “father” and “farming” being a strong match. The topic “family” matches 50%. The weights have two purposes:

1) They help in matching by showing how much a topic matches the phrase.
2) They are used in modifying the conversation context when they are used. (More on this below.)

The idea behind 2) is that our minds are very associative – when we discuss topic “A”, it brings in other related topics (“B”, “C”, and “F”). We want to have a similar behavior in our phrase selection.

Initially, the conversation context is empty. Nothing has been discussed.

Context = {}
Let’s say the player enters “ask about father”. Due to this, the “father” topic gets injected into the current conversation context:

{ father = 100 }

Now, we search. The search is done by generating scores for each phrase via a sort of “dot product”. (If you don’t know what that is, don’t worry.) Basically, we multiply the context with each phrase’s topics and generate a score. In the following, the first number multiplied is the value in the context; the second number is the number in the phrase weights. A missing weight has value 0.

[id=1] score = (father) 100*100 + (farming) 0*100 + (family) 0*50 + (history) 0*80 = 10000
[id=2] score = (father) 100*0 + (farming) 0*100 + (history) 0*80 + (home) 0*100 = 0
[id=3] score = (father) 100*0 + (brother) 0*100 + (family) 0*50 + (John) 0*100 = 0

In this case, phrase 1 is the clear winner. If the topic were “brother”, I hope it’s clear that phrase 3 would be the winner.

Let’s see what happens if we have “ask about family” as the topic. In this case, the context would be {family=100}. Running scores, we get:

[id=1] score = (family) 100*50 + (father) 0*100 + (farming) 0*100 + (history) 0*80 = 5000
[id=2] score = (family) 0*0 + (farming) 0*100 + (history) 0*80 + (home) 0*100 = 0
[id=3] score = (father) 100*50 + (brother) 0*100 + (John) 0*100 = 5000

In this case, both phrases 1 and 3 match “family” about the same. What happens is to be defined. Either it could spit out one phrase (chosen randomly perhaps, or in order), or it could spit the both out (“My father was a farmer. My brother’s name is John.”).

Let’s go back to the “father” case. In that case, we would have a result of phrase 1. So the NPC would say, “My father was a farmer.” Based on standard human conversational associations, we would want to update the conversation context with any related topics brought in due to that phrase. I’m not sure of the ideal algorithm for that. For this case, let’s assume we generate averages. (A better weighting scheme might make more sense.)

Context = {father = 100}
Phrase = {father = 100, farming = 100, family=50, history = 80 }

new “father” = (100 + 100)/2 = 100
new “farming” = (0 + 100)/2 = 50
new “family” = (0 + 50)/2 = 25
new “history = (0 + 80)/2 = 40

New Context = {father = 100, farming = 50, family = 25, history = 40)

This is now the current conversation state. What I had wanted was for NPCs to be able to initiate conversation as well, not just respond to player queries. If the player were idle in this case, the NPC might decide to come back with its own search for something to say. Performing the search again with the current conversation context (let’s assume we won’t repeat a phrase), we get these weights:
[id=2] score = (father) 100*0 + (farming) 50*100 + (family) 25*0 + (history) 80*40 + (home) 0*100 = 8200
[id=3] score = (father) 100*0 + (farming) 50*0 + (brother) 0*100 + (family) 25*50 + (John) 0*100 + (history) 40*0 = 1250

In this case, phrase 2 matches, so the NPC will follow up with: “I grew up on a farm.” After this phrase is uttered, the conversation context will be updated to:

New Context = {father = 50, farming = 75, family = 12.5, history = 60, home = 50)

Note that we didn’t discuss “father” again, and so its weight has decreased. Also note that farming has been emphasized. And we now have a new topic (“home”) which may trigger additional, subsequent phrases.

There are many variants to this, possibilities for manipulating the parameters. Perhaps the new conversation context should not be a simple average but a weighted one. Perhaps the conversation context should “decay” over time, if there is no conversation (that is, if you cease talking, the weights gradually move to 0 and disappear with each command). Perhaps a new topic injected should enter into the context with some lower weight than 100. As far as not repeating phrases, perhaps the “memory” of a phrase being spoken decreases over time (possibly at a rate determined by the age of the NPC), such that it will eventually be repeated. There would also need to be some determination of what to do if either no phrases match (“I don’t know about that”), or all matching phrases have already been spoken (“I don’t have any more to say about that.”)

There is one downside to these weights which needs to be addressed. A queried subject might want to be searched more forcefully than one where the NPC follows up on its own. For example, after “ask about father”, if the player enters “ask about the moon”, it wouldn’t make sense for the NPC to come back with “I grew up on a farm” (which it would if straight weights were used and the priority of the topic wasn’t taken into account). One way to work that out is that a new query from the player generates a new temporary search context with just that topic, with the weights from any chosen phrase adding into the current context afterwards.

Next: Bringing in the world state, the best of both worlds, and some emotions.

(Continued)

(Note – this article is referenced below: http://emshort.wordpress.com/how-to-play/writing-if/my-articles/conversation/)

Assuming what we have been discussing so far actually works, then we now have some sort of scheme for modeling an evolving conversation. It does mean that you as the author have to actually go in and create all the response phrases – and decide all the topic weights. While the thought of having NPCs actually generating utterances on their own (putting words together to form coherent sentences) is a wild pipe dream, that is not what we’re talking about here.

(Aside: In Emily Short’s article listed above and in her other ones, she uses the word “quip” for what a character says. While that is a bit of a fun word, it had a connotation to me of levity which I didn’t think was generally applicable. So, being the programmer that I am, I am going with the more generic “phrase”. Even that might not be entirely accurate, but we need something.)

What we have gone over attempts to address selecting phrases based on topics, but it’s fairly self-contained. The only inputs are topics. We also want to interact with the game world, to somehow have the world state influence phrase selection.

By “world state,” I mean pretty much anything of interest in the game world. It can be things like:
– where the player is
– where they have been
– what they possess
– what they have possessed
– whether a murder (or some other significant event) has occurred
– the time of day
– the presence or absence of other NPCs
– the emotions of the various NPCs
– who has just walked past in the corridor
– choices the player has made in the past
– anything else relevant to the story being told (or the puzzles therein)

You could, in theory, use weights for that, and inject state in as topics. I tried that for my room descriptions at first but quickly abandoned it. There are two problems:
1) You need to create a topic for each piece of world state (“has_stake”, “visited_crypt”, “saw_vampire”, “killed_vampire”, etc or, in my case, “east”, “west”, “north”, etc ), which can quickly become unwieldy.
2) Such state is typically binary – we only want certain phrases to be eligible when certain conditions are true. In order to do binary in a weighted scheme, you have to not only add weights for what you want but also (short of some notation which I tried and gave up on) add negative weights for what you don’t want, to prevent the phrase from being selected when those topics are present. It’s possible but, again, quickly becomes painful.

What I have come to is that we want to somehow utilize both schemes, “binary” and “fuzzy”. The “binary” part would be used for phrase eligibility, based on world state; the “fuzzy” part would be used for selecting from among the eligible phrases, based on topic or other fuzzy considerations. This is the next area of thought for me, so I don’t have any ready answers yet. Perhaps some sort of uniform notation could be adopted. I’m open to that if it would work; in fact, I’ll probably revisit it myself, as I like to unify things.

One piece of “world state” we might want to consider is the emotions of the NPC. For example, if I ask a character about her father, if she loves me, she might respond, “I can’t wait for you to meet Papa!” whereas if she is feeling antagonistic towards me, such queries might be met with, “That’s none of your business!” or something even more venomous. Whether such state is “hard” (binary) or “fuzzy” is really a question of design, depending on how the emotions are modeled. That’s another discussion to be had. It could be implemented as simply (but crudely) as a boolean “inLove”, if that’s all you care about, or as a variable “loveState” ranging from 0 to some upper number, or as a scale ranging from hate to love. You can also have different ranges for different kinds of emotions. The point is: you will need to determine how that is going to be modeled before you can decide how to integrate it with a conversation model. Hopefully, if this all comes together, you’ll have plenty of flexibility to do it the way you want.

(Continued)

A random, somewhat related thought: this one’s about room descriptions.

Typically, room descriptions are centralized. When I say “look”, it goes to the room object (in Quest) and says, “Give me your description”, and that description is either a string or a script. And there is boilerplate code that dumps out the objects in the room, the exits, etc.

Now, let’s say that conditions can change in the room. Maybe a chair is there sometimes and other times not. How do you handle it?

The typical way in Quest is via an “if”. You make your room description a script, you dump out the stock part of the room description, and then you put in an “if”: “if the chair is in the room, also print *this*”. It’s all a bit clunky, and it’s also rather centralized. The room has to know about the possibility of the chair. It’s all very static, very hard-wired, very brittle.

Let’s turn the notion on its head a bit. What if we look at the command “look” as an invitation from the player for description, which goes not just to the room but to all within it. Now, instead of the room having to know that a chair is possibly there in order to add in custom text, we will have the room respond with its description and we’ll let the chair chime in as well with its own description (with such description being the minimal “There is a chair in the corner” sort of thing, with a full description forthcoming if the player directly queries the chair further). And if the chair isn’t present, well, then nothing is there to say it. Imagine the room saying in a booming voice, “You’re in the library” and then you hear a small voice from the corner say, “There’s a plush chair in the corner.” They get written out together in one block of text. Now, instead of a single voice, we have mutiple voices all responding together. Instead of having to put “To the east, there is a foyer”, the east exit will itself add in the text to alert the player to its presence – if it wishes. “Hey look! You can go this way.”

A bit bizarre on first thought, perhaps, but I really like this sort of thing…

(Finally)

I’m in the process of working on a general “response” library, which I’m using in a fledgling game. The game is forcing me to actually use it in a real-world way, and it’s helping to point out where the design has flaws or can be expanded. Lots of uses cases being folded in…

To back up, I had a bit of turn of thought, based on (what else?) terminology. I came to realize that the word “phrase” was not very good, as it just didn’t fit with what it actually was, since a phrase is a piece of a sentence. So I went in search of a better word. I came across “response” and it stuck. But that word opened up new directions in thought. A response need not be verbal. It could be a reply, but it could also be a shrug, a smile, or even a punch in the face.

Explorations in Interactive Fiction

This is my first post before diving deeper into both my thoughts and efforts around interactive fiction. It will provide an overview of where I am and where I’d like to go.

Let me begin by saying that my definition of “interactive fiction” may or may not be the same as anyone else’s. The term has been applied to such disparate concepts as parser-based “text adventures” and hyperlink-based “choose your own adventure” or “gamebook” creations. In fact, if you look at the Wikipedia entry for “Interactive Fiction”, it begins with the definition that IF “use[s] text commands to control characters and influence the environment.” It states later that the term “can also be used to refer to” gamebooks. There has always been a bit of a divide between those two camps.

For my own purposes, I consider “interactive fiction” as hewing closely to the name – fiction that is interactive. That’s it. It can include all of the above and more – where “more” can include new ways to make fiction interactive that might not even have been conceived yet. If it’s not clear yet, I have my own ideas about the types of IF works (“games”? “pieces”?) that I’d like to create.

I won’t define IF for you, but I hope the things explored under this umbrella can provide food for thought, if nothing else. The majority of ideas discussed here will be in relation to my “ResponsIF” system, a response-based interactive fiction engine written in JavaScript, but that doesn’t mean that they can’t be applied to other systems or just considered in general. You don’t have to use ResponsIF or even have a desire to do so in order to take something from all of this.

With that, I’ll end this general overview, and we can get down to business.

(For those interested, the latest version of “ResponsIF” can be found here: https://github.com/jaynabonne/responsif)