1

I'm working on a very simple text adventure in javascript. You are shown a paragraph of text, there is a continue for you to click which will progress you to the next paragraph of the story. Occasionally the button is replaced with several option buttons, for instance yes/no, or options 1/2/3 etc, which will alter the course of the story.

Example of text adventure

What is a clean and logical way to structure such a 'dialog system'?

This is what I have right now:

A variable timeline determines the next message and continuity of the story by cycling through a switch. When the story is linear, timeline increments by one, which leads to the next message. When a choice is encountered (such as in timeline = 2), my functions will allow the player to choose whether to continue through story path 1 (timeline 3,4) or story path 2 (timeline = 5...).

function nextMsg(){
 switch(timeline) {
  case 1:
   nextMessage = "With a little bit of force you wrestle the door open. A draft of cool wind refreshingly glides over your body. You take a deep breath of fresh air and wander into the forest.";
  break;
  case 2:
   nextMessage = "As you traverse the evergreen maze you stumble upon a small glade. A dark figure stands in the middle. You feel uneasy. Do you wish to investigate?";
   showQuestion(3,5);
  break;
  case 3:
   nextMessage = "You approach the dark figure. The silhouette, mysteriously, does not cast a shadow, nor does it reflect any light. Apprehensive but curious, you cautiously advance.";
   showContinue();
  break;
  case 4:
   nextMessage = "Drawing closer, you notice the ambient sounds of the forest around you fade into silence. In their place, a deep, rhythmic howling, much like that of a strong wind becomes audible.";
  break;
  case 5:
   nextMessage = "Apprehensive of the shadowy figure, you decide to venture deeper into the forest.";
  break;
 }
}

In theory, even if this gets overly complicated and convoluted it will all work. But if I decide to add/remove messages in between, the timeline numbers will get very messy and disorganised. It will also become very difficult to keep track of the possible story paths, especially as they weave in and out of each other. Is there a better way to structure data like this? A switch is the only thing I can think of, yet it feels stupid.

EDIT OF SUCCESS:


The 'story' is broken down into smaller linear 'sub-events', so individual paragraphs don't need to have any id. When the subevent reaches the last paragraph, any amount of choice buttons leading to different sub events will be generated. Thank you Dellirium for giving me insight on how to do this!

var subEvents =
[
{
 id: 0,
 text: ["par1","par2","par3","par4"],
 options: ["Yes","No","Maybe"],
 optionPaths: [1,2,2]
},
{
 id: 1,
 text: ["par5","par6","par7"],
 options: ["Jes","No"],
 optionPaths: [1,2]
},
{
 id: 2,
 text: ["no path","noo","nooooo"],
 options: ["Y tho","No"],
 optionPaths: [1,2]
}
]
var currentEvent = 0;
var eventCycle = 0;


function updateEventCycle(){

 for(i=0;i<4;i++){
  document.getElementById("l" + i).innerHTML = document.getElementById("l"+ (i+1)).innerHTML;
 }

 document.getElementById("l4").innerHTML = subEvents[currentEvent]['text'][eventCycle];
 eventCycle++;

}
function clickEventHandler(nextEvent){
  eventLength = subEvents[currentEvent]['text'].length;

  if(eventCycle<eventLength) { //if event not completed
    updateEventCycle();
    //createContinueOption();
    if(eventCycle==eventLength) {
     createEventOptions();
    }
  }
  if(typeof nextEvent !== 'undefined') {
   currentEvent = nextEvent;
   eventCycle = 0;
   createContinueOption();
   updateEventCycle();
  }
}
function createContinueOption(){  
  document.getElementById("optionForm").innerHTML = '<input type="button" value="Continue" onclick="clickEventHandler()"/>';
}

function createEventOptions() {
  options = subEvents[currentEvent]['options'].length;
  optionsHTML = "";
  for(i=0;i<options;i++) {
   optionsHTML = optionsHTML + '<input type="button" value="'+subEvents[currentEvent]['options'][i]+'" onclick="clickEventHandler('+subEvents[currentEvent]['optionPaths'][i]+')"/>';
  }
  document.getElementById("optionForm").innerHTML = optionsHTML;
}
#line4 {
 color: rgba(0, 0, 0, 0.7);
}
#line3 {
 color: rgba(0, 0, 0, 0.5);
}
#line2 {
 color: rgba(0, 0, 0, 0.3);
}
#line1 {
 color: rgba(0, 0, 0, 0.2);
}
<div>
 <span id="line1"><p id="l0">one</p></span>
 <span id="line2"><p id="l1">two</p></span>
 <span id="line3"><p id="l2">tre</p></span>
 <span id="line4"><p id="l3">quatro</p></span>
 <span id="line5"><p id="l4">ok</p></span>
</div>

<div id="optionForm">
 <input type="button" value="Continue" onclick="clickEventHandler()"/>
</div>
Coma
  • 179
  • 10

1 Answers1

1

The way I'd do it is with objects that structure the data properly, as in:

var allStories: [{
  id: 23 //uniqueNumericID 
  message: "Your message",
  continue: 24,
  yes: 28,
  no: 35,
  anyOptionName: anyID
},
{
  //Another object, and so on
}]

//Then use a script like this to add them under
//a single object under their ID's:

var stories = {}
var currentStory = 1; //ID of the first story
allStories.forEach(function(element, index, array){
  stories[element.id] = element;
});

//Now on your buttons, just deliver the "keyword" 
//that should be used to go forward, like so:

function ContinueClickEventHandler(){
  currentStory = stories[currentStory['continue']]
  // Your currentStory will now have the message.
}

If your continue keyword is yes or no or whatever it is, it jumps to that segment, you can even make it all a single handler with a parameter and just pass it instead of a fixed continue

Dellirium
  • 1,362
  • 16
  • 30
  • From looking at, messing with your code and trying to learn the syntax I ended up learning how objects work and created a beautiful, scalable and elegant system for this. Thanks! – Coma Aug 09 '16 at 14:15
  • I am glad that you've fiddled with it instead of taking it as is, this is what most people never do and it is the right approach! Keep it up! – Dellirium Aug 10 '16 at 10:13
  • 1
    I am sorry for not being here while you were struggling, I went home shortly after posting the answer and saw what you did this morning. I am glad you solved everything and if you have any other questions, I would be glad to help. You said the code does not work, I might have made a mistake (haven't tested it) somewhere in the syntax, the concept should work though. Once again, been a pleasure reading what you did and imagining myself going through the same struggle a few months ago. If you need anything else feel free to ask. Pozz – Dellirium Aug 10 '16 at 10:52
  • Hey thank you for the kind words! I've edited my post with a runnable snippet of what I have so far. Every feature I wanted is currently working. But the power of objects is still blowing my mind. Perhaps you can offer me a resource to learn more ways to use them? I also had huge problems figuring out correct syntax using [ ] s and { }s where appropriate. I still don't really get the rules, and google isn't helping too much. Also is dynamically creating buttons like I do in the code above a good idea? It seems a bit hacky but works nicely. Again thank you for nudging me in the right direction! – Coma Aug 10 '16 at 14:27
  • Javascript knows no associative arrays, we got regular enumerated arrays `[]` and objects `{}`. Objects use `key : value` pairs with that notation, arrays are indexed. You cannot 'loop through' or perform any type of ordering on an object, but you can for an array. You can however have objects that use numbers as keys such as `1 : "something"` but it is not recommended. Everything in javascript is rather dynamic so you can at any time add or remove properties/keys/fields in an object. You can access object's properties by both `object.fieldname` and `object["fieldname"]`. – Dellirium Aug 10 '16 at 17:38
  • As far as the resource to learn more, I'd recommend Douglas Croakford's articles and his website, http://javascript.crockford.com/ since it offers a bit deeper approach. I would direct you to also try as much as you can to use native javascript and avoid any frameworks, this is how you will end up learning it the best. Later when you understand it, using a framework will be a timesave, but it is not good for learning. When you feel confident that you know a bit about object constructors through functions, look here: http://stackoverflow.com/questions/111102/how-do-javascript-closures-work – Dellirium Aug 10 '16 at 17:41
  • One last thing to add, many, MANY people write JS baddly, it is a language that is flexible enough to allow it. Optimization is something you do not need to worry about at start but later will. I'd focus on learning how the code works in the background. I started my study with Tim Wright's Learning JavaScript book, and it teaches good basics, the very basic, basics.... but I cannot recommend it for anything other then simple stuff. I learned a lot more by just fiddling around with the code. Javascript's functions are very powerful due to closures, once you understand how to use it, fiddle! – Dellirium Aug 10 '16 at 17:52