Sign in to follow this  
Jompe71

Text adventure design.

Recommended Posts

Hi, I'm thinking on creating a remake of an old C64 "text adventure" game for 2 other platforms. User input in the old game is mostly (if not always) a 2 word command, ex: "open door", "climb up", "pull lever" etc. I was thinking of creating a dictionary for all words acceptable but my main concern is to handle the user input. Is there any "common" or smart way of mapping user command to code action. Lets say user is on a certain location in the adventure and there is an item on the floor. In this location giving the command "use item" is valid and shall respond in an action. Thus this command is only valid if it was entered after "pickup item". Next thing is how to map commands into code calls. The variation of commands only used for one purpose and at one location at a certain time responding in only one result is probably very large. I would like to avoid to create one method for each available and valid command. If any of you have valuable input or perhaps links to resources I'd be glad. Note that one of the platforms uses old Java so I seem to have to go without script support which could have made things easier. ;/

Share this post


Link to post
Share on other sites
Well from the examples given the first word is always a command and the second a parameter.

You could simply have your game check the first word to see if it is a valid command and then if it is use the given parameter to work with it.

"In this location giving the command "use item" is valid and shall respond in an action. Thus this command is only valid if it was entered after "pickup item""

I'm not sure I understand this correctly but couldn't you just give the user an "inventory" and have it so that "use item" will only work if the item is in the user's inventory. "pickup item" could be use to add the item to the user's inventory.

I don't see why you want to avoid creating a method for each possible command. For each location you can attach a list of valid commands which are associated with a function pointer or equivalent so that your command parser can directly call the command's function.

I couldn't make a lot of sense out of your post so sorry if that is all useless to you =/

Share this post


Link to post
Share on other sites
Dom_152 has the right approach to "use" versus "get" or "pickup."

An approach that I took many years ago (don't ask how many) is to store information about each item. Then have a function for each way any item can be used and let the item decide. You can use a class for each item or (the old old way to do it), store a "use" function pointer for each item and dispatch execution to that function. An item would also have a location, either in the "map" or in the inventory.

Each item could also have attributes: useable, openable, pullable, etc. They can be set and tested as a single bit.

For instance:

"Get" item: is the item in this location? If yes, AddToInventory(item). If no, "There is no <item> here."

"Use" item: is the item in Inventory? If no, "You don't have <item>." If yes, item->UseYourself().

"Open" item: is item openable?

"Move" direction {up,down,left,right,etc.} : Check the map. Is there a <direction> here?

If you don't want to use function pointers (which gets sort of complicated), you'll probably have to use dispatch tables. And, yes, they'll be big.

Share this post


Link to post
Share on other sites
Thx for the input guys, sorry for not beeing albe to express myself 100%.

Quote: "Dom_152"
I'm not sure I understand this correctly but couldn't you just give the user an "inventory" and have it so that "use item" will only work if the item is in the user's inventory

Well there might be more to it than just the inventory issue. It's all about some commands are only valid if other commands have been executed before.
Example: You cannot lit the torch if you haven't executed the command "look wall" which reveiled the feedback "There is an unlit torch attached here..." ;)

Function pointers are out since it's Java. Thus reflection could be used...
You both have good issues with having lists of stuff to pick up attached to the players inventory as well as for every room in the map. It makes pickup/drop stuff easier as well as saving game states.

Quote "Buckeye":
store a "use" function pointer for each item and dispatch execution to that function

Perhaps not bad at all. Keeps spreading logic out into classes where it belongs(might try it).

My thought at the moment is to use some kind of "command-tree" which upon executing a user command takes the current room and inventory etc as arguments.
My hope with the tree was to somehow be able to combine commands which are similar like "get item"/"pickup item"/"fetch item" etc.

I also really wanna come up with some scripting syntax which I can share for save games as well as the inital game setup as for where items are located, visibillity, directions etc. Since I'm gonna use a VM which requires a small footprint I'm thinking of JSON which goes well with Java.

Again, thx for the input and sorry for the poor english.
(Suppose this is of no interest but I'm aiming for the Android and BD-J platforms ;) )

Share this post


Link to post
Share on other sites
I think a "command tree" might be a good idea in this case.

The system will start at root and iterate through the tree and checks the input against all the "activated" commands. Once a command is executed it's sub commands becomes activated so they can be used in the correct order.

Share this post


Link to post
Share on other sites
Sorry for bringing life to such an old thread, but I need comments on my ideas.

Soon I'll be having the main engine for the text adventure up and running. using JSON as data format turned out to be more profitable than expected, beats the crap out of XML in turns of devloping process speed and general visuallity.
At the moment I have a few hundred lines of code and have the functionallity of walking, picking up stuff, dropping of, command interpeter, response handler, command aliases, rule handling etc. Extreemly flexible and reusable for other games (This one is just a C64 remake).

Next question (going ahead of development and assuming future luck in engine progress) is how to handle the memory issue using a platform which requires a small footprint.

Fact: I can't load the entire map/world into memory at once.
1st thought: Load only the current map location and always save the last visited location as a temporary serialization of it's current state to disc.

This sounds good when having autosave vs. manuall save of games in mind, just turn tmp files into regular in manual save and just save regular when auto is turned of.
Dissadvantage: Engine must ba able to query for available map directions (N, S, E, W etc.) which requires "peeking" into persisted locations i.e. disc access when loading each new location.

Fact: The game will be intended for platforms where disc access might be an issue.
1st thought: Zip! :-/

Fact: I'm new to game programming and need your expert input.
1st thought: You guys will spam me with you knowledge, even if 3D stuff is your hard-ons. My most concern is for Fact no.1

// Jompe71

Share this post


Link to post
Share on other sites
I'd suggest you have a look at the Inform languge, http://www.inform-fiction.org

It is a language specialized for writing text adventures. It'll take care of all the actual handling of objects and commands.

Share this post


Link to post
Share on other sites
Thx, I already did. The format looks similar to my JSON:
Snippet:

{
"TEXT": "YEAH RIGHT, AND ADD IT TO MY COLLECTION OF STIFFS BACK HOME?",
"RULES": [],
"DIRECTION": 0,
}
],
"ERRORS": [],
"RULES": [],
"INDEX": 0
},
{
"ALIASES": [ "SEARCH BODY", "FRISK BODY", "EXAMINE BODY" ],
"RESPONSES": [
{
"TEXT": "OK. YOU FOUND SOMETHING. WALLET.",
"RULES": [ "$WALLET" ],
"DIRECTION": 0
},
{
"TEXT": "OK. YOU FOUND SOMETHING. TELEGRAM.",
"RULES": [ "$TELEGRAM" ],
"DIRECTION": 0
},
{
"TEXT": "HMMM... THE CHEAP BASTARD KEPT NOTHING ELSE USEFUL ON HIM.",
"RULES": [],
"DIRECTION": 0
}
],
"ERRORS": [],
"RULES": [],
"INDEX": 0
},
{
"ALIASES": [ "DRAG BODY", "MOVE BODY", "FLIP BODY" ],
"RESPONSES": [
{
"TEXT": "OK. THERE WAS SOMETHING UNDER IT.",


But it's not the format of the map I'm concerned about it's the interpeter. Don't know if the app is open source or what, but writing my own will serve my needs to the most I think.

Giving me the link made me more comfortable with my solution even if the Infom plaftorm might be more flexible.

One thing I could have done was to "rip" their format right off and be able to get some more solid grounds to work on. But now I already got the ball rollin' and as said if I don't know what goes on behind the sceenes of the format I'm back to square one never the less I think.

Quiz: Giving the "config" snippet above, what game am I "remaking"? ;)

Share this post


Link to post
Share on other sites
Quote:
Fact: I can't load the entire map/world into memory at once...
Fact: The game will be intended for platforms where disc access might be an issue.

No memory and no disk. What're you targeting, calculator watches??

Just bluesky thinking:

You might think in the direction of dividing up the map into sections (like you haven't thought of that) like an octree (if it's a 3D map) or quadtree. Load the section of the map within a certain number of nodes of the current location. That would help if the user is exploring a limited area.

If the user has to backtrack ("You forgot to pick up the framitz back in the train station, you idiot!"), it'll be sort of grueling. That would probably occur in any case. Or, design the map to limit the need for long treks between stops to explore - make it difficult to progress without having the right items or knowledge.

EDIT: If you're really serious about memory limitations, the old PDP-8 (or some DEC machine, if I remember correctly) used a text packing method. If you can limit yourself to 32 characters (5 bits) for your text, you can pack 3 characters into 16 bits, a savings of over 30% if you're using 1 byte/character. [WINK] Bit-shifting and masking are quick operations. With a text adventure, I can't imagine performance being an issue anyway.

EDIT2: If you want to use a text packing method and you need more than 31 characters (I know I said 32 but you have to have a stop character), you can also use something like RTTY (I used to be a ham radio operator). Besides 26 alphabet characters, a couple of the "extra" 5 characters can be "shift" characters - something like "change to character set 2" or "change to numbers," etc. Depends on how serious you are about considering code to be cheaper than data.



[Edited by - Buckeye on August 26, 2009 4:18:51 PM]

Share this post


Link to post
Share on other sites
I just wanted to point out that someone has written (or was writing some time ago) an Android port of a z-code interpreter (used by the Zork series). It could probably be Googled, I can't remember if its open source or not, but it may give you some platform-specific ideas (personally, I know nothing about the systems you are targeting).

Interestingly, I did write a simple rpg/text adventure game on a C64 many years ago. In basic. I don't remember the details of project, but I also don't remember even coming close to the limits of that machine. I can't imagine a platform so limited in memory that you can only have 1 'room' loaded at a time. Are you sure you need to optimize so heavily?

P.S. Reading some example source code in Inform 7 is an interesting experience. Finally, a natural language programming language! That is, until I saw the hideous source code for the fixed math extensions...

Share this post


Link to post
Share on other sites
A lot of the "adventure" type code on the 8bits had fairly simple parsers.

You look up the "verb" into a table and it gets you an integer. Synonyms simply have the same integer.

You look the "noun" up, and it gets you an object number.

Objects are usually stored using arrays; one for the "long" name, one for the "short" name and one which gives the object's location. Special values for the location mean "held" and "worn".

It's hence pretty easy to see how they end up limited to 255 objects and locations. There's usually a bunch of counters and flags for the code to use. Again these are usually just arrays of bytes and bits.

Most of the game logic ends up being "hardcoded" in a couple of blocks. There's a block for when you enter a location. Typically these have a whole string of if/thens.

That handles conditions like

"if we're in the elephant's lair and carrying a mouse then 'the elephant runs away scared', move the elephant object out of sight, done"

"if we're in the elephant's lair and the elephant is here then 'the elephant chases you out', location = lastlocation, done"


Then there's a "per verb" block.

"if you said DROP and object was CHEESE and we're in the room with the mousehole then move the mouse object here, put the cheese object out of sight, 'the mouse appears and eats the cheese', done"

Ending with the default actions for each verb.


Then there's often a "after command" block which is always run.

"if our location == the mouse's location, 'the mouse squeaks'"

And.. that's actually about it. The internal structures really were pretty simple.


In general, adventure games tried not to have generic verbs like "use X" because the whole point is working out how to use the X. The way that the problem of working out what directions were possible was done was to separate out the room descriptions from the map architecture.

Typically the map architecture would be stored as (say) 8, 2 byte triples per room -- each pair containing a verb and the destination[1]. zero verbs mean it's unused, zero destinations mean the way is blocked and may be changed by unlocking something. You keep that array of 16 byte blocks in RAM so you can list available directions. (and alter it when needed).

Each location also has a "short" and a "long" description (used the first time) and some flags ("previously visited" is common, "lit" is another common one).
The text descriptions are kept separately and pulled off disk in sections as and when needed.



[1] This is so you can have N,S,E,W,NW,NE,SE,SW,UP,DOWN,FLY,TELEPORT... all as possible directions without needing tons of either space or code. It does also mean you could have "KILL" or "GET" as a direction, but you just don't do that :-)

Share this post


Link to post
Share on other sites
I've gotten i bit further! Sorry for picking up this old thread btw.
Current progress can be seen here for those interested: http://www.youtube.com/watch?v=iPJCwjQDdFk

Now I got he basix engine up and running, but I'm still struggling with the response code from each command.
It so happens that not all things are static. For instance time goes on (watch can be queried) some events occurs at certain times etc.

My 1st approach was to concat the static responses for commands with event driven. This caused a lot of String mambo-jambo so I just wanna throw out an idea for you gurus to respond to.

I was thinking that the engine would keep an internal list of Strings holding N responses from N commands back in time.
Since the events are both command driven and time based the event handler could just populate the same list whenever nesseseary.

This way the UI on top of the engine could chose to display the number of messages it want's and the end user can (if provided) scroll up to see old messages. Also this makes it easier to implement "monkey island" styled responses, where not everything fits the screen so the user must click to see more..

What do you think about that ?

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this