I'm in the alpha stages of development for my console RPG, and I need some input.
My main question is how should I handle attacks? (You'll see what I mean if you look through my world, item, and enemy classes code.)
Here are some code snippets and a link to my full code. Please note that my latest revision has some unfinished code.
Full code: http://code.google.com/p/escape-text-rpg/source/browse/Escape/
Main Class:
using System; using System.IO; using System.Collections.Generic; using System.Text.RegularExpressions; using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Binary; using System.Diagnostics; using System.Reflection; namespace Escape { class Program { #region Declarations private const int Width = 73; private const int Height = 30; private const string saveFile = "save.dat"; public enum GameStates { Start, Playing, Battle, Quit, GameOver }; public static GameStates GameState = GameStates.Start; private static bool run = true; private static bool isError = false; private static List<string> errors = new List<string>(); private static bool isNotification = false; private static List<string> notifications = new List<string>(); public static Random Rand = new Random(); #endregion #region Main public static void Main(string[] args) { Console.WindowWidth = Width; Console.WindowHeight = Height; Console.BufferWidth = Width; Console.BufferHeight = Height; World.Initialize(); while(run) { if (!isError) { if (Player.Health <= 0) { GameState = GameStates.GameOver; } switch (GameState) { case GameStates.Start: StartState(); break; case GameStates.Playing: PlayingState(); break; case GameStates.Battle: BattleState(); break; case GameStates.Quit: QuitState(); break; case GameStates.GameOver: GameOverState(); break; } } else { DisplayError(); } } } #endregion #region GameState Methods private static void StartState() { Text.WriteLine("Hello adventurer! What is your name?"); Player.Name = Text.SetPrompt("> "); Text.Clear(); GameState = GameStates.Playing; } private static void PlayingState() { if (isNotification) { DisplayNotification(); } World.LocationHUD(); string temp = Text.SetPrompt("[" + World.Map[Player.Location].Name + "] > "); Text.Clear(); Player.Do(temp); } private static void BattleState() { if (isNotification) { DisplayNotification(); } BattleCore.BattleHUD(); } private static void QuitState() { Console.Clear(); Text.WriteColor("`r`/-----------------------------------------------------------------------\\", false); Text.WriteColor("|`w` Are you sure you want to quit? (y/n) `r`|", false); Text.WriteColor("\\-----------------------------------------------------------------------/`w`", false); ConsoleKeyInfo quitKey = Console.ReadKey(); if (quitKey.KeyChar == 'y') { run = false; } else { Text.Clear(); GameState = GameStates.Playing; } } private static void GameOverState() { Console.Clear(); Text.WriteColor("`r`/-----------------------------------------------------------------------\\", false); Text.WriteColor("|`w` Game Over! `r`|", false); Text.WriteColor("|`w` Try again? (y/n) `r`|", false); Text.WriteColor("\\-----------------------------------------------------------------------/`w`", false); ConsoleKeyInfo quitKey = Console.ReadKey(); if (quitKey.KeyChar == 'y') { Process.Start(Assembly.GetExecutingAssembly().Location); run = false; } else { run = false; } } #endregion #region Notification Handling private static void DisplayNotification() { Console.CursorTop = Console.WindowHeight - 1; Text.WriteColor("`g`/-----------------------------------------------------------------------\\", false); foreach (string notification in notifications) { List<string> notificationLines = Text.Limit(string.Format("`g`Alert: `w`" + notification), Console.WindowWidth - 4); foreach (string line in notificationLines) { Text.WriteColor("| `w`" + line + Text.BlankSpaces(Console.WindowWidth - Regex.Replace(line, @"`.`", "").Length - 4, true) + "`g` |", false); } } Text.Write("\\-----------------------------------------------------------------------/"); Console.SetCursorPosition(0, 0); UnsetNotification(); } public static void SetNotification(string message) { notifications.Add(message); isNotification = true; } private static void UnsetNotification() { notifications.Clear(); isNotification = false; } #endregion #region Error Handling private static void DisplayError() { Console.CursorTop = Console.WindowHeight - 1; Text.WriteColor("`r`/-----------------------------------------------------------------------\\", false); foreach (string error in errors) { List<string> errorLines = Text.Limit(string.Format("`r`Error: `w`" + error), Console.WindowWidth - 4); foreach (string line in errorLines) { Text.WriteColor("| `w`" + line + Text.BlankSpaces(Console.WindowWidth - Regex.Replace(line, @"`.`", "").Length - 4, true) + "`r` |", false); } } Text.Write("\\-----------------------------------------------------------------------/"); Console.SetCursorPosition(0, 0); UnsetError(); } public static void SetError(string message) { errors.Add(message); isError = true; } private static void UnsetError() { errors.Clear(); isError = false; } #endregion #region Save and Load public static void Save() { SaveGame saveGame = new SaveGame(); try { using (Stream stream = File.Open(saveFile, FileMode.Create)) { BinaryFormatter bin = new BinaryFormatter(); bin.Serialize(stream, saveGame); } Program.SetNotification("Save Successful!"); } catch (AccessViolationException) { Program.SetError("Save Failed! File access denied."); } catch (Exception) { Program.SetError("Save Failed! An unspecified error occurred."); } } public static void Load() { try { using (Stream stream = File.Open(saveFile, FileMode.Open)) { BinaryFormatter bin = new BinaryFormatter(); SaveGame saveGame = (SaveGame)bin.Deserialize(stream); saveGame.Load(); } Program.SetNotification("Load Successful!"); } catch (FileNotFoundException) { Program.SetError("No savegame exists!"); } catch (AccessViolationException) { Program.SetError("Load failed! File access denied."); } catch (Exception) { Program.SetError("Load failed! An unspecified error occurred."); } } #endregion } } Player Class:
using System; using System.Collections.Generic; namespace Escape { static class Player { #region Declarations public static string Name; public static int Location = 0; public static int MaxHealth = 100; public static int Health = MaxHealth; public static int MaxMagic = 100; public static int Magic = MaxMagic; public static List<int> Inventory = new List<int>(); #endregion #region Public Methods public static void Do(string aString) { if(aString == "") return; string verb = ""; string noun = ""; if (aString.IndexOf(" ") > 0) { string[] temp = aString.Split(new char[] {' '}, 2); verb = temp[0].ToLower(); noun = temp[1].ToLower(); } else { verb = aString.ToLower(); } switch(Program.GameState) { case Program.GameStates.Playing: switch(verb) { case "help": case "?": WriteCommands(); break; case "exit": case "quit": Program.GameState = Program.GameStates.Quit; break; case "move": case "go": MoveTo(noun); break; case "examine": Examine(noun); break; case "take": case "pickup": Pickup(noun); break; case "drop": case "place": Place(noun); break; case "use": Use(noun); break; case "items": case "inventory": case "inv": DisplayInventory(); break; case "attack": //attack command break; case "hurt": Player.Health -= Convert.ToInt32(noun); break; case "save": Program.Save(); break; case "load": Program.Load(); break; default: InputNotValid(); break; } break; case Program.GameStates.Battle: switch(verb) { case "attack": //attack command break; case "flee": case "escape": //flee command break; case "use": //use command break; case "items": case "inventory": case "inv": //items command break; default: InputNotValid(); break; } break; } } public static void RemoveItemFromInventory(int itemId) { if (ItemIsInInventory(itemId)) { Inventory.Remove(itemId); } } #endregion #region Command Methods private static void WriteCommands() { Text.WriteColor("`g`Available Commands:`w`"); Text.WriteColor("help/? - Display this list."); Text.WriteColor("exit/quit - Exit the game."); Text.WriteColor("move/go <`c`location`w`> - Move to the specified location."); Text.WriteColor("examine <`c`item`w`> - Show info about the specified item."); Text.WriteColor("take/pickuip <`c`item`w`> - Put the specified item in your inventory."); Text.WriteColor("drop/place <`c`item`w`> - Drop the specified item from your inventory and place it in the world."); Text.WriteColor("items/inventory/inv - Display your current inventory."); Text.WriteColor("use <`c`item`w`> - Use the specified item."); Text.WriteColor("save/load - saves/loads the game respectively."); Text.BlankLines(); } private static void MoveTo(string locationName) { if (World.IsLocation(locationName)) { int locationId = World.GetLocationIdByName(locationName); if (World.Map[Location].ContainsExit(locationId)) { Location = locationId; World.Map[Location].CalculateRandomBattle(); } else if (Player.Location == locationId) { Program.SetError("You are already there!"); } else { Program.SetError("You can't get there from here!"); } } else { Program.SetError("That isn't a valid location!"); } } private static void Examine(string itemName) { int itemId = World.GetItemIdByName(itemName); if (World.IsItem(itemName)) { if (World.Map[Location].ContainsItem(itemId) || ItemIsInInventory(itemId)) { World.ItemDescription(itemId); } else { Program.SetError("That item isn't here!"); } } else { Program.SetError("That isn't a valid item!"); } } private static void Pickup(string itemName) { if (World.IsItem(itemName)) { int itemId = World.GetItemIdByName(itemName); if (World.Map[Location].ContainsItem(itemId)) { World.Map[Location].Items.Remove(itemId); Inventory.Add(itemId); Program.SetNotification("You put the " + World.Items[itemId].Name + " in your bag!"); } else { Program.SetError("That item isn't here!"); } } else { Program.SetError("That isn't a valid item!"); } } private static void Place(string itemName) { if (World.IsItem(itemName)) { int itemId = World.GetItemIdByName(itemName); if (ItemIsInInventory(itemId)) { Inventory.Remove(itemId); World.Map[Location].Items.Add(itemId); Program.SetNotification("You placed the " + World.Items[itemId].Name + " in the room!"); } else { Program.SetError("You aren't holding that item!"); } } else { Program.SetError("That isn't a valid item!"); } } private static void Use(string itemName) { if (World.IsItem(itemName)) { int itemId = World.GetItemIdByName(itemName); if (ItemIsInInventory(itemId)) { World.Items[itemId].Use(); } else { Program.SetError("You aren't holding that item!"); } } else { Program.SetError("That isn't a valid item!"); } } private static void DisplayInventory() { if (Inventory.Count <= 0) { Program.SetNotification("You aren't carrying anything!"); return; } Text.WriteColor("`m`/-----------------\\"); Text.WriteColor("|`w` Inventory `m`|"); Text.WriteLine(">-----------------<"); for (int i = 0; i < Inventory.Count; i++) { string name = World.Items[Inventory[i]].Name; Text.WriteColor("|`w` " + name + Text.BlankSpaces(16 - name.Length, true) + "`m`|"); } Text.WriteColor("\\-----------------/`w`"); Text.BlankLines(); } #endregion #region Helper Methods private static void InputNotValid() { Program.SetError("That isn't a valid command!"); } private static bool ItemIsInInventory(int itemId) { if (Inventory.Contains(itemId)) return true; else return false; } #endregion } } World Class:
using System; using System.Collections.Generic; namespace Escape { static class World { #region Declarations public static List<Location> Map = new List<Location>(); public static List<Item> Items = new List<Item>(); public static List<Enemy> Enemies = new List<Enemy>(); #endregion #region Initialization public static void Initialize() { GenerateWorld(); GenerateItems(); GenerateEnemies(); } #endregion #region World Generation Methods private static void GenerateWorld() { Map.Add(new Location( "Room 1", "This is a room.", new List<int>() {1}, new List<int>() {0, 2})); Map.Add(new Location( "Room 2", "This is another room.", new List<int>() {0, 2}, new List<int>() {1}, new List<int>() {0}, 50)); Map.Add(new Location( "Room 3", "This is yet another room.", new List<int>() {1}, new List<int>(), new List<int>() {0, 1}, 75)); Map.Add(new Location( "Secret Room", "This is a very awesome secret room.", new List<int>() {2})); } private static void GenerateItems() { Items.Add(new Key( "Brass Key", "Just your generic key thats in almost every game.", 2, 3, true)); Items.Add(new ShinyStone( "Shiny Stone", "Its a stone, and its shiny, what more could you ask for?")); Items.Add(new Rock( "Rock", "It doesn't do anything, however, it is said that the mystical game designer used this for testing.")); } private static void GenerateEnemies() { Enemies.Add(new Rat( "Rat", "Its just a pwesious wittle wat that will KILL YOU!", new List<int>() {10, 3, 5}, new List<int>() {0, 1})); Enemies.Add(new Hawk( "Hawk", "It flies around looking for prey to feed on.", new List<int>() {15, 5, 0}, new List<int>() {2, 3})); } #endregion #region Public Location Methods public static bool IsLocation(string locationName) { for (int i = 0; i < Map.Count; i++) { if (Map[i].Name.ToLower() == locationName.ToLower()) return true; } return false; } public static int GetLocationIdByName(string locationName) { for (int i = 0; i < Map.Count; i++) { if (Map[i].Name.ToLower() == locationName.ToLower()) return i; } return -1; } public static void LocationHUD() { Text.WriteColor("`c`/-----------------------------------------------------------------------\\", false); List<string> locationDesctiption = Text.Limit(Map[Player.Location].Description, Console.WindowWidth - 4); foreach (string line in locationDesctiption) { Text.WriteColor("| `w`" + line + Text.BlankSpaces((Console.WindowWidth - line.Length - 4), true) + "`c` |", false); } Text.WriteColor(">-----------------v-----------------v-----------------v-----------------<", false); Text.WriteColor("| `w`Exits`c` | `w`Items`c` | `w`People`c` | `w`Stats`c` |", false); Text.WriteColor(">-----------------#-----------------#-----------------#-----------------<`w`", false); int currentY = Console.CursorTop; int i; int longestList = 0; for (i = 0; i < Map[Player.Location].Exits.Count; i++) { string name = Map[Map[Player.Location].Exits[i]].Name; Text.WriteColor(" " + name); } longestList = (i > longestList) ? i : longestList; Console.SetCursorPosition(18, currentY); for (i = 0; i < Map[Player.Location].Items.Count; i++) { string name = Items[Map[Player.Location].Items[i]].Name; Text.WriteColor(" " + name); } longestList = (i > longestList) ? i : longestList; Console.SetCursorPosition(36, currentY); for (i = 0; i < Map[Player.Location].Enemies.Count; i++) { string name = Enemies[Map[Player.Location].Enemies[i]].Name; Text.WriteColor(" " + name); } longestList = (i > longestList) ? i : longestList; Console.SetCursorPosition(54, currentY); Text.WriteColor(" HP [`r`" + Text.ToBar(Player.Health, Player.MaxHealth, 10) + "`w`]"); Text.WriteColor(" MP [`g`" + Text.ToBar(Player.Magic, Player.MaxMagic, 10) + "`w`]"); longestList = (2 > longestList) ? 2 : longestList; Console.SetCursorPosition(0, currentY); for (i = 0; i < longestList; i++) { for (int j = 0; j < 4; j++) { Text.WriteColor("`c`|", false); Console.CursorLeft += 17; } Text.Write("|"); Console.CursorLeft = 0; } Text.WriteColor("\\-----------------^-----------------^-----------------^-----------------/`w`"); } #endregion #region Public Item Methods public static bool IsItem(string itemName) { for (int i = 0; i < Items.Count; i++) { if (Items[i].Name.ToLower() == itemName.ToLower()) return true; } return false; } public static int GetItemIdByName(string itemName) { for (int i = 0; i < Items.Count; i++) { if (Items[i].Name.ToLower() == itemName.ToLower()) return i; } return -1; } public static void ItemDescription(int itemId) { Text.WriteLine(Items[itemId].Description); Text.BlankLines(); } #endregion } }