-
-
Save ScottLilly/7d28882a8e8a4c49b03f to your computer and use it in GitHub Desktop.
Lesson 22.3 - Creating the SQL to save and load the saved game data
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.ComponentModel; | |
using System.Linq; | |
using System.Text; | |
using System.Threading.Tasks; | |
using System.Xml; | |
namespace Engine | |
{ | |
public class Player : LivingCreature | |
{ | |
private int _gold; | |
private int _experiencePoints; | |
private Location _currentLocation; | |
private Monster _currentMonster; | |
public event EventHandler<MessageEventArgs> OnMessage; | |
public int Gold | |
{ | |
get { return _gold; } | |
set | |
{ | |
_gold = value; | |
OnPropertyChanged("Gold"); | |
} | |
} | |
public int ExperiencePoints | |
{ | |
get { return _experiencePoints; } | |
private set | |
{ | |
_experiencePoints = value; | |
OnPropertyChanged("ExperiencePoints"); | |
OnPropertyChanged("Level"); | |
} | |
} | |
public int Level | |
{ | |
get { return ((ExperiencePoints / 100) + 1); } | |
} | |
public Location CurrentLocation | |
{ | |
get { return _currentLocation; } | |
set | |
{ | |
_currentLocation = value; | |
OnPropertyChanged("CurrentLocation"); | |
} | |
} | |
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<HealingPotion> Potions | |
{ | |
get { return Inventory.Where(x => x.Details is HealingPotion).Select(x => x.Details as HealingPotion).ToList(); } | |
} | |
public BindingList<PlayerQuest> Quests { get; set; } | |
private Player(int currentHitPoints, int maximumHitPoints, int gold, int experiencePoints) : base(currentHitPoints, maximumHitPoints) | |
{ | |
Gold = gold; | |
ExperiencePoints = experiencePoints; | |
Inventory = new BindingList<InventoryItem>(); | |
Quests = new BindingList<PlayerQuest>(); | |
} | |
public static Player CreateDefaultPlayer() | |
{ | |
Player player = new Player(10, 10, 20, 0); | |
player.Inventory.Add(new InventoryItem(World.ItemByID(World.ITEM_ID_RUSTY_SWORD), 1)); | |
player.CurrentLocation = World.LocationByID(World.LOCATION_ID_HOME); | |
return player; | |
} | |
public void AddExperiencePoints(int experiencePointsToAdd ) | |
{ | |
ExperiencePoints += experiencePointsToAdd; | |
MaximumHitPoints = (Level * 10); | |
} | |
public static Player CreatePlayerFromXmlString(string xmlPlayerData) | |
{ | |
try | |
{ | |
XmlDocument playerData = new XmlDocument(); | |
playerData.LoadXml(xmlPlayerData); | |
int currentHitPoints = Convert.ToInt32(playerData.SelectSingleNode("/Player/Stats/CurrentHitPoints").InnerText); | |
int maximumHitPoints = Convert.ToInt32(playerData.SelectSingleNode("/Player/Stats/MaximumHitPoints").InnerText); | |
int gold = Convert.ToInt32(playerData.SelectSingleNode("/Player/Stats/Gold").InnerText); | |
int experiencePoints = Convert.ToInt32(playerData.SelectSingleNode("/Player/Stats/ExperiencePoints").InnerText); | |
Player player = new Player(currentHitPoints, maximumHitPoints, gold, experiencePoints); | |
int currentLocationID = Convert.ToInt32(playerData.SelectSingleNode("/Player/Stats/CurrentLocation").InnerText); | |
player.CurrentLocation = World.LocationByID(currentLocationID); | |
if(playerData.SelectSingleNode("/Player/Stats/CurrentWeapon") != null) | |
{ | |
int currentWeaponID = Convert.ToInt32(playerData.SelectSingleNode("/Player/Stats/CurrentWeapon").InnerText); | |
player.CurrentWeapon = (Weapon)World.ItemByID(currentWeaponID); | |
} | |
foreach(XmlNode node in playerData.SelectNodes("/Player/InventoryItems/InventoryItem")) | |
{ | |
int id = Convert.ToInt32(node.Attributes["ID"].Value); | |
int quantity = Convert.ToInt32(node.Attributes["Quantity"].Value); | |
for(int i = 0; i < quantity; i++) | |
{ | |
player.AddItemToInventory(World.ItemByID(id)); | |
} | |
} | |
foreach(XmlNode node in playerData.SelectNodes("/Player/PlayerQuests/PlayerQuest")) | |
{ | |
int id = Convert.ToInt32(node.Attributes["ID"].Value); | |
bool isCompleted = Convert.ToBoolean(node.Attributes["IsCompleted"].Value); | |
PlayerQuest playerQuest = new PlayerQuest(World.QuestByID(id)); | |
playerQuest.IsCompleted = isCompleted; | |
player.Quests.Add(playerQuest); | |
} | |
return player; | |
} | |
catch | |
{ | |
// If there was an error with the XML data, return a default player object | |
return Player.CreateDefaultPlayer(); | |
} | |
} | |
public static Player CreatePlayerFromDatabase(int currentHitPoints, int maximumHitPoints, int gold, int experiencePoints, int currentLocationID) | |
{ | |
Player player = new Player(currentHitPoints, maximumHitPoints, gold, experiencePoints); | |
player.MoveTo(World.LocationByID(currentLocationID)); | |
return player; | |
} | |
public bool HasRequiredItemToEnterThisLocation(Location location) | |
{ | |
if(location.ItemRequiredToEnter == null) | |
{ | |
// There is no required item for this location, so return "true" | |
return true; | |
} | |
// See if the player has the required item in their inventory | |
return Inventory.Any(ii => ii.Details.ID == location.ItemRequiredToEnter.ID); | |
} | |
public bool HasThisQuest(Quest quest) | |
{ | |
return Quests.Any(pq => pq.Details.ID == quest.ID); | |
} | |
public bool CompletedThisQuest(Quest quest) | |
{ | |
foreach(PlayerQuest playerQuest in Quests) | |
{ | |
if(playerQuest.Details.ID == quest.ID) | |
{ | |
return playerQuest.IsCompleted; | |
} | |
} | |
return false; | |
} | |
public bool HasAllQuestCompletionItems(Quest quest) | |
{ | |
// See if the player has all the items needed to complete the quest here | |
foreach(QuestCompletionItem qci in quest.QuestCompletionItems) | |
{ | |
// Check each item in the player's inventory, to see if they have it, and enough of it | |
if(!Inventory.Any(ii => ii.Details.ID == qci.Details.ID && ii.Quantity >= qci.Quantity)) | |
{ | |
return false; | |
} | |
} | |
// If we got here, then the player must have all the required items, and enough of them, to complete the quest. | |
return true; | |
} | |
public void RemoveQuestCompletionItems(Quest quest) | |
{ | |
foreach(QuestCompletionItem qci in quest.QuestCompletionItems) | |
{ | |
// Subtract the quantity from the player's inventory that was needed to complete the quest | |
InventoryItem item = Inventory.SingleOrDefault(ii => ii.Details.ID == qci.Details.ID); | |
if(item != null) | |
{ | |
RemoveItemFromInventory(item.Details, qci.Quantity); | |
} | |
} | |
} | |
public void AddItemToInventory(Item itemToAdd, int quantity = 1) | |
{ | |
InventoryItem item = Inventory.SingleOrDefault(ii => ii.Details.ID == itemToAdd.ID); | |
if(item == null) | |
{ | |
// They didn't have the item, so add it to their inventory | |
Inventory.Add(new InventoryItem(itemToAdd, quantity)); | |
} | |
else | |
{ | |
// They have the item in their inventory, so increase the quantity | |
item.Quantity += quantity; | |
} | |
RaiseInventoryChangedEvent(itemToAdd); | |
} | |
public void RemoveItemFromInventory(Item itemToRemove, int quantity = 1) | |
{ | |
InventoryItem item = Inventory.SingleOrDefault(ii => ii.Details.ID == itemToRemove.ID); | |
if(item == null) | |
{ | |
// The item is not in the player's inventory, so ignore it. | |
// We might want to raise an error for this situation | |
} | |
else | |
{ | |
// They have the item in their inventory, so decrease the quantity | |
item.Quantity -= quantity; | |
// Don't allow negative quantities. | |
// We might want to raise an error for this situation | |
if(item.Quantity < 0) | |
{ | |
item.Quantity = 0; | |
} | |
// If the quantity is zero, remove the item from the list | |
if(item.Quantity == 0) | |
{ | |
Inventory.Remove(item); | |
} | |
// Notify the UI that the inventory has changed | |
RaiseInventoryChangedEvent(itemToRemove); | |
} | |
} | |
private void RaiseInventoryChangedEvent(Item item) | |
{ | |
if(item is Weapon) | |
{ | |
OnPropertyChanged("Weapons"); | |
} | |
if(item is HealingPotion) | |
{ | |
OnPropertyChanged("Potions"); | |
} | |
} | |
public void MarkQuestCompleted(Quest quest) | |
{ | |
// Find the quest in the player's quest list | |
PlayerQuest playerQuest = Quests.SingleOrDefault(pq => pq.Details.ID == quest.ID); | |
if(playerQuest != null) | |
{ | |
playerQuest.IsCompleted = true; | |
} | |
} | |
private void RaiseMessage(string message, bool addExtraNewLine = false) | |
{ | |
if(OnMessage != null) | |
{ | |
OnMessage(this, new MessageEventArgs(message, addExtraNewLine)); | |
} | |
} | |
public void MoveTo(Location newLocation) | |
{ | |
//Does the location have any required items | |
if(!HasRequiredItemToEnterThisLocation(newLocation)) | |
{ | |
RaiseMessage("You must have a " + newLocation.ItemRequiredToEnter.Name + " to enter this location."); | |
return; | |
} | |
// Update the player's current location | |
CurrentLocation = newLocation; | |
// Completely heal the player | |
CurrentHitPoints = MaximumHitPoints; | |
// Does the location have a quest? | |
if(newLocation.QuestAvailableHere != null) | |
{ | |
// See if the player already has the quest, and if they've completed it | |
bool playerAlreadyHasQuest = HasThisQuest(newLocation.QuestAvailableHere); | |
bool playerAlreadyCompletedQuest = CompletedThisQuest(newLocation.QuestAvailableHere); | |
// See if the player already has the quest | |
if(playerAlreadyHasQuest) | |
{ | |
// If the player has not completed the quest yet | |
if(!playerAlreadyCompletedQuest) | |
{ | |
// See if the player has all the items needed to complete the quest | |
bool playerHasAllItemsToCompleteQuest = HasAllQuestCompletionItems(newLocation.QuestAvailableHere); | |
// The player has all items required to complete the quest | |
if(playerHasAllItemsToCompleteQuest) | |
{ | |
// Display message | |
RaiseMessage(""); | |
RaiseMessage("You complete the '" + newLocation.QuestAvailableHere.Name + "' quest."); | |
// Remove quest items from inventory | |
RemoveQuestCompletionItems(newLocation.QuestAvailableHere); | |
// Give quest rewards | |
RaiseMessage("You receive: "); | |
RaiseMessage(newLocation.QuestAvailableHere.RewardExperiencePoints + " experience points"); | |
RaiseMessage(newLocation.QuestAvailableHere.RewardGold + " gold"); | |
RaiseMessage(newLocation.QuestAvailableHere.RewardItem.Name, true); | |
AddExperiencePoints(newLocation.QuestAvailableHere.RewardExperiencePoints); | |
Gold += newLocation.QuestAvailableHere.RewardGold; | |
// Add the reward item to the player's inventory | |
AddItemToInventory(newLocation.QuestAvailableHere.RewardItem); | |
// Mark the quest as completed | |
MarkQuestCompleted(newLocation.QuestAvailableHere); | |
} | |
} | |
} | |
else | |
{ | |
// The player does not already have the quest | |
// Display the messages | |
RaiseMessage("You receive the " + newLocation.QuestAvailableHere.Name + " quest."); | |
RaiseMessage(newLocation.QuestAvailableHere.Description); | |
RaiseMessage("To complete it, return with:"); | |
foreach(QuestCompletionItem qci in newLocation.QuestAvailableHere.QuestCompletionItems) | |
{ | |
if(qci.Quantity == 1) | |
{ | |
RaiseMessage(qci.Quantity + " " + qci.Details.Name); | |
} | |
else | |
{ | |
RaiseMessage(qci.Quantity + " " + qci.Details.NamePlural); | |
} | |
} | |
RaiseMessage(""); | |
// Add the quest to the player's quest list | |
Quests.Add(new PlayerQuest(newLocation.QuestAvailableHere)); | |
} | |
} | |
// Does the location have a monster? | |
if(newLocation.MonsterLivingHere != null) | |
{ | |
RaiseMessage("You see a " + newLocation.MonsterLivingHere.Name); | |
// Make a new monster, using the values from the standard monster in the World.Monster list | |
Monster standardMonster = World.MonsterByID(newLocation.MonsterLivingHere.ID); | |
_currentMonster = new Monster(standardMonster.ID, standardMonster.Name, standardMonster.MaximumDamage, | |
standardMonster.RewardExperiencePoints, standardMonster.RewardGold, standardMonster.CurrentHitPoints, standardMonster.MaximumHitPoints); | |
foreach(LootItem lootItem in standardMonster.LootTable) | |
{ | |
_currentMonster.LootTable.Add(lootItem); | |
} | |
} | |
else | |
{ | |
_currentMonster = null; | |
} | |
} | |
public void UseWeapon(Weapon weapon) | |
{ | |
// Determine the amount of damage to do to the monster | |
int damageToMonster = RandomNumberGenerator.NumberBetween(weapon.MinimumDamage, weapon.MaximumDamage); | |
// Apply the damage to the monster's CurrentHitPoints | |
_currentMonster.CurrentHitPoints -= damageToMonster; | |
// Display message | |
RaiseMessage("You hit the " + _currentMonster.Name + " for " + damageToMonster + " points."); | |
// Check if the monster is dead | |
if(_currentMonster.CurrentHitPoints <= 0) | |
{ | |
// Monster is dead | |
RaiseMessage(""); | |
RaiseMessage("You defeated the " + _currentMonster.Name); | |
// Give player experience points for killing the monster | |
AddExperiencePoints(_currentMonster.RewardExperiencePoints); | |
RaiseMessage("You receive " + _currentMonster.RewardExperiencePoints + " experience points"); | |
// Give player gold for killing the monster | |
Gold += _currentMonster.RewardGold; | |
RaiseMessage("You receive " + _currentMonster.RewardGold + " gold"); | |
// Get random loot items from the monster | |
List<InventoryItem> lootedItems = new List<InventoryItem>(); | |
// Add items to the lootedItems list, comparing a random number to the drop percentage | |
foreach(LootItem lootItem in _currentMonster.LootTable) | |
{ | |
if(RandomNumberGenerator.NumberBetween(1, 100) <= lootItem.DropPercentage) | |
{ | |
lootedItems.Add(new InventoryItem(lootItem.Details, 1)); | |
} | |
} | |
// If no items were randomly selected, then add the default loot item(s). | |
if(lootedItems.Count == 0) | |
{ | |
foreach(LootItem lootItem in _currentMonster.LootTable) | |
{ | |
if(lootItem.IsDefaultItem) | |
{ | |
lootedItems.Add(new InventoryItem(lootItem.Details, 1)); | |
} | |
} | |
} | |
// Add the looted items to the player's inventory | |
foreach(InventoryItem inventoryItem in lootedItems) | |
{ | |
AddItemToInventory(inventoryItem.Details); | |
if(inventoryItem.Quantity == 1) | |
{ | |
RaiseMessage("You loot " + inventoryItem.Quantity + " " + inventoryItem.Details.Name); | |
} | |
else | |
{ | |
RaiseMessage("You loot " + inventoryItem.Quantity + " " + inventoryItem.Details.NamePlural); | |
} | |
} | |
// Add a blank line to the messages box, just for appearance. | |
RaiseMessage(""); | |
// Move player to current location (to heal player and create a new monster to fight) | |
MoveTo(CurrentLocation); | |
} | |
else | |
{ | |
// Monster is still alive | |
// Determine the amount of damage the monster does to the player | |
int damageToPlayer = RandomNumberGenerator.NumberBetween(0, _currentMonster.MaximumDamage); | |
// Display message | |
RaiseMessage("The " + _currentMonster.Name + " did " + damageToPlayer + " points of damage."); | |
// Subtract damage from player | |
CurrentHitPoints -= damageToPlayer; | |
if(CurrentHitPoints <= 0) | |
{ | |
// Display message | |
RaiseMessage("The " + _currentMonster.Name + " killed you."); | |
// Move player to "Home" | |
MoveHome(); | |
} | |
} | |
} | |
public void UsePotion(HealingPotion potion) | |
{ | |
// Add healing amount to the player's current hit points | |
CurrentHitPoints = (CurrentHitPoints + potion.AmountToHeal); | |
// CurrentHitPoints cannot exceed player's MaximumHitPoints | |
if(CurrentHitPoints > MaximumHitPoints) | |
{ | |
CurrentHitPoints = MaximumHitPoints; | |
} | |
// Remove the potion from the player's inventory | |
RemoveItemFromInventory(potion, 1); | |
// Display message | |
RaiseMessage("You drink a " + potion.Name); | |
// Monster gets their turn to attack | |
// Determine the amount of damage the monster does to the player | |
int damageToPlayer = RandomNumberGenerator.NumberBetween(0, _currentMonster.MaximumDamage); | |
// Display message | |
RaiseMessage("The " + _currentMonster.Name + " did " + damageToPlayer + " points of damage."); | |
// Subtract damage from player | |
CurrentHitPoints -= damageToPlayer; | |
if(CurrentHitPoints <= 0) | |
{ | |
// Display message | |
RaiseMessage("The " + _currentMonster.Name + " killed you."); | |
// Move player to "Home" | |
MoveHome(); | |
} | |
} | |
private void MoveHome() | |
{ | |
MoveTo(World.LocationByID(World.LOCATION_ID_HOME)); | |
} | |
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 string ToXmlString() | |
{ | |
XmlDocument playerData = new XmlDocument(); | |
// Create the top-level XML node | |
XmlNode player = playerData.CreateElement("Player"); | |
playerData.AppendChild(player); | |
// Create the "Stats" child node to hold the other player statistics nodes | |
XmlNode stats = playerData.CreateElement("Stats"); | |
player.AppendChild(stats); | |
// Create the child nodes for the "Stats" node | |
XmlNode currentHitPoints = playerData.CreateElement("CurrentHitPoints"); | |
currentHitPoints.AppendChild(playerData.CreateTextNode(this.CurrentHitPoints.ToString())); | |
stats.AppendChild(currentHitPoints); | |
XmlNode maximumHitPoints = playerData.CreateElement("MaximumHitPoints"); | |
maximumHitPoints.AppendChild(playerData.CreateTextNode(this.MaximumHitPoints.ToString())); | |
stats.AppendChild(maximumHitPoints); | |
XmlNode gold = playerData.CreateElement("Gold"); | |
gold.AppendChild(playerData.CreateTextNode(this.Gold.ToString())); | |
stats.AppendChild(gold); | |
XmlNode experiencePoints = playerData.CreateElement("ExperiencePoints"); | |
experiencePoints.AppendChild(playerData.CreateTextNode(this.ExperiencePoints.ToString())); | |
stats.AppendChild(experiencePoints); | |
XmlNode currentLocation = playerData.CreateElement("CurrentLocation"); | |
currentLocation.AppendChild(playerData.CreateTextNode(this.CurrentLocation.ID.ToString())); | |
stats.AppendChild(currentLocation); | |
if(CurrentWeapon != null) | |
{ | |
XmlNode currentWeapon = playerData.CreateElement("CurrentWeapon"); | |
currentWeapon.AppendChild(playerData.CreateTextNode(this.CurrentWeapon.ID.ToString())); | |
stats.AppendChild(currentWeapon); | |
} | |
// Create the "InventoryItems" child node to hold each InventoryItem node | |
XmlNode inventoryItems = playerData.CreateElement("InventoryItems"); | |
player.AppendChild(inventoryItems); | |
// Create an "InventoryItem" node for each item in the player's inventory | |
foreach(InventoryItem item in this.Inventory) | |
{ | |
XmlNode inventoryItem = playerData.CreateElement("InventoryItem"); | |
XmlAttribute idAttribute = playerData.CreateAttribute("ID"); | |
idAttribute.Value = item.Details.ID.ToString(); | |
inventoryItem.Attributes.Append(idAttribute); | |
XmlAttribute quantityAttribute = playerData.CreateAttribute("Quantity"); | |
quantityAttribute.Value = item.Quantity.ToString(); | |
inventoryItem.Attributes.Append(quantityAttribute); | |
inventoryItems.AppendChild(inventoryItem); | |
} | |
// Create the "PlayerQuests" child node to hold each PlayerQuest node | |
XmlNode playerQuests = playerData.CreateElement("PlayerQuests"); | |
player.AppendChild(playerQuests); | |
// Create a "PlayerQuest" node for each quest the player has acquired | |
foreach(PlayerQuest quest in this.Quests) | |
{ | |
XmlNode playerQuest = playerData.CreateElement("PlayerQuest"); | |
XmlAttribute idAttribute = playerData.CreateAttribute("ID"); | |
idAttribute.Value = quest.Details.ID.ToString(); | |
playerQuest.Attributes.Append(idAttribute); | |
XmlAttribute isCompletedAttribute = playerData.CreateAttribute("IsCompleted"); | |
isCompletedAttribute.Value = quest.IsCompleted.ToString(); | |
playerQuest.Attributes.Append(isCompletedAttribute); | |
playerQuests.AppendChild(playerQuest); | |
} | |
return playerData.InnerXml; // The XML document, as a string, so we can save the data to disk | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Data; | |
using System.Data.SqlClient; | |
namespace Engine | |
{ | |
public static class PlayerDataMapper | |
{ | |
private static readonly string _connectionString = "Data Source=(local);Initial Catalog=SuperAdventure;Integrated Security=True"; | |
public static Player CreateFromDatabase() | |
{ | |
try | |
{ | |
// This is our connection to the database | |
using(SqlConnection connection = new SqlConnection(_connectionString)) | |
{ | |
// Open the connection, so we can perform SQL commands | |
connection.Open(); | |
Player player; | |
// Create a SQL command object, that uses the connection to our database | |
// The SqlCommand object is where we create our SQL statement | |
using(SqlCommand savedGameCommand = connection.CreateCommand()) | |
{ | |
savedGameCommand.CommandType = CommandType.Text; | |
// This SQL statement reads the first rows in teh SavedGame table. | |
// For this program, we should only ever have one row, | |
// but this will ensure we only get one record in our SQL query results. | |
savedGameCommand.CommandText = "SELECT TOP 1 * FROM SavedGame"; | |
// Use ExecuteReader when you expect the query to return a row, or rows | |
SqlDataReader reader = savedGameCommand.ExecuteReader(); | |
// Check if the query did not return a row/record of data | |
if(!reader.HasRows) | |
{ | |
// There is no data in the SavedGame table, | |
// so return null (no saved player data) | |
return null; | |
} | |
// Get the row/record from the data reader | |
reader.Read(); | |
// Get the column values for the row/record | |
int currentHitPoints = (int)reader["CurrentHitPoints"]; | |
int maximumHitPoints = (int)reader["MaximumHitPoints"]; | |
int gold = (int)reader["Gold"]; | |
int experiencePoints = (int)reader["ExperiencePoints"]; | |
int currentLocationID = (int)reader["CurrentLocationID"]; | |
// Create the Player object, with the saved game values | |
player = Player.CreatePlayerFromDatabase(currentHitPoints, maximumHitPoints, gold, | |
experiencePoints, currentLocationID); | |
} | |
// Read the rows/records from the Quest table, and add them to the player | |
using(SqlCommand questCommand = connection.CreateCommand()) | |
{ | |
questCommand.CommandType = CommandType.Text; | |
questCommand.CommandText = "SELECT * FROM Quest"; | |
SqlDataReader reader = questCommand.ExecuteReader(); | |
if(reader.HasRows) | |
{ | |
while(reader.Read()) | |
{ | |
int questID = (int)reader["QuestID"]; | |
bool isCompleted = (bool)reader["IsCompleted"]; | |
// Build the PlayerQuest item, for this row | |
PlayerQuest playerQuest = new PlayerQuest(World.QuestByID(questID)); | |
playerQuest.IsCompleted = isCompleted; | |
// Add the PlayerQuest to the player's property | |
player.Quests.Add(playerQuest); | |
} | |
} | |
} | |
// Read the rows/records from the Inventory table, and add them to the player | |
using(SqlCommand inventoryCommand = connection.CreateCommand()) | |
{ | |
inventoryCommand.CommandType = CommandType.Text; | |
inventoryCommand.CommandText = "SELECT * FROM Inventory"; | |
SqlDataReader reader = inventoryCommand.ExecuteReader(); | |
if(reader.HasRows) | |
{ | |
while(reader.Read()) | |
{ | |
int inventoryItemID = (int)reader["InventoryItemID"]; | |
int quantity = (int)reader["Quantity"]; | |
// Add the item to the player's inventory | |
player.AddItemToInventory(World.ItemByID(inventoryItemID), quantity); | |
} | |
} | |
} | |
// Now that the player has been built from the database, return it. | |
return player; | |
} | |
} | |
catch(Exception ex) | |
{ | |
// Ignore errors. If there is an error, this function will return a "null" player. | |
} | |
return null; | |
} | |
public static void SaveToDatabase(Player player) | |
{ | |
try | |
{ | |
using(SqlConnection connection = new SqlConnection(_connectionString)) | |
{ | |
// Open the connection, so we can perform SQL commands | |
connection.Open(); | |
// Insert/Update data in SavedGame table | |
using(SqlCommand existingRowCountCommand = connection.CreateCommand()) | |
{ | |
existingRowCountCommand.CommandType = CommandType.Text; | |
existingRowCountCommand.CommandText = "SELECT count(*) FROM SavedGame"; | |
// Use ExecuteScalar when your query will return one value | |
int existingRowCount = (int)existingRowCountCommand.ExecuteScalar(); | |
if(existingRowCount == 0) | |
{ | |
// There is no existing row, so do an INSERT | |
using(SqlCommand insertSavedGame = connection.CreateCommand()) | |
{ | |
insertSavedGame.CommandType = CommandType.Text; | |
insertSavedGame.CommandText = | |
"INSERT INTO SavedGame " + | |
"(CurrentHitPoints, MaximumHitPoints, Gold, ExperiencePoints, CurrentLocationID) " + | |
"VALUES " + | |
"(@CurrentHitPoints, @MaximumHitPoints, @Gold, @ExperiencePoints, @CurrentLocationID)"; | |
// Pass the values from the player object, to the SQL query, using parameters | |
insertSavedGame.Parameters.Add("@CurrentHitPoints", SqlDbType.Int); | |
insertSavedGame.Parameters["@CurrentHitPoints"].Value = player.CurrentHitPoints; | |
insertSavedGame.Parameters.Add("@MaximumHitPoints", SqlDbType.Int); | |
insertSavedGame.Parameters["@MaximumHitPoints"].Value = player.MaximumHitPoints; | |
insertSavedGame.Parameters.Add("@Gold", SqlDbType.Int); | |
insertSavedGame.Parameters["@Gold"].Value = player.Gold; | |
insertSavedGame.Parameters.Add("@ExperiencePoints", SqlDbType.Int); | |
insertSavedGame.Parameters["@ExperiencePoints"].Value = player.ExperiencePoints; | |
insertSavedGame.Parameters.Add("@CurrentLocationID", SqlDbType.Int); | |
insertSavedGame.Parameters["@CurrentLocationID"].Value = player.CurrentLocation.ID; | |
// Perform the SQL command. | |
// Use ExecuteNonQuery, because this query does not return any results. | |
insertSavedGame.ExecuteNonQuery(); | |
} | |
} | |
else | |
{ | |
// There is an existing row, so do an UPDATE | |
using(SqlCommand updateSavedGame = connection.CreateCommand()) | |
{ | |
updateSavedGame.CommandType = CommandType.Text; | |
updateSavedGame.CommandText = | |
"UPDATE SavedGame " + | |
"SET CurrentHitPoints = @CurrentHitPoints, " + | |
"MaximumHitPoints = @MaximumHitPoints, " + | |
"Gold = @Gold, " + | |
"ExperiencePoints = @ExperiencePoints, "+ | |
"CurrentLocationID = @CurrentLocationID"; | |
// Pass the values from the player object, to the SQL query, using parameters | |
// Using parameters helps make your program more secure. | |
// It will prevent SQL injection attacks. | |
updateSavedGame.Parameters.Add("@CurrentHitPoints", SqlDbType.Int); | |
updateSavedGame.Parameters["@CurrentHitPoints"].Value = player.CurrentHitPoints; | |
updateSavedGame.Parameters.Add("@MaximumHitPoints", SqlDbType.Int); | |
updateSavedGame.Parameters["@MaximumHitPoints"].Value = player.MaximumHitPoints; | |
updateSavedGame.Parameters.Add("@Gold", SqlDbType.Int); | |
updateSavedGame.Parameters["@Gold"].Value = player.Gold; | |
updateSavedGame.Parameters.Add("@ExperiencePoints", SqlDbType.Int); | |
updateSavedGame.Parameters["@ExperiencePoints"].Value = player.ExperiencePoints; | |
updateSavedGame.Parameters.Add("@CurrentLocationID", SqlDbType.Int); | |
updateSavedGame.Parameters["@CurrentLocationID"].Value = player.CurrentLocation.ID; | |
// Perform the SQL command. | |
// Use ExecuteNonQuery, because this query does not return any results. | |
updateSavedGame.ExecuteNonQuery(); | |
} | |
} | |
} | |
// The Quest and Inventory tables might have more, or less, rows in the database | |
// than what the player has in their properties. | |
// So, when we save the player's game, we will delete all the old rows | |
// and add in all new rows. | |
// This is easier than trying to add/delete/update each individual rows | |
// Delete existing Quest rows | |
using(SqlCommand deleteQuestsCommand = connection.CreateCommand()) | |
{ | |
deleteQuestsCommand.CommandType = CommandType.Text; | |
deleteQuestsCommand.CommandText = "DELETE FROM Quest"; | |
deleteQuestsCommand.ExecuteNonQuery(); | |
} | |
// Insert Quest rows, from the player object | |
foreach(PlayerQuest playerQuest in player.Quests) | |
{ | |
using(SqlCommand insertQuestCommand = connection.CreateCommand()) | |
{ | |
insertQuestCommand.CommandType = CommandType.Text; | |
insertQuestCommand.CommandText = "INSERT INTO Quest (QuestID, IsCompleted) VALUES (@QuestID, @IsCompleted)"; | |
insertQuestCommand.Parameters.Add("@QuestID", SqlDbType.Int); | |
insertQuestCommand.Parameters["@QuestID"].Value = playerQuest.Details.ID; | |
insertQuestCommand.Parameters.Add("@IsCompleted", SqlDbType.Bit); | |
insertQuestCommand.Parameters["@IsCompleted"].Value = playerQuest.IsCompleted; | |
insertQuestCommand.ExecuteNonQuery(); | |
} | |
} | |
// Delete existing Inventory rows | |
using(SqlCommand deleteInventoryCommand = connection.CreateCommand()) | |
{ | |
deleteInventoryCommand.CommandType = CommandType.Text; | |
deleteInventoryCommand.CommandText = "DELETE FROM Inventory"; | |
deleteInventoryCommand.ExecuteNonQuery(); | |
} | |
// Insert Inventory rows, from the player object | |
foreach(InventoryItem inventoryItem in player.Inventory) | |
{ | |
using(SqlCommand insertInventoryCommand = connection.CreateCommand()) | |
{ | |
insertInventoryCommand.CommandType = CommandType.Text; | |
insertInventoryCommand.CommandText = "INSERT INTO Inventory (InventoryItemID, Quantity) VALUES (@InventoryItemID, @Quantity)"; | |
insertInventoryCommand.Parameters.Add("@InventoryItemID", SqlDbType.Int); | |
insertInventoryCommand.Parameters["@InventoryItemID"].Value = inventoryItem.Details.ID; | |
insertInventoryCommand.Parameters.Add("@Quantity", SqlDbType.Int); | |
insertInventoryCommand.Parameters["@Quantity"].Value = inventoryItem.Quantity; | |
insertInventoryCommand.ExecuteNonQuery(); | |
} | |
} | |
} | |
} | |
catch(Exception ex) | |
{ | |
// We are going to ignore erros, for now. | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.ComponentModel; | |
using System.Data; | |
using System.Drawing; | |
using System.Linq; | |
using System.Text; | |
using System.Threading.Tasks; | |
using System.Windows.Forms; | |
using System.IO; | |
using Engine; | |
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(); | |
} | |
} | |
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" | |
}); | |
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") | |
{ | |
cboWeapons.DataSource = _player.Weapons; | |
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.MonsterLivingHere == null) | |
{ | |
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); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment