Interactive Fiction / Text Based Adventure

Hello,

Long time lurker, first time poster. Wondering if I could ask on some advice and help on a group project.

What we’d like to do is to put together an:

Interactive Fiction / Text Based Adventure games with say

  • 10 Story Sections / Rooms
  • An Item System
  • A Combat System
  • A save system
  • And perhaps the ability to change the rooms (editing the story)

Now we’ve had no problems so far with the combat system and are currently upgrading the code to add more complex options, as for the Item system I think we’re going to do something simple with say giving each item a true or false state and changing certain things depending on what state each items variable is in (just need to work out how to integrate it)

We have a fairly good idea for the save system also just dump some relevant information to say a txt file on where the user is within the game and what items they have picked up etc

The main problem we are having is coming up with the rooms thinking of using an ArrayList with different rooms / sections then having a class to implement each section of the Array with the text associated with that rooms and then links to different rooms… only problem is we’re not sure how to code it…

Anyway I was wondering if anyone had any suggestions or ideas on any part of project particularly how to implement the rooms, if someone could post some code or link to an existing project that would great.

Thanks in advance for any advice given

You could just use the old Infocom system and a Z-machine. There is a Java version of the Z-machine around that will play most of the old Infocom games. I’m sure there are tools to make the games as well.

Sure, I’ve got some advice as usual, hopefully my advice is usually helpful as well.

Save System:
I recommend using ObjectOutputStream and ObjectInputStream for saving and accessing game files. It basically does everything for you, and so can be very useful. Create a class called SaveManager, and give it static method for saving and loading. Also give it all the variables you may need to store to the file.


import java.io.*;
import java.util.ArrayList;

public class SaveManager
{
    //The following makes it so that if you update this class
    //you will still be able to read old versions of it. However,
    //it is not necessary here, because you do not actually write the
    //class SaveManager to the file. I've only included it so you can
    //see how this works.
    private static final long serialVersionUID = 1L;

    //static variables that keep track of the ordering of the saved List
    public static final int PLAYER_HP = 0;
    public static final int PLAYER_POS = 1;
    //etc. etc.

    //generally it is nicer to put all of the information into a List before writing it to a file
    //this means that you do not have to assure ordering as much.
    public static void save(String path, ArrayList info)
    {
        //Now create the output stream to write to the file.
        //A try/catch statement will keep errors from messing up your
        //program, and is necessary here.
        try
        {
            //path might be something like "saves/player.save"
            //you can use any file extension you want, as long as you are consistent
            ObjectOutputStream writer = new ObjectOutputStream(new FileOutputStream(path));
            writer.writeObject(info);
            writer.close();
        }
        catch(Exception e) {System.out.println("Error saving to file: " + e);}
    }

    //obviously, it needs some place to put the information
    public static void load(String path, InfoPlace putter)
    {
        //Now create the output stream to read to the file.
        //A try/catch statement will keep errors from messing up your
        //program, and is necessary here.
        try
        {
            ObjectInputStream reader = new ObjectInputStream(new FileInputStream(path));
            LinkedList info = (LinkedList) reader.readObject();
            putter.setPlayerHP(((Integer)info.get(PLAYER_HP)).intValue());
            putter.setPlayerPos(((Integer)info.get(PLAYER_POS)).intValue());
            //etc. etc. etc.
            reader.close();
        }
        catch(Exception e) {System.out.println("Error saving to file: " + e);}
    }
}

I hope you can understand that. If there’s anything that doesn’t make sense to you, just ask me. I would actually recommend that InfoPlace have a method to get the information from the ArrayList, like putter.loadValues(info), just to keep everything separate and in a smart place. However, I wanted you to see why I had those constants at the top, so I put that in there.

Level System:
I would not recommend ArrayList. Although this would work just fine, you will have wasted memory (ArrayList always does that), and your code will have no room for expansion outside of a simple 2D grid. Here is what I recommend instead.


public class Level
{
    private Room currentRoom;

    //Return true/false depending on whether that room exists or not
    public boolean goEast()
    {
        if (currentRoon.east() == null)
            return false;
        currentRoom = currentRoom.east();
        return true;
    }

    /***etc. on all the different directions***/
}

public class Room
{
    private Room east;
    private Room west;
    private Room north;
    private Room south;
    private Room up;
    private Room down;
    private Room secret;
    //etc. etc. etc.

    //Your actual game variables could go here
    private ArrayList stuffInTheRoom;

    public Room east()
    {
        return east;
    }
    //etc. etc. etc.
}

Obviously, these classes are incomplete, but I think you should get the idea. Basically I am using a linked version rather than an array version. Each room is linked by pointers to other rooms in the level.This way you can easily add in more directions if you want, like up and down, and you are not wasting any memory like a 2D array or ArrayList’s will do. This results in very robust and efficient code.

Make sense?

ArrayList can be initialized with the exact capacity needed so that no memory is wasted, even though the actual waste will probably be negligible.

[quote], and your code will have no room for expansion outside of a simple 2D grid.
[/quote]
I don’t see the connection between ArrayList and a simple 2D grid.

[quote]Here is what I recommend instead.


public class Level
{
    private Room currentRoom;

    //Return true/false depending on whether that room exists or not
    public boolean goEast()
    {
        if (currentRoon.east() == null)
            return false;
        currentRoom = currentRoom.east();
        return true;
    }

    /***etc. on all the different directions***/
}

public class Room
{
    private Room east;
    private Room west;
    private Room north;
    private Room south;
    private Room up;
    private Room down;
    private Room secret;
    //etc. etc. etc.

    //Your actual game variables could go here
    private ArrayList stuffInTheRoom;

    public Room east()
    {
        return east;
    }
    //etc. etc. etc.
}

Obviously, these classes are incomplete, but I think you should get the idea. Basically I am using a linked version rather than an array version. Each room is linked by pointers to other rooms in the level.This way you can easily add in more directions if you want, like up and down, and you are not wasting any memory like a 2D array or ArrayList’s will do.
[/quote]
Actually the way you have done the Room class you have made it hard to add more directions becuase you have hard-coded them into the class. What about:


class Room
{
    protected HashMap<Direction,Room> connectedRooms;
    //Your actual game variables could go here
    protected ArrayList stuffInTheRoom;

    public Room move(Direction d)
    {
        return connectedRooms.get(d);
    }
    //etc. etc. etc.
}

enum Direction
{
    NORTH,SOUTH,EAST,WEST,UP,DOWN,NORTHEAST,SOUTHEAST,SIDEWAYS,BACKWARDS /// etc....
}

Well an ArrayList can be initialized with whatever size you want, but if you add in another item beyond that size then it will double its current size, wasting memory. What I thought was going to do would be an ArrayList of ArrayList’s to represent a 2D grid of rooms. Just what I assumed.

As for your Hashmap method of doing things, that’s definitely a fine idea. I guess it all depends on whether or not he will be having an external level editor type thing or if all the levels will be hard coded.

Ah, I was thinking that the map would be more static after loading so lists could trimmed to the ideal size, and that the ArrayLists would be just of rooms that were reachable from the current room or something like that. You would also probably have a master list of all rooms for some purposes (e.g. saving game state).

But really it just seemed like a very premature optimization. Considering that the ArrayList element is only going to be about 4 bytes or so, doubling the capacity of the lists is still not likely to be an issue even with thousands of rooms.

True, true. I just try to steal that extra bit of speed wherever I can get it, because Java is always slower than C++ will be.

Thanks, guys much appreciated… I’ll definately try some of the code (though it may be a complicated for me)

Just wondering if I could trouble everyone for some more advice. So I’m using an array list to store the text / descriptions for various rooms. and I’m thinking a class called something like BookSection So I think the BookSection class should display the text / description associated with the current room and that it should also have links to 1 or more rooms and depending on user input (left, right etc) it should move the user to that room and change the text

I’ve come up with the following code and after searching the books I have (Head First Java, Just Java 2 and How to Program Java) and checking online I’m at a loss and was wondering if anyone had any idead how to code this (based on the bad and very limited code I have below)

class booksection{
int index //page number
string text //the story
int[]choices // the pages links
}

to display a page the program would display the string and the choices
and then load the choice the user made

method getchoices(page, thispage){
string text = “choises are”
thispage.choices.length
for (int i=0; i<2, i++){
text = text+thispage.choice[i]
}

return text
}

this would display the story and the appropriate choices

Once thanks for the replies regarding the save system.

Well…

Is this a text adventure? a Text mud? or a text based action game?

The old scott adams/infocom style adventures were pretty simple state machines.
Each room is a state. Each recognized command is a state transition. A state transition ca be dependnat on an inventory item. (if you dont have the item you ether transitionerent state then i you do, or you cannot transition at all.)

State transitions can have two special modes, the first, all links to the old state are re-written as links to the new one. The second special type goes to the new state and ends the game. (This can also be done with a specially flagged state.)

Each state has an inveotry list associated with it for items “in the room”

Thats about all there is to a basic text adventure engine.

MUDs need top be mroe flexible. Typically therefor MUDs follow a more object oriented design. I personally have ahd excellent success in the past with the DOOR paradigm (Door Object or ROOM.)

Basically it works like this, there is only one kind of object in the world: a DOOR.

A DOOR has an inventory list and two command lists, an “external” command list and an “internal” command list. One special kind of DOOR is a player. A player is an endpoint for input. Other then that its rpetty much liek any other DOOR. (If you have a combat system it may have stats too.)

When input comes in, it is senbt to the player. All DOORs handle input in the same way. Input has sent to the list of commands in the order in the list. Any command can recognize the input and consume it or pass it on.

The order of command processing by DOORs is as follows:
(1) Check the external list of commands on each of the obejcts in my inventory.
(2) Check the internal list of commands on my parent
(3) Check my internal list.

A DOOR may be visible, in which case it shows up in an inventory list, or invisible, in which case it doesnt.

Some quick examples:
Player has an internal command “look” which prinst the inventory list of its parent.

Player gets an invisible “blindness curse” object added to their invetory. It has a “look” command which simple prints “you are blind.”

Room contains a gaint robot DOOR.
Giant Robot has an external command “Enter Robot” that puts the4 caller in its own inventory.

Giant Robot has internal commands “stand up”, “sit down”, “walk n|s|e|w”…
Start to get the idea? Almost any text-based physical sim cna be built in the DOOR paradigm. Thre are lost of little details (like having “this” type calls to get caller, callee, etc) that will likely becoem obvious to you as you start experimenting with such a system.

I think I’d like to go for something like the transitional adventure (though not based on items) just user input (left, right etc)

What I mean by the below

Is I’d like to come up a very basic and simple text based adventure… say have a fixed array of 10 items, each item will contain the description / text of a room then they will link to each other in some way the function of the booksection class (as described below) will be to display the text of the current room and then ask from the users input on where they would like to go next and then put up the next for that new room (looking for something fairly basic) I’ve posted some bad pseudo-code below but would really like some help expanding it


Thanks, guys much appreciated… I’ll definately try some of the code (though it may be a complicated for me)

Just wondering if I could trouble everyone for some more advice. So I’m using an array list to store the text / descriptions for various rooms. and I’m thinking a class called something like BookSection So I think the BookSection class should display the text / description associated with the current room and that it should also have links to 1 or more rooms and depending on user input (left, right etc) it should move the user to that room and change the text

I’ve come up with the following code and after searching the books I have (Head First Java, Just Java 2 and How to Program Java) and checking online I’m at a loss and was wondering if anyone had any idead how to code this (based on the bad and very limited code I have below)

class booksection{
int index //page number
string text //the story
int[]choices // the pages links
}

to display a page the program would display the string and the choices
and then load the choice the user made

method getchoices(page, thispage){
string text = “choises are”
thispage.choices.length
for (int i=0; i<2, i++){
text = text+thispage.choice[i]
}

return text
}

this would display the story and the appropriate choices

Once thanks for the replies regarding the save system.

Hey everyone,

someone I know gave me some advice but I’m not entirely sure what to do

You should have a booksection class. This class can only contain methods and variables related to a booksection so,

a booksection can have an int ID, String text, ArrayList or array of choices: int[] choice;
and the methods it can implement are for example:(although there may be more)

public String getText(){
return text;
}

public String getchoices(){ <----- see the difference between this and yours. No parameters
String response = “choices are”;
for (int i=0; i<choices.length, i++){
response = response+choice[i]
}

So each booksection can now output its text and choices.
In the main section not the booksection class we can (assuming we have created a booksection object called myBookSection) get the choices for a specific booksection by using for example:

String choices= myBookSection.getchoices();

The important point here is that each booksection object can now return the text and choices that it contains. In the main java file, you have to find the right booksection id from your ArrayList and then use its methods.

In the main program you should create around 10 booksection objects (read from file or hard coded) and add these to an ArrayList of type .

The functionality for operating the book and turning to different booksections should be implemented in the main java file.

If the user selects page 10 for example, you should find the booksection with id 10 from your ArrayList of booksections and display the text and the links for this page. This is then a recursive process.

Pseudo code for navigating the book:

create an empty booksection object
get the first page from your book arraylist and assign it to the booksection object created above

While (number of links in booksection is not equal to 0)

{
Display the booksection id
Display the booksection text
Get the user to input the id of the next booksection -(use getchoice method)
Get the user selected page from your book arraylist and assign it to the booksection object created above
}

That was fascinating - I am a noob game programmer. I did google that door method, but wasn’t able to find any in-depth material (unless you count ‘the girl next door’ :). Can you point us to some guides and examples (not that yours was bad)? thanks.

Well, actually, my brother wrote a paper on it some time ago :slight_smile:

I cna ask him if he still has a copy somewhere.