package AdventureModel;
import views.AdventureGameView;
import java.io.*;
import java.util.*;
/**
* Class AdventureGame. Handles all the necessary tasks to run the Adventure game.
*/
public class AdventureGame implements Serializable {
private final String directoryName; //An attribute to store the Introductory text of the game.
private String helpText; //A variable to store the Help text of the game. This text is displayed when the user types "HELP" command.
private final HashMap<Integer, Room> rooms; //A list of all the rooms in the game.
private HashMap<String,String> synonyms = new HashMap<>(); //A HashMap to store synonyms of commands.
private final String[] actionVerbs = {"QUIT","INVENTORY","TAKE","DROP","ATTACK","CONTINUE"}; //List of action verbs (other than motions) that exist in all games. Motion vary depending on the room and game.
public AdventureGameView adventureGameView;
public Player player; //The Player of the game.
/**
* Adventure Game Constructor
* __________________________
* Initializes attributes
*
* @param name the name of the adventure
*/
public AdventureGame(String name){
this.synonyms = new HashMap<>();
this.rooms = new HashMap<>();
this.directoryName = "Games/" + name; //all games files are in the Games directory!
try {
setUpGame();
} catch (IOException e) {
throw new RuntimeException("An Error Occurred: " + e.getMessage());
}
}
/**
* Save the current state of the game to a file
*
* @param file pointer to file to write to
*/
public void saveModel(File file) {
try {
FileOutputStream outfile = new FileOutputStream(file);
ObjectOutputStream oos = new ObjectOutputStream(outfile);
oos.writeObject(this);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* setUpGame
* __________________________
*
* @throws IOException in the case of a file I/O error
*/
public void setUpGame() throws IOException {
String directoryName = this.directoryName;
// set up the player
this.player = new Player("Heisenberg", new GunAttack(), 50);
// load game
AdventureLoader loader = new AdventureLoader(this, directoryName, player);
loader.loadGame();
player.setCurrentRoom(rooms.get(1));
}
/**
* tokenize
* __________________________
*
* @param input string from the command line
* @return a string array of tokens that represents the command.
*/
public String[] tokenize(String input){
input = input.toUpperCase();
String[] commandArray = input.split(" ");
int i = 0;
while (i < commandArray.length) {
if(this.synonyms.containsKey(commandArray[i])){
commandArray[i] = this.synonyms.get(commandArray[i]);
}
i++;
}
return commandArray;
}
/**
* movePlayer
* __________________________
* Moves the player in the given direction, if possible.
* Return false if the player wins or dies as a result of the move.
*
* @param direction the move command
* @return 0, if move results in death or a win (and game is over).
* 2, if room has combat options.
* 3, if room is a combat room.
* Else, 1.
*/
public int movePlayer(String direction) {
direction = direction.toUpperCase();
PassageTable motionTable = this.player.getCurrentRoom().getMotionTable(); //where can we move?
if (!motionTable.optionExists(direction)) return 1; //no move
ArrayList<Passage> possibilities = new ArrayList<>();
for (Passage entry : motionTable.getDirection()) {
if (entry.getDirection().equals(direction)) { //this is the right direction
possibilities.add(entry); // are there possibilities?
}
}
//try the blocked passages first
Passage chosen = null;
for (Passage entry : possibilities) {
if (chosen == null && entry.getIsBlocked()) {
if (this.player.getInventory().contains(entry.getKeyName())) {
chosen = entry; //we can make it through, given our stuff
break;
}
} else { chosen = entry; } //the passage is unlocked
}
if (chosen == null) return 1; //doh, we just can't move.
int roomNumber = chosen.getDestinationRoom();
Room room = this.rooms.get(roomNumber);
this.player.setCurrentRoom(room);
startCombat(room);
if (CombatMediator.checkPreCombatRoom(room.getRoomName())) {
return 2;
}
if (CombatMediator.checkCombatRoom(room.getRoomName())) {
return 3;
}
if (!this.player.getCurrentRoom().getMotionTable().getDirection().get(0).getDirection().equals("FORCED")) {
return 1;
}
else return 0;
}
public void startCombat(Room room) {
if (CombatMediator.checkCombatRoom(room.getRoomName())) {
room.setRoomDescription(room.getRoomDescription() + CombatMediator.mediateCombat(this.player, room.getRoomName().split(" ")[0]));
}
if (this.player.getHitPoints() == 0) adventureGameView.endGame();
}
/**
* interpretAction
* interpret the user's action.
*
* @param command String representation of the command.
*/
public String interpretAction(String command){
String[] inputArray = tokenize(command); //look up synonyms
PassageTable motionTable = this.player.getCurrentRoom().getMotionTable(); //where can we move?
if (inputArray[0].equals("ATTACK")) {
if (inputArray.length > 1) {
if (inputArray[1].equals("GUN")) {
this.player.setAttack(new GunAttack());
} else if (inputArray[1].equals("HANDTOHAND")) {
this.player.setAttack(new HandToHandAttack());
} else this.player.setAttack(new MagicAttack());
}
}
if (motionTable.optionExists(inputArray[0])) {
int moveResult = movePlayer(inputArray[0]);
if (moveResult == 0) {
if (this.player.getCurrentRoom().getMotionTable().getDirection().get(0).getDestinationRoom() == 0)
return "GAME OVER";
else return "FORCED";
}
else if (moveResult == 2) {
this.adventureGameView.toggleAttackButtons(true);
}
else if (moveResult == 3) {
this.adventureGameView.toggleAttackButtons(false);
}
return null;
} else if(Arrays.asList(this.actionVerbs).contains(inputArray[0])) {
if(inputArray[0].equals("QUIT")) { return "GAME OVER"; } //time to stop!
else if(inputArray[0].equals("INVENTORY") && this.player.getInventory().size() == 0) return "INVENTORY IS EMPTY";
else if(inputArray[0].equals("INVENTORY") && this.player.getInventory().size() > 0) return "THESE OBJECTS ARE IN YOUR INVENTORY:\n" + this.player.getInventory().toString();
else if(inputArray[0].equals("TAKE") && inputArray.length < 2) return "THE TAKE COMMAND REQUIRES AN OBJECT";
else if(inputArray[0].equals("DROP") && inputArray.length < 2) return "THE DROP COMMAND REQUIRES AN OBJECT";
else if(inputArray[0].equals("TAKE") && inputArray.length == 2) {
if(this.player.getCurrentRoom().checkIfObjectInRoom(inputArray[1])) {
this.player.takeObject(inputArray[1]);
return "YOU HAVE TAKEN:\n " + inputArray[1];
} else {
return "THIS OBJECT IS NOT HERE:\n " + inputArray[1];
}
}
else if(inputArray[0].equals("DROP") && inputArray.length == 2) {
if(this.player.checkIfObjectInInventory(inputArray[1])) {
this.player.dropObject(inputArray[1]);
return "YOU HAVE DROPPED:\n " + inputArray[1];
} else {
return "THIS OBJECT IS NOT IN YOUR INVENTORY:\n " + inputArray[1];
}
}
}
return "INVALID COMMAND.";
}
/**
* getDirectoryName
* __________________________
* Getter method for directory
* @return directoryName
*/
public String getDirectoryName() {
return this.directoryName;
}
/**
* getInstructions
* __________________________
* Getter method for instructions
* @return helpText
*/
public String getInstructions() {
return helpText;
}
/**
* getPlayer
* __________________________
* Getter method for Player
*/
public Player getPlayer() {
return this.player;
}
/**
* getRooms
* __________________________
* Getter method for rooms
* @return map of key value pairs (integer to room)
*/
public HashMap<Integer, Room> getRooms() {
return this.rooms;
}
/**
* getSynonyms
* __________________________
* Getter method for synonyms
* @return map of key value pairs (synonym to command)
*/
public HashMap<String, String> getSynonyms() {
return this.synonyms;
}
/**
* setHelpText
* __________________________
* Setter method for helpText
* @param help which is text to set
*/
public void setHelpText(String help) {
this.helpText = help;
}
}