Interactive Story Script

Javascript UI

I’ve finally got a new piece of this Interactive Story Script project to show off! I now have the language compiling to something that can be displayed with pure JavaScript. Which means that I can provide the same animated UI that you saw in the Android example in any web browser (the ones I’ve tested anyway). Unfortunately, the story I’m compiling in still the same poorly written example I’ve been throwing up here the whole time but at least now it looks cooler (after all the work it’s taken to get to this point it’s hard to wait long enough to write something better before sharing the results). As usual, I’ll put the raw code that the story is compiled from at the end of the post for anyone who wants to follow along.

The Quest: Javascript Edition

The reader is still pretty bare bones and could use some more polish but those are the easy parts. I’ll post another update when I have a more fully featured reader (and hopefully a new example story). Alright, so some basic Q&A.

What happened to the Android Version?

I’ve hit an unfortunate hurdle with the mobile readers that’s required me to shelve them for now. The base compiler/reader system is written in something called Mono which requires a specific piece of software if you want to compile it for mobile platforms. Unfortunately, the readers now exceed the free license for that software which means I have to purchase some very expensive yearly licenses if I want to push forward. The cost is more than I’m willing to throw at a hobby project so I can’t really justify getting the licenses if I can’t commit to releasing something with this system within a year; which I definitely cannot do. As a result, I’ve decided to push forward in other areas and I’ll hopefully pick up the mobile side of this somewhere down the road.

Why Javascript?

Javascript is a bit of a mess but it is, arguable, the single most cross platform language out there right now and the ability to write a story once and push it out across multiple platforms is one of the key features of this system so the two go well together. Being able to share the results with people just by linking them to a webpage instead of forcing them to download something is also a big plus. The only reason I didn’t do this before was that it required me to duplicate some of the Mono code which is something I was hoping to avoid.

Being able to actually produce something I can share with other people also means I can start experimenting with the other phase of this project; which is to see if it’s possible to apply some of these Interactive Narrative tools I spent so much time writing about in a stripped down world of text and buttons. Hopefully I’ll have something to show on that end in the not too distant future (I wouldn’t recommend holding your breath on that though).

What was wrong with the HTML compiler?

The original example of this I posted had used the compiler to turn the story into a set of basic HTML pages. So you might be wondering why I put so much effort into creating the animated JavaScript version when I could have just kept using that. After all, it has the same cross platform and sharing benefits as the JavaScript version.

The truth is that while the HTML trick worked as a basic proof of concept, it doesn’t do one of the big things that the JavaScript UI does. It doesn’t dynamically generate pages. The example story starts by asking you to pick a gender. In the JavaScript UI this just means that it has to swap some gender pronouns while it’s building the pages. In the HTML UI all the pages have to be built in advance so the choice effectively doubles the number of pages that have to be generated. This problem can get much worse as the language gives you the ability to write stories that loop back on themselves which is no problem for the JavaScript UI but could result in an infinite number of pages for the HTML UI. The example story doesn’t really show this but there are also some language features that just don’t work in the HTML version.

new template Character;
bool Character.Male;

new group r : Character;
bool r.Male = true;
string r.Name = #Dave#;

function string he(Character c)
{
	return c.Male ? #he# : #she#;
}

function string He(Character c)
{
	return c.Male ? #He# : #She#;
}

function string him(Character c)
{
	return c.Male ? #him# : #her#;
}

function string his(Character c)
{
	return c.Male ? #his# : #her#;
}

function string man(Character c)
{
	return c.Male ? #man# : #woman#;
}

function string himself(Character c)
{
	return c.Male ? #himself# : #herself#;
}

function void WriteAudienceResponse(string response)
{
	FontStyle(italic);
	#\n\n"#;
	response;
	#"\n\n#;
	FontStyle();
}

page selection(start=true)
{
	body
	{
		FontSize(24);
		FontStyle(center, bold);
		#The Quest#
		FontSize(10);
		FontStyle(center, italic);
		#\nA heroic tale of heroism#
		FontSize();
		FontStyle();
		#\nSelect your heroic gender.#
	}
	
	choices
	{
		Male(text=#Male#){}
		Female(text=#Female#)
		{
			r.Male = false;
			r.Name = #Kate#
		}
	}
	
	chosen
	{
		GoTo(beginning);
	}
}

page beginning
{
	body
	{
		Clear();
		#This is the tale of Sir # r.Name #, the bravest and most noble knight in the court of King Oscar the Fourth. The story begins with our hero traveling down a road toward a date with destiny. An ogre had invaded the kingdom and been making meals of the local peasantry and so the king ordered # him(r) # to slay it as proof of # his(r) # strength and valor.\n\n#
		
		#This would be no easy task. An ogre is more than twice the size of a man and ten times as strong with skin so tough that only the sharpest blades can hope to pierce it. Some might have call this a suicide mission. Some might say that pitting a lone # man(r) # against such a foe was lunacy. But King Oscar was not these people.#
	}
	
	choices
	{
		Brave(text=#I fear neither man nor beast. Bring it on.#)
		{
			WriteAudienceResponse(#I fear neither man nor beast. Bring it on.#);
			GoTo(meetOgre);
		}
		
		Measured(text=#Alright, lets get this over with.#)
		{
			WriteAudienceResponse(#Alright, lets get this over with.#);
			GoTo(meetOgre);
		}
		
		Question(text=#Wait. I have to do what?#)
		{
			WriteAudienceResponse(#Wait. I have to do what?#);
			GoTo(questioning);
		}
	}
}

page questioning
{
	body
	{
		#You must slay a creature capable of ripping a man in half with it's bare hands in single combat as proof that you are worthy of your heroic stature.#
	}
	
	choices
	{
		Ok(text=#Okay then. Just checking. Lets get on with it.#)
		{
			WriteAudienceResponse(#Okay then. Just checking. Lets get on with it.#);
			GoTo(meetOgre);
		}
		
		Question(text=#Who thought this was a good idea? Why don't I have a full squad with me?#)
		{
			WriteAudienceResponse(#Who thought this was a good idea? Why don't I have a full squad with me?#);
			GoTo(moreQuestioning);
		}
		
		Leave(text=#Screw that. I'm getting out of here.#)
		{
			WriteAudienceResponse(#Screw that. I'm getting out of here.#);
			#Realizing that the road ahead lead to certain doom#
			GoTo(quit);
		}
	}
}

page moreQuestioning
{
	body
	{
		#Years of inbreeding can make all kinds of things seem like a good idea. Plus King Oscar was a big fan of heroic tales. What did you expect? At least he didn't chop people's heads off and have ridiculous monuments built in his honor... much.#
	}
	
	choices
	{
		Ok(text=#Fine. Let's get on with this hero fantasy.#)
		{
			WriteAudienceResponse(#Fine. Let's get on with this hero fantasy.#);
			GoTo(meetOgre);
		}
		
		Leave(text=#No way. I'm not dying for this doofus. I'm out of here.#)
		{
			WriteAudienceResponse(#No way. I'm not dying for this doofus. I'm out of here.#);
			#Realizing that the king was just an inbred hick with a thing for hero narratives and lack luster tactical skills#
			GoTo(quit);
		}
	}
}

page quit
{
	body
	{
		# our noble and cowardly hero fled. It was a glorious retreat. Brilliant in it's simplicity and execution. Fearing neither humiliation nor ridicule # he(r) # defied destiny it self and chose a different path.#
	}
	
	choices
	{
		Return(text=#I'm going back to the castle.#)
		{
			WriteAudienceResponse(#I'm going back to the castle.#);
			GoTo(quitCastle);
		}
		
		Hide(text=#I'm starting a new life somewhere else.#)
		{
			WriteAudienceResponse(#I'm starting a new life somewhere else.#);
			GoTo(quitHide);
		}
	}
}

page quitHide
{
	body
	{
		#Our hero decided that heroing wasn't worth the constant threat of horrible painful death and went in search of a more humble profession. # He(r) # took up residence in a far away village where # he(r) # worked as a blacksmith. # He(r) # started a family and lived happily ever after. Or at least # he(r) # did until a traveler recognized # him(r) # and the king had # his(r) # head chopped off for cowardice.\n#
		FontStyle(center);
		#The End#
		
	}
}

page quitCastle
{
	body
	{
		#And how do you want to handle King Oscar?#
	}
	
	choices
	{
		Truth(text=#I'll tell him the truth.#)
		{
			WriteAudienceResponse(#I'll tell him the truth.#);
			GoTo(quitCastleTruth);
		}
		
		Lie(text=#I'll make up a story about how I heroically killed the ogre.#)
		{
			WriteAudienceResponse(#I'll make up a story about how I heroically killed the ogre.#);
			GoTo(quitCastleLie);
		}
	}
}

page quitCastleTruth
{
	body
	{
		#Our hero returned to the castle and, being the truthful sort, admitted that # he(r) # had failed to slay the ogre and suggested that perhaps it would be better to send a team. Unfortunately, the king didn't take kindly to # his(r) # defiance and had # him(r) # executed for cowardice.\n#
		FontStyle(center);
		#The End#
	}
}

page quitCastleLie
{
	body
	{
		#Our hero returned to the court of King Oscar and spun a fanciful tale of # his(r) # battle with the terrible ogre. A great feast was held in # his(r) # honor and celebrating went on far into the night. Things started to look dark for our hero when another ogre attack was reported the next morning. Fortunately, King Oscar wasn't the sharpest tool in the shed and assuming this was a different ogre and picked a different sucker to go out there and find glory in hopeless single combat.\n#
		FontStyle(center);
		#The End#
	}
}

page meetOgre
{
	body
	{
		#After a long journey our hero finally reached the ogre's lair where # he(r) # was greeted by a most grisly sight. The lair it self was a cave with human and animal remains scattered all around the entrance. The ogre was in front of the cave stirring a large pot the contents of which are not to be discussed in polite conversation. Sufficed to say it gave off a truly fowl oder.\n\n#
		
		#Worse yet was the ogre itself. No words could possible do justice to just how ugly and smelly the creature was. It was a mountain of muscles with hands the size of tables and a mouth filled with crooked, sharp teeth.#
	}
	
	choices
	{
		Confront(text=#This monster must die! I draw my sword and charge.#)
		{
			WriteAudienceResponse(#This monster must die! I draw my sword and charge.#);
			#Knowing no fear our hero drew # his(r) # sword and charged the ogre head on. But for a creature so big the ogre was surprisingly fast and scooped up the charging knight before # he(r) # could strike a single blow.\n\n#
			GoTo(grabbed);
		}
		
		Parley(text=#Lets try reasoning with it.#)
		{
			WriteAudienceResponse(#Lets try reasoning with it.#);
			#Being a # man(r) # of strong moral character our hero felt obliged to try a peaceful solution before resorting to violence. # He(r) # walked into the clearing with weapon sheathed and greeted the ogre with politeness and respect. Unfortunately, the ogre didn't seem to hear what our hero had to say. For such a large creature it was deceptively fast. It crossed the clearing and scooped up the unfortunate knight before # he(r) # could finish # his(r) # first sentence.\n\n#
			GoTo(grabbed);
		}
		
		Sneaky(text=#Maybe I'll just wait till it's asleep#)
		{
			WriteAudienceResponse(#Maybe I'll just wait till it's asleep#);
			GoTo(assassin);
		}
		
		Flee(text=#Screw this. I'm leaving.#)
		{
			WriteAudienceResponse(#Screw this. I'm leaving.#);
			#Soiling # himself(r) # in terror#;
			GoTo(quit);
		}
	}
}

page grabbed
{
	body
	{
		#"Ooh, shiny" said the Ogre as it looked over the knight; # his(r) (meetOgre.Confront ? # war cries# : # words of peace#) # muffled beneath the creature's giant palms. "You make good stew" it said it loped back to it's pot and unceremoniously dumped # him(r) # in. And so the tale ends with our dashing hero becoming a heroic feast.\n#
		FontStyle(center);
		#The End#
	}
}

page assassin
{
	body
	{
		#Realizing the pointlessness of direct confrontation, our sneaky hero waited until it was dark and the ogre was sleeping soundly in it's cave. Valiantly fighting against the urge to vomit, # he(r) # descended into the monster's lair and slew the beast with a single well placed cut across it's throat. Unfortunately, the stench of the creature's blood proved too strong and our hero's dinner became as a victim of the encounter.\n\n#
		
		#Exhausted and in desperate need of a bath, the heroic knight returned to the castle and presented the ogre's head to King Oscar. He was delighted at the sight and asked to hear of the battle.#
	}
	
	choices
	{
		Truth(text=#I tell him of my clever plan to slay the monster in it's sleep.#)
		{
			WriteAudienceResponse(#I tell him of my clever plan to slay the monster in it's sleep.#);
			GoTo(slayerTruth);
		}
		
		Lie(text=#I make up a story about my heroic battle with the beast.#)
		{
			WriteAudienceResponse(#I make up a story about my heroic battle with the beast.#);
			GoTo(slayerLie);
		}
	}
}

page slayerTruth
{
	body
	{
		#As a truthful and noble knight our hero told of how # he(r) # recognized the hopelessness of direct combat and instead waited for the creature to fall asleep so that it could be slain without risk of death. Though # he(r) # did leave out the vomiting part. Unfortunately, vomiting or not King Oscar was not amused. He expected bravery and strength from his knights. Not trickery and deceit. And so our sly and cunning hero was executed for cowardice.\n#
		FontStyle(center);
		#The End#
	}
}

page slayerLie
{
	body
	{
		#Realizing that Oscar wanted a story about a heroic battle our hero gave him exactly that. A gripping tale of a desperate struggle between man and monster. As fanciful and far fetched as it was King Oscar was delighted and showered our hero with riches. And so our mildly dishonest hero lived in wealth and happiness. That is, until King Oscar found some other suicidal task to send # him(r) # on. But that's a story for another time.\n#
		FontStyle(center);
		#The End#
	}
}
Posted in Interactive Story Script | Comments Off