Building a text game (advanced)


Tutorial Updated

Updated 20/10/06.  This tutorial has been updated from a previous one, I've had a lot of feedback and made major 
modifications to the code, because much has been added this is now recommended only for experienced scripters, otherwise 
I might cause you a major headache!  However there is some good stuff anyone can take from it like the save / load coding. 
Special thanks to Hugh Hamilton for putting the code to good use and developing some great ideas. 
Check out the attached .fla file to see what a couple of rooms in the final game will look like.  
A full text game is included in the Flashkit Movies section, search for scalar. Download the .fla here FLA FILE

The layers

Create 2 layers as shown in the image below, 'Code', 'Main'.  Add any image layers below these if you want images 
as aids in the text game.

The interface

In the 'Main' layer add a keyframe to cover 3 frames of the timeline.  Then add the following (see image for layout) -
1)	A TEXTBOX - This will display the main storyline text.
 Set to dynamic text, with a variable name of 'texty'. Set the Name as 'TextBoxMain'.
2)	A SCROLLBAR - This will scroll the text if it overflows in the box. Set the Target TextField to 'TextBoxMain'.
3)	A TEXTBOX - This will display the objects you can pick up or drop in any room.
 Set to dynamic text, with a variable name of 'objecty'.
4)	A TEXTBOX - This will let you type and control the game.
 Set to input text, with a variable name of 'inputy'.
5)	A LISTBOX - This will display objects you pick up throughout the game.
 Label this 'listbox1'.
6)	A MOVIE CLIP SYMBOL - This is optional, you can have images to aid in describing a scene.
 Label this 'image1'.

Click for more detail on how to add the above
 

Script Structure

The 'Code' Layer is made up of 3 keyframes.  I've added all functions into the first keyframe to keep things tidy,
these functions will all be called from the second keyframe script.  I've added an explanation to each line of
script, but will add more detailed explanation in the next section.
In the first keyframe copy & paste this script in -

//GENERAL STUFF
//sets the font
globalStyleFormat.textFont = "TimesNewRoman";
globalStyleFormat.applyChanges("textFont");
//hides the scrollbar on the items listbox
_root.listbox1.setAutoHideScrollBar(true);
// hides help option until it is called for
_root.help._visible = false;
//Place
_root.Place = 1;
//Ensures Enter can only be pressed once at a time
_root.EnterIsPressed = 0;
//Object Positions
_root.Object1Position = 1;
ResetAll();
function ResetAll() {
	//Empty input line
	_root.inputy = "";
	//Empty object line
	_root.objecty = "";
	// Ensure First Object actions only occur once.
	_root.Object1 = 0;
	//Clear image box
	_root.ImageBlack._visible = false;
}
function ResetTextLine() {
	//Empty object line everytime return is pressed.
	_root.inputy = "";
}
function AddObjects() {
	// Empty items held box
	_root.listbox1.removeAll();
	if (_root.Object1Position == "bag") {
		_root.listbox1.addItemAt(0, "KEY");
		//Update items held box
	}
}

In the Second Keyframe add -


if (_root.EnterIsPressed == 0) {
	//This line is only needed if you have images in the game
	_root.ImageBlack._visible = false;
	if (_root.Place == 100) {
		//Rude
		_root.texty = "Hey!  Don't be so rude!";
		// Images
		_root.Image3._visible = true;
		///////////////////////////
		if (Key.isDown(Key.ENTER)) {
			_root.Place = _root.PlaceReturn;
			ResetAll();
		}
	}
	if (_root.Place == 5) {
		//Door
		_root.texty = "DOOR - You place the key in the keyhole, it fits!  END OF TEXT GAME SAMPLE.  CHECK OUT A FULL TEXT GAME BY GOING TO FLASHKIT - MOVIES SECTION, SEARCH FOR scalar.";
		// Images
		_root.Image4._visible = true;
		///////////////////////////
	}
	if (_root.Place == 4) {
		//Key
		_root.texty = "KEY - The key is gold and shiny.";
		// Images
		_root.Image4._visible = true;
		///////////////////////////
		if (Key.isDown(Key.ENTER)) {
			_root.Place = _root.PlaceReturn;
			ResetAll();
		}
	}
	if (_root.Place == 3) {
		//Door
		_root.texty = "ROOM 2 - The door is made of wood, there is a keyhole.";
		// Images
		_root.Image3._visible = true;
		///////////////////////////
		if (Key.isDown(Key.ENTER)) {
			_root.Place = 2;
			ResetAll();
		}
	}
	if (_root.Place == 2) {
		//Room 1
		_root.texty = "ROOM 2 - You are in room 2.  There is a door here.  You can go West into room 1.";
		// Images
		_root.Image2._visible = true;
		///////////////////////////
		if (Key.isDown(Key.ENTER)) {
			_root.inputy.toLowerCase();
			myStringSub = "west";
			myStringSub1 = "go";
			myStringSub2 = "walk";
			myStringSub3 = "head";
			myStringSub4 = "door";
			myStringSub5 = "examine";
			myStringSub6 = "look";
			//CHECKS IF WHAT THE USER WRITE IN THE BOX CONTAINS THE WORDS ABOVE
			Occurred = _root.inputy.indexOf(myStringSub, 0);
			Occurred1 = _root.inputy.indexOf(myStringSub1, 0);
			Occurred2 = _root.inputy.indexOf(myStringSub2, 0);
			Occurred3 = _root.inputy.indexOf(myStringSub3, 0);
			Occurred4 = _root.inputy.indexOf(myStringSub4, 0);
			Occurred5 = _root.inputy.indexOf(myStringSub5, 0);
			Occurred6 = _root.inputy.indexOf(myStringSub6, 0);
			//GO TO ROOM 2 IF THERE IS A MENTION OF WEST & EITHER GO, WALK OR HEAD.
			if ((Occurred<>"-1") and ((Occurred1<>"-1") or (Occurred2<>"-1") or (Occurred3<>"-1"))) {
				_root.Place = 1;
				ResetAll();
			}
			//GO TO DESCRIPTION IF THERE IS A MENTION OF DOOR & EITHER EXAMINE OR LOOK.
			if ((Occurred4<>"-1") and ((Occurred5<>"-1") or (Occurred6<>"-1"))) {
				_root.Place = 3;
				ResetAll();
			}
		}
	}
	if (_root.Place == 1) {
		//Room 1
		_root.texty = "A ROOM - You are in room 1.  You can go East into room 2.";
		// Images
		_root.Image1._visible = true;
		///////////////////////////
		if (Key.isDown(Key.ENTER)) {
			_root.inputy.toLowerCase();
			myStringSub = "east";
			myStringSub1 = "go";
			myStringSub2 = "walk";
			myStringSub3 = "head";
			//CHECKS IF WHAT YOU WRITE IN THE BOX CONTAINS THE WORDS ABOVE
			Occurred = _root.inputy.indexOf(myStringSub, 0);
			Occurred1 = _root.inputy.indexOf(myStringSub1, 0);
			Occurred2 = _root.inputy.indexOf(myStringSub2, 0);
			Occurred3 = _root.inputy.indexOf(myStringSub3, 0);
			//GO TO ROOM 2 IF THERE IS A MENTION OF EAST & EITHER GO, WALK OR HEAD.
			if ((Occurred<>"-1") and ((Occurred1<>"-1") or (Occurred2<>"-1") or (Occurred3<>"-1"))) {
				_root.Place = 2;
				ResetAll();
			}
		}
	}
	if (_root.Place == 0) {
		//Start Screen
		_root.texty = "TEXT GAME SAMPLE - Press return to continue...";
		// Images
		_root.Image1._visible = true;
		///////////////////////////
		if (Key.isDown(Key.ENTER)) {
			_root.Place = 1;
			ResetAll();
		}
	}
	///////////////////////////////////////////////////////////////////////////
	//WORDS THAT ACTIVATE REGARDLESS OF PLACE IN THE GAME
	if (Key.isDown(Key.ENTER)) {
		_root.inputy.toLowerCase();
		myStringSub100 = "poo";
		myStringSub101 = "toilet";
		Occurred100 = _root.inputy.indexOf(myStringSub100, 0);
		Occurred101 = _root.inputy.indexOf(myStringSub101, 0);
		if ((Occurred100<>"-1") or (Occurred101<>"-1")) {
			_root.PlaceReturn = _root.Place;
			_root.Place = 100;
			ResetAll();
		}
	}
	// OBJECTS
	if ((_root.Object1Position == _root.Place) and (_root.Object1 == 0)) {
		_root.objecty = _root.objecty+"There is a KEY on the floor.  ";
		_root.Object1 = 1;
		//the purpose of object1 is just to ensure that this line is added only once.
	}
	//////////////////////////////OBJECT ACTIONS
	if (Key.isDown(Key.ENTER)) {
		//PICK UP KEY
		_root.inputy.toLowerCase();
		myStringSub102 = "key";
		myStringSub103 = "pick";
		myStringSub104 = "get";
		myStringSub105 = "take";
		Occurred102 = _root.inputy.indexOf(myStringSub102, 0);
		Occurred103 = _root.inputy.indexOf(myStringSub103, 0);
		Occurred104 = _root.inputy.indexOf(myStringSub104, 0);
		Occurred105 = _root.inputy.indexOf(myStringSub105, 0);
		if ((Occurred102<>"-1") and ((Occurred103<>"-1") or (Occurred103<>"-1") or (Occurred104<>"-1") or (Occurred105<>"-1"))) {
			if ((_root.Object1Position == _root.Place)) {
				_root.listbox1.addItemAt(0, "KEY");
				_root.Object1Position = "bag";
				AddObjects();
				ResetAll();
			}
		}
		myStringSub106 = "drop";
		Occurred106 = _root.inputy.indexOf(myStringSub106, 0);
		//SPECIFY WHERE KEY CAN BE DROPPED
		if ((Occurred102<>"-1") and (Occurred106<>"-1") and ((_root.Place == 1) or (_root.Place == 2))) {
			if (Object1Position == "bag") {
				_root.Object1Position = _root.Place;
				AddObjects();
			}
		}
		//EXAMINE THE KEY
		myStringSub107 = "examine";
		myStringSub108 = "look";
		myStringSub109 = "observe";
		Occurred107 = _root.inputy.indexOf(myStringSub107, 0);
		Occurred108 = _root.inputy.indexOf(myStringSub108, 0);
		Occurred109 = _root.inputy.indexOf(myStringSub109, 0);
		if ((Occurred102<>"-1") and ((Occurred107<>"-1") or (Occurred108<>"-1") or (Occurred109<>"-1"))) {
			if (Object1Position == "bag") {
				_root.PlaceReturn = _root.Place;
				_root.Place = 4;
			}
		}
		//USE THE KEY
		myStringSub110 = "use";
		Occurred110 = _root.inputy.indexOf(myStringSub110, 0);
		if ((Occurred102<>"-1") and (Occurred110<>"-1")) {
			//SPECIFY WHERE KEY CAN BE USED
			if ((Object1Position == "bag") and (_root.Place == 2)) {
				_root.PlaceReturn = _root.Place;
				_root.Place = 5;
				Object1Position = "Finished";
				_root.Object1Position = 1000;
				AddObjects();
			}
		}
	}
	//////////////////////////////////////////////LOAD AND SAVE
	if (Key.isDown(Key.ENTER)) {
		/////////////////LOADING
		if (_root.inputy == "load") {
			//OPEN LSO
			my_l_so = SharedObject.getLocal("myFirstLSO", "/");
			_root.Place = my_l_so.data.Place;
			_root.Object1Position = my_l_so.data.Object1Position;
			ResetAll();
			AddObjects();
		}
		/////////////////SAVING
		if (_root.inputy == "save") {
			//OPEN LSO
			my_l_so = SharedObject.getLocal("myFirstLSO", "/");
			//ADD TO LSO
			//Store a username value to the shared object.
			my_l_so.data.Place = _root.Place;
			my_l_so.data.Object1Position = _root.Object1Position;
			//SAVE
			result = my_l_so.flush();
			ResetAll();
			AddObjects();
		}
	}
	//////////////////////////////////////////////
	//RESETTEXTLINE
	if (Key.isDown(Key.ENTER)) {
		//Image screen goes black for screen transition
		_root.ImageBlack._visible = true;
		//Stops return being registered continuously
		_root.EnterIsPressed = 1;
		ResetTextLine();
	}
} else {
        if (!Key.isDown(Key.ENTER)) {
	//This stops anything happening if Enter is held down continuously
	_root.EnterIsPressed = 0;
}

In the Third Keyframe add -

gotoAndPlay(2);

Creating new rooms

This might seem a bit long or complex to start with, but it is very easy.  It is all cutting and pasting.
To create a new room you just need to copy & paste the section of script in the 2nd keyframe that reads as
shown below, ensure to paste this above the section below.

	if (_root.Place == 1) {
		//Room 1
		_root.texty = "A ROOM - You are in room 1.  You can go East into room 2.";
		// Images
		_root.Image1._visible = true;
		///////////////////////////
		if (Key.isDown(Key.ENTER)) {
			_root.inputy.toLowerCase();
			myStringSub = "east";
			myStringSub1 = "go";
			myStringSub2 = "walk";
			myStringSub3 = "head";
			//CHECKS IF WHAT YOU WRITE IN THE BOX CONTAINS THE WORDS ABOVE
			Occurred = _root.inputy.indexOf(myStringSub, 0);
			Occurred1 = _root.inputy.indexOf(myStringSub1, 0);
			Occurred2 = _root.inputy.indexOf(myStringSub2, 0);
			Occurred3 = _root.inputy.indexOf(myStringSub3, 0);
			//GO TO ROOM 2 IF THERE IS A MENTION OF EAST & EITHER GO, WALK OR HEAD.
			if ((Occurred<>"-1") and ((Occurred1<>"-1") or (Occurred2<>"-1") or (Occurred3<>"-1"))) {
				_root.Place = 2;
				ResetAll();
			}
		}
	}

The Place variable is a scene or room in the game.  Change this to another number, describe the new room in
texty which then shows in the main textbox. The myStringSub lines define how to get to the new scene, to add 
a new action add a new line below myStringSub3 = "head"; reading myStringSub4 = "north"; ,then copy and paste the 
line Occurred3 = _root.inputy.indexOf(myStringSub3, 0);  Change the 3's to 4's in this line, and finally 
copy and paste the //GO TO ROOM 2 lines and modify as below - 
	//GO TO ROOM ??? IF THERE IS A MENTION OF NORTH & GO.
	if ((Occurred1<>"-1") and (Occurred4<>"-1")) {
		_root.Place = ???;
		ResetAll();
	}
 
If you have an image for this scene set it to visible here but make sure to set it to visible = false in the ResetAll function, keyframe 1.

Creating new objects

To create a new object first specify which room or Place it will be found in.  Copy this line of script you can
see in the first few lines of keyframe 1.  Change the name to Object2Position = (Place to be found);

_root.Object1Position = 0;

Also copy and change this variable to Object2.

_root.Object1 = 0; // Ensure First Object actions only occur once.

In the AddObjects function, copy and paste the following code, then change the variable for object1Position to
object2Position and change the "box" description.

if (_root.Object1Position == "bag") {
 _root.listbox1.addItemAt(0, "box"); //Update items held box
 }

Then copy the following script found in the OBJECTS section of script, keyframe 2 -

if ((_root.Object1Position == _root.Place) and (_root.Object1 == 0)) {
 _root.objecty = _root.objecty+"There is a SMALL BOX SHAPED OBJECT on the floor";
 _root.Object1 = 1; //the purpose of object1 is just to ensure that this line is added only once.
}

Add a number to the variables (object1Position will be object2Position, etc.).  Add a description for the object in
objecty. Then copy and paste the OBJECT ACTIONS section in the second keyframe code and just change the variables & 
descriptions to suit the new object.  The only bits that need changing are the Substring number for the object which
must be unique and the Place numbers where you can drop the object.
Obviously you can create any commands you want, throw object, move object, push object, etc.

Events

Events like 'Examine object' are very easy to create.  You can see in the Place = 0 script that the user can type
in 'examine door' and this will send them to Place = 3.  Place 3 is not a room, it just pulls up text giving
a description of the light and then will send them back once return is pressed.

Help Button (optional)

You can see I've added a help button to describe some of the commands you can use.  For this I just used a button
symbol and a movieclip symbol labelled 'help' with the help information.  In the Actions for the button you just add
this code -

on (rollOver) {
 _root.help._visible = true;
}
on (rollOut) {
 _root.help._visible = false;
}

Loading and Saving

Loading and Saving code is included in keyframe 2, just add all the variables which need to be saved, I've added
_root.Place and _root.Object1Position as examples, any extra variables need to be added underneath these.
FONT color=black>

One line too many...

Flash has a limit of about 1,000 lines of text before you need to use another keyframe.  
In case your text game goes over (it probably will!) you need to start writing on the third keyframe.  
In the 2nd keyframe, 3rd line, call a function, e.g. GoToPage2().  Then in the third keyframe which reads gotoAndPlay(2); 
add function GoToPage2(){ and continue adding script in there.

That's it!

Well, you're now ready to create a massive text world of your own. Send me an e-mail if you need any help with
the script or if you've created a brilliant text game!  
You can see the code in action by going back to my site and playing Startship Scalar.