User:JeevesMkII/javascript/textadventure.js

var _text_adv_move_count = 0; var _text_adv_handle = null; var _text_adv_display = null; var _text_adv_current_node = null; var _text_adv_inventory = new Array; var _text_adv_input_box = null;

var _text_adv_preposition_list = new Array("TO", "IN", "UNDER", "INSIDE", "BEHIND", "AT"); var _text_adv_synonyms = {	"LOOK_AT" : "EXAMINE", "GO_TO" : "GO", "TALK_TO" : "TALK", "GET" : "TAKE", "INV" : "INVENTORY", "I" : "INVENTORY", "N" : "NORTH", "E" : "EAST", "S" : "SOUTH", "W" : "WEST", "U" : "UP", "D" : "DOWN" };

function trim(str) {	var	str = str.replace(/^\s\s*/, ''), ws = /\s/, i = str.length; while (ws.test(str.charAt(--i))); return str.slice(0, i + 1); } function node_text(node) {	return trim(node.textContent != "undefined" ? node.textContent : node.innerText); }

function text_adventure_find_child_node(parent, child_name) {	var ret = null; for (var i = 0; i < parent.childNodes.length; ++i) {		if (typeof(parent.childNodes[i].id) != "undefined" && parent.childNodes[i].id == child_name) {			ret = parent.childNodes[i]; break; }		}	return ret; }

function text_adventure_init_turn {	var move = ++_text_adv_move_count; var anchor = document.createElement("a"); anchor.name = "move" + move; anchor.innerHTML = "Move #" + move; _text_adv_display.appendChild(anchor); window.location.hash = "move" + move; }

function text_adventure_append_text(text) {	var para = document.createElement("p"); para.innerHTML = text; _text_adv_display.appendChild(para); }

function text_adventure_do_action_skipto(node) {	var arg = node_text(node); /* We need more circular skip protection, but for now check we're just skipping to the current screen */ if (arg == _text_adv_current_node.id) {		/* TODO: Error reporting */ return; }	/* Set the indicated screen to be the current, and re-enter the main loop */ _text_adv_current_node = text_adventure_find_child_node(_text_adv_handle, arg); if (_text_adv_current_node != null) {		text_adventure_main_loop("LOOK", ""); }	}

function text_adventure_do_action_prompt(node) {	text_adventure_append_text(node_text(node)); } function text_adventure_do_action_display_text(node) {	text_adventure_append_text(node.innerHTML); }

function text_adventure_add_items(node) {	var items = node_text(node); var objects = text_adventure_find_child_node(_text_adv_current_node, "objects"); if (null == objects) {		objects = document.createElement("div"); objects.id = "objects"; _text_adv_current_node.appendChild(objects); }	var existing = node_text(objects); if ("" != existing) {		items += "," + existing; }	objects.innerHTML = items; }

var _text_adv_action_table = {	"SKIPTO" : text_adventure_do_action_skipto, "PROMPT" : text_adventure_do_action_prompt, "DISPLAYTEXT" : text_adventure_do_action_display_text, "ADDITEMS" : text_adventure_add_items };

function text_adventure_parse_action(action_node) {	var action = action_node.className; var func = _text_adv_action_table[action]; if (typeof(func) != "undefined") {		func(action_node); }	}

function text_adventure_execute_actions(node) {	for (i = 0; i < node.childNodes.length; ++i) {		var child = node.childNodes[i] if (typeof(child.id) != "undefined" && "action" == child.id) {			text_adventure_parse_action(child); }		}	}

function text_adventure_parse_object_synonyms {	var synonyms = new Object; var synonyms_node = text_adventure_find_child_node(_text_adv_current_node, "synonyms"); if (null != synonyms_node) {		var raw = node_text(synonyms_node); var sepr = raw.indexOf("="); var delimiter = raw.indexOf(","); while (-1 != sepr) {			var from = raw.substring(0, sepr); if (-1 == delimiter) {				synonyms[from] = raw.substring(sepr+1); raw = ""; }			else {				synonyms[from] = raw.substring(sepr+1, delimiter); raw = raw.substring(delimiter+1); }			sepr = raw.indexOf("="); delimiter = raw.indexOf(","); }		}	return synonyms; }

function text_adventure_execute_look(subject, subject_node) {	var description = text_adventure_find_child_node(_text_adv_current_node, "screentext"); if (null != description) {		text_adventure_append_text(description.innerHTML); }	}

function text_adventure_execute_take(subject, subject_node) {	/* ensure the item to be taken exists in the current screen */ var objects_node = text_adventure_find_child_node(_text_adv_current_node, "objects"); var objects = new Array; if (null != objects_node) {		objects = node_text(objects_node).split(","); }	var found = false; for (var i = 0; i < objects.length; ++i) {		if (objects[i].toUpperCase == subject) {			_text_adv_inventory.push(objects[i]); objects.splice(i, 1); found = true; break; }		}	}

var _text_adventure_builtin_verb_table = {	"LOOK" : text_adventure_execute_look, "TAKE" : text_adventure_execute_take };

function text_adventure_main_loop(verb, subject) {	text_adventure_init_turn; /* load the synonyms table, if any */ var synonyms = text_adventure_parse_object_synonyms; /* see if we can locate the subject to which the user is refering */ if (typeof(synonyms[subject]) != "undefined") {		subject = synonyms[subject]; }	var subject_node = text_adventure_find_child_node(_text_adv_current_node, subject); /* make sure the subject referred to is actually an object in the room */ if (subject_node != null && subject_node.className != "textadvobject") {		subject_node = null; }	/* if the verb is a built-in, execute it now */ if (typeof(_text_adventure_builtin_verb_table[verb]) != "undefined") {		_text_adventure_builtin_verb_table[verb](subject, subject_node); }	/* if it isn't a built-in, try and find an appropriate node to execute on the subject*/ else if (null != subject_node) {		var verb_node = text_adventure_find_child_node(subject_node, verb); if (null != verb_node) {			/* TODO: execute any decision nodes for this node */ /* Execute action nodes */ text_adventure_execute_actions(verb_node); }		}	/* Finally, execute any actions for the room */ text_adventure_execute_actions(_text_adv_current_node); }

function text_adventure_parse_input {	var input = trim(_text_adv_input_box.value); text_adventure_append_text("> " + input); input = input.toUpperCase; var index = input.indexOf(" "); var verb = (index == -1) ? input : input.substring(0, index); var subject = (index == -1) ? "" : input.substring(index+1); index = subject.indexOf(" "); if (-1 != index) {		/* check if the second word is in the preposition list. */		var preposition = subject.substring(0, index); for (var i = 0; i < _text_adv_preposition_list.length; ++i) {			if (preposition == _text_adv_preposition_list[i]) {				verb += "_" + preposition; subject = subject.substring(index+1); break; }			}		}	/* substitute any synonyms */ if (typeof(_text_adv_synonyms[verb]) != "undefined") {		verb = _text_adv_synonyms[verb]; }	text_adventure_main_loop(verb, subject); return false; }

function init_text_adventure {	/* find the text adventure description and display area for this adventure */ _text_adv_handle = document.getElementById("textadventure"); _text_adv_display = document.getElementById("textadvdisplay"); if (_text_adv_handle != null && _text_adv_display != null) {		/* Create an input text box */ var hr = document.createElement("hr"); _text_adv_display.parentNode.appendChild(hr); var form = document.createElement("form"); form.name = "text_adv_input_form"; form.onsubmit = text_adventure_parse_input; form.action = "#" var input = document.createElement("input"); input.type = "text"; input.name = "text_adventure_input_box"; input.size = 100; form.appendChild(input); _text_adv_display.parentNode.appendChild(form); _text_adv_input_box = input; /* Good show, find the intro and begin the main loop */ _text_adv_current_node = text_adventure_find_child_node(_text_adv_handle, "introscreen");

if (_text_adv_current_node != null) { 			text_adventure_main_loop("LOOK", ""); }		}	}

addOnloadHook(init_text_adventure);