the bare bones convo engine

This commit is contained in:
Nicky Case 2019-02-11 12:04:23 -05:00
commit 8655f71e8f
4 changed files with 335 additions and 0 deletions

47
game.css Normal file
View File

@ -0,0 +1,47 @@
html,body{
width: 100%;
height: 100%;
}
body{
margin:0;
background: #ddd;
}
#game_container{
position: absolute;
top:0; left:0; bottom:0; right:0;
margin: auto;
width: 360px;
height: 600px;
background: #fff;
font-size: 20px;
font-family: Helvetica, Arial, sans-serif;
font-weight: 100;
line-height: 1.3em;
}
#game_text{
width: auto;
height: 450px;
overflow: scroll;
}
#game_text > div{
margin: 30px;
}
#game_choices{
width: 100%;
height: 150px;
position: absolute;
bottom:0;
background: #666;
}

218
game.js Normal file
View File

@ -0,0 +1,218 @@
var xhr = new XMLHttpRequest();
xhr.open('GET', 'woods.md?v='+Math.random());
xhr.onload = function() {
if(xhr.status===200){
Game.onload(xhr.responseText);
}
};
xhr.send();
/*****************************/
/*****************************/
/*****************************/
window._ = {};
window.Game = {};
Game.sections = {};
Game.startSectionID = null;
Game.dom = document.querySelector("#game_container");
Game.textDOM = document.querySelector("#game_text");
Game.choicesDOM = document.querySelector("#game_choices");
// Parse data!
Game.onload = function(data){
// THE FIRST ID
Game.startSectionID = null;
// Split into sections...
data = data.trim();
data = "\n" + data;
var sections = data.split(/\n\#\s*/);
sections.shift();
sections.forEach(function(section){
var split_index = section.indexOf("\n\n");
var id = section.slice(0, split_index).toLocaleLowerCase();
var text = section.slice(split_index+2);
// Split into lines
text = text.trim();
var lines = text.split("\n\n");
for(var i=0; i<lines.length; i++) lines[i]=lines[i].trim(); // trim it all!
// New section
Game.sections[id] = {
id: id,
lines: lines
};
if(!Game.startSectionID){
Game.startSectionID = id;
}
});
// Let's go!
Game.start();
}
Game.start = function(){
window._ = {}; // global var, reset
Game.goto(Game.startSectionID);
};
Game.goto = function(sectionID){
// Clear choices
Game.choicesDOM.innerHTML = "";
// Show each line...
var section = Game.sections[sectionID];
var lines = section.lines;
for(var i=0; i<lines.length; i++){
// Parse handlebars
var originalLine = lines[i];
line = Game.parseLine(originalLine);
// Execute line
if(line!=""){ // none, don't execute...
// Execute based on what type it is!
var lineType = Game.getLineType(line);
switch(lineType){
case "text":
Game.executeText(line);
break;
case "choice":
Game.executeChoice(line);
break;
case "code":
Game.executeCode(line);
break;
}
// If it's a goto, end THIS section immediately.
if(lineType=="goto"){
Game.executeGoto(line);
break;
}
}
}
};
// Execute text! Just add it to text DOM.
Game.executeText = function(line){
var div = document.createElement("div");
div.innerHTML = line;
Game.textDOM.appendChild(div);
}
// Execute choice! Add it to choice DOM.
Game.executeChoice = function(line){
var choiceText = line.match(/\[(.*)\]/)[1].trim();
var choiceID = line.match(/\(\#(.*)\)/)[1].trim().toLocaleLowerCase();
var div = document.createElement("div");
div.innerHTML = choiceText;
div.onclick = function(){
Game.executeText("> "+choiceText);
Game.goto(choiceID);
};
Game.choicesDOM.appendChild(div);
}
// Execute code!
Game.executeCode = function(line){
var code = line.match(/\`+([^\`]*)\`+/)[1].trim();
try{
eval(code);
}catch(e){
console.log(e);
}
}
// Execute goto! Just goto.
Game.executeGoto = function(line){
var gotoID = line.match(/^\(\#(.*)\)/)[1].trim().toLocaleLowerCase();
Game.goto(gotoID);
}
// Determine line type... text, choice, or code?
Game.getLineType = function(line){
// Is it a choice?
var isChoice = /\[.*\]\(\#.*\)/.test(line);
if(isChoice) return "choice";
// Is it a goto?
var isGoto = /^\(\#(.*)\)/.test(line);
if(isGoto) return "goto";
// Is it code?
var isCode = /^\`/.test(line);
if(isCode) return "code";
// Otherwise, it's text.
return "text";
};
// Parse all the handlebars...
Game.parseLine = function(line){
// Get the IFs, if any
var lookForIfs = true;
while(lookForIfs){
lookForIfs = false;
// Look for an IF!
var regex = /\{\{if.*\/if\}\}/ig;
var regexResult = regex.exec(line);
if(regexResult){
// The result...
var fullConditional = regexResult[0];
var startsAtIndex = regexResult.index;
var endsAtIndex = startsAtIndex + fullConditional.length;
// Extract the condition
var condition = fullConditional.match(/\{\{if\s+([^\{\}]*)\}\}/)[1];
// Extract the inside text
var insideText = fullConditional.match(/\}\}([^\{\}]*)\{\{/)[1].trim();
// Eval condition!
var conditionIsTrue = false;
try{
conditionIsTrue = eval(condition);
}catch(e){
console.log(e);
}
// Edit the line
var insert = conditionIsTrue ? insideText : "";
line = line.slice(0,startsAtIndex) + insert + line.slice(endsAtIndex);
// Keep searching...
lookForIfs = true;
}
}
// Return line!
return line;
};

20
index.html Normal file
View File

@ -0,0 +1,20 @@
<!DOCTYPE html>
<html>
<head>
<title>Adventures with Anxiety!</title>
<link rel="stylesheet" type="text/css" href="game.css">
<meta name="viewport" content="width=device-width">
</head>
<body>
<div id="game_container">
<div id="game_text">
</div>
<div id="game_choices">
</div>
</div>
</body>
</html>
<script src="game.js"></script>

50
woods.md Normal file
View File

@ -0,0 +1,50 @@
# woods
Two woods diverged in the woods and I...
{{if _.eaten}} (this time try not to get eaten by wolves) {{/if}}
`document.body.style.background = "#ddd"`
[Took the one less travelled by](#woods-less)
[Took the one more travelled by](#woods-more)
{{if _.played_less && _.played_more}} [Went back home](#home) {{/if}}
# woods-less
And that's how I got lost in the woods and was eaten by wolves
`document.body.style.background = "#ff4040"`
`_.eaten = true`
`_.played_less = true`
[Try again](#woods)
[Goodbye](#end)
# woods-more
And that's how I found my way back to civilization and was not eaten by wolves
`_.eaten = false`
`_.played_more = true`
[Try again](#woods)
[Goodbye](#end)
# home
Good choice.
(#END)
do NOT show this line
# END
THE END.