ScottLilly / SuperAdventure

Source code for my "Learn C# by building a simple RPG" guide
MIT License
46 stars 12 forks source link

Player can not be created or accessed outside of "program" class. #1

Closed bcornw2 closed 4 years ago

bcornw2 commented 4 years ago

Hi Scott,

I know this is from a long time ago but I recently found your blog post about the adventure game and I am thoroughly enjoying it. Thanks for contributing to coding knowledge as a whole.

Anyway, I hope that if you still check this repo, you can help me get to the bottom of this issue. I followed your blog and re-created this program from scratch, in the steps that your blog outlined. I tried to add some additional features, such as character stats (Strength, Wisdom, Spell Power, etc.), but my issue is this:

Whenever I create the Player object for the player, it can only be seen in the class that created it. I tried to make everything static, call it from the Player class like how you did with the CreatDefaultPlayer() method, declare it globally (as globally as C# can get), and many other things. I'm sure its something simple. I just get a NullReferenceException no matter what I try. I do not think that the program is creating the player in a way that is reachable by the other classes. Any advice? Thanks again for making that blog, it's been really enjoyable and informative.

I just want to be able to create a Player object that can be worked on by the rest of the classes, and that player object has customizable stats.

P.S. - I've included both wrong ways - lines 94 and 97 - to show you what I've done so far. Both builds have 0 errors and 0 warnings. code:

`using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Security.Cryptography;

namespace FantasyRPG { class Program { public static Player _player;

    static void Main(string[] args)
    {

        Console.WriteLine("Type 'Help' to see a list of commands");
        Console.WriteLine("");
        Console.WriteLine("Ben's Fantasy RPG - Gravothos");
        Console.WriteLine("What is your name?");
        string characterName = Console.ReadLine();
        characterName = (char.ToUpper(characterName[0]) + characterName.Substring(1));
        string characterClass = "default";
        Console.WriteLine("Select your Class:");
        Console.Write(" 1.) -  "); Console.ForegroundColor = ConsoleColor.Yellow; Console.Write("Paladin \n"); Console.ResetColor();
        Console.Write(" 2.) -  "); Console.ForegroundColor = ConsoleColor.DarkGreen; Console.Write("Huntsman\n"); Console.ResetColor();
        Console.Write(" 3.) -  "); Console.ForegroundColor = ConsoleColor.DarkRed; Console.Write("Warrior\n"); Console.ResetColor();
        Console.Write(" 4.) -  "); Console.ForegroundColor = ConsoleColor.DarkMagenta; Console.Write("Sorcerer\n"); Console.ResetColor();
        Console.Write(" 5.) -  "); Console.ForegroundColor = ConsoleColor.DarkYellow; Console.Write("Rogue\n"); Console.ResetColor();
        Console.ResetColor();
        //Console.WriteLine("\n(If no class is selected, then you will be assigned one at random...)");
        Console.ForegroundColor = ConsoleColor.Cyan;
        Console.WriteLine("");
        Console.Write("Or, enter ");
        Console.ForegroundColor = ConsoleColor.Yellow;
        Console.Write("i");
        Console.ForegroundColor = ConsoleColor.Cyan;
        Console.Write(" to learn more about the classes.");
        Console.ResetColor();
        int health, wisdom, strength, spellPower, determination;
        health = -2; wisdom = -2; strength = -2; spellPower = -2; determination = -2;
        bool menu = true;

        Console.Write(">> ");
        while (menu)
        {
            switch (Console.ReadLine().ToLower())
            {
                case "1":
                    characterClass = "Paladin"; health = 10; wisdom = 5; strength = 8; spellPower = 7; determination = 5;
                    menu = false;
                    break;
                case "2":
                    characterClass = "Huntsman"; health = 10; wisdom = 5; strength = 6; spellPower = 4; determination = 10;
                    menu = false;
                    break;
                case "3":
                    characterClass = "Warrior"; health = 12; wisdom = 1; strength = 12; spellPower = 0; determination = 10;
                    menu = false;
                    break;
                case "4":
                    characterClass = "Sorcerer"; health = 8; wisdom = 10; strength = 2; spellPower = 10; determination = 5;
                    menu = false;
                    break;
                case "5":
                    characterClass = "Rogue"; health = 8; wisdom = 5; strength = 8; spellPower = 2; determination = 12;
                    menu = false;
                    break;
                case "i":
                    Console.WriteLine("\n - Paladins are holy agents, who are strong both physically and magically. They have high health, and are privy to maces and axes. They have damage bonus against undead type enemies. They are a very balanced class.");
                    Console.WriteLine(" - Huntsmen are survivalists, in tune with nature, and while they tend to favor physical damage, they do have magical defensive abilities. They are best with axes or staves. They have a strong damage bonus against beast type enemies. They are a very balanced class.");
                    Console.WriteLine(" - Warriors are strong, and are capable of dealing and receiving enormous amounts of damage. They have no magical abilities, but are able to get damage bonuses from most of the weapons in the game, where other classes get only one or two. They have the highest strength and health of any class.");
                    Console.WriteLine(" - Sorcerers are strongly magical, and most of their damage will come from spell casting. They have a high wisdom pool and depend very little on physical attacks. They can have Spell Power or Wisdom buffs from their choice weapon - staves. They have a damage bonus against ghost type enemies. Sorcerers can also use daggers and swords for a balanced magical and physical build. They have the highest wisdom and spell power of any class.");
                    Console.WriteLine(" - Rogues are silent and cunning adversaries, who tend to favor physcial damage over magical damage. They are unqiue in that they are able to use two weapons at the same time, where every other class uses one, and due to their Sneak Attack passive ability, they almost always get to attack first. Their magcal abilities are purely defensive. They have a damage buff with daggers. They have a damage bonus against human enemies. They also have the highest determination of any class.");
                    Console.WriteLine("\n ");
                    Console.WriteLine("Select your Class:");
                    Console.Write(" 1.) -  "); Console.ForegroundColor = ConsoleColor.Yellow; Console.Write("Paladin \n"); Console.ResetColor();
                    Console.Write(" 2.) -  "); Console.ForegroundColor = ConsoleColor.DarkGreen; Console.Write("Woodsman\n"); Console.ResetColor();
                    Console.Write(" 3.) -  "); Console.ForegroundColor = ConsoleColor.DarkRed; Console.Write("Warrior\n"); Console.ResetColor();
                    Console.Write(" 4.) -  "); Console.ForegroundColor = ConsoleColor.DarkMagenta; Console.Write("Sorcerer\n"); Console.ResetColor();
                    Console.Write(" 5.) -  "); Console.ForegroundColor = ConsoleColor.DarkYellow; Console.Write("Rogue\n"); Console.ResetColor();
                    Console.ResetColor();
                    menu = true;
                    break;
                default:
                    Console.WriteLine("Incorrect choice - please enter a number 1 through 5 to select class.");
                    health = -1; wisdom = -1; strength = -1; spellPower = -1; determination = -1;
                    menu = true;
                    break;
            }
        }

        //doesnt work
        Player _player = new Player(characterName, characterClass, health, wisdom, strength, spellPower, determination, health, health, 0, 1);

        //this also doesn't work
        _player = _player.CreatePlayer();

        Console.WriteLine("You are {0}, a fledgling {1} in Gravothos, at the foot of the mountain where the fabled Scholomanarie school of dark magic lies.", _player.Name, _player.Class);
        Console.WriteLine("Stats:");
        Console.WriteLine("Total Health Points: {0}", _player.Health);
        Console.WriteLine("Total Wisdom Points: {0}", _player.Wisdom);
        Console.WriteLine("Strength: {0}", _player.Strength);
        Console.WriteLine("Spell Power: {0}", _player.SpellPower);
        Console.WriteLine("Determination: {0}", _player.Determination);
        Console.WriteLine("");
        Console.WriteLine("\nWould you like to read an explanation on your stats? (Y/n)");
        string yn = Console.ReadLine();
        if (yn.ToLower() == "y" || yn.ToLower() == "yes")
        {
            Console.Write(" - ");
            Console.ForegroundColor = ConsoleColor.DarkRed;
            Console.Write("Health");
            Console.ResetColor();
            Console.WriteLine(" is how much damage you can sustain from enemies, monsters, and the environment.");

            Console.Write(" - ");
            Console.ForegroundColor = ConsoleColor.DarkBlue;
            Console.Write("Wisdom ");
            Console.ResetColor();
            Console.WriteLine(" is the meter that determines how strong a spell can be cast in any given turn. More powerful spells require more wisdom to cast.");

            Console.Write(" - ");
            Console.ForegroundColor = ConsoleColor.DarkGreen;
            Console.Write("Strength ");
            Console.ResetColor();
            Console.WriteLine(" correlates to how much physical damage you can do to enemies and objects, and also correlates to how much health you regenerate per turn.");

            Console.Write(" - ");
            Console.ForegroundColor = ConsoleColor.Magenta;
            Console.Write("Spell Power ");
            Console.ResetColor();
            Console.WriteLine(" correlates to how much magical damage you can do to enemies, or the general effectiveness of your spells, and also correlates to how much wisdom you regenerate per turn.");

            Console.Write(" - ");
            Console.ForegroundColor = ConsoleColor.Blue;
            Console.Write("Determination ");
            Console.ResetColor();
            Console.Write("correlates to your chance to land a critical strike against an enemy, the chance to resist a strike from an enemy, and also general luck in loot.");
        }

        Console.WriteLine("\nWould you like to read an explanation of your Class? (Y/n)");
        yn = Console.ReadLine();
        if (yn.ToLower() == "y" || yn.ToLower() == "yes")
        {
            switch (_player.Class.ToLower())
            {
                case "paladin":
                    Console.WriteLine("The Paladin is an agent of God, sent to this demonic academy to purge the unholiness that is studied within. You have high health, and high stregnth, and high spell power. In combat, he has the ability to Heal Self to recoupe a fair amount of health, and also the option to cast Smite, to cause the enemy a large amount of damage. Undead-type enemies being the most vulnerable to your holy magic and blessed weapons. The paladin is trained in maces and axes, and will see a greater damage bonus if he chooses these weapons over others.");
                    break;
                case "huntsman":
                    Console.WriteLine("The Huntsman is a man of nature, living reclusively on the mountain, living off the fertile land and streams. he is a master of all beasts, but recent dark activity have corrupted the beast, deforming them and turning them violent and unworldly. He has set upon the dark academy to destroy the source of nature's corruption. The huntsman is a balanced class, with high health and high determination. He has offensive and defensive magical abilites. In combat, he can cast Stun, which causes the enemy to lose a turn. In combat with beasts, he can cast Cure Beast, which has a chance to cure the beast of its magical corruption, causing it to run away with no further harm to the hunter. Spell Power increases the effectiveness of Stun, and the likelihood that Cure Beast is sucessfull. The hunter has a strong damage bonus against beasts. He is adept at staves, axes, and daggers.");
                    break;
                case "warrior":
                    Console.WriteLine("The Warrior is a combatantant trained in all manner of weapons, and has come to the Scholomanarie academy as revenge for the corruption of Earth on his father's farm, at the foot of the mountain. The dry and rotting soil, corrupted by the dark magic of the school has rotted his families crops and drained the area of life. The warrior has high health and high strength, meaning he can take a lot of damage, and deal out a lot of damage as well. He lacks magical abilities, but makes up for this with his vast weapon specialization - meaning he gets a damage buff from axes, swords, maces, and daggers. He also has high determination, meaning he is more likely to land a critical strike.");
                    break;
                case "sorcerer":
                    Console.WriteLine("The Sorcerer is an agent of great magical ability, but was banished from his studies after the head priest of his village wrongfully accused him of studying dark magic at the Scholomanarie. To clear his name and return home, he has set upon the dark academy with the intent to destroy it and release its fearful hold on the population of Gravothos. The sorcerer has strong magical abilities, each of which consume an amount of regenerable wisdom when cast. The effectiveness of each spell he weilds is determined by his spell power stat. His wisdom stat and his spell power stat are the highest of any class, but he has low health and medium strength. He can cast Fireball, Frostbolt, Arcanae Beam, and the defensive Nether Shield, which reduces damage dealth to the sorcerer temporarily. The sorcerer is most effective against ghost-type enemies, and will earn a damage bonus when fighting against them. The sorcerer also has the ability to attack physically, and will have a damage bonus for staves, swords and daggers.");
                    break;
                case "rogue":
                    Console.WriteLine("The Rogue is a man of great cunning, an assassin that can move through the night undetected. It is known that there is great treasure in this cursed academy and was hired to take it by a mysterious patron. What the Rogue lacks in health and magic, he makes up in strength and determination, meaning that he can land huge critical strikes. He is also able to weild two weapons at the same time, as long as one is a dagger.  A passive stealth ability means his has a very high chance of always attacking first in combat against any enemy besides beasts. His only magical ability is to Distract, which subdues the enemy, if it is human or undead, and allows the rogue to escape unscathed. He has a strong damage bonus with daggers, and a fair damage bonus with swords.");
                    break;
                default:
                    yn = "n";
                    break;
            }

        }
        Console.WriteLine("\nAre you ready to begin your journey into the Scholomanarie? (Y/n)");
        yn = Console.ReadLine();
        if (yn.ToLower() == "y" || yn.ToLower() == "yes")
        {

            //Game Start

            Console.WriteLine("\n ============================================== \n Deep inside the wooded hills of Gravothos, overlooking a lake of still black water, wolves howl in the night. A giant stone spire erupts out of the side of the mountain, its windows illuminated by candle light within, but even the very stars behind it seem to be sucked into dark forboding. There stands the Scholomanarie, a vessel of dark academia, where withes and wizards and scholars of black magic study under the Devil himself.");
        }
        else
        {
            Console.WriteLine("Do you want to change your name or your class?");
            // add functionality to change class or name.
        }
        while (true)
        {
            // Display a prompt, so the user knows to type something
            Console.Write(">");

            // Wait for the user to type something, and press the <Enter> key
            string userInput = Console.ReadLine();

            // If they typed a blank line, loop back and wait for input again
            if (userInput == null)
            {
                continue;
            }

            // Convert to lower-case, to make comparisons easier
            string cleanedInput = userInput.ToLower();

            // Save the current game data, and break out of the "while(true)" loop
            if (cleanedInput == "exit")
            {
                break;
            }

            // If the user typed something, try to determine what to do
            ParseInput(cleanedInput, _player);
        }
    }

    private static void ParseInput(string input, Player _player)
    {
        if (input.Contains("help") || input == "?")
        {
            DisplayHelpText();
        }
        else if (input == "stats")
        {
            DisplayPlayerStats();
        }
        else if (input == "look")
        {
            DisplayCurrentLocation(_player);
        }
        else if (input.Contains("north"))
        {
            if (_player.CurrentLocation.LocationToNorth == null)
            {
                Console.WriteLine("You cannot move North");
            }
            else
            {
                _player.MoveNorth();
            }
        }
        else if (input.Contains("east"))
        {
            if (_player.CurrentLocation.LocationToEast == null)
            {
                Console.WriteLine("You cannot move East");
            }
            else
            {
                _player.MoveEast();
            }
        }
        else if (input.Contains("south"))
        {
            if (_player.CurrentLocation.LocationToSouth == null)
            {
                Console.WriteLine("You cannot move South");
            }
            else
            {
                _player.MoveSouth();
            }
        }
        else if (input.Contains("west"))
        {
            if (_player.CurrentLocation.LocationToWest == null)
            {
                Console.WriteLine("You cannot move West");
            }
            else
            {
                _player.MoveWest();
            }
        }
        else if (input == "inventory")
        {
            foreach (InventoryItem inventoryItem in _player.Inventory)
            {
                Console.WriteLine("{0}: {1}", inventoryItem.Description, inventoryItem.Quantity);
            }
        }
        else if (input.Contains("attack"))
        {
            AttackMonster();
        }
        else if (input.StartsWith("equip "))
        {
            EquipWeapon(input);
        }
        else if (input.StartsWith("eat "))
        {
            EatFood(input);
        }
        else
        {
            Console.WriteLine("I do not understand");
            Console.WriteLine("Type 'Help' to see a list of available commands");
        }
        Console.WriteLine("");
    }
    private static void DisplayHelpText()
    {
        Console.WriteLine("Available commands");
        Console.WriteLine("====================================");
        Console.WriteLine("Stats - Display player information");
        Console.WriteLine("Look - Get the description of your location");
        Console.WriteLine("Inventory - Display your inventory");
        Console.WriteLine("Attack - Fight the monster");
        Console.WriteLine("Equip <weapon name> - Set your current weapon");
        Console.WriteLine("Eat <potion name> - Drink a potion");
        Console.WriteLine("North - Move North");
        Console.WriteLine("South - Move South");
        Console.WriteLine("East - Move East");
        Console.WriteLine("West - Move West");
        Console.WriteLine("Exit - Save the game and exit");
    }
    private static void DisplayPlayerStats()
    {
        Console.WriteLine("Name: {0}", _player.Name);
        Console.WriteLine("Level: {0}", _player.Level);
        Console.WriteLine("Current health: {0}", _player.CurrentHealth);
        Console.WriteLine("Maximum health: {0}", _player.Health);
        Console.WriteLine("Experience Points: {0}/100", _player.Experience);

        Console.WriteLine("Wisdom: {0}", _player.Wisdom);
        Console.WriteLine("Strength {0}", _player.Strength);
        Console.WriteLine("Spell Power {0}", _player.SpellPower);
        Console.WriteLine("Determinatin {0}", _player.Determination);
        Console.WriteLine("========================");
    }
    private static void AttackMonster()
    {
        if (!_player.CurrentLocation.HasMob)
        {
            Console.WriteLine("There is nothing here to attack");
        }
        else
        {
            if (_player.CurrentWeapon == null)
            {
                // Select the first weapon in the player's inventory 
                // (or 'null', if they do not have any weapons)
                _player.CurrentWeapon = _player.Weapons.FirstOrDefault();
            }

            if (_player.CurrentWeapon == null)
            {
                Console.WriteLine("You do not have any weapons");
            }
            else
            {
                _player.UseWeapon(_player.CurrentWeapon);
            }
        }
    }

    private static void EquipWeapon(string input)
    {
        string inputWeaponName = input.Substring(6).Trim();

        if (string.IsNullOrEmpty(inputWeaponName))
        {
            Console.WriteLine("You must enter the name of the weapon to equip");
        }
        else
        {
            Weapon weaponToEquip =
                _player.Weapons.SingleOrDefault(
                    x => x.Name.ToLower() == inputWeaponName || x.NamePlural.ToLower() == inputWeaponName);

            if (weaponToEquip == null)
            {
                Console.WriteLine("You do not have the weapon: {0}", inputWeaponName);
            }
            else
            {
                _player.CurrentWeapon = weaponToEquip;

                Console.WriteLine("You equip your {0}", _player.CurrentWeapon.Name);
            }
        }
    }
    private static void EatFood(string input)
    {
        string inputFoodName = input.Substring(6).Trim();

        if (string.IsNullOrEmpty(inputFoodName))
        {
            Console.WriteLine("You must enter the name of the food to eat it.");
        }
        else
        {
            Food foodToEat =
                _player.Foods.SingleOrDefault(
                    x => x.Name.ToLower() == inputFoodName || x.NamePlural.ToLower() == inputFoodName);

            if (foodToEat == null)
            {
                Console.WriteLine("You do not have the potion: {0}", inputFoodName);
            }
            else
            {
                _player.EatFood(foodToEat);
            }
        }
    }
    private static void DisplayCurrentLocation(Player _player)
    {
        Console.WriteLine("You are at: {0}", _player.CurrentLocation.Name);

        if (_player.CurrentLocation.Description != "")
        {
            Console.WriteLine(_player.CurrentLocation.Description);
        }
    }

    public static int GetRandomNumber(int minimum, int maximum)
    {
        Random random = new Random();
        return Convert.ToInt32(random.NextDouble() * (maximum - minimum) + minimum);
    }

    public class Player : LivingCreature
    {

        private int _experiencePoints;
        private Location _currentLocation;
        public string Name { get; set; }
        public string Class { get; set; }
        public int Health { get; set; }
        public int Wisdom { get; set; }
        public int Strength { get; set; }
        public int SpellPower { get; set; }
        public int Determination { get; set; }
        public int Experience { get { return _experiencePoints; } private set { _experiencePoints = value; } }
        public int Level { get { return ((Experience / 100) + 1); } }
        public Location CurrentLocation
        {
            get { return _currentLocation; }
            set
            {
                _currentLocation = value;
            }
        }
        public Weapon CurrentWeapon { get; set; }

        public BindingList<InventoryItem> Inventory { get; set; }

        public List<Weapon> Weapons
        {
            get {  return Inventory.Where(x => x.Details is Weapon).Select(x => x.Details as Weapon).ToList();  }
        }
        public List<Food> Foods
        {
            get { return Inventory.Where(x => x.Details is Food).Select(x => x.Details as Food).ToList(); }
        }
        public List<int> LocationsVisited { get; set; }
        private Mob CurrentMob { get; set; }
        public Player(string name, string characterClass, int health, int wisdom, int strength, int spellPower, int determination, int currentHealth, int maxHealth, int experience, int level) : base(currentHealth, maxHealth)
        {
            Name = name;
            Class = characterClass;
            Health = health;
            Wisdom = wisdom;
            Strength = strength;
            SpellPower = spellPower;
            Determination = determination;
            CurrentHealth = currentHealth;
            MaxHealth = maxHealth;
            Experience = experience;

            Inventory = new BindingList<InventoryItem>();
            LocationsVisited = new List<int>();
        }
        public static Player CreatePlayer()
        {
            Player player = new Player("ben", "Warrior", 10, 10, 10, 10, 10, 10, 10, 0, 1);
            player.CurrentLocation = World.LocationByID(World.LOCATION_ID_EMPTY_FIELD);
            return player;
        }
        public void MoveTo(Location location)
        {
            if (PlayerDoesNotHaveTheRequiredItemToEnter(location))
            {
                Console.WriteLine("You must have a " + location.ItemRequiredToEnter.Name + " to enter this location.");
                return;
            }

            // The player can enter this location
            CurrentLocation = location;

            if (!LocationsVisited.Contains(CurrentLocation.ID))
            {
                LocationsVisited.Add(CurrentLocation.ID);
            }

            HealPlayer(1);

            SetTheCurrentMobForTheCurrentLocation(location);
        }
        public void MoveNorth() { if (CurrentLocation.LocationToNorth != null) {MoveTo(CurrentLocation.LocationToNorth); } }

        public void MoveEast() { if (CurrentLocation.LocationToEast != null) {MoveTo(CurrentLocation.LocationToEast); } }

        public void MoveSouth() { if (CurrentLocation.LocationToSouth != null) {MoveTo(CurrentLocation.LocationToSouth); } }

        public void MoveWest() { if (CurrentLocation.LocationToWest != null) {MoveTo(CurrentLocation.LocationToWest); } }

        public void UseWeapon(Weapon weapon)
        {
            int criticalMultiplier = (Determination /50) + 1;
            int damage = (GetRandomNumber(weapon.MinDamage, weapon.MaxDamage) * ((Strength / 50)+1));
            if ((damage == weapon.MaxDamage) || (damage == (weapon.MaxDamage - 1)))
            {
                double dmg = (damage * criticalMultiplier);
                damage = Convert.ToInt32(dmg);
                Console.ForegroundColor = ConsoleColor.DarkRed;
                CurrentMob.CurrentHealth -= damage;
                Console.WriteLine("Critical Strike!");
                Console.ResetColor();
                Console.Write("You hit the " + CurrentMob + " for " + damage + " points!");
                ;
            }
            if (damage == 0)
            {
                Console.WriteLine("You missed the " + CurrentMob.Name);
            }
            else
            {
                CurrentMob.CurrentHealth -= damage;
                Console.WriteLine("You hit the " + CurrentMob.Name + " for " + damage + " points.");
            }

            if (CurrentMob.IsDead)
            {
                LootTheCurrentMob();

                // "Move" to the current location, to refresh the current monster
                MoveTo(CurrentLocation);
            }
            else
            {
                LetTheMobAttack();
            }
        }
        private void LootTheCurrentMob()
        {
            Console.WriteLine("");
            Console.WriteLine("You defeated the " + CurrentMob.Name);
            Console.WriteLine("You receive " + CurrentMob.Experience + " experience points");

            AddExperiencePoints(CurrentMob.Experience);

            // Give monster's loot items to the player
            foreach (InventoryItem inventoryItem in CurrentMob.LootItems)
            {
                AddItemToInventory(inventoryItem.Details);

                Console.WriteLine(string.Format("You loot {0} {1}", inventoryItem.Quantity, inventoryItem.Description));
            }

            Console.WriteLine("");
        }
        public void EatFood(Food food)
        {
            Console.WriteLine("You eat " + food.Name);

            HealPlayer(food.AmountToHeal);

            RemoveItemFromInventory(food);

            // The player used their turn to drink the potion, so let the monster attack now
            LetTheMobAttack();
        }

        public void AddItemToInventory(Item itemToAdd, int quantity = 1)
        {
            InventoryItem existingItemInInventory = Inventory.SingleOrDefault(ii => ii.Details.ID == itemToAdd.ID);

            if (existingItemInInventory == null)
            {
                Inventory.Add(new InventoryItem(itemToAdd, quantity));
            }
            else
            {
                existingItemInInventory.Quantity += quantity;
            }

        }
        public void RemoveItemFromInventory(Item itemToRemove, int quantity = 1)
        {
            InventoryItem item = Inventory.SingleOrDefault(ii => ii.Details.ID == itemToRemove.ID && ii.Quantity >= quantity);

            if (item != null)
            {
                item.Quantity -= quantity;

                if (item.Quantity == 0)
                {
                    Inventory.Remove(item);
                }

            }
        }

        private bool HasRequiredItemToEnterThisLocation(Location location)
        {
            if (location.DoesNotHaveAnItemRequiredToEnter)
            {
                return true;
            }

            // See if the player has the required item in their inventory
            return Inventory.Any(ii => ii.Details.ID == location.ItemRequiredToEnter.ID);
        }

        private void SetTheCurrentMobForTheCurrentLocation(Location location)
        {
            // Populate the current monster with this location's monster (or null, if there is no monster here)
            CurrentMob = location.NewInstanceOfMob();

            if (CurrentMob != null)
            {
                Console.WriteLine("You see a " + CurrentMob.Name);
            }
        }
        private bool PlayerDoesNotHaveTheRequiredItemToEnter(Location location)
        {
            return !HasRequiredItemToEnterThisLocation(location);
        }

        private void AddExperiencePoints(int experiencePointsToAdd)
        {
            Experience += experiencePointsToAdd;
            Health = (Level * 10);
        }

        private void LetTheMobAttack()
        {
            int damageToPlayer = GetRandomNumber(0, CurrentMob.MaxDamage);

            Console.WriteLine("The " + CurrentMob.Name + " did " + damageToPlayer + " points of damage.");

            CurrentHealth -= damageToPlayer;

            if (IsDead)
            {
                Console.WriteLine("The " + CurrentMob.Name + " killed you.");

                MoveHome();
            }
        }
        private void HealPlayer(int hitPointsToHeal)
        {
            CurrentHealth = Math.Min(CurrentHealth + hitPointsToHeal + (Strength/10), MaxHealth);
        }
        private void MoveHome()
        {
            MoveTo(World.LocationByID(World.LOCATION_ID_EMPTY_FIELD));
        }

    }
    public class Item
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public string NamePlural { get; set; }
        public Item(int id, string name, string namePlural)
        {
            ID = id;
            Name = name;
            NamePlural = namePlural;
        }
    }
    public class Food : Item
    {
        public int AmountToHeal { get; set; }
        public int BuffInt { get; set; }
        public string BuffStat { get; set; }
        public Food(int id, string name, string namePlural, int amountToHeal, int buffInt = 0, string buffStat = null) : base(id, name, namePlural)
        {
            AmountToHeal = amountToHeal;
            BuffInt = buffInt;
            BuffStat = BuffStat;
        }

    }
    public class InventoryItem
    {
        private Item _details;
        private int _quantity;
        public Item Details { get { return _details; } set { _details = value; } }
        public int Quantity { get { return _quantity; } set { _quantity = value; } }
        public int ItemID {  get { return Details.ID; } }
        public string Description {  get {  return Quantity > 1 ? Details.NamePlural : Details.Name;} }
        public InventoryItem(Item details, int quantity)
        {
            Details = details;
            Quantity = quantity;
        }

    }
    public class LootItem
    {
        public Item Details { get; set; }
        public int DropPercentage { get; set; }
        public bool IsDefaultItem { get; set; }

        public LootItem(Item details, int dropPercentage, bool isDefaultItem)
        {
            Details = details;
            DropPercentage = dropPercentage;
            IsDefaultItem = isDefaultItem;
        }
    }
    public class Weapon : Item
    {
        public int MinDamage { get; set; }
        public int MaxDamage { get; set; }
        public string Type { get; set; }
        public string Stat { get; set; }
        public int StatInt { get; set; }
        public string Stat2 { get; set; }
        public int StatInt2 { get; set; }
        public Weapon(int id, string name, string type, string namePlural, int minDamage, int maxDamage, int statInt = 0, string stat = null, int statInt2 = 0, string stat2 = null) : base(id, name, namePlural)
        {
            MaxDamage = maxDamage;
            MinDamage = minDamage;
            Type = type;
            StatInt = statInt;
            Stat = stat;
            StatInt2 = statInt2;
            Stat2 = stat2;
        }
    }
    public class Location
    {
        private readonly SortedList<int, int> _mobAtLocation = new SortedList<int, int>();
        public int ID { get; set; }
        public string Name { get; set; }
        public string Description { get; set; }
        public Item ItemRequiredToEnter { get; set; }
        public Mob MobLivingHere { get; set; }
        public Location LocationToNorth { get; set; }
        public Location LocationToEast { get; set; }
        public Location LocationToSouth { get; set; }
        public Location LocationToWest { get; set; }
        //public NPC NPChere { get; set}

        public bool HasMob { get { return _mobAtLocation.Count > 0; } }
        public bool DoesNotHaveAnItemRequiredToEnter { get { return ItemRequiredToEnter == null; } }

        public Location(int id, string name, string description, Item itemRequiredToEnter = null, Mob mobLivingHere = null)
        {
            ID = id;
            Name = name;
            Description = description;
            ItemRequiredToEnter = itemRequiredToEnter;
            MobLivingHere = mobLivingHere;
        }
        public void AddMob(int MobID, int chanceOfAppearance)
        {
            if (_mobAtLocation.ContainsKey(MobID))
            {
                _mobAtLocation[MobID] = chanceOfAppearance;
            }
            else
            {
                _mobAtLocation.Add(MobID, chanceOfAppearance);
            }

        }
        public Mob NewInstanceOfMob()
        {
            if (!HasMob) { return null; }
            int totalPercentages = _mobAtLocation.Values.Sum();
            int randomNumber = GetRandomNumber(1, totalPercentages);
            int total = 0;
            foreach (KeyValuePair<int, int> mobKeyValuePair in _mobAtLocation)
            {
                total += mobKeyValuePair.Value;
                if (randomNumber <= total)
                {
                    return World.MobByID(mobKeyValuePair.Key).NewInstanceOfMob();
                }
            }
            return World.MobByID(_mobAtLocation.Keys.Last()).NewInstanceOfMob();
        }

    }
    public class LivingCreature
    {
        private int _currentHealth;

        public int MaxHealth { get; set; }
        public int CurrentHealth { get { return _currentHealth; } set { _currentHealth = value; } }
        public bool IsDead {  get { return CurrentHealth <= 0; } }
        public LivingCreature(int currentHealth, int maxHealth)
        {
            CurrentHealth = currentHealth;
            MaxHealth = maxHealth;
        }
    }
    public class Mob : LivingCreature
    {
        public int ID { get; set; }
        public string Name { get; set; }
        //public int MaxHealth { get; set; }
        //public int CurrentHealth { get; set; }
        public string Type { get; set; }
        public int MaxDamage { get; set; }
        public int Experience { get; set; }
        public List<LootItem> LootTable { get; set; }
        internal List<InventoryItem> LootItems { get; }
        public Mob(int id, string name, string type, int maxDamage, int experience, int currentHealth, int maxHealth) : base(currentHealth, maxHealth)
        {
            ID = id;
            Name = name;
            Type = type;
            MaxDamage = maxDamage;
            Experience = experience;
            LootTable = new List<LootItem>();
        }
        internal Mob NewInstanceOfMob()
        {
            Mob NewMob = new Mob(ID, Name, Type, MaxDamage, Experience, CurrentHealth, MaxHealth);
            foreach (LootItem lootItem in LootTable.Where(lootItem => GetRandomNumber(1, 100) <= lootItem.DropPercentage))
            {
                NewMob.LootItems.Add(new InventoryItem(lootItem.Details, 1));
            }
            if (NewMob.LootItems.Count == 0)
            {
                foreach (LootItem lootItem in LootTable.Where(x => x.IsDefaultItem))
                {
                    NewMob.LootItems.Add(new InventoryItem(lootItem.Details, 1));
                }
            }
            return NewMob;
        }

    }

    public static class World
    {
        public static readonly List<Item> Items = new List<Item>();
        public static readonly List<Mob> Mobs = new List<Mob>();
        public static readonly List<Location> Locations = new List<Location>();

        // warriors like maces, swords, axes
        // paladins like maces, swords, axes
        // huntsman like daggers, axes, staves
        // scorercers like daggers, swords, staves
        // rogues like daggers

        // daggers are usually high damage and you can have 2 at a time, way higher crit rate
        // swords are standard - some give str, some give spw
        // maces are standard - some give wisdom, some give health
        // staves give buffs to wisdom and spell power
        // axes give buff to dtm

        // weapons      -   warrior 10  -  paladins 8  -  huntsman 8  -  sorcerer 7  -  rogue 6
        public const int ITEM_ID_GNARGLED_STICK = 1;  // Favor warrior and palladin
        public const int ITEM_ID_RUSTY_SWORD = 2; /// favor warrior and sorcerer
        public const int ITEM_ID_FIREPLACE_POKER = 3; // favor warrior and huntsman
        public const int ITEM_ID_SHINY_SWORD = 4;  // favor warrior and palladin
        public const int ITEM_ID_WOOD_HANDLED_HATCHET = 5;  // favor huntsman and rogues
        public const int ITEM_ID_CHAMPION_BROADSWORD = 6; // favor huntsman  and rogue
        public const int ITEM_ID_SHINY_DAGGER = 7; // favor huntsman and rogue
        public const int ITEM_ID_SACRIFICIAL_DAGGER = 8; // favor sorcerer and rogue
        public const int ITEM_ID_STONE_MALLET = 9; // favor palladin and warrior
        public const int ITEM_ID_BIG_MIGHTY_MACE = 10; // favor warriors and paladins
        public const int ITEM_ID_FARMERS_PITCHFORK = 11; // favor warriors and huntsman
        public const int ITEM_ID_CEREMONIAL_HALBERD = 12; // favor warriors and paladins
        public const int ITEM_ID_LETTER_OPENER = 13; // favor rogues and sorcerers
        public const int ITEM_ID_GARDEN_SCYTHE = 14; // favor huntsman and scorcerer
        public const int ITEM_ID_RAZOR_SWORD = 15; // favors scorcerers and warriors
        public const int ITEM_ID_HEAVY_CHAIN_WHIP = 16; // favors paladins
        public const int ITEM_ID_HEAVY_MAUL = 17; //favors paladins and warriors
        public const int ITEM_ID_LONG_FELLING_AXE = 18; // favor Paladins and huntsman
        public const int ITEM_ID_RUNED_STAVE = 19; //favors scorcerer
        public const int ITEM_ID_BONE_HANDLED_STILETTO = 20; // favors rogues and scorcerers and huntsman

        //items

        // vendor trash
        public const int ITEM_ID_RAT_TAIL = 35;
        public const int ITEM_ID_WOLF_PAW = 36;
        public const int ITEM_ID_WOLF_FUR = 37;
        public const int ITEM_ID_NEOPHYTES_EAR = 38;
        public const int ITEM_ID_GOLD_THREADED_CLOTH = 39;
        public const int ITEM_ID_ROTTING_FEMUR = 40;
        //food
        public const int ITEM_ID_BUGS = 21; //restors 1 hp
        public const int ITEM_ID_BERRIES = 22; //restores 2-3 hp
        public const int ITEM_ID_BREAD = 23; //restors 4-6 hp
        public const int ITEM_ID_MEAT = 24; //restores 6-9 hp
        public const int ITEM_ID_PIE = 25; //restores 10-15 hp

        //food special
        public const int ITEM_ID_MARYS_BERRY_PRESERVE = 26; // buffs dtr by 10 for next 4 turns; restores 10 hp
        public const int ITEM_ID_LOUS_SPUD_STEW = 27; // buffs str by 10 for next 4 turns, restores 10 hp
        public const int ITEM_ID_LOUISES_PLATTER_OF_CHEESES = 28; // buffs spw by 10 for next 4 turns, restores 10 hp
        public const int ITEM_ID_TRISHES_SMOKED_FISHES = 29; // restores 10 wis

        //keys
        public const int ITEM_ID_STONE_KEY = 30;
        public const int ITEM_ID_IRON_KEY = 31;
        public const int ITEM_ID_COPPER_KEY = 32;
        public const int ITEM_ID_SILVER_KEY = 35;
        public const int ITEM_ID_GOLD_KEY = 33;
        public const int ITEM_ID_CRYSTAL_KEY = 36;
        public const int ITEM_ID_ORB_OF_THE_TOWER = 34;

        //LOCATIONS
        public const int LOCATION_ID_EMPTY_FIELD = 1; //where you find the stone key glinting in the grass.
        public const int LOCATION_ID_STONE_GATE = 2;
        public const int LOCATION_ID_DARK_WOODS = 3; //going backwards at empty field goes to dark woods, any direction goes to empty field. Going off path in scary path goes to dark woods
        public const int LOCATION_ID_SCARY_PATH = 4;
        public const int LOCATION_ID_MANOR_YARD = 5;
        public const int LOCATION_ID_MANOR_DOOR = 6;
        public const int LOCATION_ID_FOYER = 7;
        public const int LOCATION_ID_GREAT_ROOM = 8;
        public const int LOCATION_ID_PANTRY = 9;
        public const int LOCATION_ID_CELLAR = 10;
        public const int LOCATION_ID_WITCHES_DEN = 11;
        public const int LOCATION_ID_STUDY = 12; //
        public const int LOCATION_ID_TREASURE_ROOM = 13; //
        public const int LOCATION_ID_RICKETY_SHED = 14;
        public const int LOCATION_ID_GHOUL_PIT = 15;
        public const int LOCATION_ID_PARLOR = 16;
        public const int LOCATION_ID_UPSTAIRS_HALLWAY = 17;
        public const int LOCATION_ID_LIBRARY = 18;
        public const int LOCATION_ID_ALCHEMY_LAB = 20;
        public const int LOCATION_ID_ARBUTUS_CHAMBERS = 21;
        public const int LOCATION_ID_ROOF = 22;
        public const int LOCATION_ID_DUNGEON1 = 23;
        public const int LOCATION_ID_DUNGEON2 = 24;
        public const int LOCATION_ID_DUNGEON3 = 24;
        public const int LOCATION_ID_DUNGEON4 = 24;
        public const int LOCATION_ID_DUNGEON5 = 24;
        public const int LOCATION_ID_DUNGEON6 = 24;
        public const int LOCATION_ID_DUNGEON7 = 24;
        public const int LOCATION_ID_RICKETY_SHACK_INSIDE = 25;
        public const int LOCATION_ID_DROP_TO_PIT = 25;

        public const int MOB_ID_RAT = 1;
        public const int MOB_ID_WOLF = 2;
        public const int MOB_ID_NEOPHYTE = 3;
        public const int MOB_ID_ACOLYTE = 4;
        public const int MOB_ID_SOLOMONARI = 5;
        public const int MOB_ID_SHAMBLING_CORPSE = 6;
        public const int MOB_ID_ANIMATED_REMAINS = 7;
        public const int MOB_ID_WITCH = 8;
        public const int MOB_ID_CORRUPTED_SPIRIT = 9;
        public const int MOB_ID_ROTTING_GHOUL = 10;
        public const int MOB_ID_DEATH_KNIGHT_ARBUTUS = 11;
        public const int MOB_ID_WEATHERMAKER_VRITRONIA = 12;
        public const int MOB_ID_TORTURED_SUBJECT = 13;
        public const int MOB_ID_WISP = 14;
        public const int MOB_ID_SERPENT = 15;
        public const int MOB_ID_INTERROGATOR_WRISTH = 16;

        static World()
        {
            PopulateItems();
            PopulateMonsters();
            PopulateLocations();
        }

        private static void PopulateItems()
        {

            // first level weps
            Items.Add(new Weapon(ITEM_ID_GNARGLED_STICK, "mace", "Gnargled Stick", "Gnarlged Sticks", 0, 2));
            Items.Add(new Weapon(ITEM_ID_RUSTY_SWORD, "sword", "Rusty Sword", "Rusty Swords", 2, 4));
            Items.Add(new Weapon(ITEM_ID_LETTER_OPENER, "dagger", "Rusty Dagger", "Rusty Daggers", 2, 4));

            // second level weps
            Items.Add(new Weapon(ITEM_ID_FIREPLACE_POKER, "stave", "Fireplace Poker", "Fireplace Pokers", 4, 6, 1, "wisdom"));
            Items.Add(new Weapon(ITEM_ID_SHINY_SWORD, "sword", "Shiny Sword", "Shiny Swords", 4, 6, 1, "strength"));
            Items.Add(new Weapon(ITEM_ID_WOOD_HANDLED_HATCHET, "axe", "Wood Handled Hatchet", "Wood Handled Hatchets", 4, 6, 1, "strength"));
            Items.Add(new Weapon(ITEM_ID_SHINY_DAGGER, "dagger", "Shiny Dagger", "Shiny Daggers", 3, 5, 1, "determination"));
            Items.Add(new Weapon(ITEM_ID_STONE_MALLET, "mace", "Stone Mallet", "Stone Mallets", 4, 6, 1, "health"));

            // mid game
            Items.Add(new Weapon(ITEM_ID_BIG_MIGHTY_MACE, "mace", "Big Mighy Mace", "Big Mighty Maces", 8, 12, 1, "health"));
            Items.Add(new Weapon(ITEM_ID_SACRIFICIAL_DAGGER, "dagger", "Sacrifical Dagger", "Sacrifical Daggers", 7, 10, 2, "determination"));
            Items.Add(new Weapon(ITEM_ID_FARMERS_PITCHFORK, "stave", "Farmer's Pitchfork", "Farmer's Pitchforks", 4, 8, 2, "strength"));
            Items.Add(new Weapon(ITEM_ID_RAZOR_SWORD, "sword", "Razor Sword", "Razor Swords", 7, 10, 2, "strength"));
            Items.Add(new Weapon(ITEM_ID_LONG_FELLING_AXE, "axe", "Long Felling Axe", "Long Felling Axes", 8, 11, 3, "health", 1, "strength"));

            // end game
            Items.Add(new Weapon(ITEM_ID_BONE_HANDLED_STILETTO, "dagger", "Bone-Handled Stiletto", "Bone-Handled Stilettos", 15, 20, 4, "wisdom", 2, "determination"));
            Items.Add(new Weapon(ITEM_ID_RUNED_STAVE, "stave", "Runed Stave", "Runed Staves", 11, 14, 4, "wisdom", 5, "spellPower"));
            Items.Add(new Weapon(ITEM_ID_HEAVY_CHAIN_WHIP, "mace", "Heavy Chains", "Heavy Chains", 16, 22, 5, "strength", 4, "spellPower"));
            Items.Add(new Weapon(ITEM_ID_CHAMPION_BROADSWORD, "sword", "Champion's Broadsword", "Champion's Broadswords", 17, 21, 5, "stregnth", 5, "health"));
            Items.Add(new Weapon(ITEM_ID_HEAVY_MAUL, "axe", "Heavy Maul", "Heavy Mauls", 18, 20, 8, "stregnth", 2, "health"));

            // rare
            Items.Add(new Weapon(ITEM_ID_GARDEN_SCYTHE, "stave", "Garden Scythe", "Garden Scythes", 22, 26, 10, "spellPower", 3, "determination"));
            Items.Add(new Weapon(ITEM_ID_CEREMONIAL_HALBERD, "axe", "Ceremonial Halberd", "Ceremonial Halberd", 24, 27, 10, "stregnth", 3, "determination"));

            // food
            Items.Add(new Food(ITEM_ID_BUGS, "Bugs", "Bugs", 2));
            Items.Add(new Food(ITEM_ID_BERRIES, "Berries", "Berries", 3));
            Items.Add(new Food(ITEM_ID_BREAD, "Bread", "Bread", 5));
            Items.Add(new Food(ITEM_ID_MEAT, "Meat", "Meat", 8));
            Items.Add(new Food(ITEM_ID_PIE, "Pie", "Pies", 10));
            Items.Add(new Food(ITEM_ID_MARYS_BERRY_PRESERVE, "Mary's Berry Preserves", "Mary's Berry Preserves", 10, 10, "determination"));
            Items.Add(new Food(ITEM_ID_LOUS_SPUD_STEW, "Lou's Spud Stew", "Lou's Spud Stew", 10, 10, "strength"));
            Items.Add(new Food(ITEM_ID_LOUISES_PLATTER_OF_CHEESES, "Louise's Platter of Cheeses", "Louise's Platter of Cheeses", 10, 10, "spellPower"));
            Items.Add(new Food(ITEM_ID_TRISHES_SMOKED_FISHES, "Trish's Smoked Fishes", "Trish's Smoked Fishes", 10, 10, "wisdom"));
            // TODO : maybe add water? For wisdom regen

        }
        private static void PopulateMonsters()
        {
            Mob rat = new Mob(MOB_ID_RAT, "Rat", "beast", 5, 3, 3, 3);
            rat.LootTable.Add(new LootItem(ItemByID(ITEM_ID_BUGS), 50, false));
            rat.LootTable.Add(new LootItem(ItemByID(ITEM_ID_RAT_TAIL), 75, true));
            rat.LootTable.Add(new LootItem(ItemByID(ITEM_ID_BERRIES), 15, false));
            rat.LootTable.Add(new LootItem(ItemByID(ITEM_ID_LETTER_OPENER), 25, false));
            rat.LootTable.Add(new LootItem(ItemByID(ITEM_ID_STONE_KEY), 50, false));

            Mob wolf = new Mob(MOB_ID_WOLF, "Wolf", "beast", 6, 3, 5, 5);
            wolf.LootTable.Add(new LootItem(ItemByID(ITEM_ID_WOLF_FUR), 75, true));
            wolf.LootTable.Add(new LootItem(ItemByID(ITEM_ID_WOLF_PAW), 25, false));
            wolf.LootTable.Add(new LootItem(ItemByID(ITEM_ID_RUSTY_SWORD), 40, false));
            wolf.LootTable.Add(new LootItem(ItemByID(ITEM_ID_LETTER_OPENER), 50, false));
            wolf.LootTable.Add(new LootItem(ItemByID(ITEM_ID_BUGS), 75, true));
            wolf.LootTable.Add(new LootItem(ItemByID(ITEM_ID_STONE_KEY), 40, false));

            Mob wisp = new Mob(MOB_ID_WISP, "Wisp", "ghost", 5, 5, 5, 5);
            wisp.LootTable.Add(new LootItem(ItemByID(ITEM_ID_STONE_KEY), 10, false));

            Mob neophyte = new Mob(MOB_ID_NEOPHYTE, "Neophyte", "human", 7, 5, 7, 7);
            neophyte.LootTable.Add(new LootItem(ItemByID(ITEM_ID_BREAD), 50, false));
            neophyte.LootTable.Add(new LootItem(ItemByID(ITEM_ID_FIREPLACE_POKER), 25, false));
            neophyte.LootTable.Add(new LootItem(ItemByID(ITEM_ID_SHINY_DAGGER), 25, false));
            neophyte.LootTable.Add(new LootItem(ItemByID(ITEM_ID_WOOD_HANDLED_HATCHET), 15, false));
            neophyte.LootTable.Add(new LootItem(ItemByID(ITEM_ID_GOLD_THREADED_CLOTH), 15, false));
            neophyte.LootTable.Add(new LootItem(ItemByID(ITEM_ID_LOUS_SPUD_STEW), 25, false));
            neophyte.LootTable.Add(new LootItem(ItemByID(ITEM_ID_NEOPHYTES_EAR), 75, false));
            neophyte.LootTable.Add(new LootItem(ItemByID(ITEM_ID_IRON_KEY), 40, false));

            Mob acolyte = new Mob(MOB_ID_ACOLYTE, "Acolyte", "human", 10, 10, 10, 10);
            acolyte.LootTable.Add(new LootItem(ItemByID(ITEM_ID_BREAD), 50, false));
            acolyte.LootTable.Add(new LootItem(ItemByID(ITEM_ID_FIREPLACE_POKER), 25, false));
            acolyte.LootTable.Add(new LootItem(ItemByID(ITEM_ID_SHINY_DAGGER), 25, false));
            acolyte.LootTable.Add(new LootItem(ItemByID(ITEM_ID_SACRIFICIAL_DAGGER), 5, false));
            acolyte.LootTable.Add(new LootItem(ItemByID(ITEM_ID_SHINY_SWORD), 25, false));
            acolyte.LootTable.Add(new LootItem(ItemByID(ITEM_ID_STONE_MALLET), 25, false));
            acolyte.LootTable.Add(new LootItem(ItemByID(ITEM_ID_GOLD_THREADED_CLOTH), 15, false));
            acolyte.LootTable.Add(new LootItem(ItemByID(ITEM_ID_LOUS_SPUD_STEW), 25, false));
            acolyte.LootTable.Add(new LootItem(ItemByID(ITEM_ID_LOUISES_PLATTER_OF_CHEESES), 10, false));
            acolyte.LootTable.Add(new LootItem(ItemByID(ITEM_ID_IRON_KEY), 40, false));

            Mob torturedSubject = new Mob(MOB_ID_TORTURED_SUBJECT, "Tortured Subject", "human", 3, 5, 2, 5);
            torturedSubject.LootTable.Add(new LootItem(ItemByID(ITEM_ID_GNARGLED_STICK), 50, false));
            torturedSubject.LootTable.Add(new LootItem(ItemByID(ITEM_ID_NEOPHYTES_EAR), 50, false));
            torturedSubject.LootTable.Add(new LootItem(ItemByID(ITEM_ID_LOUS_SPUD_STEW), 15, false));
            torturedSubject.LootTable.Add(new LootItem(ItemByID(ITEM_ID_TRISHES_SMOKED_FISHES), 15, false));

            Mob shamblingCorpse = new Mob(MOB_ID_SHAMBLING_CORPSE, "Shambling Corpse", "undead", 8, 8, 6, 12);
            shamblingCorpse.LootTable.Add(new LootItem(ItemByID(ITEM_ID_ROTTING_FEMUR), 50, true));
            shamblingCorpse.LootTable.Add(new LootItem(ItemByID(ITEM_ID_BUGS), 50, true));
            shamblingCorpse.LootTable.Add(new LootItem(ItemByID(ITEM_ID_WOOD_HANDLED_HATCHET), 15, true));
            shamblingCorpse.LootTable.Add(new LootItem(ItemByID(ITEM_ID_SHINY_DAGGER), 15, true));
            shamblingCorpse.LootTable.Add(new LootItem(ItemByID(ITEM_ID_SACRIFICIAL_DAGGER), 15, true));
            shamblingCorpse.LootTable.Add(new LootItem(ItemByID(ITEM_ID_STONE_MALLET), 25, false));
            shamblingCorpse.LootTable.Add(new LootItem(ItemByID(ITEM_ID_BREAD), 85, false));

            Mob reanimatedRemains = new Mob(MOB_ID_ANIMATED_REMAINS, "Reanimated Remains", "undead", 8, 8, 4, 8);
            reanimatedRemains.LootTable.Add(new LootItem(ItemByID(ITEM_ID_ROTTING_FEMUR), 50, true));
            reanimatedRemains.LootTable.Add(new LootItem(ItemByID(ITEM_ID_BUGS), 50, true));
            reanimatedRemains.LootTable.Add(new LootItem(ItemByID(ITEM_ID_WOOD_HANDLED_HATCHET), 15, true));
            reanimatedRemains.LootTable.Add(new LootItem(ItemByID(ITEM_ID_SHINY_DAGGER), 15, true));
            reanimatedRemains.LootTable.Add(new LootItem(ItemByID(ITEM_ID_SACRIFICIAL_DAGGER), 15, true));
            reanimatedRemains.LootTable.Add(new LootItem(ItemByID(ITEM_ID_BIG_MIGHTY_MACE), 25, false));
            reanimatedRemains.LootTable.Add(new LootItem(ItemByID(ITEM_ID_RAZOR_SWORD), 25, false));
            reanimatedRemains.LootTable.Add(new LootItem(ItemByID(ITEM_ID_TRISHES_SMOKED_FISHES), 30, false));

            Mob witch = new Mob(MOB_ID_WITCH, "Witch", "human", 9, 12, 10, 10);
            witch.LootTable.Add(new LootItem(ItemByID(ITEM_ID_BREAD), 75, false));
            witch.LootTable.Add(new LootItem(ItemByID(ITEM_ID_RUNED_STAVE), 50, false));
            witch.LootTable.Add(new LootItem(ItemByID(ITEM_ID_FARMERS_PITCHFORK), 50, false));
            witch.LootTable.Add(new LootItem(ItemByID(ITEM_ID_GARDEN_SCYTHE), 15, false));
            witch.LootTable.Add(new LootItem(ItemByID(ITEM_ID_GOLD_THREADED_CLOTH), 50, false));
            witch.LootTable.Add(new LootItem(ItemByID(ITEM_ID_LOUISES_PLATTER_OF_CHEESES), 50, false));
            witch.LootTable.Add(new LootItem(ItemByID(ITEM_ID_MEAT), 25, false));
            witch.LootTable.Add(new LootItem(ItemByID(ITEM_ID_SACRIFICIAL_DAGGER), 75, false));
            witch.LootTable.Add(new LootItem(ItemByID(ITEM_ID_COPPER_KEY), 100, true));

            Mob rottingGhoul = new Mob(MOB_ID_ROTTING_GHOUL, "Rotting Ghoul", "undead", 8, 8, 18, 20);
            rottingGhoul.LootTable.Add(new LootItem(ItemByID(ITEM_ID_ROTTING_FEMUR), 50, true));
            rottingGhoul.LootTable.Add(new LootItem(ItemByID(ITEM_ID_PIE), 40, false));

            Mob solomonari = new Mob(MOB_ID_SOLOMONARI, "Solomari", "human", 11, 20, 28, 28);
            solomonari.LootTable.Add(new LootItem(ItemByID(ITEM_ID_SILVER_KEY), 100, true));
            solomonari.LootTable.Add(new LootItem(ItemByID(ITEM_ID_BONE_HANDLED_STILETTO), 25, false));
            solomonari.LootTable.Add(new LootItem(ItemByID(ITEM_ID_RUNED_STAVE), 25, false));
            solomonari.LootTable.Add(new LootItem(ItemByID(ITEM_ID_HEAVY_CHAIN_WHIP), 25, false));
            solomonari.LootTable.Add(new LootItem(ItemByID(ITEM_ID_LONG_FELLING_AXE), 25, false));
            solomonari.LootTable.Add(new LootItem(ItemByID(ITEM_ID_MARYS_BERRY_PRESERVE), 40, false));

            Mob corruptedSpirit = new Mob(MOB_ID_CORRUPTED_SPIRIT, "Corrupted Spirit", "ghost", 9, 10, 7, 7);

            Mob deathKnightArbutus = new Mob(MOB_ID_DEATH_KNIGHT_ARBUTUS, "Death Knight Arbutus", "undead", 15, 30, 40, 40);
            deathKnightArbutus.LootTable.Add(new LootItem(ItemByID(ITEM_ID_GOLD_KEY), 100, true));
            deathKnightArbutus.LootTable.Add(new LootItem(ItemByID(ITEM_ID_HEAVY_CHAIN_WHIP), 40, false));
            deathKnightArbutus.LootTable.Add(new LootItem(ItemByID(ITEM_ID_HEAVY_MAUL), 40, false));
            deathKnightArbutus.LootTable.Add(new LootItem(ItemByID(ITEM_ID_CEREMONIAL_HALBERD), 10, false));
            deathKnightArbutus.LootTable.Add(new LootItem(ItemByID(ITEM_ID_GARDEN_SCYTHE), 10, false));
            deathKnightArbutus.LootTable.Add(new LootItem(ItemByID(ITEM_ID_CHAMPION_BROADSWORD), 40, false));
            deathKnightArbutus.LootTable.Add(new LootItem(ItemByID(ITEM_ID_MARYS_BERRY_PRESERVE), 40, false));
            deathKnightArbutus.LootTable.Add(new LootItem(ItemByID(ITEM_ID_NEOPHYTES_EAR), 40, false));
            deathKnightArbutus.LootTable.Add(new LootItem(ItemByID(ITEM_ID_RAZOR_SWORD), 40, false));
            deathKnightArbutus.LootTable.Add(new LootItem(ItemByID(ITEM_ID_RUNED_STAVE), 40, false));
            deathKnightArbutus.LootTable.Add(new LootItem(ItemByID(ITEM_ID_PIE), 40, false));
            deathKnightArbutus.LootTable.Add(new LootItem(ItemByID(ITEM_ID_LOUISES_PLATTER_OF_CHEESES), 40, false));

            Mob serpent = new Mob(MOB_ID_SERPENT, "Serpent", "beast", 9, 9, 12, 12);

            Mob weathermakerVritronia = new Mob(MOB_ID_WEATHERMAKER_VRITRONIA, "Weathermaker Vritronia", "human", 18, 50, 65, 65);
            weathermakerVritronia.LootTable.Add(new LootItem(ItemByID(ITEM_ID_CEREMONIAL_HALBERD), 25, false));
            weathermakerVritronia.LootTable.Add(new LootItem(ItemByID(ITEM_ID_CHAMPION_BROADSWORD), 25, false));
            weathermakerVritronia.LootTable.Add(new LootItem(ItemByID(ITEM_ID_GARDEN_SCYTHE), 25, false));
            weathermakerVritronia.LootTable.Add(new LootItem(ItemByID(ITEM_ID_CEREMONIAL_HALBERD), 25, false));
            weathermakerVritronia.LootTable.Add(new LootItem(ItemByID(ITEM_ID_ORB_OF_THE_TOWER), 100, true));

            Mobs.Add(rat);
            Mobs.Add(wolf);
            Mobs.Add(wisp);
            Mobs.Add(neophyte);
            Mobs.Add(acolyte);
            Mobs.Add(serpent);
            Mobs.Add(shamblingCorpse);
            Mobs.Add(reanimatedRemains);
            Mobs.Add(witch);
            Mobs.Add(torturedSubject);
            Mobs.Add(rottingGhoul);
            Mobs.Add(solomonari);
            Mobs.Add(corruptedSpirit);
            Mobs.Add(deathKnightArbutus);
            Mobs.Add(weathermakerVritronia);

        }

        public static Item ItemByID(int id)
        {
            return Items.SingleOrDefault(x => x.ID == id);
        }
        public static Mob MobByID(int id)
        {
            return Mobs.SingleOrDefault(x => x.ID == id);
        }
        public static Location LocationByID(int id)
        {
            return Locations.SingleOrDefault(x => x.ID == id);
        }
        public static void PopulateLocations()
        {
            Location field = new Location(LOCATION_ID_EMPTY_FIELD, "Empty Field", "You are in an empty field, standing on dead grass with short brown bushes and dead trees around you, at the base of a tall mountain.There stands before you an immense stone gate.");
            int i = GetRandomNumber(1, 3);
            switch (i)
            {
                case 1:
                    field.AddMob(MOB_ID_RAT, 100);
                    break;
                case 2:
                    field.AddMob(MOB_ID_WOLF, 100);
                    break;
                case 3:
                    field.AddMob(MOB_ID_WISP, 33);
                    break;
            }
            Location darkWoods = new Location(LOCATION_ID_DARK_WOODS, "Dark Woods", "You find yourself lost in dark woods. Dense thickets of brush obstruct your path. The howls of beasts and the stirrings of night cloud your senses");
            i = GetRandomNumber(1, 3);
            switch (i)
            {
                case 1:
                    darkWoods.AddMob(MOB_ID_RAT, 100);
                    break;
                case 2:
                    darkWoods.AddMob(MOB_ID_WOLF, 100);
                    break;
                case 3:
                    darkWoods.AddMob(MOB_ID_WISP, 33);
                    break;
            }
            Location stoneGate = new Location(LOCATION_ID_STONE_GATE, "Stone Gate", "A great and looming stone gate, adorned on either pillar with chiseled gargoyles and creeping brown vines stands before you. The wrought-iron gate, tipped with spikes, is locked, but there is a great iron lock on it, with a rusty keyhole.", ItemByID(ITEM_ID_STONE_KEY));

            Location scaryPath = new Location(LOCATION_ID_SCARY_PATH, "Frightful Path", "You pass through the stone gate, into a dark grove. The grass had withered long ago, and you tread on dusty dirt towards a dim light up ahead. The woods on either side of the path seem to be calling to you.");
            i = GetRandomNumber(1, 3);
            switch (i)
            {
                case 1:
                    scaryPath.AddMob(MOB_ID_SERPENT, 100);
                    break;
                case 2:
                    scaryPath.AddMob(MOB_ID_NEOPHYTE, 33);
                    break;
                case 3:
                    scaryPath.AddMob(MOB_ID_WISP, 33);
                    break;
            }

            Location manorYard = new Location(LOCATION_ID_MANOR_YARD, "Manor Yard", "You stand now before a dilapidated stone castle. The wooden roof is collapsing in on itself. The great stone walls stretch around your view. Great twisting spires covered in creeping dead vines adorn the structure. It stood immense on the side of pined mountain, and it overlooked an unfamiliar and still lake below. Dark woods loom on either side.");
            i = GetRandomNumber(1, 3);
            switch (i)
            {
                case 1:
                    manorYard.AddMob(MOB_ID_NEOPHYTE, 100);
                    break;
                case 2:
                    manorYard.AddMob(MOB_ID_WOLF, 33);
                    break;
                case 3:
                    manorYard.AddMob(MOB_ID_WISP, 33);
                    break;
            }

            Location manorDoor = new Location(LOCATION_ID_MANOR_DOOR, "Manor Entrance", "You come upon a large wooden door, reinforced with bars of iron, set into the grey stone wall. There is a greening copper lock on this door. Above the frame, in script, is the word: \"Scholomonarie\"", ItemByID(ITEM_ID_IRON_KEY));

            Location manorFoyer = new Location(LOCATION_ID_FOYER, "The Castle's Foyer", "A once immaculate vestibule into the academy, the wood in the floors have begun to rot and the paiting on the walls appear to be degrading from the corners. A large ornate candle chanedlier hangs from the ceiling and globules of solid wax cling to it grotesquely. Before you is a great archway that leads to a more well lit room. A man with black, sunken eyes comes around a corner and appears shocked that you are here. \n 'You will make a fine specimen', he cackles, as he begins summoning black nether around him.");
            manorFoyer.AddMob(MOB_ID_ACOLYTE, 100);

            Location ricketyShack = new Location(LOCATION_ID_RICKETY_SHED, "Rickety Shed", "Near the tree line stands an old rickety wooden shack. It is locked from the inside. It sounds like something is moving inside");

            Location ricketyShackInside = new Location(LOCATION_ID_RICKETY_SHACK_INSIDE, "Inside the Rickety Shed", "You climb a short ladder up a stone well, and through the tattered wooden roof you can see the night sky. You place the Gold Key into the lock on the inside of the shack door, and step out into the night.", ItemByID(ITEM_ID_GOLD_KEY));

            Location greatRoom = new Location(LOCATION_ID_GREAT_ROOM, "The Great Room", "A huge central room, where the wooden floor is sinking into the basement. Candelabras hang on the walls and dark materials litter the tables and shelves. Soulless students of the devil shamble among each other silently. At the west of the room is the pantry, at the east is the parlor, and at the north is a great staircase, covered in a makeshift wrought-iron fence, with a large copper lock sealing it.");
            i = GetRandomNumber(1, 4);
            switch (i)
            {
                case 1:
                    greatRoom.AddMob(MOB_ID_NEOPHYTE, 100);
                    break;
                case 2:
                    greatRoom.AddMob(MOB_ID_ACOLYTE, 100);
                    break;
                case 3:
                    greatRoom.AddMob(MOB_ID_SHAMBLING_CORPSE, 100);
                    break;
            }

            Location pantry = new Location(LOCATION_ID_PANTRY, "Castle Pantry", "You come into the pantry, long neglected, its pots and pans and utensils long ago converted to instruments of witchcraft or alchemy. At the south of the room, you notice a small stone doorway that leads to stairs going into a cellar.");
            i = GetRandomNumber(1, 3);
            switch (i)
            {
                case 1:
                    pantry.AddMob(MOB_ID_RAT, 100);
                    break;
                case 2:
                    pantry.AddMob(MOB_ID_ACOLYTE, 100);
                    break;
                case 3:
                    pantry.AddMob(MOB_ID_CORRUPTED_SPIRIT, 33);
                    break;
            }

            Location ghoulPit = new Location(LOCATION_ID_GHOUL_PIT, "Cellar Ghoul Pit", "You descend the stairs to see a stone cellar illuminated by candles. In the center is a pile of discarded yellowing bones, and on top of it wrestles two reanimated corpses, with a Witch, deformed and cackling, orchestrating the battle. When she sees you, she shreiks and casts the two reanimated corpses to you and barricades herself in her den at the north end of the room.");
            ghoulPit.AddMob(MOB_ID_ANIMATED_REMAINS, 100);
            ghoulPit.AddMob(MOB_ID_ANIMATED_REMAINS, 100);

            Location witchesDen = new Location(LOCATION_ID_WITCHES_DEN, "The Witches Den", "On a nest build of body parts and bones rests the Witch. She is disfigured from her abuse of black magic, and her nervous cackling as she paces towards you with her blood-stained knife in her impossibly long fingers.");
            witchesDen.AddMob(MOB_ID_WITCH, 100);

            Location parlor = new Location(LOCATION_ID_PARLOR, "Scholomanarie Parlor", "You step into the parlor. There are dried and cracked leather chairs, tables that have been stained by years of alchemic spills, and what looks to have been at one time a man, dressed in a suit. He now shambles, his rotting green flesh bloated and sloughing and the once-fine linen of his suit stained a dark yellow from his decaying body. His lower jaw missing, teeth perpetually bared, he charges you.");
            parlor.AddMob(MOB_ID_ROTTING_GHOUL, 100);

            Location upstairsHallway = new Location(LOCATION_ID_UPSTAIRS_HALLWAY, "Upstairs Hallway", "You step onto a long red carpet, matted and threadbare, stretches from the west side of the cold corridor to the east. Heavy wooden doors at both ends.");
            i = GetRandomNumber(1, 3);
            switch (i)
            {
                case 1:
                    upstairsHallway.AddMob(MOB_ID_NEOPHYTE, 100);
                    break;
                case 2:
                    upstairsHallway.AddMob(MOB_ID_ACOLYTE, 33);
                    break;
                case 3:
                    upstairsHallway.AddMob(MOB_ID_WISP, 33);
                    break;
            }

            Location study = new Location(LOCATION_ID_STUDY, "Study", "You open the great wooden door that leads into the study, and you step in to the cleanest room in the castle so far. Volumes of books, on wall to wall shelves, reach 30 feet up. A great wooden desk sits in the middle of the room and a man sits with his back to you in a wooden chair at the end of the desk. He appears to be starting down out of his window, into the night. \n \"Nice of you to finally pay me a visit, {0}\", he says. He slowly stands up, great purple robes fall about him, and he turns to you. Black magic has corrupted his soul, his hair had withered, his skin greyed, and in his eye sockets there burned two green flames. This was the Solomonari - a professor at the Scholomanarie school. He brough his hands together, and drew them back out, materializing from dark energy a large, thin blade made of nether energy. He drew it towards you and before you could take your first step, he silently glided towards you without even a single step", ItemByID(ITEM_ID_COPPER_KEY));
            study.AddMob(MOB_ID_SOLOMONARI, 100);

            Location library = new Location(LOCATION_ID_LIBRARY, "Library", "In the library are great many book shelves, writing tables, and bubbling alchemical vials and pots with sprawled-open notebooks open next to them, illegible arahmaic script and demonic symbology littering the pages. To the north stands an immense iron door, adorned with rivulates of gold inlay.", ItemByID(ITEM_ID_SILVER_KEY));
            library.AddMob(MOB_ID_ACOLYTE, 100);

            Location arbutusChambers = new Location(LOCATION_ID_ARBUTUS_CHAMBERS, "Arbutus's Chambers", "The giant metal and gold door swings inwards to a silent and dark room. There appears to be a large throne in the center with an exit on both the west and the east sides. The room was freezing and you can see your own breath now as you stare about the room. You grab a torch off the wall and step inside, and cast it over the room. You star into the dark, when two blue glowing eyes appear in front of you. The slumbering Death Knight awakes, and this monstrous lich drags its mace on the floor as it shambles over to you. He is like a golem, standing far taller than you, his face a white skull with a black crown and inexplicably long white hair below the crow that went down the back of his blue iron carapice. Huge spiked spaulders of matching blue iron and a black cloak in tatters that covered the his of his body. His gauntlets clanked as he raced his mace above his head and brough the weight of it smashing down to where you were.", ItemByID(ITEM_ID_GOLD_KEY));
            arbutusChambers.AddMob(MOB_ID_DEATH_KNIGHT_ARBUTUS, 100);

            Location dropToPit = new Location(LOCATION_ID_DROP_TO_PIT, "Falling down", "You step onto a wooden floor, but the rotted boards collapse, and you tumble down a great distance until you land on pile of hay. The room is dark and you can hear nothing excepot for the frequent dripping of a pipe or a wellstone onto the wet floor. There is a green stone archway in the east of this room, and what lies beyond it is covered in absolute dark.");

            Location dungeon1 = new Location(LOCATION_ID_DUNGEON1, "Dank Dungeon", "You are in a dank dungeon. The sound of pipes dripping to the wet cobblestone floor echo through these tunnels. A large S in carved into the floor.");
            i = GetRandomNumber(1, 3);
            switch (i)
            {
                case 1:
                    dungeon1.AddMob(MOB_ID_SHAMBLING_CORPSE, 100);
                    break;
                case 2:
                    dungeon1.AddMob(MOB_ID_SERPENT, 100);
                    break;
                case 3:
                    dungeon1.AddMob(MOB_ID_ROTTING_GHOUL, 100);
                    break;
            }
            Location dungeon2 = new Location(LOCATION_ID_DUNGEON3, "Dank Dungeon", "You are in a dank dungeon. The sound of pipes dripping to the wet cobblestone floor echo through these tunnels. A large S in carved into the floor. The S seems to be tilted diagonally.");
            i = GetRandomNumber(1, 3);
            switch (i)
            {
                case 1:
                    dungeon2.AddMob(MOB_ID_RAT, 100);
                    break;
                case 2:
                    dungeon2.AddMob(MOB_ID_CORRUPTED_SPIRIT, 100);
                    break;
                case 3:
                    dungeon2.AddMob(MOB_ID_TORTURED_SUBJECT, 33);
                    break;
            }
            Location dungeon3 = new Location(LOCATION_ID_DUNGEON3, "Dank Dungeon", "You are in a dank dungeon. The sound of pipes dripping to the wet cobblestone floor echo through these tunnels. A large S in carved into the floor. You can hear far-away laughing coming from the east.");
            i = GetRandomNumber(1, 3);
            switch (i)
            {
                case 1:
                    dungeon3.AddMob(MOB_ID_TORTURED_SUBJECT, 100);
                    break;
                case 2:
                    dungeon3.AddMob(MOB_ID_CORRUPTED_SPIRIT, 33);
                    break;
                case 3:
                    dungeon3.AddMob(MOB_ID_RAT, 33);
                    break;
            }

            Location dungeon4 = new Location(LOCATION_ID_DUNGEON4, "Dank Dungeon", "You are in a dank dungeon. The sound of pipes dripping to the wet cobblestone floor echo through these tunnels. A large S in carved into the floor. It seems to be getting brighter in here.");
            dungeon4.AddMob(MOB_ID_TORTURED_SUBJECT, 100);

            Location dungeon5 = new Location(LOCATION_ID_DUNGEON5, "Dank Dungeon", "You are in a dank dungeon. The sound of pipes dripping to the wet cobblestone floor echo through these tunnels. A large S in carved into the floor. It's definitely brighter now. The laughing is getting closer.");
            dungeon5.AddMob(MOB_ID_TORTURED_SUBJECT, 100);

            Location dungeon6 = new Location(LOCATION_ID_DUNGEON6, "Dank Dungeon", "You step into the next identical room and are greeted with the razor sharp smile of a hooded man. Long white teeth and tiny eyes that squint when he giggles. \n \"What secrets do you have? Will you tell me?\", he asks. He discards his hood and robe is a vulgar display of speed as he grips a large executioners battle axe and charges at you, still smiling.");
            dungeon6.AddMob(MOB_ID_INTERROGATOR_WRISTH, 100);
            Location dungeon7 = new Location(LOCATION_ID_DUNGEON7, "Dank Dungeon", "You are in a dank dungeon. The sound of pipes dripping to the wet cobblestone floor echo through these tunnels. A large S in carved into the floor. There is bright moonlight coming out of the south tunnel, and the cool breeze draws you nearer to the exit.");

            Location roof = new Location(LOCATION_ID_ROOF, "Roof", "This is where Vritronia, the demon weathermaker, is riding a giant bat. Killing her gives you the Orb of the Tower, which you can destroy to free the tormented souls of The Sholomanarie.");

            field.LocationToNorth = stoneGate;
            field.LocationToEast = darkWoods;
            field.LocationToSouth = darkWoods;
            field.LocationToWest = darkWoods;

            darkWoods.LocationToNorth = field;
            darkWoods.LocationToWest = darkWoods;
            darkWoods.LocationToSouth = darkWoods;
            darkWoods.LocationToEast = darkWoods;

            stoneGate.LocationToNorth = scaryPath;
            stoneGate.LocationToEast = darkWoods;
            stoneGate.LocationToSouth = field;
            stoneGate.LocationToWest = darkWoods;

            scaryPath.LocationToNorth = manorYard;
            scaryPath.LocationToEast = darkWoods;
            scaryPath.LocationToSouth = darkWoods;
            scaryPath.LocationToWest = darkWoods;

            manorYard.LocationToNorth = manorDoor;
            manorYard.LocationToEast = darkWoods;
            manorYard.LocationToSouth = manorYard;
            manorYard.LocationToWest = darkWoods;

            manorDoor.LocationToNorth = manorFoyer;
            manorDoor.LocationToEast = darkWoods;
            manorDoor.LocationToSouth = manorYard;
            manorDoor.LocationToWest = darkWoods;

            manorFoyer.LocationToNorth = greatRoom;
            manorFoyer.LocationToSouth = manorFoyer;

            greatRoom.LocationToNorth = upstairsHallway;
            greatRoom.LocationToEast = parlor;
            greatRoom.LocationToSouth = manorFoyer;
            greatRoom.LocationToWest = pantry;

            pantry.LocationToSouth = ghoulPit;
            pantry.LocationToEast = greatRoom;

            ghoulPit.LocationToNorth = pantry;
            ghoulPit.LocationToWest = witchesDen;

            witchesDen.LocationToEast = ghoulPit;

            upstairsHallway.LocationToEast = library;
            upstairsHallway.LocationToSouth = greatRoom;
            upstairsHallway.LocationToWest = study;

            library.LocationToNorth = arbutusChambers;
            library.LocationToWest = upstairsHallway;

            arbutusChambers.LocationToEast = roof;
            arbutusChambers.LocationToWest = dropToPit;

            dropToPit.LocationToWest = dungeon1;

            // after fall into dungeon

            dungeon1.LocationToNorth = dungeon1;
            dungeon1.LocationToEast = dungeon1;
            dungeon1.LocationToSouth = dungeon1;
            dungeon1.LocationToWest = dungeon2;

            dungeon2.LocationToNorth = dungeon1;
            dungeon2.LocationToEast = dungeon1;
            dungeon2.LocationToSouth = dungeon3;
            dungeon2.LocationToWest = dungeon1;

            dungeon3.LocationToNorth = dungeon1;
            dungeon3.LocationToEast = dungeon4;
            dungeon3.LocationToSouth = dungeon3;
            dungeon3.LocationToWest = dungeon1;

            dungeon4.LocationToNorth = dungeon1;
            dungeon4.LocationToEast = dungeon5;
            dungeon4.LocationToSouth = dungeon1;
            dungeon4.LocationToWest = dungeon1;

            dungeon5.LocationToNorth = dungeon1;
            dungeon5.LocationToEast = dungeon1;
            dungeon5.LocationToSouth = dungeon6;
            dungeon5.LocationToWest = dungeon1;

            dungeon6.LocationToNorth = dungeon1;
            dungeon6.LocationToEast = dungeon1;
            dungeon6.LocationToSouth = dungeon1;
            dungeon6.LocationToWest = dungeon7;

            dungeon7.LocationToNorth = dungeon1;
            dungeon7.LocationToEast = dungeon1;
            dungeon7.LocationToSouth = ricketyShackInside;
            dungeon7.LocationToWest = dungeon1;

            ricketyShackInside.LocationToSouth = manorYard;

        }

    }
}

} `

ScottLilly commented 4 years ago

Hi Benjamin,

The way to handle this is generally to pass the “_player” variable into the other classes and methods that need to use it. When you call a function in another object, that function will need to have a Player parameter to accept the _player object, and do whatever the function needs to do with that object.

Because the _player object’s datatype is “Player” (a class you created, and not a built-in class – like “string”, or “int”), the variable will be passed as a reference. This means there is really only one _player object in memory, each function will modify that one object. It’s not like a variable that is passed “by reference”. Those variables basically make a copy of the value, and do not point to one shared object.

Let me know if that doesn’t work, or if you still have questions. If you can’t get it to work, can you upload your code to GitHub, Dropbox, or some other file-sharing location? I’d need all the files in the folder where the .sln file is located, all the sub-folders underneath that location (those will probably be named FantasyRPG.Engine, FantasyRPG.Console, etc. – whatever projects you added to your solution), and files in those project sub-folders. That way I can build it and help you figure out a solution.

Scott

From: Benjamin Cornwell notifications@github.com Sent: Monday, January 6, 2020 10:03 PM To: ScottLilly/SuperAdventure SuperAdventure@noreply.github.com Cc: Subscribed subscribed@noreply.github.com Subject: [ScottLilly/SuperAdventure] Player can not be created or accessed outside of "program" class. (#1)

Hi Scott,

I know this is from a long time ago but I recently found your blog post about the adventure game and I am thoroughly enjoying it. Thanks for contributing to coding knowledge as a whole.

Anyway, I hope that if you still check this repo, you can help me get to the bottom of this issue. I followed your blog and re-created this program from scratch, in the steps that your blog outlined. I tried to add some additional features, such as character stats (Strength, Wisdom, Spell Power, etc.), but my issue is this:

Whenever I create the Player object for the player, it can only be seen in the class that created it. I tried to make everything static, call it from the Player class like how you did with the CreatDefaultPlayer() method, declare it globally (as globally as C# can get), and many other things. I'm sure its something simple. I just get a NullReferenceException no matter what I try. I do not think that the program is creating the player in a way that is reachable by the other classes. Any advice? Thanks again for making that blog, it's been really enjoyable and informative.

I just want to be able to create a Player object that can be worked on by the rest of the classes, and that player object has customizable stats.

P.S. - I've included both wrong ways - lines 94 and 97 - to show you what I've done so far. Both builds have 0 errors and 0 warnings. code:

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/ScottLilly/SuperAdventure/issues/1?email_source=notifications&email_token=AARKPMQL6A63IX2LFRAUUVDQ4P5H7A5CNFSM4KDQYUZ2YY3PNVWWK3TUL52HS4DFUVEXG43VMWVGG33NNVSW45C7NFSM4IEMKACA , or unsubscribe https://github.com/notifications/unsubscribe-auth/AARKPMRLGDJL46V4IGD4TCDQ4P5H7ANCNFSM4KDQYUZQ . https://github.com/notifications/beacon/AARKPMV4ECNHGL3BDXZ5UALQ4P5H7A5CNFSM4KDQYUZ2YY3PNVWWK3TUL52HS4DFUVEXG43VMWVGG33NNVSW45C7NFSM4IEMKACA.gif

bcornw2 commented 4 years ago

Hi Scott,

Thanks for the help. I really appreciate it. I've since added quite a bit of functionality, including stats like Strength and SpellPower, classes with different abilities like Sorcerer, Paladin, Huntsman, and class-specific spells like Smite and Heal for paladins, Fireball and frostbolt for sorcerers, and that ability to tame beast to act as a pet who attacks on your behalf (for hunters), and the ability to dual-wield daggers for rogues.

You can check it out here if you're interested. >> https://github.com/bcornw2/ScholomanceAdventure

Again, thanks for the help. You made a great blog post that enabled me to do this. It was a ton of fun! And thanks for responding to my issue too. For now, I think I've finished this project, besides adding some more rooms and some more dialog from bosses.

Thanks!