Interactive Fiction / Text Based Adventure

D

Dante

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
 
T

TechBookReport

Dante said:
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

Have you looked here: http://community.java.net/games/
 
I

iamfractal

Hi,

Did the same thing myself to get to know Java a few years back. A fine
exercise. Some points:

1. Good that you thought of your save system early; I tried to bolt-on
serialization at a late stage and discovered that serialization has to
be considered from day 1. Painful.

2. Your room approach, that of a List of essentially room objects, is
exactly what I tried, and it worked fine. See my two, no doubt
indentation-mangled classes below. (Remember, this was a learning
project, so the code's not pretty.)

3. Don't have, "10," story sections if that, "10," is hard-coded into
the design. OO is flexibility through variance encapsulation, and your
story sections will definitely vary. I think the key to a good
adventure framework is the behaviour engine: how characters and things
behave as their environment changes. You should consider putting some
time into encapsulating this.

4. From your final point, "And perhaps the ability to change the rooms
(editing the story)," it could be interpreted that you are basing story
development on room-discovery. Again, and this could just be personal
taste, basing story development on how objects and characters interact
seems more fruitful. (Proof-of-pudding time: see, "Violentia," at site
below.)

5. Use MVC. At some time, you may want to make your game multi-player,
so a controller and view to ecapsulate i/o is a fine idea.

6. Check out http://sourceforge.net and search for, "Interactive
fiction." There's loads of Java stuff to give you ideas.

..ed

--
www.EdmundKirwan.com - Home of The Fractal Class Composition.



package edkirwan.infrastructure.location;
import java.util.List;
import java.util.ArrayList;
import edkirwan.infrastructure.Context;

/**
* Class implements the location-specific object functionality.
*/
public class LocationController implements LocationFacade {
private Location nullPlace = null; // Storage area for unused
Things
private Context context = null;

// Collection of all locations created for the game
private List locations = new ArrayList();

/**
* Constructor - registers the subsystem.
*
* @param inContext repository for all subsystem references
*/
public LocationController(Context inContext) {
context = inContext;
context.register(Context.LOCATION, this);
}

/**
* Creates a location and adds it to the collection of all
locations. This
* method returns the newly created location.
*
* @param desc location description
* @param isIndoor indicates whether location is indoors
* @param ambientSound sound generated at this location
* @param grfx graphics at this location
* @return identifier corresponding to this location
*/
public Location create(String desc, boolean isIndoor,
LocationSound ambientSound, LocationGrfx grfx) {
Location newLocation = new Location(desc, isIndoor, ambientSound,
grfx, locations.size(),
context);
locations.add(newLocation);
return newLocation;
}

/**
* Creates a location and adds it to the collection of all
locations. This
* method returns the newly created location. Some of the values
for the
* location are defaulted.
*
* @param desc location description
* @param isIndoor indicates whether location is indoors
* @return identifier corresponding to this location
*/
public Location create(String desc, boolean isIndoor) {
Location newLocation = new Location(desc, isIndoor, locations.size(),
context);
locations.add(newLocation);
return newLocation;
}

/**
* Returns the location object for the given location identifier.
*
* @param locationId the given location identifier
* @return the corresponding location
*/
public Location getLocation(int locationId) {
return (Location)locations.get(locationId);
}

/**
* Returns the location object for the given location identifier.
*
* @param locationId the given location identifier
* @return the corresponding location
* @throws LocationException if any error occurs
*/
public Location getLocation(Integer locationId) throws
LocationException {
int id = locationId.intValue();
if ((id < 0) || (id >= locations.size())) {
throw new LocationException();
}
return (Location)locations.get(id);
}

/**
* Sets the place where all Things are put, "in storage." Whenever
a
* Thing is destroyed, its object is not garbage collected -
instead it
* is put into an otherwise inaccessible location where it waits
for
* eternity. Objects may also be created here and wait until they
are
* called into the game.
*
* @param inNullPlace location of the null place
*/
public void setNullPlace(Location inNullPlace) {
nullPlace = inNullPlace;
}

/**
* Returns the null place location.
*
* @return location of the null place
*/
public Location getNullPlace() {
return nullPlace;
}
}


package edkirwan.infrastructure.location;
import java.util.List;
import java.util.ArrayList;
import edkirwan.infrastructure.shell.Verb;
import edkirwan.infrastructure.shell.VerbFactory;
import edkirwan.infrastructure.shell.ShellFacade;
import edkirwan.infrastructure.thing.Door;
import edkirwan.infrastructure.Context;
import edkirwan.library.Library;
import edkirwan.infrastructure.shell.SerializableElement;

/**
* This class models a location.
*/
public class Location implements SerializableElement {
private String desc = null; // location description
private boolean isIndoor = false; // if true location is indoors
private LocationSound ambientSound = null; // location ambient
sound
private LocationGrfx grfx = null; // location graphics
private int locationId = 0; // unique identifier
private String grfxFileName = null; // File name of graphics if
any
private static final int MAX_EXITS = 6; // north, south, etc
private Context context = null;

// Exits hindered by doors or hatches
private Door[] hinderedExits = new Door[MAX_EXITS];

// Unhindered exits
private Location[] unhinderedExits = new Location[MAX_EXITS];

/**
* Constructor - stores the location data.
*
* @param inDesc location description
* @param inIsIndoor indicates whether location is indoors
* @param inAmbientSound sound generated at this location
* @param inGrfx graphics at this location
* @param inLocationId location identifier
* @param inContext game context
*/
public Location(String inDesc, boolean inIsIndoor,
LocationSound inAmbientSound, LocationGrfx inGrfx,
int inLocationId, Context inContext) {
desc = inDesc;
isIndoor = inIsIndoor;
ambientSound = inAmbientSound;
grfx = inGrfx;
locationId = inLocationId;
context = inContext;
}

/**
* Constructor - stores the location data with some defaults.
*
* @param inDesc location description
* @param inIsIndoor indicates whether location is indoors
* @param inLocationId location identifier
* @param inContext game context
*/
public Location(String inDesc, boolean inIsIndoor,
int inLocationId, Context inContext) {
desc = inDesc;
isIndoor = inIsIndoor;
ambientSound = new LocationSound();
grfx = new LocationGrfx();
locationId = inLocationId;
context = inContext;
}

/**
* Returns location identifier
*
* @return unique location identifier
*/
public int getLocationId() {
return locationId;
}

/**
* Returns location description
*
* @return location description
*/
public String getDescription() {
return desc;
}

/**
* Returns true if this location is the same as the given location
*
* @param inLocation given location to test
* @return true if both locations are the same
*/
public boolean isEquals(Location inLocation) {
return (this.locationId == inLocation.getLocationId());
}

/**
* Adds the given location as the northern path from here and vice
versa.
*
* @param north northern location
*/
public void addNorth(Location north) {
unhinderedExits[LocationFacade.NORTH] = north;
if (!north.isDirectionSet(LocationFacade.SOUTH)) {
north.addSouth(this);
}
}

/**
* Adds the given location as the southern path from here and vice
versa.
*
* @param south southern location
*/
public void addSouth(Location south) {
unhinderedExits[LocationFacade.SOUTH] = south;
if (!south.isDirectionSet(LocationFacade.NORTH)) {
south.addNorth(this);
}
}

/**
* Adds the given location as the eastern path from here and vice
versa.
*
* @param east eastern location
*/
public void addEast(Location east) {
unhinderedExits[LocationFacade.EAST] = east;
if (!east.isDirectionSet(LocationFacade.WEST)) {
east.addWest(this);
}
}

/**
* Adds the given location as the western path from here and vice
versa.
*
* @param west western location
*/
public void addWest(Location west) {
unhinderedExits[LocationFacade.WEST] = west;
if (!west.isDirectionSet(LocationFacade.EAST)) {
west.addEast(this);
}
}

/**
* Adds the given location as the upwards path from here and vice
versa.
*
* @param up upwards location
*/
public void addUp(Location up) {
unhinderedExits[LocationFacade.UP] = up;
if (!up.isDirectionSet(LocationFacade.DOWN)) {
up.addDown(this);
}
}

/**
* Adds the given location as the downwards path from here and vice
versa.
*
* @param down downwards location
*/
public void addDown(Location down) {
unhinderedExits[LocationFacade.DOWN] = down;
if (!down.isDirectionSet(LocationFacade.UP)) {
down.addUp(this);
}
}

/**
* Adds the given door as the northern path from here and vice
versa.
*
* @param door
*/
public void addNorthDoor(Door door) {
Location north = door.getOtherLocation(this);
hinderedExits[LocationFacade.NORTH] = door; // Set door direction
if (!north.hasDoor()) { // If other location has no door yet
north.addSouthDoor(door); // Assign this door
}
}

/**
* Adds the given door as the southern path from here and vice
versa.
*
* @param door
*/
public void addSouthDoor(Door door) {
Location south = door.getOtherLocation(this);
hinderedExits[LocationFacade.SOUTH] = door; // Set door direction
if (!south.hasDoor()) { // If other location has no door yet
south.addNorthDoor(door); // Assign this door
}
}

/**
* Adds the given door as the eastern path from here and vice
versa.
*
* @param door
*/
public void addEastDoor(Door door) {
Location east = door.getOtherLocation(this);
hinderedExits[LocationFacade.EAST] = door; // Set door direction
if (!east.hasDoor()) { // If other location has no door yet
east.addWestDoor(door); // Assign this door
}
}

/**
* Adds the given door as the western path from here and vice
versa.
*
* @param door
*/
public void addWestDoor(Door door) {
Location west = door.getOtherLocation(this);
hinderedExits[LocationFacade.WEST] = door; // Set door direction
if (!west.hasDoor()) { // If other location has no door yet
west.addEastDoor(door); // Assign this door
}
}

/**
* Adds the given door as the upward path from here and vice versa.
*
* @param door
*/
public void addUpDoor(Door door) {
Location up = door.getOtherLocation(this);
hinderedExits[LocationFacade.UP] = door; // Set door direction
if (!up.hasDoor()) { // If other location has no door yet
up.addDownDoor(door); // Assign this door
}
}

/**
* Adds the given door as the upward path from here and vice versa.
*
* @param door
*/
public void addDownDoor(Door door) {
Location down = door.getOtherLocation(this);
hinderedExits[LocationFacade.DOWN] = door; // Set door direction
if (!down.hasDoor()) { // If other location has no door yet
down.addUpDoor(door); // Assign this door
}
}

/**
* Returns true if this location has a door assigned.
*
* @return true if this location has a door.
*/
private boolean hasDoor() {
for (int i = 0; i < hinderedExits.length; i++) {
if (hinderedExits != null) {
return true;
}
}
return false;
}

/**
* Returns true if the given direction is already set from this
location.
*
* @param direction direction to test for
* @return true if direction already set, else false
*/
private boolean isDirectionSet(int dir) {
switch(dir) {
case LocationFacade.NORTH:
if (unhinderedExits[LocationFacade.NORTH] == null) {
return false;
}
break;
case LocationFacade.SOUTH:
if (unhinderedExits[LocationFacade.SOUTH] == null) {
return false;
}
break;
case LocationFacade.EAST:
if (unhinderedExits[LocationFacade.EAST] == null) {
return false;
}
break;
case LocationFacade.WEST:
if (unhinderedExits[LocationFacade.WEST] == null) {
return false;
}
break;
case LocationFacade.UP:
if (unhinderedExits[LocationFacade.UP] == null) {
return false;
}
break;
case LocationFacade.DOWN:
if (unhinderedExits[LocationFacade.DOWN] == null) {
return false;
}
break;
}
return true;
}

/**
* Returns a descriptions of the available exits.
*
* @returns description of available exits
*/
public StringBuffer getExitsDesc() {
StringBuffer str = new StringBuffer(); // Output description
int numOfExits = 0; // Number of exits from here
int exitCount = 0;
for (int i = 0; i < MAX_EXITS; i++) { // Count number of exits
if (unhinderedExits != null) {
numOfExits++;
}
if (hinderedExits != null) {

// If a door allows passage then add another exit
if (hinderedExits.isPassable()) {
numOfExits++;
}
}
}
if (numOfExits == 0) {
str.append("nowhere");
} else {
for (int i = 0; i < MAX_EXITS; i++) { // Show all exits
if (unhinderedExits != null) {
str.append(LocationFacade.EXIT_STRINGS);
Library.addCommaAnd(str, numOfExits, exitCount);
exitCount++;
}
if (hinderedExits != null) {
if (hinderedExits.isPassable()) {
str.append(LocationFacade.EXIT_STRINGS);
Library.addCommaAnd(str, numOfExits, exitCount);
exitCount++;
}
}
}
}
return str;
}

/**
* Returns a list of all locations neighbouring this location.
*
* @return list of all neighbouring locations
*/
public List getNeighbourLocations() {
List neighbours = new ArrayList();
for (int i = 0; i < MAX_EXITS; i++) {
if (unhinderedExits != null) {
neighbours.add(unhinderedExits);
}
if (hinderedExits != null) {

// If a door allows passage then add exit
if (hinderedExits.isPassable()) {
neighbours.
add(hinderedExits.getOtherLocation(this));
}
}
}
return neighbours;
}

/**
* Returns the northern location or null.
*
* @return northern location or null
*/
public Location getNorth() {
if (unhinderedExits[LocationFacade.NORTH] != null) {
return unhinderedExits[LocationFacade.NORTH];
}
if (hinderedExits[LocationFacade.NORTH] != null) {
if (hinderedExits[LocationFacade.NORTH].isPassable()) {
return hinderedExits[LocationFacade.NORTH].
getOtherLocation(this);
}
}
return null;
}

/**
* Returns the southern location or null.
*
* @return southern location or null
*/
public Location getSouth() {
if (unhinderedExits[LocationFacade.SOUTH] != null) {
return unhinderedExits[LocationFacade.SOUTH];
}
if (hinderedExits[LocationFacade.SOUTH] != null) {
if (hinderedExits[LocationFacade.SOUTH].isPassable()) {
return hinderedExits[LocationFacade.SOUTH].
getOtherLocation(this);
}
}
return null;
}

/**
* Returns the eastern location or null.
*
* @return eastern location or null
*/
public Location getEast() {
if (unhinderedExits[LocationFacade.EAST] != null) {
return unhinderedExits[LocationFacade.EAST];
}
if (hinderedExits[LocationFacade.EAST] != null) {
if (hinderedExits[LocationFacade.EAST].isPassable()) {
return hinderedExits[LocationFacade.EAST].
getOtherLocation(this);
}
}
return null;
}

/**
* Returns the western location or null.
*
* @return western location or null
*/
public Location getWest() {
if (unhinderedExits[LocationFacade.WEST] != null) {
return unhinderedExits[LocationFacade.WEST];
}
if (hinderedExits[LocationFacade.WEST] != null) {
if (hinderedExits[LocationFacade.WEST].isPassable()) {
return hinderedExits[LocationFacade.WEST].
getOtherLocation(this);
}
}
return null;
}

/**
* Returns the upwards location or null.
*
* @return upwards location or null
*/
public Location getUp() {
if (unhinderedExits[LocationFacade.UP] != null) {
return unhinderedExits[LocationFacade.UP];
}
if (hinderedExits[LocationFacade.UP] != null) {
if (hinderedExits[LocationFacade.UP].isPassable()) {
return hinderedExits[LocationFacade.UP].
getOtherLocation(this);
}
}
return null;
}

/**
* Returns the downwards location or null.
*
* @return downwards location or null
*/
public Location getDown() {
if (unhinderedExits[LocationFacade.DOWN] != null) {
return unhinderedExits[LocationFacade.DOWN];
}
if (hinderedExits[LocationFacade.DOWN] != null) {
if (hinderedExits[LocationFacade.DOWN].isPassable()) {
return hinderedExits[LocationFacade.DOWN].
getOtherLocation(this);
}
}
return null;
}

/**
* Returns a verb that will cause the performer to leave this
location.
* If there are no exits, then this returns null.
*
* @return verb to move in given direction, or null
*/
public Verb getExitVerb() {
int numExits = 0;
int[] exits = new int[MAX_EXITS];
for (int i = 0; i < MAX_EXITS; i++) {
if (unhinderedExits != null) { // If an exit found
exits[numExits] = i; // Record direction
numExits++;
}
if (hinderedExits != null) { // If an exit found
if (hinderedExits.isPassable()) {
exits[numExits] = i; // Record direction
numExits++;
}
}
}
if (numExits == 0) {
return null; // Return if no exits found
} else {
return tryDirection(exits[Library.random(numExits - 1)]);
}
}


/**
* Returns a verb that will cause the performer to leave this
location.
* If there are no exits, then this returns null. If there are more
than
* one exit, then this will make one attempt to select a random
exit.
* If this attempt succeeds, the verb will be returned. If it
fails,
* then null will be returned even if there are other, valid exits.
*/
public Verb maybeGetExitVerb() {
return tryDirection(Library.random(MAX_EXITS));
}

/**
* Returns a verb to move in given direction, if direction is
clear. If
* not clean, return null.
*
* @param givenDirection given direction in which to try to move
* @return verb to move in given direction, or null
*/
private Verb tryDirection(int givenDirection) {
ShellFacade gameShell = (ShellFacade)context.
lookup(Context.GAME_SHELL);
VerbFactory verbFactory = gameShell.getVerbFactory();
switch(givenDirection) {
case LocationFacade.NORTH:
if (unhinderedExits[LocationFacade.NORTH] != null) {
return verbFactory.createNorth();
} else if (hinderedExits[LocationFacade.NORTH] != null) {
if (hinderedExits[LocationFacade.NORTH].isPassable()) {
return verbFactory.createNorth();
}
}
break;
case LocationFacade.SOUTH:
if (unhinderedExits[LocationFacade.SOUTH] != null) {
return verbFactory.createSouth();
} else if (hinderedExits[LocationFacade.SOUTH] != null) {
if (hinderedExits[LocationFacade.SOUTH].isPassable()) {
return verbFactory.createSouth();
}
}
break;
case LocationFacade.EAST:
if (unhinderedExits[LocationFacade.EAST] != null) {
return verbFactory.createEast();
} else if (hinderedExits[LocationFacade.EAST] != null) {
if (hinderedExits[LocationFacade.EAST].isPassable()) {
return verbFactory.createEast();
}
}
break;
case LocationFacade.WEST:
if (unhinderedExits[LocationFacade.WEST] != null) {
return verbFactory.createWest();
} else if (hinderedExits[LocationFacade.WEST] != null) {
if (hinderedExits[LocationFacade.WEST].isPassable()) {
return verbFactory.createWest();
}
}
break;
case LocationFacade.UP:
if (unhinderedExits[LocationFacade.UP] != null) {
return verbFactory.createUp();
} else if (hinderedExits[LocationFacade.UP] != null) {
if (hinderedExits[LocationFacade.UP].isPassable()) {
return verbFactory.createUp();
}
}
break;
case LocationFacade.DOWN:
if (unhinderedExits[LocationFacade.DOWN] != null) {
return verbFactory.createDown();
} else if (hinderedExits[LocationFacade.DOWN] != null) {
if (hinderedExits[LocationFacade.DOWN].isPassable()) {
return verbFactory.createDown();
}
}
break;
}
return null;
}

/**
* Returns verb needed to get from here to the given location, if
possible.
*
* @param destination next location to go to
*/
public Verb getExitTo(Location destination) {
ShellFacade gameShell = (ShellFacade)context.
lookup(Context.GAME_SHELL);
VerbFactory verbFactory = gameShell.getVerbFactory();
if (unhinderedExits[LocationFacade.EAST] != null) {
if (destination.equals(unhinderedExits[LocationFacade.EAST])) {
return verbFactory.createEast();
}
} else if (hinderedExits[LocationFacade.EAST] != null) {
if (hinderedExits[LocationFacade.EAST].isPassable()) {
if (destination.equals(hinderedExits[LocationFacade.EAST].
getOtherLocation(this))) {
return verbFactory.createEast();
}
}
}
if (unhinderedExits[LocationFacade.NORTH] != null) {
if (destination.equals(unhinderedExits[LocationFacade.NORTH])) {
return verbFactory.createNorth();
}
} else if (hinderedExits[LocationFacade.NORTH] != null) {
if (hinderedExits[LocationFacade.NORTH].isPassable()) {
if (destination.equals(hinderedExits[LocationFacade.NORTH].
getOtherLocation(this))) {
return verbFactory.createNorth();
}
}
}
if (unhinderedExits[LocationFacade.SOUTH] != null) {
if (destination.equals(unhinderedExits[LocationFacade.SOUTH])) {
return verbFactory.createSouth();
}
} else if (hinderedExits[LocationFacade.SOUTH] != null) {
if (hinderedExits[LocationFacade.SOUTH].isPassable()) {
if (destination.equals(hinderedExits[LocationFacade.SOUTH].
getOtherLocation(this))) {
return verbFactory.createSouth();
}
}
}
if (unhinderedExits[LocationFacade.WEST] != null) {
if (destination.equals(unhinderedExits[LocationFacade.WEST])) {
return verbFactory.createWest();
}
} else if (hinderedExits[LocationFacade.WEST] != null) {
if (hinderedExits[LocationFacade.WEST].isPassable()) {
if (destination.equals(hinderedExits[LocationFacade.WEST].
getOtherLocation(this))) {
return verbFactory.createWest();
}
}
}
if (unhinderedExits[LocationFacade.UP] != null) {
if (destination.equals(unhinderedExits[LocationFacade.UP])) {
return verbFactory.createUp();
}
} else if (hinderedExits[LocationFacade.UP] != null) {
if (hinderedExits[LocationFacade.UP].isPassable()) {
if (destination.equals(hinderedExits[LocationFacade.UP].
getOtherLocation(this))) {
return verbFactory.createUp();
}
}
}
if (unhinderedExits[LocationFacade.DOWN] != null) {
if (destination.equals(unhinderedExits[LocationFacade.DOWN])) {
return verbFactory.createDown();
}
} else if (hinderedExits[LocationFacade.DOWN] != null) {
if (hinderedExits[LocationFacade.DOWN].isPassable()) {
if (destination.equals(hinderedExits[LocationFacade.DOWN].
getOtherLocation(this))) {
return verbFactory.createDown();
}
}
}
return null;
}

/**
* Sets the file name for the graphics to be displayed at this
location
*
* @param fileName name of graphics file
*/
public void setGraphicsFileName(String fileName) {
grfxFileName = fileName;
}

/**
* Getthe file name for the graphics to be displayed at this
location
*
* @return name of graphics file
*/
public String getGraphicsFileName() {
return grfxFileName;
}

/**
* Returns the String form of this object.
*
* @return string form of object
*/
public String toString() {
return "Location " + locationId + " is: " + desc;
}

/**
* Converts this element to an Integer.
*
* @return Integer version of this element.
*/
public Integer toInteger() {
return new Integer(getLocationId());
}

/**
* Returns the list of hindered exits.
*
* @return list of hindered exits
*/
public Door[] getHinderedExits() {
return hinderedExits;
}
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,996
Messages
2,570,238
Members
46,826
Latest member
robinsontor

Latest Threads

Top