There are properties and functions in the Player class that aren’t really attributes of a player. They’re really properties to hold the current state of the game session.
So, I’ll create a GameSession viewmodel, to hold this information. The viewmodel’s purpose will be to manage communication between the views and the models and between different models (like the player, locations, and monsters).
However, there’s a problem.
Once I start pulling the CurrentMonster and CurrentLocation properties from the Player class, I’ll need to move a lot of code out of the Player class: all the movement functions (MoveNorth, MoveEast, MoveSouth, MoveWest, and MoveTo), the code to check if the player has the required item to move to a location, the code to populate the current monster (when the player moves to a location), and the saved game code (which saves the player’s current location).
So, to start, the only thing I’ll put in the GameSession class is a CurrentPlayer property. We’ll move the rest of the code into the GameSession class in small steps.
Next, I changed the code in SuperAdventure\SuperAdventure.cs and SuperAdventureConsole\Program.cs (the views) to:
- Add a class-level _gameSession variable
- Instantiate a GameSession object and save it to _gameSession
- Delete the existing class-level _player variables
- Change all uses of “_player” to “_gameSession.CurrentPlayer”
After making the change, I rebuilt the solution and tested that the game still worked.
This isn’t a big change, as far as lines of code. But, it is the beginning of a significant architectural change. We’ll be able to use this GameSession class for our automated tests.
ORIGINAL CODE
SuperAdventure\SuperAdventure.cs (Windows form)
using System; using System.ComponentModel; using System.Linq; using System.Windows.Forms; using System.IO; using Engine; using Engine.CustomEventArgs; using Engine.Models; using Engine.Utilities; namespace SuperAdventure { public partial class SuperAdventure : Form { private const string PLAYER_DATA_FILE_NAME = "PlayerData.xml"; private Player _player; public SuperAdventure() { InitializeComponent(); _player = PlayerDataMapper.CreateFromDatabase(); if(_player == null) { if(File.Exists(PLAYER_DATA_FILE_NAME)) { _player = Player.CreatePlayerFromXmlString(File.ReadAllText(PLAYER_DATA_FILE_NAME)); } else { _player = Player.CreateDefaultPlayer(); } } _player.AddItemToInventory(World.ItemByID(World.ITEM_ID_CLUB)); lblHitPoints.DataBindings.Add("Text", _player, "CurrentHitPoints"); lblGold.DataBindings.Add("Text", _player, "Gold"); lblExperience.DataBindings.Add("Text", _player, "ExperiencePoints"); lblLevel.DataBindings.Add("Text", _player, "Level"); dgvInventory.RowHeadersVisible = false; dgvInventory.AutoGenerateColumns = false; dgvInventory.DataSource = _player.Inventory; dgvInventory.Columns.Add(new DataGridViewTextBoxColumn { HeaderText = "Name", Width = 197, DataPropertyName = "Description" }); dgvInventory.Columns.Add(new DataGridViewTextBoxColumn { HeaderText = "Quantity", DataPropertyName = "Quantity" }); dgvInventory.ScrollBars = ScrollBars.Vertical; dgvQuests.RowHeadersVisible = false; dgvQuests.AutoGenerateColumns = false; dgvQuests.DataSource = _player.Quests; dgvQuests.Columns.Add(new DataGridViewTextBoxColumn { HeaderText = "Name", Width = 197, DataPropertyName = "Name" }); dgvQuests.Columns.Add(new DataGridViewTextBoxColumn { HeaderText = "Done?", DataPropertyName = "IsCompleted" }); cboWeapons.DataSource = _player.Weapons; cboWeapons.DisplayMember = "Name"; cboWeapons.ValueMember = "Id"; if(_player.CurrentWeapon != null) { cboWeapons.SelectedItem = _player.CurrentWeapon; } cboWeapons.SelectedIndexChanged += cboWeapons_SelectedIndexChanged; cboPotions.DataSource = _player.Potions; cboPotions.DisplayMember = "Name"; cboPotions.ValueMember = "Id"; _player.PropertyChanged += PlayerOnPropertyChanged; _player.OnMessage += DisplayMessage; _player.MoveTo(_player.CurrentLocation); } private void DisplayMessage(object sender, MessageEventArgs messageEventArgs) { rtbMessages.Text += messageEventArgs.Message + Environment.NewLine; if(messageEventArgs.AddExtraNewLine) { rtbMessages.Text += Environment.NewLine; } rtbMessages.SelectionStart = rtbMessages.Text.Length; rtbMessages.ScrollToCaret(); } private void PlayerOnPropertyChanged(object sender, PropertyChangedEventArgs propertyChangedEventArgs) { if (propertyChangedEventArgs.PropertyName == "Weapons") { Weapon previouslySelectedWeapon = _player.CurrentWeapon; cboWeapons.DataSource = _player.Weapons; if (previouslySelectedWeapon != null && _player.Weapons.Exists(w => w.ID == previouslySelectedWeapon.ID)) { cboWeapons.SelectedItem = previouslySelectedWeapon; } if (!_player.Weapons.Any()) { cboWeapons.Visible = false; btnUseWeapon.Visible = false; } } if(propertyChangedEventArgs.PropertyName == "Potions") { cboPotions.DataSource = _player.Potions; if(!_player.Potions.Any()) { cboPotions.Visible = false; btnUsePotion.Visible = false; } } if(propertyChangedEventArgs.PropertyName == "CurrentLocation") { // Show/hide available movement buttons btnNorth.Visible = (_player.CurrentLocation.LocationToNorth != null); btnEast.Visible = (_player.CurrentLocation.LocationToEast != null); btnSouth.Visible = (_player.CurrentLocation.LocationToSouth != null); btnWest.Visible = (_player.CurrentLocation.LocationToWest != null); btnTrade.Visible = (_player.CurrentLocation.VendorWorkingHere != null); // Display current location name and description rtbLocation.Text = _player.CurrentLocation.Name + Environment.NewLine; rtbLocation.Text += _player.CurrentLocation.Description + Environment.NewLine; if(!_player.CurrentLocation.HasAMonster) { cboWeapons.Visible = false; cboPotions.Visible = false; btnUseWeapon.Visible = false; btnUsePotion.Visible = false; } else { cboWeapons.Visible = _player.Weapons.Any(); cboPotions.Visible = _player.Potions.Any(); btnUseWeapon.Visible = _player.Weapons.Any(); btnUsePotion.Visible = _player.Potions.Any(); } } } private void btnNorth_Click(object sender, EventArgs e) { _player.MoveNorth(); } private void btnEast_Click(object sender, EventArgs e) { _player.MoveEast(); } private void btnSouth_Click(object sender, EventArgs e) { _player.MoveSouth(); } private void btnWest_Click(object sender, EventArgs e) { _player.MoveWest(); } private void btnUseWeapon_Click(object sender, EventArgs e) { // Get the currently selected weapon from the cboWeapons ComboBox Weapon currentWeapon = (Weapon)cboWeapons.SelectedItem; _player.UseWeapon(currentWeapon); } private void btnUsePotion_Click(object sender, EventArgs e) { // Get the currently selected potion from the combobox HealingPotion potion = (HealingPotion)cboPotions.SelectedItem; _player.UsePotion(potion); } private void SuperAdventure_FormClosing(object sender, FormClosingEventArgs e) { File.WriteAllText(PLAYER_DATA_FILE_NAME, _player.ToXmlString()); PlayerDataMapper.SaveToDatabase(_player); } private void cboWeapons_SelectedIndexChanged(object sender, EventArgs e) { _player.CurrentWeapon = (Weapon)cboWeapons.SelectedItem; } private void btnTrade_Click(object sender, EventArgs e) { TradingScreen tradingScreen = new TradingScreen(_player); tradingScreen.StartPosition = FormStartPosition.CenterParent; tradingScreen.ShowDialog(this); } private void btnMap_Click(object sender, EventArgs e) { WorldMap mapScreen = new WorldMap(_player); mapScreen.StartPosition = FormStartPosition.CenterParent; mapScreen.ShowDialog(this); } } }
SuperAdventureConsole\Program.cs (console class)
using System; using System.ComponentModel; using System.IO; using System.Linq; using Engine; using Engine.CustomEventArgs; using Engine.Models; using Engine.Utilities; namespace SuperAdventureConsole { public class Program { private const string PLAYER_DATA_FILE_NAME = "PlayerData.xml"; private static Player _player; private static void Main() { // Load the player LoadGameData(); Console.WriteLine("Type 'Help' to see a list of commands"); Console.WriteLine(""); DisplayCurrentLocation(); // Connect player events to functions that will display in the UI _player.PropertyChanged += Player_OnPropertyChanged; _player.OnMessage += Player_OnMessage; // Infinite loop, until the user types "exit" 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") { SaveGameData(); break; } // If the user typed something, try to determine what to do ParseInput(cleanedInput); } } private static void Player_OnPropertyChanged(object sender, PropertyChangedEventArgs e) { if(e.PropertyName == "CurrentLocation") { DisplayCurrentLocation(); if(_player.CurrentLocation.VendorWorkingHere != null) { Console.WriteLine("You see a vendor here: {0}", _player.CurrentLocation.VendorWorkingHere.Name); } } } private static void Player_OnMessage(object sender, MessageEventArgs e) { Console.WriteLine(e.Message); if(e.AddExtraNewLine) { Console.WriteLine(""); } } private static void ParseInput(string input) { if(input.Contains("help") || input == "?") { DisplayHelpText(); } else if(input == "stats") { DisplayPlayerStats(); } else if(input == "look") { DisplayCurrentLocation(); } 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 == "quests") { if(_player.Quests.Count == 0) { Console.WriteLine("You do not have any quests"); } else { foreach(PlayerQuest playerQuest in _player.Quests) { Console.WriteLine("{0}: {1}", playerQuest.Name, playerQuest.IsCompleted ? "Completed" : "Incomplete"); } } } else if(input.Contains("attack")) { AttackMonster(); } else if(input.StartsWith("equip ")) { EquipWeapon(input); } else if(input.StartsWith("drink ")) { DrinkPotion(input); } else if(input == "trade") { ViewTradeInventory(); } else if(input.StartsWith("buy ")) { BuyItem(input); } else if(input.StartsWith("sell ")) { SellItem(input); } else { Console.WriteLine("I do not understand"); Console.WriteLine("Type 'Help' to see a list of available commands"); } // Write a blank line, to keep the UI a little cleaner 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("Quests - Display your quests"); Console.WriteLine("Attack - Fight the monster"); Console.WriteLine("Equip <weapon name> - Set your current weapon"); Console.WriteLine("Drink <potion name> - Drink a potion"); Console.WriteLine("Trade - display your inventory and vendor's inventory"); Console.WriteLine("Buy <item name> - Buy an item from a vendor"); Console.WriteLine("Sell <item name> - Sell an item to a vendor"); 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("Current hit points: {0}", _player.CurrentHitPoints); Console.WriteLine("Maximum hit points: {0}", _player.MaximumHitPoints); Console.WriteLine("Experience Points: {0}", _player.ExperiencePoints); Console.WriteLine("Level: {0}", _player.Level); Console.WriteLine("Gold: {0}", _player.Gold); } private static void AttackMonster() { if(!_player.CurrentLocation.HasAMonster) { 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 DrinkPotion(string input) { string inputPotionName = input.Substring(6).Trim(); if(string.IsNullOrEmpty(inputPotionName)) { Console.WriteLine("You must enter the name of the potion to drink"); } else { HealingPotion potionToDrink = _player.Potions.SingleOrDefault( x => x.Name.ToLower() == inputPotionName || x.NamePlural.ToLower() == inputPotionName); if(potionToDrink == null) { Console.WriteLine("You do not have the potion: {0}", inputPotionName); } else { _player.UsePotion(potionToDrink); } } } private static void ViewTradeInventory() { if(LocationDoesNotHaveVendor()) { return; } Console.WriteLine("PLAYER INVENTORY"); Console.WriteLine("================"); if(_player.Inventory.Count(x => x.Price != World.UNSELLABLE_ITEM_PRICE) == 0) { Console.WriteLine("You do not have any inventory"); } else { foreach( InventoryItem inventoryItem in _player.Inventory.Where(x => x.Price != World.UNSELLABLE_ITEM_PRICE)) { Console.WriteLine("{0} {1} Price: {2}", inventoryItem.Quantity, inventoryItem.Description, inventoryItem.Price); } } Console.WriteLine(""); Console.WriteLine("VENDOR INVENTORY"); Console.WriteLine("================"); if(_player.CurrentLocation.VendorWorkingHere.Inventory.Count == 0) { Console.WriteLine("The vendor does not have any inventory"); } else { foreach(InventoryItem inventoryItem in _player.CurrentLocation.VendorWorkingHere.Inventory) { Console.WriteLine("{0} {1} Price: {2}", inventoryItem.Quantity, inventoryItem.Description, inventoryItem.Price); } } } private static void BuyItem(string input) { if(LocationDoesNotHaveVendor()) { return; } string itemName = input.Substring(4).Trim(); if(string.IsNullOrEmpty(itemName)) { Console.WriteLine("You must enter the name of the item to buy"); } else { // Get the InventoryItem from the trader's inventory InventoryItem itemToBuy = _player.CurrentLocation.VendorWorkingHere.Inventory.SingleOrDefault( x => x.Details.Name.ToLower() == itemName); // Check if the vendor has the item if(itemToBuy == null) { Console.WriteLine("The vendor does not have any {0}", itemName); } else { // Check if the player has enough gold to buy the item if(_player.Gold < itemToBuy.Price) { Console.WriteLine("You do not have enough gold to buy a {0}", itemToBuy.Description); } else { // Success! Buy the item _player.AddItemToInventory(itemToBuy.Details); _player.Gold -= itemToBuy.Price; Console.WriteLine("You bought one {0} for {1} gold", itemToBuy.Details.Name, itemToBuy.Price); } } } } private static void SellItem(string input) { if(LocationDoesNotHaveVendor()) { return; } string itemName = input.Substring(5).Trim(); if(string.IsNullOrEmpty(itemName)) { Console.WriteLine("You must enter the name of the item to sell"); } else { // Get the InventoryItem from the player's inventory InventoryItem itemToSell = _player.Inventory.SingleOrDefault(x => x.Details.Name.ToLower() == itemName && x.Quantity > 0 && x.Price != World.UNSELLABLE_ITEM_PRICE); // Check if the player has the item entered if(itemToSell == null) { Console.WriteLine("The player cannot sell any {0}", itemName); } else { // Sell the item _player.RemoveItemFromInventory(itemToSell.Details); _player.Gold += itemToSell.Price; Console.WriteLine("You receive {0} gold for your {1}", itemToSell.Price, itemToSell.Details.Name); } } } private static bool LocationDoesNotHaveVendor() { bool locationDoesNotHaveVendor = _player.CurrentLocation.VendorWorkingHere == null; Console.WriteLine("There is no vendor at this location"); return locationDoesNotHaveVendor; } private static void DisplayCurrentLocation() { Console.WriteLine("You are at: {0}", _player.CurrentLocation.Name); if(_player.CurrentLocation.Description != "") { Console.WriteLine(_player.CurrentLocation.Description); } } private static void LoadGameData() { _player = PlayerDataMapper.CreateFromDatabase(); if(_player == null) { if(File.Exists(PLAYER_DATA_FILE_NAME)) { _player = Player.CreatePlayerFromXmlString(File.ReadAllText(PLAYER_DATA_FILE_NAME)); } else { _player = Player.CreateDefaultPlayer(); } } } private static void SaveGameData() { File.WriteAllText(PLAYER_DATA_FILE_NAME, _player.ToXmlString()); PlayerDataMapper.SaveToDatabase(_player); } } }
REFACTORED CODE
Engine\ViewModels\GameSession.cs
using Engine.Models; namespace Engine.ViewModels { public class GameSession { public Player CurrentPlayer { get; set; } } }
SuperAdventure\SuperAdventure.cs
using System; using System.ComponentModel; using System.Linq; using System.Windows.Forms; using System.IO; using Engine; using Engine.CustomEventArgs; using Engine.Models; using Engine.Utilities; using Engine.ViewModels; namespace SuperAdventure { public partial class SuperAdventure : Form { private const string PLAYER_DATA_FILE_NAME = "PlayerData.xml"; private GameSession _gameSession; public SuperAdventure() { InitializeComponent(); _gameSession = new GameSession(); //_gameSession.CurrentPlayer = PlayerDataMapper.CreateFromDatabase(); if(_gameSession.CurrentPlayer == null) { if(File.Exists(PLAYER_DATA_FILE_NAME)) { _gameSession.CurrentPlayer = Player.CreatePlayerFromXmlString(File.ReadAllText(PLAYER_DATA_FILE_NAME)); } else { _gameSession.CurrentPlayer = Player.CreateDefaultPlayer(); } } _gameSession.CurrentPlayer.AddItemToInventory(World.ItemByID(World.ITEM_ID_CLUB)); lblHitPoints.DataBindings.Add("Text", _gameSession.CurrentPlayer, "CurrentHitPoints"); lblGold.DataBindings.Add("Text", _gameSession.CurrentPlayer, "Gold"); lblExperience.DataBindings.Add("Text", _gameSession.CurrentPlayer, "ExperiencePoints"); lblLevel.DataBindings.Add("Text", _gameSession.CurrentPlayer, "Level"); dgvInventory.RowHeadersVisible = false; dgvInventory.AutoGenerateColumns = false; dgvInventory.DataSource = _gameSession.CurrentPlayer.Inventory; dgvInventory.Columns.Add(new DataGridViewTextBoxColumn { HeaderText = "Name", Width = 197, DataPropertyName = "Description" }); dgvInventory.Columns.Add(new DataGridViewTextBoxColumn { HeaderText = "Quantity", DataPropertyName = "Quantity" }); dgvInventory.ScrollBars = ScrollBars.Vertical; dgvQuests.RowHeadersVisible = false; dgvQuests.AutoGenerateColumns = false; dgvQuests.DataSource = _gameSession.CurrentPlayer.Quests; dgvQuests.Columns.Add(new DataGridViewTextBoxColumn { HeaderText = "Name", Width = 197, DataPropertyName = "Name" }); dgvQuests.Columns.Add(new DataGridViewTextBoxColumn { HeaderText = "Done?", DataPropertyName = "IsCompleted" }); cboWeapons.DataSource = _gameSession.CurrentPlayer.Weapons; cboWeapons.DisplayMember = "Name"; cboWeapons.ValueMember = "Id"; if(_gameSession.CurrentPlayer.CurrentWeapon != null) { cboWeapons.SelectedItem = _gameSession.CurrentPlayer.CurrentWeapon; } cboWeapons.SelectedIndexChanged += cboWeapons_SelectedIndexChanged; cboPotions.DataSource = _gameSession.CurrentPlayer.Potions; cboPotions.DisplayMember = "Name"; cboPotions.ValueMember = "Id"; _gameSession.CurrentPlayer.PropertyChanged += PlayerOnPropertyChanged; _gameSession.CurrentPlayer.OnMessage += DisplayMessage; _gameSession.CurrentPlayer.MoveTo(_gameSession.CurrentPlayer.CurrentLocation); } private void DisplayMessage(object sender, MessageEventArgs messageEventArgs) { rtbMessages.Text += messageEventArgs.Message + Environment.NewLine; if(messageEventArgs.AddExtraNewLine) { rtbMessages.Text += Environment.NewLine; } rtbMessages.SelectionStart = rtbMessages.Text.Length; rtbMessages.ScrollToCaret(); } private void PlayerOnPropertyChanged(object sender, PropertyChangedEventArgs propertyChangedEventArgs) { if (propertyChangedEventArgs.PropertyName == "Weapons") { Weapon previouslySelectedWeapon = _gameSession.CurrentPlayer.CurrentWeapon; cboWeapons.DataSource = _gameSession.CurrentPlayer.Weapons; if (previouslySelectedWeapon != null && _gameSession.CurrentPlayer.Weapons.Exists(w => w.ID == previouslySelectedWeapon.ID)) { cboWeapons.SelectedItem = previouslySelectedWeapon; } if (!_gameSession.CurrentPlayer.Weapons.Any()) { cboWeapons.Visible = false; btnUseWeapon.Visible = false; } } if(propertyChangedEventArgs.PropertyName == "Potions") { cboPotions.DataSource = _gameSession.CurrentPlayer.Potions; if(!_gameSession.CurrentPlayer.Potions.Any()) { cboPotions.Visible = false; btnUsePotion.Visible = false; } } if(propertyChangedEventArgs.PropertyName == "CurrentLocation") { // Show/hide available movement buttons btnNorth.Visible = (_gameSession.CurrentPlayer.CurrentLocation.LocationToNorth != null); btnEast.Visible = (_gameSession.CurrentPlayer.CurrentLocation.LocationToEast != null); btnSouth.Visible = (_gameSession.CurrentPlayer.CurrentLocation.LocationToSouth != null); btnWest.Visible = (_gameSession.CurrentPlayer.CurrentLocation.LocationToWest != null); btnTrade.Visible = (_gameSession.CurrentPlayer.CurrentLocation.VendorWorkingHere != null); // Display current location name and description rtbLocation.Text = _gameSession.CurrentPlayer.CurrentLocation.Name + Environment.NewLine; rtbLocation.Text += _gameSession.CurrentPlayer.CurrentLocation.Description + Environment.NewLine; if(!_gameSession.CurrentPlayer.CurrentLocation.HasAMonster) { cboWeapons.Visible = false; cboPotions.Visible = false; btnUseWeapon.Visible = false; btnUsePotion.Visible = false; } else { cboWeapons.Visible = _gameSession.CurrentPlayer.Weapons.Any(); cboPotions.Visible = _gameSession.CurrentPlayer.Potions.Any(); btnUseWeapon.Visible = _gameSession.CurrentPlayer.Weapons.Any(); btnUsePotion.Visible = _gameSession.CurrentPlayer.Potions.Any(); } } } private void btnNorth_Click(object sender, EventArgs e) { _gameSession.CurrentPlayer.MoveNorth(); } private void btnEast_Click(object sender, EventArgs e) { _gameSession.CurrentPlayer.MoveEast(); } private void btnSouth_Click(object sender, EventArgs e) { _gameSession.CurrentPlayer.MoveSouth(); } private void btnWest_Click(object sender, EventArgs e) { _gameSession.CurrentPlayer.MoveWest(); } private void btnUseWeapon_Click(object sender, EventArgs e) { // Get the currently selected weapon from the cboWeapons ComboBox Weapon currentWeapon = (Weapon)cboWeapons.SelectedItem; _gameSession.CurrentPlayer.UseWeapon(currentWeapon); } private void btnUsePotion_Click(object sender, EventArgs e) { // Get the currently selected potion from the combobox HealingPotion potion = (HealingPotion)cboPotions.SelectedItem; _gameSession.CurrentPlayer.UsePotion(potion); } private void SuperAdventure_FormClosing(object sender, FormClosingEventArgs e) { File.WriteAllText(PLAYER_DATA_FILE_NAME, _gameSession.CurrentPlayer.ToXmlString()); //PlayerDataMapper.SaveToDatabase(_gameSession.CurrentPlayer); } private void cboWeapons_SelectedIndexChanged(object sender, EventArgs e) { _gameSession.CurrentPlayer.CurrentWeapon = (Weapon)cboWeapons.SelectedItem; } private void btnTrade_Click(object sender, EventArgs e) { TradingScreen tradingScreen = new TradingScreen(_gameSession.CurrentPlayer); tradingScreen.StartPosition = FormStartPosition.CenterParent; tradingScreen.ShowDialog(this); } private void btnMap_Click(object sender, EventArgs e) { WorldMap mapScreen = new WorldMap(_gameSession.CurrentPlayer); mapScreen.StartPosition = FormStartPosition.CenterParent; mapScreen.ShowDialog(this); } } }
SuperAdventureConsole\Program.cs (console class)
using System; using System.ComponentModel; using System.IO; using System.Linq; using Engine; using Engine.CustomEventArgs; using Engine.Models; using Engine.Utilities; using Engine.ViewModels; namespace SuperAdventureConsole { public class Program { private const string PLAYER_DATA_FILE_NAME = "PlayerData.xml"; private static GameSession _gameSession; private static void Main() { _gameSession = new GameSession(); // Load the player LoadGameData(); Console.WriteLine("Type 'Help' to see a list of commands"); Console.WriteLine(""); DisplayCurrentLocation(); // Connect player events to functions that will display in the UI _gameSession.CurrentPlayer.PropertyChanged += Player_OnPropertyChanged; _gameSession.CurrentPlayer.OnMessage += Player_OnMessage; // Infinite loop, until the user types "exit" 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") { SaveGameData(); break; } // If the user typed something, try to determine what to do ParseInput(cleanedInput); } } private static void Player_OnPropertyChanged(object sender, PropertyChangedEventArgs e) { if(e.PropertyName == "CurrentLocation") { DisplayCurrentLocation(); if(_gameSession.CurrentPlayer.CurrentLocation.VendorWorkingHere != null) { Console.WriteLine("You see a vendor here: {0}", _gameSession.CurrentPlayer.CurrentLocation.VendorWorkingHere.Name); } } } private static void Player_OnMessage(object sender, MessageEventArgs e) { Console.WriteLine(e.Message); if(e.AddExtraNewLine) { Console.WriteLine(""); } } private static void ParseInput(string input) { if(input.Contains("help") || input == "?") { DisplayHelpText(); } else if(input == "stats") { DisplayPlayerStats(); } else if(input == "look") { DisplayCurrentLocation(); } else if(input.Contains("north")) { if(_gameSession.CurrentPlayer.CurrentLocation.LocationToNorth == null) { Console.WriteLine("You cannot move North"); } else { _gameSession.CurrentPlayer.MoveNorth(); } } else if(input.Contains("east")) { if(_gameSession.CurrentPlayer.CurrentLocation.LocationToEast == null) { Console.WriteLine("You cannot move East"); } else { _gameSession.CurrentPlayer.MoveEast(); } } else if(input.Contains("south")) { if(_gameSession.CurrentPlayer.CurrentLocation.LocationToSouth == null) { Console.WriteLine("You cannot move South"); } else { _gameSession.CurrentPlayer.MoveSouth(); } } else if(input.Contains("west")) { if(_gameSession.CurrentPlayer.CurrentLocation.LocationToWest == null) { Console.WriteLine("You cannot move West"); } else { _gameSession.CurrentPlayer.MoveWest(); } } else if(input == "inventory") { foreach(InventoryItem inventoryItem in _gameSession.CurrentPlayer.Inventory) { Console.WriteLine("{0}: {1}", inventoryItem.Description, inventoryItem.Quantity); } } else if(input == "quests") { if(_gameSession.CurrentPlayer.Quests.Count == 0) { Console.WriteLine("You do not have any quests"); } else { foreach(PlayerQuest playerQuest in _gameSession.CurrentPlayer.Quests) { Console.WriteLine("{0}: {1}", playerQuest.Name, playerQuest.IsCompleted ? "Completed" : "Incomplete"); } } } else if(input.Contains("attack")) { AttackMonster(); } else if(input.StartsWith("equip ")) { EquipWeapon(input); } else if(input.StartsWith("drink ")) { DrinkPotion(input); } else if(input == "trade") { ViewTradeInventory(); } else if(input.StartsWith("buy ")) { BuyItem(input); } else if(input.StartsWith("sell ")) { SellItem(input); } else { Console.WriteLine("I do not understand"); Console.WriteLine("Type 'Help' to see a list of available commands"); } // Write a blank line, to keep the UI a little cleaner 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("Quests - Display your quests"); Console.WriteLine("Attack - Fight the monster"); Console.WriteLine("Equip <weapon name> - Set your current weapon"); Console.WriteLine("Drink <potion name> - Drink a potion"); Console.WriteLine("Trade - display your inventory and vendor's inventory"); Console.WriteLine("Buy <item name> - Buy an item from a vendor"); Console.WriteLine("Sell <item name> - Sell an item to a vendor"); 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("Current hit points: {0}", _gameSession.CurrentPlayer.CurrentHitPoints); Console.WriteLine("Maximum hit points: {0}", _gameSession.CurrentPlayer.MaximumHitPoints); Console.WriteLine("Experience Points: {0}", _gameSession.CurrentPlayer.ExperiencePoints); Console.WriteLine("Level: {0}", _gameSession.CurrentPlayer.Level); Console.WriteLine("Gold: {0}", _gameSession.CurrentPlayer.Gold); } private static void AttackMonster() { if(!_gameSession.CurrentPlayer.CurrentLocation.HasAMonster) { Console.WriteLine("There is nothing here to attack"); } else { if(_gameSession.CurrentPlayer.CurrentWeapon == null) { // Select the first weapon in the player's inventory // (or 'null', if they do not have any weapons) _gameSession.CurrentPlayer.CurrentWeapon = _gameSession.CurrentPlayer.Weapons.FirstOrDefault(); } if(_gameSession.CurrentPlayer.CurrentWeapon == null) { Console.WriteLine("You do not have any weapons"); } else { _gameSession.CurrentPlayer.UseWeapon(_gameSession.CurrentPlayer.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 = _gameSession.CurrentPlayer.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 { _gameSession.CurrentPlayer.CurrentWeapon = weaponToEquip; Console.WriteLine("You equip your {0}", _gameSession.CurrentPlayer.CurrentWeapon.Name); } } } private static void DrinkPotion(string input) { string inputPotionName = input.Substring(6).Trim(); if(string.IsNullOrEmpty(inputPotionName)) { Console.WriteLine("You must enter the name of the potion to drink"); } else { HealingPotion potionToDrink = _gameSession.CurrentPlayer.Potions.SingleOrDefault( x => x.Name.ToLower() == inputPotionName || x.NamePlural.ToLower() == inputPotionName); if(potionToDrink == null) { Console.WriteLine("You do not have the potion: {0}", inputPotionName); } else { _gameSession.CurrentPlayer.UsePotion(potionToDrink); } } } private static void ViewTradeInventory() { if(LocationDoesNotHaveVendor()) { return; } Console.WriteLine("PLAYER INVENTORY"); Console.WriteLine("================"); if(_gameSession.CurrentPlayer.Inventory.Count(x => x.Price != World.UNSELLABLE_ITEM_PRICE) == 0) { Console.WriteLine("You do not have any inventory"); } else { foreach( InventoryItem inventoryItem in _gameSession.CurrentPlayer.Inventory.Where(x => x.Price != World.UNSELLABLE_ITEM_PRICE)) { Console.WriteLine("{0} {1} Price: {2}", inventoryItem.Quantity, inventoryItem.Description, inventoryItem.Price); } } Console.WriteLine(""); Console.WriteLine("VENDOR INVENTORY"); Console.WriteLine("================"); if(_gameSession.CurrentPlayer.CurrentLocation.VendorWorkingHere.Inventory.Count == 0) { Console.WriteLine("The vendor does not have any inventory"); } else { foreach(InventoryItem inventoryItem in _gameSession.CurrentPlayer.CurrentLocation.VendorWorkingHere.Inventory) { Console.WriteLine("{0} {1} Price: {2}", inventoryItem.Quantity, inventoryItem.Description, inventoryItem.Price); } } } private static void BuyItem(string input) { if(LocationDoesNotHaveVendor()) { return; } string itemName = input.Substring(4).Trim(); if(string.IsNullOrEmpty(itemName)) { Console.WriteLine("You must enter the name of the item to buy"); } else { // Get the InventoryItem from the trader's inventory InventoryItem itemToBuy = _gameSession.CurrentPlayer.CurrentLocation.VendorWorkingHere.Inventory.SingleOrDefault( x => x.Details.Name.ToLower() == itemName); // Check if the vendor has the item if(itemToBuy == null) { Console.WriteLine("The vendor does not have any {0}", itemName); } else { // Check if the player has enough gold to buy the item if(_gameSession.CurrentPlayer.Gold < itemToBuy.Price) { Console.WriteLine("You do not have enough gold to buy a {0}", itemToBuy.Description); } else { // Success! Buy the item _gameSession.CurrentPlayer.AddItemToInventory(itemToBuy.Details); _gameSession.CurrentPlayer.Gold -= itemToBuy.Price; Console.WriteLine("You bought one {0} for {1} gold", itemToBuy.Details.Name, itemToBuy.Price); } } } } private static void SellItem(string input) { if(LocationDoesNotHaveVendor()) { return; } string itemName = input.Substring(5).Trim(); if(string.IsNullOrEmpty(itemName)) { Console.WriteLine("You must enter the name of the item to sell"); } else { // Get the InventoryItem from the player's inventory InventoryItem itemToSell = _gameSession.CurrentPlayer.Inventory.SingleOrDefault(x => x.Details.Name.ToLower() == itemName && x.Quantity > 0 && x.Price != World.UNSELLABLE_ITEM_PRICE); // Check if the player has the item entered if(itemToSell == null) { Console.WriteLine("The player cannot sell any {0}", itemName); } else { // Sell the item _gameSession.CurrentPlayer.RemoveItemFromInventory(itemToSell.Details); _gameSession.CurrentPlayer.Gold += itemToSell.Price; Console.WriteLine("You receive {0} gold for your {1}", itemToSell.Price, itemToSell.Details.Name); } } } private static bool LocationDoesNotHaveVendor() { bool locationDoesNotHaveVendor = _gameSession.CurrentPlayer.CurrentLocation.VendorWorkingHere == null; Console.WriteLine("There is no vendor at this location"); return locationDoesNotHaveVendor; } private static void DisplayCurrentLocation() { Console.WriteLine("You are at: {0}", _gameSession.CurrentPlayer.CurrentLocation.Name); if(_gameSession.CurrentPlayer.CurrentLocation.Description != "") { Console.WriteLine(_gameSession.CurrentPlayer.CurrentLocation.Description); } } private static void LoadGameData() { _gameSession.CurrentPlayer = PlayerDataMapper.CreateFromDatabase(); if(_gameSession.CurrentPlayer == null) { if(File.Exists(PLAYER_DATA_FILE_NAME)) { _gameSession.CurrentPlayer = Player.CreatePlayerFromXmlString(File.ReadAllText(PLAYER_DATA_FILE_NAME)); } else { _gameSession.CurrentPlayer = Player.CreateDefaultPlayer(); } } } private static void SaveGameData() { File.WriteAllText(PLAYER_DATA_FILE_NAME, _gameSession.CurrentPlayer.ToXmlString()); PlayerDataMapper.SaveToDatabase(_gameSession.CurrentPlayer); } } }