/*
* File: Adventure.java
* --------------------
* This program plays the Adventure game from Assignment #7.
*/

import acm.program.*;
import acm.util.*;
import java.io.*;
import java.util.*;

/* Class: Adventure */
/**
* This class is the main program class for the Adventure game.  In
* the final version, Adventure should extend ConsoleProgram directly.
*/

public class Adventure extends ConsoleProgram {

/* Static method: main(args) */
/**
* Standard Java entry point for applications.
*/

       public static void main(String[] args) {
               new Adventure().start(args);
       }

/* Method: run() */
/**
* Runs the Adventure program.
*/
       public void run() {
               println("Welcome to Tentellian Island!");
               println("-----------------------------------------------");
               println("");
               String name = "wood";
               prepareGame(name);
               playGame();
       }
// Reads in the files and prepares the game for play.
       private void prepareGame (String name) {
               readHelp(name);
               readRooms(name);
               readObjects(name);
               readSynonyms(name);
               initializeVerbs();
               currentroom = "" + 1;
               room = (AdvRoom) rooms.get(currentroom);
               AdvObject note = room.getObject(1);
               inventory.put(note.getName(), note);
               room.removeObject(note);
               currentMotionTable = room.getMotionTable();
               println(room.getName());
       }
// Reads in the help text file
       private void readHelp(String name) {
               String filename = "wood-help.txt";
               try {
                       rd = new BufferedReader(new FileReader(filename));
                       String helpstring;
                       while (true) {
                               helpstring = rd.readLine();
                               if (helpstring == null) break;
                               if (helpstring.length() > 0) help.add(helpstring);
                       }
                       rd.close();
               } catch (IOException ex) {
                       throw new ErrorException(ex);
               }
       }
// Reads in the rooms text file
       private void readRooms(String name) {
               String filename = "wood-rooms.txt";
               try {
                       rd = new BufferedReader(new FileReader(filename));
                       String roomstring;
                       while (true) {
                               room = new AdvRoom();
                               if (room.readFromFile(rd) == true) {
                                       roomstring = "" + room.getRoomNumber();
                                       rooms.put(roomstring, room);
                               } else {
                                       break;
                               }
                       }
                       rd.close();
               } catch (IOException ex) {
                       throw new ErrorException(ex);
               }
       }
// Reads in the objects text file
       private void readObjects(String name) {
               String filename = "wood-objects.txt";
               try {
                       rd = new BufferedReader(new FileReader(filename));
                       while (true) {
                               obj = new AdvObject();
                               if (obj.readFromFile(rd) == true) {
                                       objects.put(obj.getName(), obj);
                                       currentroom = "" + obj.getInitialLocation();
                                       room = (AdvRoom) rooms.get(currentroom);
                                       room.addObject(obj);
                               } else {
                                       break;
                               }
                       }
                       rd.close();
               } catch (IOException ex) {
                       throw new ErrorException(ex);
               }
       }
// Reads in the list of synonyms
       private void readSynonyms(String name) {
               String filename = "wood-synonyms.txt";
               try {
                       rd = new BufferedReader(new FileReader(filename));
                       while (true) {
                               String line = rd.readLine();
                               if (line == null) break;;
                               int equals = line.indexOf("=");
                               String synword = line.substring(0, equals);
                               String synverb = line.substring(equals + 1);
                               synonyms.put(synword, synverb);
                       }
                       rd.close();
               } catch (IOException ex) {
                       throw new ErrorException(ex);
               }
       }
// Associates each verb with the appropriate AdvCommand
       private void initializeVerbs() {
               String quit = "QUIT";
               verbs.put(quit, Quit);
               String kill = "KILL";
               verbs.put(kill, Kill);
               String liberate = "LIBERATE";
               verbs.put(liberate, Liberate);
               String helps = "HELP";
               verbs.put(helps, Help);
               String look = "LOOK";
               verbs.put(look, Look);
               String invent = "INVENTORY";
               verbs.put(invent, Inventory);
               String take = "TAKE";
               verbs.put(take, Take);
               String drop = "DROP";
               verbs.put(drop, Drop);
               String BREAK = "BREAK";
               verbs.put(BREAK, Break);
               String use = "USE";
               verbs.put(use, Use);
               String cut = "CUT";
               verbs.put(cut, Cut);
               String examine = "EXAMINE";
               verbs.put(examine, Examine);
               String laugh = "LAUGH";
               verbs.put(laugh, Laugh);
               String unlock = "UNLOCK";
               verbs.put(unlock, Unlock);
               String open = "OPEN";
               verbs.put(open, Open);
               String cry = "CRY";
               verbs.put(cry, Cry);
               String jump = "JUMP";
               verbs.put(jump, Jump);
               String yell = "YELL";
               verbs.put(yell, Yell);
               String dance = "DANCE";
               verbs.put(dance, Dance);
               String sleep = "SLEEP";
               verbs.put(sleep, Sleep);
               String wear = "WEAR";
               verbs.put(wear, Wear);
               String smell = "SMELL";
               verbs.put(smell, Smell);
               String read = "READ";
               verbs.put(read, Read);
               String sing = "SING";
               verbs.put(sing, Sing);
               String groan = "GROAN";
               verbs.put(groan, Groan);
               String sigh = "SIGH";
               verbs.put(sigh, Sigh);
               String cheer = "CHEER";
               verbs.put(cheer, Cheer);
               String sit = "SIT";
               verbs.put(sit, Sit);
               String nod = "NOD";
               verbs.put(nod, Nod);
               String blush = "BLUSH";
               verbs.put(blush, Blush);
               String clap = "CLAP";
               verbs.put(clap, Clap);
               String shrug = "SHRUG";
               verbs.put(shrug, Shrug);
               String shudder = "SHUDDER";
               verbs.put(shudder, Shudder);
               String ponder = "PONDER";
               verbs.put(ponder, Ponder);
               String talk = "TALK";
               verbs.put(talk, Talk);
               String listen = "LISTEN";
               verbs.put(listen, Listen);
               String hold = "HOLD";
               verbs.put(hold, Hold);
               String swim = "SWIM";
               verbs.put(swim, Swim);
       }
// Begins gameplay by reading the player's input
       private void playGame() {
               while(true) {
                       updateRoom();
                       parseInput();
                       actionoccurred = false;
                       if (gameover == true) break;
                       checkForMotionVerb(verb);
                       checkForActionVerb(verb, directObject);
                       checkForFORCED();
                       if (successfullyMoved == true) {
                               println(room.getName());
                               successfullyMoved = false;
                               checkforLightInCorridor();
                               checkForEmotionalContent();
                       }
                       if (actionoccurred == false) {
                               println("That doesn't make sense.");
                       }
                       if (gameWon) {
                               if (fishmurdered) {
                                       badWinnersText();
                               } else {
                                       if (fishsaved) {
                                               winnersText();
                                       } else {
                                               secondaryWinnersText();
                                       }
                               }
                               break;
                       }
               }
       }
// Displays the information for a newly visited room and records that it has been visited
       private void updateRoom () {
               if (room.hasBeenVisited() == false) {
                       room.setVisited(true);
                       if (room.getRoomNumber() == 9) {
                               checkForPendantPower();
                       }
                       String[] roomdescrip = room.getDescription();
                       for (int i = 0; i < roomdescrip.length; i++) {
                               println(roomdescrip[i]);
                       }
                       listObjects();
               }
       }
// Seperates the user's entry into a verb and a direct object
       private void parseInput() {
               String userline = readLine();
               int space = userline.indexOf(" ");
               verb = parseVerb(space, userline).toUpperCase();
               directObject = null;
               if (space != -1) directObject = parseDirectObject(space, userline).trim().toUpperCase();
       }
// Checks to see if the player entered any recognizable action verbs
       private void checkForActionVerb(String verb, String DO) {
               if (actionoccurred == false) {
                       if ((verbs.containsKey(verb)) || ((synonyms.containsKey(verb)) && (verbs.containsKey(synonyms.get(verb))))) {
                               if (synonyms.containsKey(verb)) {
                                       verb = (String) synonyms.get(verb);
                               }
                               actionoccurred = true;
                               AdvCommand command = (AdvCommand) verbs.get(verb);
                               AdvObject object = null;
                               if (objects.containsKey(DO)) {
                                       object = (AdvObject) objects.get(DO);
                               }
                               command.execute(this, object);
                       }
               }
       }
// Checks to see if the player entered any recognizable motion verbs
       private void checkForMotionVerb(String verb) {
               if (actionoccurred == false) {
                       if (synonyms.containsKey(verb)) {
                               verb = (String) synonyms.get(verb);
                       }
                       AdvMotionCommand direction = new AdvMotionCommand(verb);
                       boolean found = false;
                       for (int i = 0; i < currentMotionTable.length; i++) {
                               if (currentMotionTable[i].getDirection().equals(verb) == true) {
                                       found = true;
                               }
                       }
                       if (found == true) {
                               direction.execute(this, null);
                               actionoccurred = true;
                       }
               }
       }
// Checks to see if the current room forces the player somewhere else
       private void checkForFORCED() {
               while (currentMotionTable[0].getDirection().equals("FORCED") == true) {
                       boolean found = false;
                       for (int i = 0; i < currentMotionTable.length; i++) {
                               String keyname = currentMotionTable[i].getKeyName();
                               if ((unlocked(keyname)) && (found == false)) {
                                       currentroom = "" + currentMotionTable[i].getDestinationRoom();
                                       found = true;
                               }
                               if ((!unlocked(keyname)) && (found == false)) {
                                       currentroom = "" + currentMotionTable[i+1].getDestinationRoom();
                                       found = true;
                               }
                       }
                       for (int i = 0; i < room.getDescription().length; i++) {
                               println(room.getDescription()[i]);
                       }
                       successfullyMoved = false;
                       room = (AdvRoom) rooms.get(currentroom);
                       currentMotionTable = room.getMotionTable();
                       if (currentroom.equals("0")) {
                               gameover = true;
                       }
               }
       }

// Finds the verb in the user's entry
       private String parseVerb(int space, String line) {
               if (space == -1) return line;
               String averb = line.substring(0, space);
               return averb;
       }
// Finds the object in the user's entry
       private String parseDirectObject(int space, String line) {
               String DO = line.substring(space).trim();
               return DO;
       }
// Checks to see if the player is carrying something that gives off light.
       private boolean checkForLight() {
               if (inventory.containsKey("BULB")) {
                       return true;
               }
               return false;
       }
//       Used in room 10 to find an item to solve a puzzle
       public void checkforLightInCorridor() {
               if (((room.getRoomNumber() == 10)) && (checkForLight())) {
                       for (int i = 0; i < room.getObjectCount(); i++) {
                               AdvObject object = room.getObject(i);
                               object.setVisible(true);
                               println("The corridor is slightly illuminated by the glowing bulb, allowing you to take a closer look at things in the nasty corridor.");
                               println("You can hear the Humming Room to the North.");
                       }
               }
       }
// Makes the user feel certain emotions if they carry the emotor to the right places
       public void checkForEmotionalContent() {
               if (inventory.containsKey("EMOTOR")) {
                       if (room.getRoomNumber() == 6) {
                               println("A feeling of empty boredom emanates from the pool of water.");
                       }
                       if (room.getRoomNumber() == 14) {
                               println("You feel very giggly for some reason.");
                       }
                       if (room.getRoomNumber() == 16) {
                               println("You suddenly feel a surge of anger and rage.");
                       }
                       if (room.getRoomNumber() == 20) {
                               println("You begin to feel lonely and sad.");
                       }
                       if (room.getRoomNumber() == 21) {
                               println("You feel jaunty and light on your feet all of a sudden.");
                       }
               }
       }
       private void checkForPendantPower() {
               if (inventory.containsKey("PENDANT")) {
                       println("The pendant emits a shrill noise as the humming growns louder, canceling out its overbearing effects and making it possible to pass freely into the Humming Room.");
               }
       }
// Makes sure that each emotion only advances the emotor once
       public void advanceEmotor(String emotion) {
               int beginningemo = emotionsexpressed;
               if ((emotion.equals("laugh")) && (laughed == false)) {
                       laughed = true;
                       emotionsexpressed += 1;
               }
               if ((emotion.equals("sad")) && (cried == false)) {
                       cried = true;
                       emotionsexpressed += 1;
               }
               if ((emotion.equals("anger")) && (screamed == false)) {
                       screamed = true;
                       emotionsexpressed += 1;
               }
               if ((emotion.equals("dance")) && (danced == false)) {
                       danced = true;
                       emotionsexpressed += 1;
               }
               int endemo = emotionsexpressed;
               if (endemo > beginningemo) {
                       emotorLevelUp(emotionsexpressed);
               }
       }
// Prints a different message each time a new emotion is expressed while holding the emotor
       private void emotorLevelUp(int emo) {
               switch (emo) {
                       case 1:
                               println("The emotor grows warmer in your hands, and a surface of transparent orange light flickers underneath the box in the middle of the room.");
                               break;
                       case 2:
                               println("The emotor becomes downright hot to the touch, and the orange light over the hole becomes more opaque.");
                               break;
                       case 3:
                               println("It becomes painful to hold the emotor due to its scalding temperature. The orange light looks almost solid and is barely translucent at all.");
                               break;
                       case 4:
                               println("The emotor is burning your hands. What appears to be a smooth orange floor has formed over the hole in the middle of the room.");
                               println("The emotor's temperature finally cools down, much to your relief.");
                               platformUp = true;
                               break;
               }
       }

/* Method: executeMotionCommand(direction) */
/**
* Executes a motion command.  This method is called from the
* AdvMotionCommand class to move to a new room.
*
* @param direction The string indicating the direction of motion
*/
       public void executeMotionCommand(String direction) {
               direction = direction.toUpperCase();
               boolean found = false;
               for (int i = 0; i < currentMotionTable.length; i++) {
                       if (currentMotionTable[i].getDirection().equals(direction) == true) {
                               String keyname = currentMotionTable[i].getKeyName();
                               if ((unlocked(keyname)) && (found == false)) {
                                       currentroom = "" + currentMotionTable[i].getDestinationRoom();
                                       found = true;
                               }
                               if ((!unlocked(keyname)) && (found == false)) {
                                       currentroom = "" + currentMotionTable[i+1].getDestinationRoom();
                                       found = true;
                               }
                               successfullyMoved = true;
                       }
               }
               room = (AdvRoom) rooms.get(currentroom);
               currentMotionTable = room.getMotionTable();
               actionoccurred = true;
       }
// Checks to see if the player can pass through to an area that requires a certain key,
//      as listed in the rooms text file
       public boolean unlocked(String keyname) {
               if (keyname == null) {
                       return true;
               } else {
                       if ((room.getRoomNumber() == 13) && (bluedooropen)) {
                               return true;
                       }
                       if (((room.getRoomNumber() == 15) || (room.getRoomNumber() == 17) || (room.getRoomNumber() == 19)) && (platformUp)) {
                               return true;
                       }
                       if (inventory.containsKey(keyname)) {
                               return true;
                       }
               }
               return false;
       }
/* Method: executeQuitCommand() */
/**
* Implements the QUIT command.  This command should ask the user
* to confirm the quit request and, if so, should exit from the
* play method.  If not, the program should continue as usual.
*/
       public void executeQuitCommand() {
               while(true) {
                       String line = readLine("Do you REALLY want to quit? ").toUpperCase();
                       if ((line.equals("YES")) || (line.equals("Y"))) {
                               gameover=true;
                               println("Thanks for playing!");
                               break;
                       }
                       if ((line.equals("NO")) || (line.equals("N"))) {
                               println("Yay!");
                               break;
                       }
               }
       }

/* Method: executeHelpCommand() */
/**
* Implements the HELP command.  Your code must include some
* help text for the user, although you are free to copy (and
* with luck improve on) what is in the sample application.
* If you are making extensions for extra credit or the contest,
* you should describe any new commands in your help text.
*/
       public void executeHelpCommand() {
               for (int i = 0; i < help.size(); i++) {
                       println(help.get(i));
               }
       }

/* Method: executeLookCommand() */
/**
* Implements the LOOK command.  This method should give the full
* description of the room and its contents.
*/
       public void executeLookCommand() {
               println(room.getName());
               String[] roomdescript = room.getDescription();
               described = false;
               objectslisted = false;
               checkForBulbLightingCorridor();
               checkForDeadBulbsInBlue();
               if (described == false) {
                       for (int i = 0; i < roomdescript.length; i++) {
                               println(roomdescript[i]);
                       }
                       if (((room.getRoomNumber() == 15) || (room.getRoomNumber() == 17) || (room.getRoomNumber() == 19)) && (platformUp)) {
                               println("The center of the room, formerly a hole, is covered by a smooth orange surface. It looks like it would be safe to walk on.");
                       }
               }
               if (objectslisted == false) {
                       listObjects();
               }
       }
// Lists the objects that are present and visible in the room
       private void listObjects() {
               for (int i = 0; i < room.getObjectCount(); i++) {
                       if (room.getObject(i).isVisible()) {
                               String objectsname = room.getObject(i).getName().toLowerCase();
                               if (objectsname.charAt(objectsname.length()-1) == 's') {
                                       println("Some " +objectsname+ " are here.");
                               } else {
                                       println("A " +objectsname+ " is here.");
                               }
                       }
               }
       }
// Checks to see if the blue bulbs have been killed off. If they have, a different room
// description is displayed in response to the LOOK command.
       private void checkForDeadBulbsInBlue() {
               if ((room.getRoomNumber() == 13)) {
                       if (bluedooropen) {
                               described = true;
                               println("Bulbous blue growths still cover most surfaces around the edges of the room, but they have shriveled away in the area around the door.");
                               println("You can now pass through the doorway to the South with ease.");
                       }
               }
       }
// Checks to see if the player is carrying the glowing blue bulb in the Nasty Corridor.
// If they are, a different room description is provided in response to LOOK.
       private void checkForBulbLightingCorridor() {
               if ((room.getRoomNumber() == 10)) {
                       objectslisted = true;
                       if (checkForLight()) {
                               for (int i = 0; i < room.getObjectCount(); i++) {
                                       AdvObject object = room.getObject(i);
                                       object.setVisible(true);
                               }
                               described = true;
                               println("In the dim blue light of the bulb, you can make out the moss-covered walls, with yellow-green fluid seeping down in places.");
                               println("You can now see things lying on the rocky floor along with the general rubble.");
                               listObjects();
                       }
               }
       }
/* Method: executeInventoryCommand() */
/**
* Implements the INVENTORY command.  This method should
* display a list of what the user is carrying.
*/
       public void executeInventoryCommand() {
               if (inventory.size() == 0) {
                       println("You aren't carrying one single thing.");
               }
               if (inventory.size() == 1) {
                       println("You are carrying 1 item: ");
               }
               if (inventory.size() > 1) {
                       println("You are carrying " + inventory.size() + " items: ");
               }
               for(Iterator i = inventory.keySet().iterator(); i.hasNext(); ) {
                       String key = (String) i.next();
                       println(key.toLowerCase());
               }
       }

/* Method: executeTakeCommand(obj) */
/**
* Implements the TAKE command.  This method should check that the
* object is in the room and deliver a suitable message if not.
*
* @param obj The AdvObject you want to take
*/
       public void executeTakeCommand(AdvObject obj) {
               if (obj != null) {
                       if ((room.getRoomNumber() == 18) && (obj.getName().equals("BOX"))) {
                               println("The box itself won't move from its mid-air position. You came here for the contents of the box.");
                       } else if ((room.getRoomNumber() == 6) && (obj.getName().equals("FISH"))) {
                               if (!obj.canMove()) {
                                       println("The fish dart away from your hands with surprising agility when you try to grab them.");
                               } else {
                                       println("The fish allow to pick them up out of the water.");
                                       inventory.put(obj.getName(), obj);
                                       room.removeObject(obj);
                                       println("Taken.");
                               }
                       } else if (obj.canMove()) {
                               if (room.containsObject(obj) == true) {
                                       inventory.put(obj.getName(), obj);
                                       room.removeObject(obj);
                                       println("Taken.");
                                       if (obj.getName().equals("KEY")) {
                                               keyfound = true;
                                       }
                               } else {
                                       println("There's no " +obj.getName().toLowerCase()+ " in the room.");
                               }
                       } else {
                               println("You can't take the "+obj.getName().toLowerCase()+".");
                       }
               } else {
                       println("You can't take that!");
               }
       }

/* Method: executeDropCommand(obj) */
/**
* Implements the DROP command.  This method should check that the
* user is carrying the object and deliver a suitable message if not.
*
* @param obj The AdvObject you want to drop
*/
       public void executeDropCommand(AdvObject obj) {
               if (obj != null) {
                       if ((obj.getName().equals("FISH")) && (inventory.containsKey("FISH"))) {
                               if (room.getRoomNumber() == 1) {
                                       fishReleaseOcean();
                                       inventory.remove(obj.getName());
                               } else if ((room.getRoomNumber() >= 115) && (room.getRoomNumber()  <= 117)) {
                                       println("You release the fish into the yellow lake. They squirm spastically for a few seconds and then float still in the water.");
                                       murderFish();
                                       inventory.remove(obj.getName());
                               } else {
                                       println("You should probably drop them in a body of water somewhere if you want them to survive.");
                               }
                       } else {
                               if (hasObject(obj)) {
                                       inventory.remove(obj.getName());
                                       room.addObject(obj);
                                       println("Dropped.");
                               } else if (obj != null) {
                                       println("You don't have any " +obj.getName().toLowerCase()+ " to drop!");
                               }
                       }
               } else {
                       println("You can't drop that.");
               }
       }
       public void executeLiberateCommand(AdvObject obj) {
               if (obj != null) {
                       if ((obj.getName().equals("FISH")) && (inventory.containsKey("FISH"))) {
                               if (room.getRoomNumber() == 1) {
                                       fishReleaseOcean();
                                       inventory.remove(obj.getName());
                               } else if ((room.getRoomNumber() >= 115) && (room.getRoomNumber()  <= 117)) {
                                       println("You release the fish into the yellow lake. They squirm spastically for a few seconds and then float still in the water.");
                                       murderFish();
                                       inventory.remove(obj.getName());
                               } else {
                                       println("You should probably drop them in a body of water somewhere if you want them to survive.");
                               }
                       } else {
                               println("It makes no sense to try to liberate the "+obj.getName().toLowerCase()+ ".");
                       }
               } else {
                       println("That doesn't even make sense.");
               }
       }
       public void fishReleaseOcean() {
               println("You crouch down and release the fish into the ocean. They float still at first, and you wonder if it was too late. To your delight, they soon begin to show some signs of life and after a moment go swimming off into the ocean.");
               if (inventory.containsKey("EMOTOR")) {
                       println("The emotor surges with warmth and you are filled with a feeling of gratefulness.");
                       println("");
                       fishVision();
               }
               fishsaved = true;
       }
       public void fishVision() {
               println("There is a flash of orange light and you are struck with a vision. You are looking at yourself from the perspective of the Professor, whose thoughts you can read. You quickly recognize the scene as the last time you met before leaving. Although you feel the Professor smiling and wishing you a safe journey, in your mind you feel a cold satisfaction.");
               println("");
               println("You feel the Professor's conviction that you cannot spread stories about your adventures on this island.");
               println("You now know with frightening certainty that the Professor plans to murder you upon your return.");
               println("But what can be done...");
       }
       public void murderFish() {
               println("You have murdered the fish.");
               if (inventory.containsKey("EMOTOR")) {
                       println("The emotor grows warm and surges with a mix of agony and hatred.");
                       println("");
                       fishVision();
               }
               fishmurdered = true;
       }
// Enables the player to learn more about objects that are in the room or their inventory
       public void executeExamineCommand(AdvObject obj) {
               if (obj != null) {
                       if (((obj.getName().equals("POOL")) || (obj.getName().equals("FISH"))) && (room.getRoomNumber() == 6) && (inventory.containsKey("EMOTOR")) && (!inventory.containsKey("FISH"))) {
                               println("You gaze into the pool and see some small fish swimming slowly in circles.");
                               println("The emotor grows warm and you develop an emotional bond with the fish. You begin to feel hot, exhausted, and bored, just as they do.");
                               println("More than anything, though, the fish long to return to the ocean.");
                               for (int i = 0; i < room.getObjectCount(); i++) {
                                       obj = room.getObject(i);
                                       if (obj.getName().equals("FISH")) {
                                               obj.setMoveable(true);
                                       }
                               }
                       } else if ((room.getRoomNumber() > 0) && (room.getRoomNumber() < 5) && (obj.getName().equals("DOCK"))) {
                               println("The dock is rickety and covered in a wet, gray moss.");
                       } else {
                               if ((inventory.containsKey(obj.getName())) || (room.containsObject(obj))) {
                                       println(obj.getDescription());
                               } else {
                                       println("I don't see any " +obj.getName().toLowerCase()+ " here.");
                               }
                       }
               } else {
                       if (room.getRoomNumber() == 10) {
                               executeLookCommand();
                       } else {
                               println("You can't examine any such thing.");
                       }
               }
               searchForKey(obj);
       }
// Shows the key hidden among the plants the first time the player examines them.
// Makes the key visible and moveable
       public void searchForKey(AdvObject obj) {
               if (obj != null) {
                       if ((room.getRoomNumber() == 7) && (obj.getName().equals("PLANTS")) && (keyfound == false)) {
                               for (int i = 0; i < room.getObjectCount(); i++) {
                                       AdvObject objecto = room.getObject(i);
                                       objecto.setVisible(true);
                                       objecto.setMoveable(true);
                               }
                               keyfound = true;
                               obj.setMoveable(false);
                               obj.setVisible(false);
                               println("You spot something shiny among the plants. It appears to be a key.");
                       }
               }
       }
// Enables the player to break objects that they are carrying, namely the crystal.
       public void executeBreakCommand(AdvObject obj) {
               if (obj != null) {
                       if (hasObject(obj)) {
                               if (obj.getName().equals("CRYSTAL")) {
                                       println("You hurl the crystal to the ground with all your might.");
                                       println("It shatters into countless pieces and the swirling gas escapes.");
                                       inventory.remove("CRYSTAL");
                                       if (room.getRoomNumber() == 13) {
                                               println("The blue bulbs around the smashed crystal begin to shrivel away.");
                                               println("The gas spreads, killing off a number of the bulbs that had been growing over the doorway.");
                                               bluedooropen = true;
                                       } else {
                                               println("The gas quickly dissipates and is gone.");
                                       }
                               } else {
                                       println("You can't break the " + obj.getName().toLowerCase()+".");
                               }
                       } else {
                               if ((obj.getName().equals("BOX"))&&(room.getRoomNumber() == 18)) {
                                       println("Sheer force won't work on the box. Despite its weathered appearance, it is quite sturdy.");
                               } else {
                                       println("You don't have any " + obj.getName().toLowerCase()+" to break!");
                               }
                       }
               } else {
                       println("You can't break that.");
               }
       }
// Enables the player to laugh. This activates the emoter if it is carried in room 14
       public void executeLaughCommand() {
               if ((inventory.containsKey("EMOTOR")) && (room.getRoomNumber() == 14)) {
                       println("You giggle a little to yourself before bursting out in laughter so intense that you begin to cry.");
                       advanceEmotor("laugh");
               } else {
                       println("You laugh heartily, slapping your thigh a few times.");
               }
       }
// Enables the player to cry. This activates the emoter if it is carried in room 20.
       public void executeCryCommand() {
               if ((inventory.containsKey("EMOTOR")) && (room.getRoomNumber() == 20)) {
                       println("You sniff a few times as the tears begin to well up. Soon they are streaming down your face uncontrollably.");
                       advanceEmotor("sad");
               } else {
                       println("You hold your head in your hands and let a few tears roll down your cheeks.");
               }
       }
//       Enables the player to yell. This activates the emoter if it is carried in room 16.
       public void executeYellCommand() {
               if ((inventory.containsKey("EMOTOR")) && (room.getRoomNumber() == 16)) {
                       println("You surpise yourself with the level of rage and anger that accompanies your loud scream.");
                       advanceEmotor("anger");
               } else {
               println("You let out your frustration with a primal yell.");
               }
       }
//       Enables the player to cut a rug. This activates the emoter if it is carried in room 21.
       public void executeDanceCommand() {
               if ((inventory.containsKey("EMOTOR")) && (room.getRoomNumber() == 21)) {
                       println("You begin to bob to an imaginary beat and in no time find yourself pulling all kinds of moves that you didn't even know you were capable of.");
                       advanceEmotor("dance");
               } else {
               println("You snap your fingers and bend your knees to the tune of your favorite song.");
               }
       }

// Let's the player attempt to open something
       public void executeOpenCommand(AdvObject obj) {
               if (obj != null) {
                       if ((room.getRoomNumber() == 18) && (obj.getName().equals("BOX"))) {
                               if (!unlockedbox) {
                                       println("The box is locked. You'll need to unlock it with a key of some sort.");
                               } else {
                                       println("The box popped open by itself after you unlocked it.");
                               }
                       } else {
                               println("It's no use trying to unlock the "+obj.getName().toLowerCase()+".");
                       }
               } else {
                       println("You can't very well unlock that.");
               }
       }
//       Let's the player listen to their surroundings
       public void executeListenCommand() {
               int rnum = room.getRoomNumber();
               if (rnum == 1) {
                       println("You hear only the water lapping against the dock.");
               } else if (rnum == 8) {
                       println("You hear humming coming from within the structure. The more you listen to it, the more unbearable it becomes.");
               } else if (rnum == 9) {
                       println("You hear a gentle hum. It is a little disconcerting, and you soon become uncomfortable standing here and listening to it.");
               } else if (rnum == 10) {
                       println("Besides the perpetual noise of the nearby Humming Room, you hear a periodic dripping noise in the corridor.");
               } else if (rnum == 11) {
                       println("You hear a drip of water somewhere in the corridor every now and then, along with the distant humming.");
               } else if ((rnum > 13) && (rnum < 22)) {
                       println("The silence in this open room is a notable change from the constant humming audible throughout the rest of the structure.");
               } else {
                       println("You don't hear anything unusual.");
               }
       }
// Let's the player attempt to use objects. It usually doesn't work because they need to be
// more specific
       public void executeUseCommand(AdvObject obj) {
               if (hasObject(obj)) {
                       if (obj.getName().equals("EMOTOR")) {
                               println("You don't need to \"use\" the emotor. It is a complex device and will work automatically when the time comes.");
                       } else if (obj.getName().equals("GEM-HAT")) {
                               println("You can use the gem-hat by wearing it.");
                       } else if (obj.getName().equals("KEY")) {
                               println("Be more specific. Are you trying to unlock something?");
                       } else if (obj.getName().equals("CRYSTAL")) {
                               println("But what exactly do you want to DO with the crystal?");
                       } else println("There's no obvious way to use the " +obj.getName().toLowerCase()+".");
               } else {
                       println("Can't use that.");
               }
       }
// Let's the player read things, namely the note from the Professor
       public void executeReadCommand(AdvObject obj) {
               if (hasObject(obj)) {
                       if (obj.getName().equals("NOTE")) {
                               println(obj.getDescription());
                       } else {
                               println("You can't read the "+obj.getName().toUpperCase()+".");
                       }
               } else {
                       println("There's no way you're reading that.");
               }
       }
// Let's the player sing a song
       public void executeSingCommand() {
               if ((inventory.containsKey("EMOTOR")) && (room.getRoomNumber() == 21)) {
                       println("You belt out your favorite tune with surprising skill. You even hit the high notes!");
                       advanceEmotor("dance");
               } else {
                       println("You sing a little tune under your breath to pass the time.");
               }
       }
// Let's the player smell various objects in the game, for entertainment purposes only
       public void executeSmellCommand(AdvObject obj) {
               if (obj != null) {
                       if (room.containsObject(obj)) {
                               if (obj.getName().equals("PLANTS")) {
                                       println("Predictably, the plants reek of fish and other decomposing biomaterial.");
                               } else if (obj.getName().equals("WATER")) {
                                       println("It smells salty and fresh, but a bit fishy.");
                               } else if (obj.getName().equals("BOX")) {
                                       println("The box smells like aged wood.");
                               }else {
                                       println("There is no particularly strong scent to the "+obj.getName().toLowerCase()+".");
                               }
                       } else if (inventory.containsKey(obj.getName())) {
                               if (obj.getName().equals("PENDANT")) {
                                       println("The pendant smells metallic with a hint of musk from the rotting fabric.");
                               } else if (obj.getName().equals("NOTE")) {
                                       println("It smells like the Professor.");
                               } else if (obj.getName().equals("KEY")) {
                                       println("It smells metallic, with a fishy hint of the plants it was hidden in.");
                               } else if (obj.getName().equals("BULB")) {
                                       println("The bulb smells most like body odor.");
                               } else {
                                       println("There is no particularly strong scent to the "+obj.getName().toLowerCase()+".");
                               }
                       } else {
                               println("It's unclear what you're trying to smell.");
                       }
               } else {
                       println("It's unclear what you're trying to smell.");
               }
       }
// Let's the user wear things, namely the pendant or the illustrious gem-hat
       public void executeWearCommand(AdvObject obj) {
               if (hasObject(obj)) {
                       if ((obj.getName().equals("PENDANT")) && (inventory.containsKey("PENDANT"))) {
                               println("The tattered cloth holding the pendant together would probably fall apart if you were to try it on.");
                       } else if ((obj.getName().equals("GEM-HAT")) && (inventory.containsKey("GEM-HAT"))) {
                               println("Taking a deep breath, you bow your head and put on the gem-hat...");
                               gameWon = true;
                       } else {
                               println("There's no way you can wear the "+obj.getName().toLowerCase()+".");
                       }
               } else {
                       println("You can't wear that.");
               }
       }
       public void executeHoldCommand(AdvObject obj) {
               if (hasObject(obj)) {
                       println("You hold the "  +obj.getName().toLowerCase()+ " in your hand.");
               } else if (obj != null) {
                       println("You can't hold the "+obj.getName().toUpperCase()+".");
               } else {
                       println("It's impossible to hold that.");
               }
       }
       public void executeKillCommand(AdvObject obj) {
               if (inventory.containsKey("KNIFE")) {
                       if ((obj.getName().equals("FISH")) && (inventory.containsKey("FISH"))) {
                               println("You cut up the fish with your knife, covering yourself and the knife with blood in the process.");
                               murderFish();
                               inventory.remove("FISH");
                       } else if (obj != null) {
                               println("It's no use trying to use the knife against the "+obj.getName()+".");
                       } else {
                               println("You can't use the knife against that.");
                       }
               } else {
                       println("You have no means of doing that.");
               }
       }

//       Let's the player take a short nap
       public void executeSleepCommand() {
               println("You take a short nap and wake up completely refreshed.");
       }
// Let's the player express their joy with a grin
       public void executeGrinCommand() {
               println("You beam proudly at your accomplishments.");
       }
// Let's the player express their frustration with a frown
       public void executeFrownCommand() {
               println("You furrown your brow and frown, full of frustration.");
       }
//       Let's the player groan
       public void executeGroanCommand() {
               println("You groan loudly and roll your eyes.");
       }
// Let's the player cheer themselves on
       public void executeCheerCommand() {
               println("You throw a fist in the air and yell with all the enthusiasm you can muster.");
       }
// Let's the player shrug their cares away
       public void executeShrugCommand() {
               println("You shrug nonchalantly. No big deal.");
       }
// Lets the player sit down and take a break for a moment
       public void executeSitCommand() {
               println("You take a seat. It feels good to give your legs some rest for a moment.");
       }
// Let's the player clap their hands
       public void executeClapCommand() {
               println("You clap your hands excitedly.");
       }
//       Let's the player nod their head
       public void executeNodCommand() {
               println("You nod emphatically.");
       }
// Let's the player sigh
       public void executeSighCommand() {
               println("You take a deep breath and let out a long sigh.");
       }
// Let's the player express their embarassment by blushing
       public void executeBlushCommand() {
               println("You blush bright red. How embarassing!");
       }
//      Enables the player to jump in place
       public void executeJumpCommand() {
               println("You bend your knees, then leap skywards with all your might.");
       }
//      Enables the player to shudder with fear
       public void executeShudderCommand() {
               println("You experience a full-body shudder of fear.");
       }
// Let's the player express their embarassment by blushing
       public void executePonderCommand() {
               println("You ponder your current situation but don't come to any sure conclusions.");
       }
//      Enables the player to jump in place
       public void executeTalkCommand() {
               println("You start talking to yourself under your breath.");
       }
// Enables the player to unlock the gem-hat's box if they are carrying the key
       public void executeUnlockCommand(AdvObject obj) {
               if (obj != null) {
                       if ((room.getRoomNumber() == 18) && (obj.getName().equals("BOX"))) {
                               if (inventory.containsKey("KEY")) {
                                       for (int i = 0; i < room.getObjectCount(); i++) {
                                               AdvObject objecto = room.getObject(i);
                                               objecto.setVisible(true);
                                               objecto.setMoveable(true);
                                       }
                                       println("You heave the key into the keyhole and rotate it ninety degress. With a satisfying snap, the box unlocks and pops open.");
                                       println("Inside is what you came here for, what you were hoping to proudly bring back to the Professor... a gem-hat.");
                                       obj.setMoveable(false);
                                       unlockedbox = true;
                               } else {
                                       println("You don't have a key for the box.");
                               }
                       } else {
                               println ("It doesn't make any sense to try to unlock the "+obj.getName().toLowerCase()+".");
                       }
               } else {
                       println("Don't even think about trying to unlock that.");
               }
       }
// Checks to make sure that the object exists and that the player is carrying it
       private boolean hasObject(AdvObject obj) {
               if ((obj != null)&& (inventory.containsKey(obj.getName()))) {
                       return true;
               } else {
                       return false;
               }
       }
// This is displayed when the character finishes the game
       private void winnersText() {
               println("");
               println("...");
               println("");
               println("When you open your eyes, you find yourself on a crowded sidewalk, bustling with pedestrians.");
               println("You leap to the side just in time to avoid a speeding biker who nearly runs you down.");
               println("");
               println("If the Professor wants to keep this hat a secret, you can keep it a secret alright. Neither the Professor nor anyone else need ever find out about your sucessful mission, you think to yourself smugly.");
               println("With a grin, you fit the gem-hat snugly atop your head and disappear again...");
               println("");
               println("Congratulations! You have completed this quest.");
               println("Look for more text adventures by Zack Wood, coming soon thanks to CS106A, Eric Roberts, and Kimber Lockhart.");
       }
       private void secondaryWinnersText() {
               println("");
               println("...");
               println("");
               println("When you open your eyes, you find yourself in the Professor's office.");
               println("As you gather your senses and open your mouth to announce your arrival, the door opens.");
               println("The Professor enters and greets you warmly, eyes flicking to the illustrious gem-hat seated atop your head.");
               println("\"Ah, I see you were successful! Let me have a look at that while you tell me all about what happened.\" The Professor's hand beckons eagerly for the gem-hat.");
               println("");
               if (inventory.containsKey("EMOTOR")) {
                       println("The emotor feels warm against your body and, strangely enough, you sense malicious intent seething beneath the Professor's grinning face.");
                       println("You take a step back, clutching the gem-hat to your chest with white knuckles.");
                       println("\"Come on now, I want to hear all about your trip. Just hand over the gem-hat...\" The Professor notices your hesitancy and a strange look creeps over her face.");
                       println("");
                       println("Suddenly, the Professor's hand darts behind her back, reaching for something. Not wanting to find out what it is, you throw on the gem-hat.");
                       println("A loud bang echoes throughout the office, but the Professor was too late; the the only thing remaining where you were standing just moments earlier is a gun-shot blast in her Mahogany paneling.");
               } else {
                       println("After handing over the gem-hat with a great sense of accomplishment, you accept a cup of tea and breathlessly recount your travels and the discovery of the gem-hat.");
                       println("Your eyes grow tired as you near the end of your tale, and you realize how long it's been since you last slept.");
                       println("");
                       println("The last thing you remember before nodding off is the Professor's voice, saying \"I'm sorry, but I can't let anyone else find out about this.\"");
                       println("You never wake up.");
               }
               println("");
               println("Congratulations! You have completed the Quest for the Gem-Hat! Sadly, you did not survive this time.");
               println("Look for more text adventures by Zack Wood, coming soon thanks to CS106A, Eric Roberts, and Kimber Lockhart.");
       }
       private void badWinnersText() {
               println("");
               println("...");
               println("");
               println("When you open your eyes, you find yourself in the Professor's office.");
               println("As you gather your senses and open your mouth to announce your arrival, the door opens.");
               println("The Professor walks in with a grin at first, but it turns to a look of shock and terror upon noticing the bloody knife you clutch.");
               println("");
               println("Before the Professor can speak, you disseaper with the aid of the gem-hat and reapper on the other side of the room, grabbing the Professor from behind.");
               println("You reach around with the knife and strike swiftly three times. The limp body falls to the ground in front of you and a grin involuntarily creeps across your face.");
               println("");
               println("The Professor hoped to use you, to take advantage of you... But you proved that you are no pawn.");
               println("You press the gem-hat atop your head and disseaper from the office as blood continues to seep from beneath the Professor's corpse onto the lush carpet.");
               println("");
               println("Congratulations! You have completed this quest.");
               println("Look for more text adventures by Zack Wood, coming soon thanks to CS106A, Eric Roberts, and Kimber Lockhart.");
       }
/* Private instance variables */
       String currentroom;
       int emotionsexpressed = 0;
       boolean described;
       boolean objectslisted;
       boolean platformUp = false;
       boolean laughed = false;
       boolean cried = false;
       boolean screamed = false;
       boolean danced = false;
       boolean gameover = false;
       boolean actionoccurred;
       boolean successfullyMoved = false;
       boolean bluedooropen = false;
       boolean keyfound = false;
       boolean gameWon = false;
       boolean fishsaved = false;
       boolean fishmurdered = false;
       boolean unlockedbox = false;
       BufferedReader rd;
       AdvObject obj = new AdvObject();
       ArrayList help = new ArrayList();
       AdvMotionTableEntry[] currentMotionTable;
       AdvMotionTableEntry currentMotionEntry = null;
       AdvRoom room = new AdvRoom();
       HashMap verbs = new HashMap();
       HashMap rooms = new HashMap();
       HashMap objects = new HashMap();
       HashMap inventory = new HashMap();
       HashMap synonyms = new HashMap();
       AdvCommand Quit = new QuitCommand();
       AdvCommand Help = new HelpCommand();
       AdvCommand Look = new LookCommand();
       AdvCommand Inventory = new InventoryCommand();
       AdvCommand Take = new TakeCommand();
       AdvCommand Drop = new DropCommand();
       AdvCommand Examine = new ExamineCommand();
       AdvCommand Laugh = new LaughCommand();
       AdvCommand Cry = new CryCommand();
       AdvCommand Jump = new JumpCommand();
       AdvCommand Yell = new YellCommand();
       AdvCommand Dance = new DanceCommand();
       AdvCommand Sleep = new SleepCommand();
       AdvCommand Break = new BreakCommand();
       AdvCommand Unlock = new UnlockCommand();
       AdvCommand Wear = new WearCommand();
       AdvCommand Grin = new GrinCommand();
       AdvCommand Frown = new FrownCommand();
       AdvCommand Smell = new SmellCommand();
       AdvCommand Read = new ReadCommand();
       AdvCommand Sing = new SingCommand();
       AdvCommand Use = new UseCommand();
       AdvCommand Groan = new GroanCommand();
       AdvCommand Clap = new ClapCommand();
       AdvCommand Nod = new NodCommand();
       AdvCommand Shrug = new ShrugCommand();
       AdvCommand Sigh = new SighCommand();
       AdvCommand Cheer = new CheerCommand();
       AdvCommand Blush = new BlushCommand();
       AdvCommand Sit = new SitCommand();
       AdvCommand Open = new OpenCommand();
       AdvCommand Shudder = new ShudderCommand();
       AdvCommand Ponder = new PonderCommand();
       AdvCommand Talk = new TalkCommand();
       AdvCommand Listen = new ListenCommand();
       AdvCommand Hold = new HoldCommand();
       AdvCommand Swim = new SwimCommand();
       AdvCommand Liberate = new LiberateCommand();
       AdvCommand Kill = new KillCommand();
       AdvCommand Cut = new CutCommand();
       String verb;
       String directObject;
}