Twine Tuesday: Dynamic Dialogue

[This is the last scheduled Twine Tuesday post for awhile. I might come back to doing these later this year, but I don’t get the feeling that they are as helpful to others as they could be. It’s mostly just me posting my own code.]

For those following my weekly Twine projects, you may have noticed that I have become really interested in algorithmically generated stories lately. It’s taking some core text and having code, often randomly, make decisions about its placement, size, or even content. It’s also a trend I’m going to follow for a few more weeks too.

However, I thought I would point out something that has become key to these projects: passages can be storage. You don’t have to display passages written in Twine. They can, in fact, be used to hold content that will be reference via macros or with JavaScript.

For example, consider the following short passage:

:: HamletLines
Well, God-a-mercy.
Excellent well; you are a fishmonger.

They are lines 172 and 174 from Hamlet, Act 2, Scene 2. Normally, the paradigm is to create a link to that passage at some point. However, that doesn’t necessarily have to happen. Using that passage as storage, it could be referenced by a call to Tale.get() to retrieve its content and then used for another purpose.

var Hamlet = tale.get("HamletLines");

In fact, by placing special delimiters within the text of a passage, it can be parsed by calling String.split() to chop up a text and create an array of its lines. Everything that is in-between whatever that delimiter and the next instance of it is will become an index in an array. In turn, using a randomly chosen number or simply incremental counter, lines can be picked out and placed in another passage. (This technique has been around for a long time in various text parsers, but it didn’t occur to me to use it with Twine until a couple weeks ago.)

:: HamletLines
Well, God-a-mercy.  
Excellent well; you are a fishmonger.  
Then I would you were so honest a man.  
Ay, sir; to be honest, as this world goes, is to be
one man picked out of ten thousand.  

:: PoloniusLines
Do you know me, my lord?  
Not I, my lord.  
Honest, my lord! 
That's very true, my lord.  
I have, my lord. 


macros['dialogue'] = 
   handler: function(place, object, parameters)
      var Hamlet = tale.get("HamletLines");
      var Polonius = tale.get("PoloniusLines");
      H_wordList = Hamlet.text.split(" ");
      P_wordList = Polonius.text.split(" ");

Combining this with calling Tale.add(), as I have done in the full example, would allow for new passages to be added with the text from each of the characters. Using setInterval() then breaks up the dialogue over time.

Working Example


:: Start

:: script [script]

var line = 0;
var H_wordList = [];
var P_wordList = [];
var text = "";

Tale.prototype.add = function(title,tags,content) {
   var pTitle = unescape(encodeURIComponent(title));
   var el = insertElement($("storeArea"),"div",pTitle,"",content);
   var newP = new Passage(pTitle,$(pTitle));
   this.passages[title] = newP;
   if(tags === "stylesheet")
   { addStyle(newP.text); }
   else if(tags === "script") 
   {try {eval(newP.text);}
   catch(e) {alert("There is a technical problem with this story (" + newP.title + 
   ": " + e.message + 
   "). You may be able to continue reading, but all parts of the story may not work properly.");}

var dialogue = function() {
   if(line < 11)
		text = "''Hamlet:'' " + H_wordList[line];
		tale.add("Hamlet"+line, "", text);
		state.display("Hamlet"+line, null);

		text = "''Polonius:'' " + P_wordList[line];
		tale.add("Polonius"+line, "", text);
		state.display("Polonius"+line, null);

macros['dialogue'] = 
	handler: function(place, object, parameters)
		var Hamlet = tale.get("HamletLines");
		var Polonius = tale.get("PoloniusLines");
		H_wordList = Hamlet.text.split("&nbsp;");
		P_wordList = Polonius.text.split("&nbsp;");
  timer = setInterval(dialogue, 7800);

:: HamletLines
Well, God-a-mercy.&nbsp;
Excellent well; you are a fishmonger.&nbsp;
Then I would you were so honest a man.&nbsp;
Ay, sir; to be honest, as this world goes, is to be
one man picked out of ten thousand.&nbsp;
For if the sun breed maggots in a dead dog, being a
god kissing carrion,--Have you a daughter?&nbsp;
Let her not walk i' the sun: conception is a
blessing: but not as your daughter may conceive.
Friend, look to 't.&nbsp;
Words, words, words.&nbsp;
Between who?&nbsp;
Slanders, sir: for the satirical rogue says here
that old men have grey beards, that their faces are
wrinkled, their eyes purging thick amber and
plum-tree gum and that they have a plentiful lack of
wit, together with most weak hams: all which, sir,
though I most powerfully and potently believe, yet
I hold it not honesty to have it thus set down, for
yourself, sir, should be old as I am, if like a crab
you could go backward.&nbsp;
Into my grave.&nbsp;
You cannot, sir, take from me any thing that I will
more willingly part withal: except my life, except
my life, except my life.&nbsp;

:: PoloniusLines
Do you know me, my lord?&nbsp;
Not I, my lord.&nbsp;
Honest, my lord!&nbsp;
That's very true, my lord.&nbsp;
I have, my lord.&nbsp;
How say you by that? Still harping on my
daughter: yet he knew me not at first; he said I
was a fishmonger: he is far gone, far gone: and
truly in my youth I suffered much extremity for
love; very near this. I'll speak to him again.
What do you read, my lord?&nbsp;
What is the matter, my lord?&nbsp;
I mean, the matter that you read, my lord.&nbsp;
Though this be madness, yet there is method
in 't. Will you walk out of the air, my lord?&nbsp;
Indeed, that is out o' the air.
How pregnant sometimes his replies are! a happiness
that often madness hits on, which reason and sanity
could not so prosperously be delivered of. I will
leave him, and suddenly contrive the means of
meeting between him and my daughter.--My honourable
lord, I will most humbly take my leave of you.&nbsp;
Fare you well, my lord.&nbsp;

:: style [stylesheet]
body {
	background: #333333;

.passage {
		font-size: 3.1em;
		background: transparent;
		color: white;
		width: inherit;

.passage .title { display: none } 

h1 {
 color: white;
 font-size: 3.3em;

#sidebar { display: none;}

#footer {display: none;}

#floater { display: none; }

:: StoryTitle
Hamlet: Act 2, Scene 2, Lines 172-218