

/**
 *
 * @author Eberbach 2024
 * DastardlyDungeons.java - driver class for the text adventure game
 * Dastardly Dungeons of Doom!  
 */
import java.util.Scanner;

public class DastardlyDungeons  {

    // Declare static objects and variables in the class, providing scope to
    // see required objects and variables across methods where required
    private static Player player;
    private static NPC bear;
    private static NPC ferryCaptain;
    private static NPC dragon;
    private static Item sword;
    private static Item lamp;
    private static Item shell;
    private static Scanner myReader;
    private static char userInput;
    private static String userString;
    private static boolean hasSword, shellTaken, hasCrossed, hasLamp;
    private static Item[] backpack = new Item[5];

    //*****************************************************************************************************************************
    public static void main(String[] args)  {
        ReadData.readData();
    }
    public static void main1(String[] args)  {
        myReader = new Scanner(System.in);
        // Commencing location in the game
        String currLocation = "Enchanted Woods";

        System.out.println("****************************************************************");
        System.out.println("*                                                              *");
        System.out.println("*           Welcome to Dastardly Dungeons of Doom!!!           *");
        System.out.println("*                                                              *");
        System.out.println("****************************************************************");
        System.out.println();
        System.out.println("A game of high adventure and cunning in the mystical world of Aerendora");

        // Call the character generation method to handle initial character generation and other game objects to commence the game
        characterGenerator();

        // Game loop which evaluates a switch statement to pass between locations uses a while (true) condition
        // which is infinite. Game completion (win/death/quit) will be handled using System.exit(0) method elsewhere
        while (true)  {
            switch (currLocation) {
                case "Enchanted Woods":
                    currLocation = enchantedWoodsLocation(currLocation);
                    break;
                case "Forest Trail":
                    currLocation = forestTrailLocation(currLocation);
                    break;
                case "Cottage":
                    currLocation = cottageLocation(currLocation);
                    break;
                case "Rocky Path":
                    currLocation = rockyPathLocation(currLocation);
                    break;
                case "Lake Shore":
                    currLocation = lakeShoreLocation(currLocation);
                    break;
                case "Mountain Range":
                    currLocation = mountainRangeLocation(currLocation);
                    break;
                case "River Crossing":
                    currLocation = riverCrossingLocation(currLocation);
                    break;
                case "Grassy Plain":
                    currLocation = grassyPlainLocation(currLocation);
                    break;
                case "Cobblestone Path":
                    currLocation = cobblestonePathLocation(currLocation);
                    break;
                case "Cliff's Edge":
                    currLocation = cliffsEdgeLocation(currLocation);
                    break;
                case "Dark Dungeon":
                    currLocation = darkDungeonLocation(currLocation);
                    break;
                case "Dragon's Lair":
                    currLocation = dragonsLairLocation(currLocation);
                    break;
                case "Castle":
                    castleLocation();
                    break;
                default:
                System.out.println("Oh no! It seems you're in a location not recognised... how did that ");
                System.out.println("happen? Are you back in that dream?"); 
            }
        }
    }
    
    //*****************************************************************************************************************************
    // Character Generation method to be called at the commencement of the game
    private static void characterGenerator() {
        do  {
            System.out.print("Would you like to commence by creating a character? (y to commence, n to quit): ");
            userInput = myReader.next().charAt(0);
            myReader.nextLine();
            // Obtain character name, and randomise statistics HP and Strength. Allow a player to re-roll until they're happy with stats
            if (userInput == 'y') {
                player = new Player();
                System.out.print("What would you like to name your character? ");
                player.setName(myReader.nextLine());
                player.setType("Player");
                player.setHp((int)(Math.random() * 25.0) + 1);
                player.setStrength((int)(Math.random() * 18) + 1);
                player.setPoints(0);
                System.out.println();
                System.out.println("The character has been created. Your stats are below:");
                System.out.println(player.toString());
                System.out.println();
                System.out.println("Player hit points are out of a maximum of 25 and player strength");
                System.out.println("is out of a maximum of 18.");
                System.out.println();
                System.out.println("If the stats above are not acceptable you can re-roll. Higher stats");
                System.out.println("will make the game easier to win, and lower stats will increase the difficulty");
                System.out.println("level. Be careful... if your hit points are too low it will be very difficult!");
                do  {
                    System.out.println();
                    System.out.println("Are the character stats acceptable, or would you like to roll again?");
                    System.out.print("(y to accept, n to re-roll your stats)");
                    userInput = myReader.next().charAt(0);
                    myReader.nextLine();
                    if (userInput == 'y') {
                        System.out.println("Great! Let's play!");
                    }
                    else if (userInput == 'n')  {
                        player.setHp((int)(Math.random() * 25) + 1);
                        player.setStrength((int)(Math.random() * 18) + 1);
                        System.out.println(player.toString());
                    }
                    else  {
                        System.out.println("I'm sorry, that input is invalid... please try again.");
                    }
                }
                while (userInput != 'y');
            }
            else if (userInput == 'n')  {
                System.out.println("Thank you for coming. I hope you have more time to play next time!");
                System.exit(0);
            }
            else  {
                System.out.println("I'm sorry, that input is invalid... please try again.");
            }
        }
        while (userInput != 'y' && userInput != 'n');

        for (int i = 0; i < backpack.length; i++) {
            backpack[i] = null;
        }
        // Instantiate objects to be used in the game and initialise class static variable shellTaken
        //dragon = new Character("Ignis", "Monster", ((int)(Math.random() * 30) + 1), ((int)(Math.random() * 20) + 1), 0);
       // bear = new Character("Saevuclaw", "Monster", ((int)(Math.random() * 10) + 1), ((int)(Math.random() * 20) + 1), 0);
       // ferryCaptain = new Character("Bardman", "Friendly", ((int)(Math.random() * 15) + 1), ((int)(Math.random() * 17) + 1), 0);
        sword = new Item("Acernath", "Weapon", 8, 3);
        lamp = new Item("Lantern", "Utility", 2, 2);
        shell = new Item("Shell", "Artefact", 1, 1);
        shellTaken = false;
        hasSword = false;
        hasLamp = false;
        System.out.println();
        System.out.print("\033[H\033[2J");
        System.out.flush();
        System.out.println("You wake, startled by a weird dream - somehow you were in the mystical world of");
        sleepScroller(500);
        System.out.println("magic and make believe, Aerendora... a courageous adventurer armed only");
        sleepScroller(500);
        System.out.println("with wit, cunning, an adventurous spirit and your trusty sword Acernath. Bards");
        sleepScroller(500);
        System.out.println("write songs of your historic adventures and your deeds are known far and wide...");
        sleepScroller(500);
        System.out.println("Wait! This is no dream! I AM " + player.getName() + "...");
        sleepScroller(500);
        System.out.println();
        System.out.println("Where am I?");
        sleepScroller(1000);
        System.out.println();
        System.out.println("What has happened?");
        sleepScroller(2000);
        System.out.println();
        System.out.println("Where are all of my belongings?");
        sleepScroller(3000);
        System.out.println();
        System.out.println("I remember now!");
        sleepScroller(1000);
        System.out.println("I must  locate and retrieve my belongings and return to the castle");
        sleepScroller(500);
        System.out.println("at once to warn the King of the impending doom from the barbarous hordes of");
        sleepScroller(500);
        System.out.println("the Dark Mountains and save the people of Aerendora before darkness descends");
        sleepScroller(500);
        System.out.println("on this land!");
        sleepScroller(500);
    }

    //*****************************************************************************************************************************
    // Location methods below are called from the main game loop switch statement based on the value of the currLocation variable
    // Enchanted Woods location method
    private static String enchantedWoodsLocation(String location) {
        // Provide description of location (repeated in each location method) to player
        System.out.println();
        System.out.println("ENCHANTED WOODS: You are in an enchanted wood... the air hangs heavy under the yoke");
        System.out.println("of some strange magic. Fog envelops you and it is difficult to breath. Although");
        System.out.println("it is difficult to see beyond the nearest branch you give your eyes a few moments");
        System.out.println("to become accustomed to the strange light in this place and can eventually make out");
        System.out.println("a winding path leading downward to the north, and a forest trail ambling to the east.");
        System.out.println();
        do  {
            // Call movementPrompt (from each location method) to prompt user for actions
            // and evaluate with switch statement
            movementPrompt();
            switch (userInput)  {
                case 'n':
                    location = "River Crossing";
                    break;
                case 's':
                    System.out.println("You can't go that way! The woods are impenetrable...");
                    break;
                case 'e':
                    location = "Forest Trail";
                    break;
                case 'w':
                    System.out.println("You can't go that way! The woods are impenetrable...");
                    break;
                case 'h':
                    System.out.println("Your current hit points (HP) are :" + player.getHp());
                    break;
                case 'l':
                    listInventory();
                    break;
                case 'q':
                    playerScore();
                    playerRank();
                    System.out.println("Thank you for playing... come back soon - the adventure awaits!");
                    System.exit(0);
                default:
                    System.out.println("I'm sorry, that is invalid input... please try again");
          }
        }
        while (userInput != 'n' && userInput != 'e');
        // Return the value of location string to the main game loop to evaluate the next location to be parsed
        return location;
    }

    // Forest Trail location method
    private static String forestTrailLocation(String location) {
        System.out.println();
        System.out.println("FOREST TRAIL: You amble along the eastern path as it winds its way through the");
        System.out.println("Enchanted Woods. Eventually, the mist begins to clear and the air somehow");
        System.out.println("seems easier to breath. The trail opens into a lovely forest trail that meanders");
        System.out.println("from the west and turns southward toward a small cottage you can see in the");
        System.out.println("distance.");
        if (bear.getHp() <= 0)   {
            System.out.println("A slain bear lies on the ground at your feet. It seems to have been involved");
            System.out.println("in a bloody dispute!");
        }
        else    {
            System.out.println("As you reach a clearing in the trail you see a giant brown bear!");
            System.out.println("What would you like to do?");
            System.out.print("Try and sneak past (sneak), or attack the bear (attack)? ");
            do  {
                userString = myReader.nextLine();
                if (userString.equals("sneak"))  {
                    if ((int)((Math.random() * 100) + 1) > 70)  {
                        player.setHp((player.getHp() - 4));
                        System.out.println("The bear attacks you as you try to sneak past and you suffer 4 damage!");
                        if (player.getHp() <= 0)    {
                            death();
                        }
                    }
                    else    {
                    System.out.println("You successfully sneak past the grazing bear!");
                    }
                }
                else if (userString.equals("attack"))  {
                    int maxDamage = 1;
                    // Iterate through the backpack to find the item with the highest damage factor
                    // Assume the player will select that item in combat and apply that damage factor
                    // to the maxDamage variable to be added as a factor to damage in attack rolls
                    for (int i = 0; i < backpack.length; i++) {
                        if (backpack[i] != null)  {
                            if (backpack[i].getDamageFactor() > maxDamage)  {
                                maxDamage = backpack[i].getDamageFactor();
                            }
                        }
                    }
                    System.out.println("You attack the great brown bear!");
                    // Initiate the combatEngine() method to handle battle
                    // Pass player and enemy attributes including weapon damage factor as parameters
                    String outcome = combatEngine(player.getStrength(), maxDamage, bear.getName(), bear.getHp());
                    // combatEngine() method returns outcome of battle to be evaluated below
                    if (outcome.equals("victory"))   {
                        System.out.println("You have successfully killed the bear!");
                        player.setPoints((player.getPoints() + 3));
                        System.out.println();
                        System.out.println("Your score just went up!");
                        playerScore();
                    }
                    else if (outcome.equals("flee"))    {
                        if (player.getHp() <= 0)    {
                            death();
                        }
                        else    {
                            System.out.println("You have escaped the bear with some minor damage");
                        }
                    }
                    else if (outcome.equals("defeat"))  {
                        death();
                    }
                }
                else  {
                    System.out.print("I'm sorry, I don't know that word... please say sneak or attack:");
                }
            }
            while (!userString.equals("sneak") && !userString.equals("attack"));
        }
        System.out.println();
        do  {
            movementPrompt();
            switch (userInput)  {
                case 'n':
                    System.out.println("You can't go that way! The forest is too thick and you would surely lose your way!");
                    break;
                case 's':
                    location = "Cottage";
                    break;
                case 'e':
                    System.out.println("You can't go that way! The forest is too thick and you would surely lose your way!");
                    break;
                case 'w':
                    location = "Enchanted Woods";
                    break;
                case 'h':
                    System.out.println("Your current hit points (HP) are :" + player.getHp());
                    break;
                case 'l':
                    listInventory();
                    break;
                case 'q':
                    playerScore();
                    playerRank();
                    System.out.println("Thank you for playing... come back soon - the adventure awaits!");
                    System.exit(0);
                default:
                    System.out.println("I'm sorry, that is invalid input... please try again");
            }
        }
        while (userInput != 'w' && userInput != 's');
        return location;
    }

    // Cottage location method
    private static String cottageLocation(String location) {
        System.out.println();
        System.out.println("COTTAGE: After hours of hiking out of the forest trail that path opens up and");
        System.out.println("becomes wider and brighter. You descend into a valley which at its floor contains");
        System.out.println("an abandoned cottage. You approach the cottage carefully, unsure if you're alone and ");
        System.out.println("after waiting a while and peering through the cottage windows carefully you are");
        System.out.println("sure the cottage is empty.");
        if (!hasSword)  {
            System.out.println("Just as you come around to see the entry you notice your sword, Acernath leaning");
            System.out.println("against the wall by the front door. Boy! That would have been handy in the bear");
            System.out.println("encounter! What would you like to do?");
            do  {
                System.out.print("Take your sword (take), or ignore it and leave it for its new owner (leave): ");
                userString = myReader.nextLine();
                if (userString.equals("take")) {
                    takeItem(location);
                    playerScore();
                    hasSword = true;
                }
                else if (userString.equals("leave")) {
                    System.out.println("Really? Your old sword might be useful, but hey... I guess it's up to you.");
                }
                else {
                    System.out.println("I'm sorry, I don't know that word... please say take or leave: ");
                }
            }
            while (!userString.equals("take") && !userString.equals("leave"));
        }
        System.out.println("Looking around, you notice the trail leading north back to the forest and another");
        System.out.println("path becoming more rocky leading south.");
        System.out.println();
        do  {
            movementPrompt();
            switch (userInput)  {
                case 'n':
                    location = "Forest Trail";
                    break;
                case 's':
                    location = "Rocky Path";
                    break;
                case 'e':
                    System.out.println("You can't go that way! The cottage is bordered to the east by rugged mountains!");
                    break;
                case 'w':
                    System.out.println("You can't go that way! The cottage is bordered to the west by deep  forest!");
                    break;
                case 'h':
                    System.out.println("Your current hit points (HP) are :" + player.getHp());
                    break;
                case 'l':
                    listInventory();
                    break;
                case 'q':
                    playerScore();
                    playerRank();
                    System.out.println("Thank you for playing... come back soon - the adventure awaits!");
                    System.exit(0);
                default:
                    System.out.println("I'm sorry, that is invalid input... please try again");
            }
        }
        while (userInput != 'n' && userInput != 's');
        return location;
    }
    
    // Rocky Path location method
    private static String rockyPathLocation(String location) {
        System.out.println();
        System.out.println("ROCKY PATH: As you make your way down from the cottage you come to an open");
        System.out.println("clearing along a rocky path.");
        System.out.println("This is a nice open and sunny spot - perfect for a lie down and rest in the");
        System.out.println("afternoon sun. To your north, a path leads toward a distant cottage. To the");
        System.out.println("east you see path leading to a vast mountain range, and to the west a trail");
        System.out.println("winds down toward a beautiful inland lake.");
        System.out.println();
        do  {
            movementPrompt();
            switch (userInput)  {
                case 'n':
                    location = "Cottage";
                    break;
                case 's':
                    System.out.println("You can't go that way! You're facing a sheer rock wall!...");
                    break;
                case 'e':
                    location = "Mountain Range";
                    break;
                case 'w':
                    location = "Lake Shore";
                    break;
                case 'h':
                    System.out.println("Your current hit points (HP) are :" + player.getHp());
                    break;
                case 'l':
                    listInventory();
                    break;
                case 'q':
                    playerScore();
                    playerRank();
                    System.out.println("Thank you for playing... come back soon - the adventure awaits!");
                    System.exit(0);
                default:
                    System.out.println("I'm sorry, that is invalid input... please try again");
          }
        }
        while (userInput != 'n' && userInput != 'e' && userInput != 'w');
        return location;   
    }
    // Lake Shore location method
    private static String lakeShoreLocation(String location) {
        System.out.println();
        System.out.println("LAKE SHORE: You feel the cool breeze of the wind on water as you approach");
        System.out.println("the beautiful eastern shore of Lake Alsus Aequor. A picturesque lake that");
        System.out.println("glistens in the late afternoon sunlight. Being here revives memories of childhood");
        System.out.println("days splashing in the frigid water on playful summer days with your family.");
        if (!shellTaken)  {
            System.out.println("Looking down at your feet you see a beautiful conch shell. For nostalgia's");
            System.out.println("sake you're tempted to take a souvenir. What would you like to do?");
            do  {
                System.out.println("Take the shell (take), or leave it behind for a hermit crab to claim as a");
                System.out.print("new home? (leave): ");
                userString = myReader.nextLine();
                if (userString.equals("take")) {
                    takeItem(location);
                    playerScore();
                    shellTaken = true;
                }
                else if (userString.equals("leave")) {
                    System.out.println("Sure, what do you want with an old shell. Much nicer for it to be a new home for a crab.");
                }
                else {
                    System.out.println("I'm sorry, I don't know that word... please say take or leave: ");
                }
            }
            while (!userString.equals("take") && !userString.equals("leave"));
        }
        System.out.println("The lake is far too wide to swim westward and it's too boggy to the south.");
        System.out.println("The northern border extends into a thick forest. The only way back is the");
        System.out.println("path to the east.");
        System.out.println();
        do  {
            movementPrompt();
            switch (userInput)  {
                case 'n':
                    System.out.println("You can't go that way! The northern shore is blocked by thick forest!");
                    break;
                case 's':
                    System.out.println("You can't go that way! It's far too boggy. You would sink in the mud!");
                    break;
                case 'e':
                    location = "Rocky Path";
                    break;
                case 'w':
                    System.out.println("You can't go that way! The lake is far too wide to swim across!");
                    break;
                case 'h':
                    System.out.println("Your current hit points (HP) are :" + player.getHp());
                    break;
                case 'l':
                    listInventory();
                    break;
                case 'q':
                    playerScore();
                    playerRank();
                    System.out.println("Thank you for playing... come back soon - the adventure awaits!");
                    System.exit(0);
                default:
                    System.out.println("I'm sorry, that is invalid input... please try again");
            }
        }
        while (userInput != 'e');
        return location;
    }
    // Mountain Range location method
    private static String mountainRangeLocation(String location) {
        System.out.println();
        System.out.println("MOUNTAIN RANGE: Leaving the sunny rocky path behind you, you make your way");
        System.out.println("to a vast mountain range. You've heard of the strange lands beyond the");
        System.out.println("mountains, but you cannot see a path through. One day, brave adventurer");
        System.out.println("you might return to find a path beyond but for now you must focus your");
        System.out.println("efforts on getting to the castle and warning the King of the impending");
        System.out.println("attack from the hordes of the Dark Mountains so that we may prepare our");
        System.out.println("defences!");
        System.out.println();
        System.out.println("The only available path you can see is the way west, from whence you");
        System.out.println("came...");
        System.out.println();
        do  {
            movementPrompt();
            switch (userInput)  {
                case 'n':
                    System.out.println("You can't go that way! The mountains are impenetrable!");
                    break;
                case 's':
                    System.out.println("You can't go that way! The mountains are impenetrable!");
                    break;
                case 'e':
                    System.out.println("You can't go that way! The mountains are impenetrable!");
                    break;
                case 'w':
                    location = "Rocky Path";
                    break;
                case 'h':
                    System.out.println("Your current hit points (HP) are :" + player.getHp());
                    break;
                case 'l':
                    listInventory();
                    break;
                case 'q':
                    playerScore();
                    playerRank();
                    System.out.println("Thank you for playing... come back soon - the adventure awaits!");
                    System.exit(0);
                default:
                    System.out.println("I'm sorry, that is invalid input... please try again");
          }
        }
        while (userInput != 'w');
        return location;
    }
    // River Crossing location method
    private static String riverCrossingLocation(String location) {
        System.out.println();
        System.out.println("RIVER CROSSING: You arrive at the wide River Daylsebrook Far too deep and wide");
        System.out.println("swim across, and even if you had the stamina the current would take you so far");
        System.out.println("downstream you might never return home again!");
        System.out.println("For centuries the river folk have manned the Daylesbrook Ferry and kept the");
        System.out.println("Kingdom of Aerendora safe from the south.");
        System.out.println();
        System.out.println("The ferry captain, lying on the deck of his ferry leaning against the mast looks");
        System.out.println("up from under his hat, eyeing you with suspicion.");
        System.out.println();
        System.out.println("The ferry captain mumbles, \"what can I do for ye?... want to cross do you?\"");
        System.out.println("\"I don't just let anyone cross for nuthin, you know!\"");
        System.out.println();
        System.out.print("What would you like to do? ");
        userString = myReader.nextLine();
        if (userString.equals("give shell")) {
            // Iterate over the array with a for-each loop to find the shell and empty the inventory slot once given
            for (int i = 0; i < backpack.length; i++)   {
                if (!(backpack[i] == null))  {
                    if (backpack[i].getName().equals("Shell"))  {
                        backpack[i] = null;
                        System.out.println("\"Yep, I love me a pretty shell, that will do it. Come aboard matey!\"");
                        System.out.println("You travel with the ferry captain across the river toward the grassy plain...");
                        location = "Grassy Plain";
                        player.setPoints((player.getPoints() + 4));
                        System.out.println();
                        System.out.println("Your score just went up!");
                        playerScore();
                    }
                }
            }
            if (!location.equals("Grassy Plain"))    {
                System.out.println();
                System.out.println("You do not have the shell!");
            }
        }
        if (!location.equals("Grassy Plain") || !userString.equals("give shell"))    {
            if (!userString.equals("give shell"))   {
                System.out.println();
                System.out.println("The ferry captain mumbles something under his breath about good fer nuthin types");
                System.out.println("not wanting to pay their way...");
            }
            do  {
                movementPrompt();
                switch (userInput)  {
                    case 'n':
                        System.out.println("You can't go that way! You would drown!");
                        break;
                    case 's':
                        location = "Enchanted Woods";
                        break;
                    case 'e':
                        System.out.println("You can't go that way! You would drown!");
                        break;
                    case 'w':
                        System.out.println("You'll need to convince the ferry captain!");
                        break;
                    case 'h':
                        System.out.println("Your current hit points (HP) are :" + player.getHp());
                        break;
                    case 'l':
                        listInventory();
                        break;
                    case 'q':
                        playerScore();
                        playerRank();
                        System.out.println("Thank you for playing... come back soon - the adventure awaits!");
                        System.exit(0);
                    default:
                        System.out.println("I'm sorry, that is invalid input... please try again");
                }
            }
            while (userInput != 's');
        }
        return location;
    }
    // Grassy Plain location method
    private static String grassyPlainLocation(String location) {
        System.out.println();
        System.out.println("GRASSY PLAIN: On the west side of the river once more, you feel one step");
        System.out.println("closer to home, King and country. You are on a wide grassy plain - the");
        System.out.println("grass grows waist high and you delight in brushing your open palm along the");
        System.out.println("windswept blades as you meander in the sun. The ferry captain can be seen in");
        System.out.println("the distance aboard his ferry waiting for passengers on the eastern shore. He");
        System.out.println("seems to be deeply engrossed in something white and shiny.");
        System.out.println();
        System.out.println("To the north you see a  cobblestone path forming as you approach ever-nearer");
        System.out.println("civilisation...");
        System.out.println();
        do  {
            movementPrompt();
            switch (userInput)  {
                case 'n':
                    location = "Cobblestone Path";
                    break;
                case 's':
                    System.out.println("You can't go that way! You would drown!");
                    break;
                case 'e':
                    System.out.println("You can't go that way! The ferry captain and his boat are on the other side of the river. Despite");
                    System.out.println("your loudest cries he doesn't seem to see or hear you. It's a very wide river and the captain!");
                    System.out.println("seems preoccupied with something.");
                    break;
                case 'w':
                    System.out.println("You can't go that way! The grassy plains lead to sharp rocks in the west you dare not cross!");
                    break;
                case 'h':
                    System.out.println("Your current hit points (HP) are :" + player.getHp());
                    break;
                case 'l':
                    listInventory();
                    break;
                case 'q':
                    playerScore();
                    playerRank();
                    System.out.println("Thank you for playing... come back soon - the adventure awaits!");
                    System.exit(0);
                default:
                    System.out.println("I'm sorry, that is invalid input... please try again");
            }
        }
        while (userInput != 'n');
        return location;
    }
    // Cobblestone Path location method
    private static String cobblestonePathLocation(String location) {
        System.out.println();
        System.out.println("COBBLESTONE PATH: This cobblestone path is the first sign of civilisation leading");
        System.out.println("toward the Kingdom! It is a nondescript place, expertly hewn stones laid by the");
        System.out.println("local masons, this path has persisted for generations and will likely persist");
        System.out.println("for many more!");
        System.out.println("Looking west you see treacherous sharp rocks that seem to lead toward a cliff. To");
        System.out.println("the east there lies a darkened doorway and to the south, the grassy plain that leads");
        System.out.println("back to river country.");
        System.out.println();
        do  {
            movementPrompt();
            switch (userInput)  {
                case 'n':
                    System.out.println("You can't go that way! The path is bordered by razor sharp rocks to the north!");
                    break;
                case 's':
                    location = "Grassy Plain";
                    break;
                case 'e':
                    // Short boolean test to see if the player has the lamp required to go into the dark dungeon
                    if (hasLamp)    {
                        System.out.println("It's pretty dark in there! Are you sure... you might be eaten by a Narf!");
                        System.out.print("What would you like to do? ");
                        userString = myReader.nextLine();
                        if (userString.equals("light lamp"))    {
                            System.out.println("You take the lamp from your backpack to light your way into the dark dungeon.");
                            System.out.println("The lamp provides a soft warm glow which should warn you of any impending doom.");
                            location = "Dark Dungeon";
                            player.setPoints((player.getPoints() + 3));
                            System.out.println();
                            System.out.println("Your score just went up!");
                            playerScore();
                        }
                        else    {
                            System.out.println("You don't need to say " + userString + " to finish the story.");
                        }
                    }
                    else    {   
                        System.out.println("You dare not enter such a dark place!");
                    }
                    break;
                case 'w':
                    location = "Cliff's Edge";
                    break;
                case 'h':
                    System.out.println("Your current hit points (HP) are :" + player.getHp());
                    break;
                case 'l':
                    listInventory();
                    break;
                case 'q':
                    playerScore();
                    playerRank();
                    System.out.println("Thank you for playing... come back soon - the adventure awaits!");
                    System.exit(0);
                default:
                    System.out.println("I'm sorry, that is invalid input... please try again");
          }
        }
        while (userInput != 'n' && userInput != 'e' && userInput != 'w');
        return location;
    }
    // Cliff's Edge location method
    private static String cliffsEdgeLocation(String location) {
        System.out.println();
        System.out.println("CLIFF'S EDGE: Be careful! The rocks here are loose and it would be easy to");
        System.out.println("lose your footing. The fate of the kingdom rests on your shoulders... this is");
        System.out.println("no time for curiosity. The cliff's edge descends into a sheer drop so deep");
        System.out.println("you can hardly see the valley floor below.");
        if (!hasLamp)  {
            System.out.println("Wait! What is that in the crevice? It appears to be an old lamp. It could");
            System.out.println("be a useful item to aid you on your way when the nights are dark and creatures");
            System.out.println("most foul lurk in the shadows. What would you like to do?");
            do  {
                System.out.print("Take the lamp (take), or leave it behind for a more needy soul? (leave): ");
                userString = myReader.nextLine();
                if (userString.equals("take")) {
                    takeItem(location);
                    playerScore();
                    hasLamp = true;
                }
                else if (userString.equals("leave")) {
                    System.out.println("You're probably right. You're a good samaritan... it might save someone's life one day.");
                }
                else {
                    System.out.println("I'm sorry, I don't know that word... please say take or leave: ");
                }
            }
            while (!userString.equals("take") && !userString.equals("leave"));
        }
        System.out.println("The cliff's edge to the west looks too dangerous. The only way back seems");
        System.out.println("to be east to the cobblestone path.");
        System.out.println();
        do  {
            movementPrompt();
            switch (userInput)  {
                case 'n':
                    System.out.println("You can't go that way! The sharp rocks would slice you to pieces!");
                    break;
                case 's':
                    System.out.println("You can't go that way! The sharp rocks would slice you to pieces!");
                    break;
                case 'e':
                    location = "Cobblestone Path";
                    break;
                case 'w':
                    System.out.println("Despite a warning in the back of your mind, you wander to close to the");
                    System.out.println("cliff's edge. You slip and fall on some loose shale and plummet to your");
                    System.out.println("death. You came so far, but now, without your aid the Kingdom of Aerendora");
                    System.out.println("at the hand of the vicious hordes of the Dark Mountains");
                    playerScore();
                    playerRank();
                    System.out.println("*** GAME OVER ***");
                    System.exit(0);
                case 'h':
                    System.out.println("Your current hit points (HP) are :" + player.getHp());
                    break;
                case 'l':
                    listInventory();
                    break;
                case 'q':
                    playerScore();
                    playerRank();
                    System.out.println("Thank you for playing... come back soon - the adventure awaits!");
                    System.exit(0);
                default:
                    System.out.println("I'm sorry, that is invalid input... please try again");
            }
        }
        while (userInput != 'e');
        return location;
    }
    // Dark Dungeon location method
    private static String darkDungeonLocation(String location) {
        System.out.println();
        System.out.println("DARK DUNGEON: Holding your lamp well ahead, its soft warm glow lights the way");
        System.out.println("ahead casting hideous flickering shadows onto the rank walls.");
        System.out.println("The dark dungeon is littered with the bones of both human and beast...");
        System.out.println("Musty dampness fills the air with a kind of putrid stench you know you'll never");
        System.out.println("forget and you just know you don't want to stay in this place any longer than you have");
        System.out.println("to. You see a path leading back towards the light to the west and another way");
        System.out.println("to the east, beckoning with the smell of sulphur and a warm flickering light");
        System.out.println("of its own... Your eyes burn and your senses reel, but you know which path you");
        System.out.println("must choose.");
        System.out.println();
        do  {
            movementPrompt();
            switch (userInput)  {
                case 'n':
                    System.out.println("You can't go that way! You're in a dungeon!");
                    break;
                case 's':
                    System.out.println("You can't go that way! You're in a dungeon!");
                    break;
                case 'e':
                    location = "Dragon's Lair";
                    break;
                case 'w':
                    location = "Cobblestone Path";
                    break;
                case 'h':
                    System.out.println("Your current hit points (HP) are :" + player.getHp());
                    break;
                case 'l':
                    listInventory();
                    break;
                case 'q':
                    playerScore();
                    playerRank();
                    System.out.println("Thank you for playing... come back soon - the adventure awaits!");
                    System.exit(0);
                default:
                    System.out.println("I'm sorry, that is invalid input... please try again");
          }
        }
        while (userInput != 'e' && userInput != 'w');
        return location;
    }
    // Dragon's Lair location method
    private static String dragonsLairLocation(String location) {
        System.out.println();
        System.out.println("DRAGON'S LAIR: The stench of sulphur, steam rising from the ground, the bones and");
        System.out.println("rusted posessions of adventurers past strewn around this place don't prepare");
        System.out.println("you for what you see next...");
        if (dragon.getHp() <= 0)   {
            System.out.println();
            System.out.println("A slain dragon lies at your feet. Your battle with the great beast was epic");
            System.out.println("but there's no time to loot the treasure - you must warn the King!");
        }
        else    {
            System.out.println();
            System.out.println("A dragon - the famed Ignis atop its hoard of treasure!");
            System.out.println("For now, the dragon sleeps - steam eminating from its great nostrils,");
            System.out.println("scales the size of dinner plates glisten along the beast's flank and");
            System.out.println("razor sharp talons the size of tree branches adorn its feet.");
            System.out.println();
            System.out.println("As you try to sneak past, you step on an old adventurer's bone, and the mighty crunch");
            System.out.println("wakes the giant lizard!!!");
            System.out.println("With a flick of its tail, it whips to turn toward you, fire bellowing");
            System.out.println("from its open maw - it rears up on its hind legs and stretches out its");
            System.out.println("wings with an almighty shreik that could wake the dead!");
            System.out.println("What would you like to do?");
            System.out.print("Turn and run away (run), or attack Ignis (attack)? ");
            do  {
                userString = myReader.nextLine();
                if (userString.equals("run"))  {
                    if ((int)((Math.random() * 100) + 1) > 60)  {
                        player.setHp((player.getHp() - 8));
                        System.out.println("Ignis attacks you as you try to run and you suffer 8 damage!");
                        if (player.getHp() <= 0)    {
                            death();
                        }
                    }
                    else    {
                    System.out.println("You successfully sneak past the grazing bear!");
                    }
                }
                else if (userString.equals("attack"))  {
                    int maxDamage = 1;
                    // Iterate through the backpack to find the item with the highest damage factor
                    // Assume the player will select that item in combat and apply that damage factor
                    // to the maxDamage variable to be added as a factor to damage in attack rolls
                    for (int i = 0; i < backpack.length; i++) {
                        if (backpack[i] != null)  {
                            if (backpack[i].getDamageFactor() > maxDamage)  {
                                maxDamage = backpack[i].getDamageFactor();
                            }
                        }
                    }
                    System.out.println("Against your better judgement, you attack Ignis the dragon!");
                    // Initiate the combatEngine() method to handle battle, passing player and enemy attributes including weapon damage factor as parameters
                    String outcome = combatEngine(player.getStrength(), maxDamage, dragon.getName(), dragon.getHp());
                    // combatEngine() method returns outcome of battle to be evaluated below
                    if (outcome.equals("victory"))   {
                        System.out.println("You have successfully killed Ignis!");
                        player.setPoints((player.getPoints() + 4));
                        System.out.println();
                        System.out.println("Your score just went up!");
                        playerScore();
                    }
                    else if (outcome.equals("flee"))    {
                        if (player.getHp() <= 0)    {
                            death();
                        }
                        else    {
                            System.out.println("You have escaped the dragon with some minor damage");
                        }
                    }
                    else if (outcome.equals("defeat"))  {
                        death();
                    }
                }
                else  {
                    System.out.print("I'm sorry, I don't know that word... please say run or attack:");
                }
            }
            while (!userString.equals("run") && !userString.equals("attack"));
        }
        System.out.println();
        do  {
            movementPrompt();
            switch (userInput)  {
                case 'n':
                    System.out.println("You can't go that way! The treasure hoard blocks your path!");
                    break;
                case 's':
                    System.out.println("You can't go that way! You would be crazy to try and climb that");
                    System.out.println("pile of adventurers' bones");
                    break;
                case 'e':
                    location = "Castle";
                    break;
                case 'w':
                    location = "Dark Dungeon";
                    break;
                case 'h':
                    System.out.println("Your current hit points (HP) are :" + player.getHp());
                    break;
                case 'l':
                    listInventory();
                    break;
                case 'q':
                    playerScore();
                    playerRank();
                    System.out.println("Thank you for playing... come back soon - the adventure awaits!");
                    System.exit(0);
                default:
                    System.out.println("I'm sorry, that is invalid input... please try again");
            }
        }
        while (userInput != 'e' && userInput != 'w');
        return location;
    }

    // Castle location method
    private static void castleLocation() {
        System.out.println();
        System.out.println("CASTLE: Home at last! Being back among the pageantry of the Kingdom");
        System.out.println("is good! The castle stands invitingly atop the Hill of Aerendora,");
        System.out.println("and the drawbridge is open. As you approach the guards welcome you");
        System.out.println("as an old friend and you are brought before an audience with the King!");
        System.out.println();
        player.setPoints(player.getPoints() + 3);
        win();
    }
    
    //*****************************************************************************************************************************
    // Sleep method to provide a slower text scroll at the beginning of the game
    private static void sleepScroller(int pauseTime)    {
        try {
            Thread.sleep(pauseTime);
        }
        catch (InterruptedException ieEx)  {
            ieEx.printStackTrace();
        }
    }
    
    //*****************************************************************************************************************************
    // User menu - prompt user for movement, hit point, inventory listing and quit options
    private static void movementPrompt()    {
        System.out.println("Where to now?...");
        System.out.println("***************************************");
        System.out.println("*Travel in a direction:  (n, s, e, w) *");
        System.out.println("*Display current hit points:      (h) *");
        System.out.println("*List items in your inventory:    (l) *");
        System.out.println("*Quit the game (are you sure!?):  (q) *");
        System.out.println("***************************************");
        System.out.print("Please enter your choice: ");
        userInput = myReader.next().charAt(0);
        myReader.nextLine();
    }
    
    //*****************************************************************************************************************************
    // Method to facilitate picking up items and adding to empty inventory slots throughout the game
    private static void takeItem(String location)  {
        for (int i = 0; i < backpack.length; i++)   {
            if (backpack[i] == null)  {
                switch (location)   {
                    case "Cottage":
                        System.out.println("You slide your old friend Acernath back into the scabbard tied to your backpack!");
                        backpack[i] = sword;
                        break;
                    case "Lake Shore":
                        System.out.println("You pick up the beautiful shell and slide it into one of your backpack pockets.");
                        backpack[i] = shell;
                        break;
                    case "Cliff's Edge":
                        System.out.println("You stuff the dusty old brass lamp into your backpack!");
                        backpack[i] = lamp;
                        break;
                    default:
                        System.out.println("Location invalid... there shoud be no items here!");
                }
                player.setPoints((player.getPoints() + 1));
                System.out.println();
                System.out.println("Your score just went up!");
                break;
            }
        }
    }
    
    //*****************************************************************************************************************************
    // Simple list inventory method that iterates through the array and checks to see if a slot is empty, or call toString() for an object
    private static void listInventory()  {
        for (int i = 0; i < backpack.length; i++) {
            if (backpack[i] == null) {
                System.out.println("Inventory slot " + (i+1) + " is empty.");
            }
            else {
                System.out.println("Slot " + (i+1) + ": " + backpack[i].toString());
            }
        }
    }

    //*****************************************************************************************************************************
    // Combat engine to be used with various enemies
    private static String combatEngine(int playerStrength, int damageFactor, String enemyName, int enemyHp)  {
        String outcome = "pending";
        int damage;
        while (player.getHp() > 0 && enemyHp > 0) {
            System.out.println("Do you wish to attack (y) " + enemyName + " or try and flee (n)? ");
            userInput = myReader.next().charAt(0);
            myReader.nextLine();
            do {
                if (userInput == 'y') {
                    if (playerStrength > 15)  {
                        damage = (int)(((Math.random() * 4) + 1) * damageFactor) + 2;
                        enemyHp -= damage;
                        if (enemyName.equals("Saevuclaw"))   {
                            bear.setHp(bear.getHp() - damage);
                        }
                        else    {
                            dragon.setHp(dragon.getHp() - damage);
                        }
                        System.out.println("You strike " + enemyName + " and do " + damage + " damage!");
                    }
                    else  {
                        damage = (int)((Math.random() * 4) + 1) * damageFactor;
                        enemyHp -= damage;
                        if (enemyName.equals("Saevuclaw"))   {
                            bear.setHp(bear.getHp() - damage);
                        }
                        else    {
                            dragon.setHp(dragon.getHp() - damage);
                        }
                        System.out.println("You strike " + enemyName + " and do " + damage + " damage!");
                    }
                    // If enemyName is Saevuclaw (the bear), add damage modifier of 1
                    if (enemyName.equals("Saevuclaw"))  {
                        damage = (int)((Math.random() * 4) + 1);
                        player.setHp(player.getHp() - damage);
                        System.out.println(enemyName + " strikes you and does " + damage + " damage!");
                    }
                    // Else condition adds additional damage modifier for the dragon enemy (3)
                    else {
                        damage = (int)((Math.random() * 4) + 1) + 3;
                        player.setHp(player.getHp() - damage);
                        System.out.println(enemyName + " strikes you and does " + damage + " damage!");
                    }
                }
                else if (userInput == 'n')  {
                    System.out.println("You attempt to flee and are struck as you run away!");
                    damage = (int)((Math.random() * 4) + 1);
                    System.out.println(enemyName + "strikes you and does " + damage + " damage!");
                    player.setHp(player.getHp() - damage);
                    outcome = "flee";
                    break;
                }
                else  {
                    System.out.println("I'm sorry, that is not valid input - please try again (y/n).");
                }
            }
            while (userInput != 'y' && userInput != 'n');
            if (enemyHp <= 0 && player.getHp() > 0)  {
                outcome = "victory";
            }
            else if (player.getHp() <=0)   {
                outcome = "defeat";
            }
            else if (outcome.equals("flee")) {
                break;
            }
        }
        return outcome;
    }
    
    //*****************************************************************************************************************************
    // Score method to determine a player's score and provide them with a rank based on score
    private static void playerScore()    {
        System.out.println();
        System.out.println("Your score is " + player.getPoints() + " out of 20.");
        System.out.println();
    }
    
    //*****************************************************************************************************************************
    // When the game ends with 'q', player death or a win condition provide the player with a final rank
    private static void playerRank()    {
        System.out.print("This gives you a rank of: ");
        switch (player.getPoints())  {
            case 0:
            case 1:
            case 2:
            case 3:
            case 4:
                System.out.println("Novice");
                break;
            case 5:
            case 6:
            case 7:
            case 8:
            case 9:
                System.out.println("Apprentice");
                break;
            case 10:
            case 11:
            case 12:
            case 13:
            case 14:
                System.out.println("Guild Member");
                break;
            case 15:
            case 16:
            case 17:
            case 18:
            case 19:
                System.out.println("Adventurer");
                break;
            case 20:
                System.out.println("Knight of the Realm");
                break;
            default:
                System.out.println("Invalid score value");
        }
        System.out.println();
    }
    
    //*****************************************************************************************************************************
    // Win method to be called when the player reaches the castle!
    private static void win() {
        System.out.println("You tell the King of the plans by the hordes of the Dark Mountains to invade");
        System.out.println("your beloved Aerendora. He listens intently as you describe the plan.");
        System.out.println("The King is thankful and rewards you with the title " + player.getName() + ",");
        System.out.println("Knight of Aerendora and immediately calls his counsel to formulate a strategy");
        System.out.println("to defend the land.");
        System.out.println();
        System.out.println("Your mission is complete and now you may rest, congratulations, you have saved");
        System.out.println("your Kingdom and its people. Bards will sing tales of your deeds, and the name");
        System.out.println(player.getName() + " will go down in history. You are a true hero " + player.getName() + "!");
        System.out.println();
        System.out.println("Thank you!!!");
        playerScore();
        playerRank();
        System.out.println();
        System.out.println("***********************");
        System.out.println("*** You have won!!! ***");
        System.out.println("*      GAME OVER      *");
        System.out.println("***********************");
        System.exit(0);
    }
    
    //*****************************************************************************************************************************
    // Death method to be called to end the game in the event of a player's hit points reaching 0 or less
    private static void death() {
        System.out.println("Despite your best efforts to reach the castle and warn the King");
        System.out.println("you have died. Don't feel bad - you gave it your all!");
        System.out.println("Better luck in the next life...");
        playerScore();
        playerRank();
        System.out.println();
        System.out.println("*****************");
        System.out.println("*** GAME OVER ***");
        System.out.println("*****************");
        System.exit(0);
    }
}
