Mechanic #204 - Better CYOA|
|Posted: Dec 12, 2014|
A few simple techniques to improve the form and function of Choose Your Own Adventure style games without increasing complexity.
Better Choose Your Own Adventure|
Recently, Choose Your Own Adventure (CYOA) books have been at the forefront of my mind. It started when I made a second attempt at playing Telltale Games' Walking Dead season 1. I realized that the game had more in common with a CYOA books than traditional point and click games like Monkey Island. I realized that the game was built of a series of largely stateless nodes, with a linear progression between them.
Ironically, discovering that The Walking Dead was in a different genre than I was expecting (or wanting) opened me up to enjoying it a little more. Rather than being a genre that I was well familiar with, it became a chance to learn something new. I will say that CYOA is an accomplishment for a non-interactive medium like books (with some GameBooks being quite complex indeed), but in a primarily interactive medium like video games, it feels like laziness.
That being said, I looked into programs like Twine that exist solely to create CYOA-style games of nodes and connections. I saw the games being created for it and I realized that CYOA is appealing precisely because it is so simple and it has that ability to be so linear. It represents the most basic way to tell a linear, branching story for people who are most comfortable telling stories in a linear, branching way.
Fig 204.1 - The Back Cover of a CYOA Book.
The above image is a flowchart on the back of a Choose Your Own Adventure book I found at the bookstore the other day. Yeah, they put flowcharts on them now. It's not theoretical either. Each book had a different flowchart. The book announcing 42 endings had a much broader, shallower chart than The Abominable Snowman here.
But is there anything that flowchart reminds you of? Well, it's a tree, obviously (you guys know I love tree structures). But I was looking more for an iterative programming language. Statement, statement, branch, statement. Choose Your Own Adventure books are just the world's most boring programming language, built from nothing but IF and GOTO statements.
Fig 204.2 - Fabled Lands partial flowchart.
However, the CYOA programming language becomes more complicated when you add variables. This gives the world state, and because of this, you can return to nodes and have them change accordingly. The GameBook series Fabled Lands is much more like an open world game because it involves numerous hubs that you can move between, gaining money and abilities. These abilities, which you record on a player sheet using a pencil, act like flags, making certain connections and node available. As such, the flowchart for Fabled Lands is less like a tree, and more like a series of clusters.
Fig 204.2 - Spaghetti code. Fabled Lands complete flowchart.
The full flowchart is very large and detailed - certainly a far cry from The Abominable Snowman - but you can see the clusters quite clearly. Fabled Lands takes it one step further and allows you to take your created character through numerous books (and back again), each book being a new continent to explore at your leisure. Needless to say, something as simple as writing down variables and giving the game a state can increase the expressiveness of the CYOA programming language considerably.
But I think we can go one further. Below are two sets of techniques that can increase the expressiveness even further. One can be used with books, while the other are a few techniques I picked up writing DeathSpank dialogue trees that requires a computer (and hidden information).
If you assume that CYOA is a very simple programming language, consisting of branches and GOTO statements, the most obvious improvement we can introduce is an activation stack. If you are familiar with BASIC (and if you are under the age of 30, you probably aren't), it's the difference between GOTO and GOSUB. In other words, we can goto a node which remembers where we were when we left, and can thus return to it at leisure.
For example, there are sub-graphs that you may want to enter regardless of the circumstances of where you enter them. For example, a character that roams around the castle can be easily managed using a single variable which maintains his location. In the node for the foyer, the option to talk to this character will be available if the character's position variable is foyer. In the conservatory, the same thing.
However, talking to this character is separate from where you talk to him. If you only had GOTO available to you, you'd need to do several branches at the end determining the character's position variable and using the appropriate GOTO to get back. But this is difficult to maintain, as it creates a two way dependency. If you change or add a location he can move between, you would need to change the return branches in the character's dialogue tree to match. At a certain level of complexity, it becomes impossible to maintain.
Looking at CYOA as a programming language, it becomes immediately apparent that this can be easily solved through a function call - the resulting "return" statement would take you back to the place you were before you called the function. In this case, it would return you to the node you were in when you decided to talk to the character.
As with programming languages, this is solved through a very simple stack. Just write down the page/node-id at the top of the stack whenever you encounter a GOSUB instead of a GOTO, and return to the top value of the stack (erasing it) whenever you encounter a RETURN. It's so simple, you can
It's an obvious addition to the CYOA programming language, but it opens up the language to a variety of uses that are otherwise difficult or flat out impossible using simple GOTO statements. For instance, you can now implement an inventory system that can be called from any location-based node quite simply. And from the inventory node, you can go into specific subroutines for each inventory item, able to return and return again at any time to continue the normal flow of the CYOA program.
Perhaps even better is that it allows these procedures to be developed (and tested) separately from the main graph flow. You can develop areas, segments, and subsystems without regard to how they will be used. You can have multiple game designers working together on their own modules, and integrating them simply by changing a GOTO to GOSUB.
The second big technique I'd add to the CYOA code is something I'm basically lifting wholesale from how DeathSpank dialogue trees were created (and, I assume, dialogue trees for SCUMM-based and other LucasArts games). This is largely a way of hiding choices in order to create a progression and to hide choices based on state variables.
choice 1: "During an act of heroism, my sword was broken. Can you help me?" goto new_sword [once] [if onquest X]
choice 1: "Perhaps we can work out a trade for your sword, Bessie?" goto new_sword2 [once] [if onquest X]
choice 1: "You wanted mayonaise on your taco, right?" goto taco_ingredients [if Y == 0]
choice 1: "You wanted lots of butter on your taco, right?" goto taco_ingredients [if Y == 1]
choice 1: "You wanted lizard meat on your taco, right?" goto taco_ingredients [if Y == 2]
choice 1: "You wanted cottage cheese on your taco, right?" goto taco_ingredients [if Y == 3]
choice 1: "You wanted raw sewage on your taco, right?" goto taco_ingredients [if Y == 4]
choice 1: "You wanted a severed human head on your taco, right?" goto taco_ingredients [if Y == 5]
choice 2: "I've got your taco!" goto give_taco [if havequestitems kGetTaco]
choice 2: "I've got your taco!" goto give_taco [if onquest kGetTaco and haveitem Item_Taco]
choice 2: "You forgot to give me money to buy the taco." goto ask_for_more_money [if onquest kGetTaco]
choice 3: "Is 'adventurous days' code for cross-dressing?" goto eubricks_past [once]
choice 3: "You went from Undefeated to Bitter? I smell a juicy story." goto eubricks_past2 [once]
choice 3: "You met Lord Von Prong in battle?" goto eubricks_past3
choice 4: "I'm looking for some orphans." goto orphans1 [once]
choice 4: "It is imperative that the orphans be found." goto orphans2 [once]
choice 4: "Would you say Lord Von Prong is the orphan-stealing type?" goto orphans3 [once]
choice 4: "That's an unusual growth on your back there..." goto fluff1 [once]
choice 4: "Do you have any old adventuring treasures to sell?" goto fluff2 [once]
choice 4: "You must have found some amazing loot in your day." goto fluff3 [once]
choice 4: "Have you seen any orphans yet?" goto orphans4
choice 5: "See you later, Eubrick." goto goodbye3 [if donequest kGetTaco]
choice 5: "I'd love to stay and chat, but I'm lying." goto goodbye1 [if onquest kGetTaco]
choice 5: "See you around, Aged Hero." goto goodbye2
What you are looking at is a slightly edited version of the dialogue hub for Eubrick from the game DeathSpank. In DeathSpank, there were a limited number of a lines you could use for dialogue choices. This ended up being beneficial because you could ultimately replace lines - either by exhausting dialogue options, or by prioritizing lines based on what the game state was at the time. For instance, choice 1 is largely dedicated to the two primary quests that you'll receive from Eubrick. Choice 2 is used to finish the second quest. Choice 3 and 4 are used to ask for (optional) details about the quests and world, and choice 5 is used to end the conversation.
The way it works is that the interpreter (or whatever) will go through the choice options until it finds the first one that succeeds its conditions. After that, all other choice options for the same slot are ignored. In this way, options towards the top are prioritized. You won't ask about the severed human head unless you've exhausted the other seven choice 1 options.
The second noteworthy thing here is the [once] signifier on some of the options. Those options are only available until they have been selected. After that, [once] fails and that choice is skipped. This is used, for example, to put a lot of exposition in choice 4 by constantly showing new options as the player selects them.
Choice and Once are primarily beneficial to dialogue trees, and I do admit that I present them here in an effort to improve the quality of dialogue trees everywhere (dialogue choices based on intent, emotions, or wheels of any sort can bite me), but they could easily be used for choices made during a CYOA book.
For example, you can use the exclusive choices to represent a sequence of actions.
Sequence of Actions Using Choices
choice 1: "Examine dresser." goto dresser_examine [once]
choice 1: "Attempt to open drawer." goto dresser_locked [if !haveDresserKey and !dresserUnlocked]
choice 1: "Unlock drawer." goto dresser_unlock [once] [if haveDresserKey and !dresserUnlocked]
choice 1: "Take kazoo from drawer." goto dresser_get_kazoo [once] [if dresserUnlocked]
Here we have a sequence of actions that changes based on the state. The first time you enter the node, you will be able to examine the dresser. Thereafter, until you have a key or have unlocked the dresser, you can attempt (and fail) to open the dresser. If you have the key, but haven't unlocked the dresser, you can unlock it. Finally, if the dresser is unlocked, you can get the kazoo from the drawer - an action you can perform only once. After that, choice 1 is ignored completely.
Because CYOA are not necessarily locking into a limited number of choices, you can use identifiers instead of numbers, like "choice dresser". Similarly, the GOTO options could be replaced with GOSUBs, allowing the dresser nodes to concern themselves with behavior instead of the greater node tree.
Ultimately, this behavior could be emulated by using a series of IF branches and by declaring [once] variables explicitly, but I think that introducing them to the CYOA language would result in this sort of behavior being used more often, and towards better ends. Between choices and gosubs, I think someone could create a much more interesting CYOA game without really introducing much complexity to the structure or nature of the system.
Finally, there's transitions. I'm less enthusiastic about this idea being a necessary part of the CYOA 2.0 language, but I thought it was worth pointing out. Nodes are not, by themselves, necessarily unique. In GameBooks like Fabled Lands, nodes are visited and revisited frequently as paths are traversed over and over again or because nodes represent a hub of decisions. It might be important to consider the idea the nodes should NOT be considered unique, and design should dictate itself accordingly.
However, what is unique is the transition from one node to the next. While a node can be arrived at from numerous other nodes, the connection between one node and another has several things that are unique about it. The first is that it is one way. Node A going to Node B is different from Node B going to Node A. The second is that there may be several one-way connections that are unique to each other.
As such, I propose a "transition" type that allows you to put text and code that is displayed/called when moving from one node to another. If you use a graphical representation, you could just double-click the line between nodes and enter text. Otherwise, you could introduce it in the code itself as a block:
Sequence of Actions Using Choices
choice 1: "Examine dresser." [once]
"It is an ugly dresser that looks like someone beat it with a hammer."
"There is a drawer in the dresser that jiggles but doesn't open."
choice 1: "Attempt to open drawer." [if !haveDresserKey and !dresserUnlocked]
"The drawer will not open. It is locked."
choice 1: "Unlock drawer." [once] [if haveDresserKey and !dresserUnlocked]
"You unlock the drawer with the dresser key. Click."
dresserUnlocked = true
choice 1: "Take kazoo from drawer." [once] [if dresserUnlocked]
"You take the kazoo."
haveKazoo = true
There's a few noteworthy things about this. Before, where the choices were filled with GOTOs for each choice, the ability to put simple code and text into a transition allows us to put the behavior of these actions directly into the transitions themselves. As such, there are no GOTO statements and the transitions are between Node A and Node A directly.
The second noteworthy thing here is that the behavior is described next to the action. In a normal CYOA system, like Twine, you'd have to create a second node block to hold this text and behavior. While there is nothing wrong with this approach, if it is relied on extensively, it could increase complexity into the graph - at the end of all this, I think that you should be able to visually determine patterns and concepts from the node graph, and having too many transition nodes would ultimately be needless noise.
Ultimately, this approach allows the writer to increase behavior and complexity without gumming up the node graph. This means that the nodes in the graph represent far more significant elements to the story/world, and the patterns that they represent will be more obvious and useful for debugging.