This commit is contained in:
jslightham
2019-06-01 02:05:04 -04:00
parent c0ffa91d70
commit f937a017cd
7 changed files with 106 additions and 33 deletions

View File

@@ -7,7 +7,10 @@ import com.bayviewglen.zork.Entities.Player;
import com.bayviewglen.zork.Entities.Enemies.Enemy;
import com.bayviewglen.zork.Items.Item;
import com.bayviewglen.zork.Items.Shavingcream;
/*
* This combat class stores information, and handles turns for both the player and enemy that are in combat.
* Whenever combat takes place, this class is instantiated and stored in the Game class.
*/
public class Combat {
private Player player;
private Enemy enemy;
@@ -17,7 +20,12 @@ public class Combat {
this.player = player;
this.enemy = enemy;
}
// return new health of enemy
/*
* Handles the attack made by a player. Called whenever a player uses the command word "attack"
* This method takes the item from the command as a string, and turns it into an object so that it can find info about the item.
* When the player attacks, there is a 10% chance of missing, 10% chance of a critical hit, and an 80% chance of a normal hit.
* Returns the new health of the enemy.
*/
public double playerAttack(String item) {
Class<?> clazz;
Item object;
@@ -27,6 +35,7 @@ public class Combat {
object = (Item) ctor.newInstance();
double rand = Math.random();
// Special case when weapon is shaving cream, blind enemy
if(object.equals(new Shavingcream())) {
System.out.println("You blinded " + enemy.getName());
player.removeFromInventory(new Shavingcream());
@@ -44,6 +53,7 @@ public class Combat {
}
else {
enemy.setHealth(enemy.getHealth()-object.getDamage());
// Ensure health is not negative
if(enemy.getHealth() < 0)
enemy.setHealth(0);
System.out.println("You did " + object.getDamage() + " damage! " + enemy.getName() + " is now at " + enemy.getHealth() + "% health.");
@@ -55,9 +65,14 @@ public class Combat {
turn = 1;
return enemy.getHealth();
}
/*
* Much like the playerAttack() method, this method handles attacks for the enemy.
* Same attack probabilities as player.
* Returns new health of the player.
*/
public double enemyAttack() {
double rand = Math.random();
// If the enemy is blind, there is a 40% chance of the enemy beocoming unblinded.
if(enemy.getBlinded()) {
if(rand <0.4) {
System.out.println(enemy.getName() + " is no longer blinded!");
@@ -70,14 +85,17 @@ public class Combat {
System.out.println(enemy.getName() + " missed!");
}else if(rand < 0.20) {
player.setHealth(player.getHealth()-enemy.getDamage()*1.5);
// ensure health does not drop below 0
if(player.getHealth() < 0)
player.setHealth(0);
System.out.println(enemy.getName() + " hit you with a critical hit, doing " + enemy.getDamage()*1.5 + " damage! Your health is now " + player.getHealth() + "%");
// Set the player's bleeding status to true, when the enemy makes a critical hit
System.out.println("You are now bleeding.");
player.setBleeding(true);
}
else {
player.setHealth(player.getHealth()-enemy.getDamage());
// ensure health does not drop below 0
if(player.getHealth() < 0)
player.setHealth(0);
System.out.println(enemy.getName() + " did " + enemy.getDamage() + " damage to you! Your health is now " + player.getHealth() + "%");
@@ -86,6 +104,9 @@ public class Combat {
return player.getHealth();
}
/*
* Getters and setters for this class.
*/
public int getTurn() {
return this.turn;
}

View File

@@ -32,9 +32,9 @@ class Command {
private String riddler;
/**
* Create a command object. First and second word must be supplied, but
* either one (or both) can be null. The command word should be null to
* indicate that this was a command that is not recognised by this game.
* Create a command object.
* The command object is created by the parser, and contains all the known words that were in the input line.
* The command word should be null to indicate that this was a command that is not recognised by this game.
*/
public Command(String firstWord, ArrayList<String> otherWords, String direction, String item, String enemy, String riddler) {
commandWord = firstWord;
@@ -72,11 +72,6 @@ class Command {
public ArrayList<String> getOtherWords() {
return otherWords;
}
/*
public String getSecondWord() {
return otherWords.get(0);
}
*/
/**
* Return true if this command was not understood.

View File

@@ -15,7 +15,7 @@ import java.util.Scanner;
* This class is part of the "Zork" game.
*/
class CommandWords {
// a constant array that holds all valid command words
// Hashmaps that store known words and their types, as well as synonyms to the known words
private static HashMap<String, String> m_words = new HashMap<String, String>();
private static HashMap<String, String> m_synonyms = new HashMap<String, String>();
/**
@@ -34,7 +34,7 @@ class CommandWords {
}catch (Exception e) {
e.printStackTrace();
}
// import synonyms into hashmap
try {
Scanner in = new Scanner(new File("data/synonyms.dat"));
while(in.hasNext()){
@@ -68,7 +68,7 @@ class CommandWords {
return false;
}
}
// check if given string is item
public static boolean isItem(String aString){
try {
return m_words.get(aString).equals("item");
@@ -76,7 +76,7 @@ class CommandWords {
return false;
}
}
// check if given string is enemy
public static boolean isEnemy(String aString) {
try {
return m_words.get(aString).equals("enemy");
@@ -84,7 +84,7 @@ class CommandWords {
return false;
}
}
// check if given string is riddler
public static boolean isRiddler(String aString) {
try {
return m_words.get(aString).equals("riddler");
@@ -103,7 +103,9 @@ class CommandWords {
}
System.out.println();
}
/*
* If a known word exists for the synonym of the word given, return it. Otherwise return the given word.
*/
public static String replaceSynonym(String word) {
try {
String words = m_synonyms.get(word);

View File

@@ -1,6 +1,10 @@
package com.bayviewglen.zork.Entities;
public class Entity {
/*
* The base class of any character in the game.
* All characters have a health, which is taken care of by this class. Hunger is not used.
*/
protected double hunger;
protected double health;

View File

@@ -40,12 +40,15 @@ class Game {
// masterRoomMap.get("GREAT_ROOM") will return the Room Object that is the
// Great Room (assuming you have one).
private HashMap<String, Room> masterRoomMap;
// Stores where all enemies are currently
private HashMap<Enemy, String> masterEnemyMap;
/*
* Stores the current combat that is taking place.
* If there is a combat, this contains an instance of the combat class, if not it is null.
*/
private Combat currentCombat = null;
// private HashMap<Item, String> itemsInRooms = new HashMap<Item, String>();
private void initRooms(String fileName) throws Exception {
// itemsInRooms.put(new Candlestick(), "Candlestick");
masterRoomMap = new HashMap<String, Room>();
Scanner roomScanner;
try {
@@ -139,7 +142,9 @@ class Game {
e.printStackTrace();
}
}
/*
* Initiate enemies from the data file into the hashmap.
*/
private void initEnemies(String fileName) throws Exception {
masterEnemyMap = new HashMap<Enemy, String>();
Scanner enemyScanner = null;
@@ -227,7 +232,9 @@ class Game {
System.out.println(currentRoom.exitString());
boolean finished = false;
while (!finished) {
// Checks if there is a current combat, if so perform the enemy's action, and check for deaths.
if (currentCombat != null) {
// If enemy dies
if (currentCombat.getEnemy().getHealth() <= 0.0) {
System.out.print("You destroyed " + currentCombat.getEnemy().getName() + "! ");
System.out.println(currentCombat.getEnemy().getName() + " seems to have dropped a " + currentCombat.getEnemy().getLoot());
@@ -243,6 +250,7 @@ class Game {
currentRoom.addItem(object);
masterEnemyMap.values().remove(currentRoom.getRoomName());
currentCombat = null;
// If enemy's turn - signified by turn = 1
} else if (currentCombat.getTurn() == 1) {
currentCombat.enemyAttack();
if (currentCombat.getPlayer().getHealth() <= 0.0) {
@@ -252,6 +260,7 @@ class Game {
player.removeFromInventory(player.getInventory().get(i));
i--;
}
// On player death, reset everything
currentRoom = masterRoomMap.get("CIRCLE_ROOM");
System.out.println(
"Poof! You looked pretty banged up there, so I brought you back to the circle room. Your items are where you died.");
@@ -266,11 +275,13 @@ class Game {
}
}
}
// Checks if the player is bleeding, if they are subtract 2 from health each turn
if(player.getBleeding()) {
player.setHealth(player.getHealth()-2);
System.out.println("You are bleeding. Find, and use bandages to stop bleeding.");
System.out.println("Your health is now " + player.getHealth() + "%");
}
// Checks if the player dies, if so reset all values, and drop items
if(player.getHealth() <= 0) {
for (int i = 0; i < player.getInventory().size(); i++) {
currentRoom.addItem(player.getInventory().get(i));
@@ -287,6 +298,7 @@ class Game {
finished = processCommand(command);
}
}
// Printed when game ends
System.out.println("Thank you for playing. Goodbye!");
}
@@ -301,11 +313,14 @@ class Game {
return false;
}
String commandWord = command.getCommandWord();
// Switch that handles all commands
switch (commandWord) {
case "open":
case "unlock":
// Command to open or unlock a door
boolean hasLockPick = false;
boolean hasKey = false;
// Loop to check if player's inventory contains key or lockpick
for (int i = 0; i < player.getInventory().size(); i++) {
if (player.getInventory().get(i).equals(new Lockpick())) {
hasLockPick = true;
@@ -316,7 +331,7 @@ class Game {
break;
}
}
// Check if the room can be unlocked, if so unlock it
if (command.hasDirection() && (hasLockPick || hasKey)) {
Room nextRoom = currentRoom.nextRoom(command.getDirection());
try {
@@ -345,6 +360,8 @@ class Game {
} else {
System.out.println("What do you want to open the door with?");
}
// Similar with the above key and lockpick process, but with crowbars and battering rams for boarded doors.
boolean hasCrowbar = false;
boolean hasBatteringRam = false;
for (int i = 0; i < player.getInventory().size(); i++) {
@@ -394,6 +411,7 @@ class Game {
case "down":
case "d":
case "u":
// if player is not in combat, go in direction given
if (currentCombat == null)
goRoom(command);
else
@@ -411,7 +429,7 @@ class Game {
System.out.println("If you insist... \nPoof! You're gone. You're out of the castle now, but now a new, grand new adventure begins...");
return true;
case "eat":
// convert the item string in the command (if existent) into an item to get info about the item, and to remove from inventory
if (command.hasItem()) {
Class<?> clazz;
Item object;
@@ -422,11 +440,13 @@ class Game {
Constructor<?> ctor = clazz.getConstructor();
object = (Item) ctor.newInstance();
boolean hasItem = false;
// check if player has item
for (int i = 0; i < player.getInventory().size(); i++) {
if (object.equals(player.getInventory().get(i))) {
hasItem = true;
}
}
// If item can be eaten, and player has, eat item.
if (object.isConsumable() && hasItem) {
System.out.println("Nom Nom Nom...");
player.eat();
@@ -447,6 +467,7 @@ class Game {
}
break;
case "talk":
// Talking with riddler command
if (currentCombat == null) {
if (currentRoom.hasRiddler()) {
Scanner rScanner = new Scanner(System.in);
@@ -455,7 +476,9 @@ class Game {
String answer = currentRoom.getRiddler().getRiddle().getAnswer();
System.out.println(message + "\n\nHere's my riddle: " + riddle);
System.out.print("Enter your guess here: ");
// wait for riddle response
String guess = rScanner.nextLine();
// check if guess has any part of answer in it. And if so administer prize.
if (guess.toLowerCase().indexOf(answer.toLowerCase()) >= 0) {
Item prize = currentRoom.getRiddler().getPrize();
String prizeName = prize.getName();
@@ -511,12 +534,15 @@ class Game {
}
break;
case "take":
// Take the given item, or take all items
boolean hasAll = false;
// check if player used word all, if so take all.
for (String a : command.getOtherWords()) {
if (a.equals("all"))
hasAll = true;
}
if (hasAll) {
// Iterate through all items in room, remove from room inventory and add to player inventory.
for (int i = 0; i < currentRoom.getItems().size(); i++) {
if (player.addToInventory(currentRoom.getItem(i))) {
currentRoom.removeItem(i);
@@ -554,6 +580,7 @@ class Game {
break;
case "look":
// Print out descriptions of rooms
System.out.print(currentRoom.longDescription());
System.out.println(currentRoom.itemString());
System.out.println(currentRoom.exitString());
@@ -561,8 +588,10 @@ class Game {
case "inventory":
case "i":
// Check if player has items, if so display items, if not display message
boolean hasPlayerItems = false;
String itemsP = "";
// Iterate through to see if player has items, and add items to string to be printed
for (Item i : player.getInventory()) {
hasPlayerItems = true;
itemsP += i.getName() + " ";
@@ -576,6 +605,7 @@ class Game {
}
break;
case "drop":
// if an item is given, convert string into item so that it can be removed from inventory
if (command.hasItem()) {
Class<?> clazz;
Item object;
@@ -606,9 +636,11 @@ class Game {
}
break;
case "attack":
// If there is currently no combat
if (currentCombat == null) {
if (command.hasEnemy()) {
Enemy enemy = null;
// Using hashmap backwards
for (Enemy i : masterEnemyMap.keySet()) {
if (masterEnemyMap.get(i).equals(currentRoom.getRoomName())) {
enemy = i;
@@ -618,11 +650,13 @@ class Game {
if (command.hasItem()) {
boolean has = false;
for (Item i : player.getInventory()) {
// Removes all spaces, capital letters from name
if (i.getName().toLowerCase().replaceAll("\\s+", "").equals(command.getItem())) {
has = true;
}
}
if (has) {
// if the player has the specified item, and the enemy exists in the room set currentCombat to be the combat between the given enemy and player, and perform the first player attack
currentCombat = new Combat(player, enemy);
currentCombat.playerAttack(command.getItem());
} else {
@@ -638,6 +672,7 @@ class Game {
System.out.println("Attack what?");
}
} else {
// Ran when combat is already taking place so that a new combat is not created each time an attack is made
if (command.hasItem()) {
boolean has = false;
for (Item i : player.getInventory()) {
@@ -646,6 +681,7 @@ class Game {
}
}
if (has) {
// player attack on enemy.
currentCombat.playerAttack(command.getItem());
} else {
System.out.println("You do not have that weapon!");
@@ -656,6 +692,7 @@ class Game {
}
break;
case "craft":
// if the item is craftable, and the player has the required components give the crafted item to the player, and remove the materials
if(command.hasItem()) {
Class<?> clazz;
CraftableItem object;
@@ -666,6 +703,7 @@ class Game {
if(object.isCraftable()) {
boolean playerHasItems = true;
boolean hasItem = false;
// Nested for loops to check if player has all required items
for(Item i : object.getMaterials()) {
hasItem = false;
for(Item pi : player.getInventory()) {
@@ -710,9 +748,11 @@ class Game {
+ command.getItem().substring(1).trim());
Constructor<?> ctor = clazz.getConstructor();
object = (Item) ctor.newInstance();
// If the item is not a bandage, run what is in the catch part of the try catch
if(!object.equals(new Bandage()))
throw new Exception();
boolean hasBandage = false;
// iterate through player inventory to see if bandage exists
for(Item i : player.getInventory()) {
if(i.equals(new Bandage())) {
hasBandage = true;
@@ -762,12 +802,14 @@ class Game {
Room nextRoom = currentRoom.nextRoom(direction);
if (nextRoom == null)
System.out.println("There is no door!");
else if (nextRoom.getLocked() && nextRoom.getBoarded()) {
else if (nextRoom.getLocked() && nextRoom.getBoarded()) { // check if the room is boarded or locked, if so do not allow the player to enter
System.out.println("The door is locked and boarded shut. You need to find a key and crowbar to open it.");
} else if (nextRoom.getLocked()) {
System.out.println("The door is locked. You need a key to open it.");
} else {
// This is run when there are no problems leaving the room
currentRoom = nextRoom;
// print description and enemies in the room from the hashmap
System.out.print(currentRoom.longDescription());
boolean hasEnemy = false;
Enemy enemy = null;
@@ -783,6 +825,7 @@ class Game {
enemy = i;
}
}
// if the room has an enemy, display it.
if (hasEnemy) {
System.out.println(enemy.getName() + ", " + enemy.getDescription() + " has appeared!");
System.out.println(currentRoom.itemString());

View File

@@ -31,15 +31,17 @@ class Parser {
}
public Command getCommand() {
// If the following are blank, this means that the input line did not contain that specific type of word.
String inputLine = ""; // will hold the full input line
String verb = "";
String direction = "";
String item = "";
String enemy = "";
String riddler = "";
String verb = ""; // holds verb of command
String direction = ""; // holds direction of command
String item = ""; // holds item of command
String enemy = ""; // holds enemies in command
String riddler = ""; // holds riddler in command
boolean open = false;
//String word2;
//Store all the words in the input line in an arraylist
ArrayList<String> words = new ArrayList<String>();
// Where unknown words are stored
ArrayList<String> otherWords = new ArrayList<String>();
System.out.print("> "); // print prompt
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
@@ -48,12 +50,16 @@ class Parser {
} catch (java.io.IOException exc) {
System.out.println("There was an error during reading: " + exc.getMessage());
}
// convert inputLine into tokens, and put this into the ArrayList of words
StringTokenizer tokenizer = new StringTokenizer(inputLine.toLowerCase());
while(tokenizer.hasMoreTokens()) {
words.add(tokenizer.nextToken());
}
// For each word, check what type it is, and store it in its respective String variable if it matches.
for(int i=0; i<words.size(); i++) {
// replace all known synonyms
words.set(i, CommandWords.replaceSynonym(words.get(i)));
// Special case - check if contains open or unlock as a verb, otherwise these will be overwritten by the directions.
if(words.get(i).equals("open") || words.get(i).equals("unlock")) {
open = true;
}
@@ -72,7 +78,7 @@ class Parser {
otherWords.add(words.get(i));
}
}
//System.out.println(verb);
// Create the command
if (CommandWords.isCommand(verb))
if(!open)
return new Command(verb, otherWords, direction, item, enemy, riddler);

View File

@@ -27,7 +27,7 @@ class Room {
private String description;
private String newDescription;
private HashMap<String, Room> exits; // stores exits of this room.
private ArrayList<Item> items;
private ArrayList<Item> items; // The inventory of the room
private Riddler riddler; //needs to altered outside of the class so that riddler can be set to null.
private boolean locked; // Otherwise you can repeatedly solve the riddle and get unlimited items
private boolean boarded;
@@ -193,7 +193,9 @@ class Room {
}
return returnString;
}
/*
* Return a string of items to be printed
*/
public String itemString(){
boolean hasItems = false;
String items = "";