using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; namespace mmoRL { public enum GameMode { Default, Chat, Destroying, Inventory, Crafting, NameEntry, TextScreen, DropItem, Quitting, ServerChange, Looking, InviteParty, LeaveParty, DisbandParty, Dead, Learning, IntroScreen, KeyEntry, Connecting, TownEntry, SignEntry } public enum RepeatType { None, Craft, Use } class MainClass { public static int UPDATE_INTERVAL = 50; public static string DEFAULT_STATUS_MESSAGE = ""; public const int DEFAULT_PORT = 51525; public static Client client; public static bool running = true; public static Player player = new Player(new Image("@", ConsoleColor.DarkYellow)); public static float timecount = 0.0f; public static Map map = null; public static List chatLines = new List(); public static GameMode mode = GameMode.Default; public static Dictionary otherPlayers = new Dictionary(); public static int myID = -1; public static List inventory = new List(); public static string partyLeader = ""; public static List partyMembers = new List(); public static bool waitingForPartyMembers = false; public static RepeatType repeat = RepeatType.None; public static int repeatParameter = 0; public static int lookX = 0; public static int lookY = 0; public static bool actionLock = false; public static bool dead = false; public static bool failedName = false; public static bool waterWalking = false; public static string host = "vdzserver.org"; public static int port = DEFAULT_PORT; public static int CURRENTVERSION = 2; static void Main(string[] args) { Console.Clear(); Initialize(); ThreadPool.QueueUserWorkItem(new WaitCallback(delegate { while (running) { Thread.Sleep(UPDATE_INTERVAL); Update(); Graphics.Draw(); } })); while (running) { ConsoleKeyInfo key = Console.ReadKey(true); Input.StoreKey(key); } } public static void Initialize() { Console.Title = "mmoRL"; Graphics.Initialize(); Crafting.Initialize(); player.name = ""; mode = GameMode.IntroScreen; } public static void StartGame() { mode = GameMode.Default; MainClass.Chat("Press H for help."); } public static void MoveDirection(int x, int y) { int targetX = player.x + x; int targetY = player.y + y; MoveTo(targetX, targetY); } public static List GetItemsAtPosition(int x, int y) { List toReturn = new List(); for (int i = 0; i < map.items.Count; i++) { if (map.items[i].x == x && map.items[i].y == y) { Item foundItem = null; for (int ii = 0; ii < toReturn.Count; ii++) { if (toReturn[ii].id == map.items[i].id) foundItem = toReturn[ii]; } if (foundItem == null) { Item item = new Item(map.items[i].id); item.amount = map.items[i].amount; toReturn.Add(item); } else { foundItem.amount += map.items[i].amount; } } } return toReturn; } public static Monster GetMonsterAtPosition(int x, int y) { Monster monsterAtLoc = null; if (map != null) { for (int i = 0; i < map.monsters.Count; i++) { if (monsterAtLoc == null) { if (map.monsters[i].x == x && map.monsters[i].y == y) monsterAtLoc = map.monsters[i]; } } } return monsterAtLoc; } public static void MoveTo(int x, int y) { if (map != null) { if (x > -1 && x < 70 && y > -1 && y < 15) { Monster targetMonster = GetMonsterAtPosition(x, y); if (targetMonster != null) { client.AttackEnemy(targetMonster.x, targetMonster.y, targetMonster.name); } else { bool canPass = true; Tile targetTile = map.tiles[x, y]; Object targetObject = map.objects[x, y]; if (targetTile.solid) { canPass = false; if (waterWalking && (targetTile.id == 3 || targetTile.id == 8)) canPass = true; } if (targetObject.solid) canPass = false; if (map.turnBased) { foreach(KeyValuePair kp in otherPlayers) { if (kp.Value.location == player.location) { if (kp.Value.x == x && kp.Value.y == 1) canPass = false; } } } if (canPass) { if (map.turnBased) { client.LockAction(); } //Success! player.x = x; player.y = y; client.SendPosition(x, y); Graphics.SetStatus(DEFAULT_STATUS_MESSAGE); List atYourFeet = GetItemsAtPosition(x, y); if (atYourFeet.Count > 0) { string atFeetString = "There is "; for (int i = 0; i < atYourFeet.Count; i++) { if (i != 0) { if (i != atYourFeet.Count - 1) { atFeetString += ", "; } else atFeetString += " and "; } atFeetString += atYourFeet[i].Describe(); } atFeetString += " at your feet."; Graphics.SetStatus(atFeetString); } } } } } } //----------------------------- public static void DescribeLocation(int x, int y) { string targetStatus = ""; //Describe yourself if present if (x == player.x && y == player.y) { targetStatus = "You see yourself."; } else { //Describe other player if present string thatPlayer = ""; //for (int i = 0; i < otherPlayers.Count; i++) foreach (KeyValuePair kp in otherPlayers) { if (kp.Value.location == player.location) { if (kp.Value.x == x && kp.Value.y == y) { thatPlayer = kp.Value.name; } } } if (thatPlayer != "") { targetStatus = "You see " + thatPlayer + "."; } else { //Else describe monster if present Monster monsterAtLoc = GetMonsterAtPosition(x, y); if (monsterAtLoc != null) { targetStatus = "You see a " + monsterAtLoc.name + "."; } else { //Else describe items if present List atLocation = GetItemsAtPosition(x, y); if (atLocation.Count > 0) { string itemText = ""; for (int i = 0; i < atLocation.Count; i++) { if (i != 0) { if (i != atLocation.Count - 1) { itemText += ", "; } else { itemText += " and "; } } itemText += atLocation[i].Describe(); } targetStatus = "You see " + itemText + " on the ground."; } else { //Else describe objects if present Object thatObject = map.objects[x, y]; if (thatObject.id != 0) { if (thatObject.id == 38) //Sign { targetStatus = "The sign reads: '" + thatObject.text + "'"; } else { targetStatus = "You see a " + thatObject.name.ToLower() + "."; } } else { //Else just describe the ground. targetStatus = "You see " + map.tiles[x, y].name + "."; } } } } } targetStatus += " (Z to exit look mode)"; if (targetStatus.Length > 70) targetStatus = targetStatus.Substring(0, 70); Graphics.SetStatus(targetStatus, true); } public static void ActivateChat() { mode = GameMode.Chat; Graphics.SetStatus("Chat: ", true); Input.enteringString = ""; } public static void EndStringEntry(string msg) { switch(mode) { case GameMode.Chat: if(msg != "") client.SendChat(msg); MainClass.ReturnToMain(); Graphics.SetStatus(DEFAULT_STATUS_MESSAGE); break; case GameMode.NameEntry: if (msg != "") { player.name = msg; client.SendName(); } else { //Don't accept it, simple } break; case GameMode.ServerChange: try { host = msg; if (msg.Contains(":")) { string[] split = msg.Split(new string[] { ":" }, StringSplitOptions.None); host = split[0]; port = Convert.ToInt32(split[1]); } else port = DEFAULT_PORT; Input.enteringString = ""; mode = GameMode.IntroScreen; } catch { } break; case GameMode.KeyEntry: if (msg != "") { mode = GameMode.Connecting; Console.Clear(); Console.ForegroundColor = ConsoleColor.White; Console.WriteLine(""); Console.WriteLine("Identifying..."); client.SendKey(msg); } else { //Don't accept it, simple } break; case GameMode.TownEntry: if (msg != "") { ReturnToMain(); MainClass.moveToArea(msg, true); } else { ReturnToMain(); } break; } } public static void moveToArea(string area, bool isTown = false) { client.mapLock = true; map = null; if (isTown) { MainClass.player.x = 35; MainClass.player.y = 14; MainClass.client.SendPosition(MainClass.player.x, MainClass.player.y, true); Graphics.SetStatus("You enter the area.", true); client.RequestTown(area); } else { client.RequestMap(area); } } public static void StartDestroying() { if (map.canDestroy) { mode = GameMode.Destroying; Graphics.SetStatus("Destroy in which direction?", true); } else { Graphics.SetStatus("You cannot destroy anything in this location.", true); } } public static void ChooseDirection(int x, int y, bool cancel = false) { switch (mode) { case GameMode.Destroying: if (cancel) { Graphics.SetStatus("Canceled destroying.", true); } else { int targetX = player.x + x; int targetY = player.y + y; if (targetX < 0 || targetX > 69 || targetY < 0 || targetY > 14) { Graphics.SetStatus("Out of bounds. Please destroy something inside the area instead.", true); } else { Object targetObject = map.objects[targetX, targetY]; if (targetObject.id == 0) { Graphics.SetStatus("There is nothing to destroy there.", true); } else if (targetObject.indestructible) { Graphics.SetStatus("You cannot destroy that object.", true); } else { int resultItem = -1; switch (targetObject.id) { case 1: resultItem = 1; break; //Tree case 4: resultItem = 19; break; //Rock case 18: resultItem = 22; break; //Lavarock case 19: resultItem = 23; break; //Sandrock case 20: resultItem = 24; break; //Darkrock case 5: resultItem = 19; break; //Stone wall = stone } if (resultItem != -1) { client.AddItem(targetX, targetY, resultItem); } Graphics.SetStatus("Destroyed the " + targetObject.name.ToLower() + "."); client.ChangeObject(targetX, targetY, 0); client.SkipTurn(); } } } MainClass.ReturnToMain(); break; } } public static void TakeItem(Item item, int x, int y) { map.RemoveItem(x, y, item.id); client.RemoveItem(x, y, item.id); client.SkipTurn(); AddItem(item); } public static void AddItem(Item item, bool silent = false) { bool added = false; for (int i = 0; i < inventory.Count; i++) { if (!added) { if (inventory[i].id == item.id) { inventory[i].AddAmount(item.amount); added = true; } } } if (!added) { inventory.Add(item); } if (!silent) { client.AddItem(item); } } public static void RemoveItem(Item originalItem, int amount = 1) { RemoveItem(originalItem.id, amount); } public static void RemoveItem(int id, int amount = 1) { Item item = null; for (int i = 0; i < inventory.Count; i++) { if (id == inventory[i].id) item = inventory[i]; } if (item != null) { item.amount -= amount; if (item.amount == 0) { inventory.Remove(item); } } client.RemoveItem(id); } public static bool UseItem(int number) { if (number < inventory.Count) { Item item = inventory[number]; switch (item.type) { case ItemType.Placeable: if (map.canBuild) { if (!map.objects[player.x, player.y].indestructible) { repeat = RepeatType.Use; repeatParameter = item.id; client.ChangeObject(player.x, player.y, item.parameter1); Graphics.SetStatus("You placed the " + item.name.ToLower() + "."); RemoveItem(item); client.SkipTurn(); return true; } else { Graphics.SetStatus("You cannot build over indestructible objects.", true); } } else { Graphics.SetStatus("You cannot build anything in this location.", true); } break; case ItemType.Material: Graphics.SetStatus("You can use the materials through the crafting menu.", true); break; case ItemType.Discovery: Graphics.SetStatus("Discovering...", true); client.DiscoverSkill(item); return true; case ItemType.Equipment: if (item.equipped) { Graphics.SetStatus("Unequipping...", true); item.equipped = false; client.UnEquip(item.id); CheckWaterWalking(); } else { Graphics.SetStatus("Equipping...", true); client.Equip(item.id); } return true; case ItemType.Magic: repeat = RepeatType.Use; repeatParameter = item.id; player.experience += 10; client.GainXP(10); Graphics.SetStatus("The magic fuses with your skin. You feel more experienced.", true); RemoveItem(item); client.SkipTurn(); return true; default: Graphics.SetStatus("There is no way to use the " + item.Describe() + ".", true); break; } } return false; } public static bool HasItem(Item item, int amount = 1) { return HasItem(item.id, amount); } public static bool HasItem(int id, int amount = 1) { for (int i = 0; i < inventory.Count; i++) { if (inventory[i].id == id) { if (inventory[i].amount >= amount) return true; } } return false; } public static void Chat(string chatLine) { string hours = DateTime.Now.Hour.ToString(); string minutes = DateTime.Now.Minute.ToString(); if (hours.Length < 2) hours = "0" + hours; if (minutes.Length < 2) minutes = "0" + minutes; MainClass.chatLines.Add("[" + hours + ":" + minutes + "] " + chatLine); } public static void MenuChoice(int number) { bool finished = false; switch (mode) { case GameMode.Inventory: if (number != -1 && Menu.options.Count > number) { if (Menu.options[number].result != -2) { if (UseItem(number)) { finished = true; } } } else finished = true; break; case GameMode.Crafting: if (Menu.options.Count > number) { if (number != -1) { //if (Menu.options[originalNumber].result != -1 && Menu.options[originalNumber].result != -2) if (Menu.options[number].result != -1 && Menu.options[number].result != -2) { //Crafting.Craft(Crafting.recipes[Menu.options[originalNumber].result]); Crafting.Craft(Crafting.recipes[Menu.options[number].result]); repeat = RepeatType.Craft; repeatParameter = Menu.options[number].result; finished = true; } } else { finished = true; } } break; case GameMode.Learning: if (Menu.options.Count > number) { if (number != -1) { if (Menu.options[number].result != -2) { if (Skill.GetSkill(Menu.options[number].result).expCost > player.experience) { Graphics.SetStatus("You do not have enough experience to learn that.", true); } else { client.LearnSkill(Menu.options[number].result); finished = true; } } } else { finished = true; } } break; case GameMode.TextScreen: if (number == -1) finished = true; break; case GameMode.DropItem: if (Menu.options.Count > number) { if (number != -1) { if (inventory.Count > number) { Item item = inventory[number]; if (!item.equipped) { RemoveItem(item); client.AddItem(player.x, player.y, item.id); Graphics.SetStatus("You dropped a " + item.name + "."); client.SkipTurn(); finished = true; } else { Graphics.SetStatus("Please unequip the item first.", true); } } } else finished = true; } break; case GameMode.Quitting: if (Menu.options.Count > number) { if (number == -1 || number == 0) { finished = true; } else { Console.Clear(); System.Threading.Thread.Sleep(1000); Console.WriteLine("Press any key to exit."); running = false; } } break; } if (finished) { MainClass.ReturnToMain(); Menu.active = false; } } public static void Crash(string message) { MainClass.running = false; System.Threading.Thread.Sleep(2 * MainClass.UPDATE_INTERVAL); Console.WriteLine("FATAL ERROR: " + message); Console.WriteLine(" Press enter to exit."); Console.ReadLine(); Environment.Exit(0); } public static void ReturnToMain() { if (!dead) { mode = GameMode.Default; } else { mode = GameMode.Dead; } } public static void CheckWaterWalking() { waterWalking = false; for (int i = 0; i < inventory.Count; i++) { if (inventory[i].equipped) { if (inventory[i].id == 69) waterWalking = true; } } } //------------------------------------- public static bool AddOtherPlayer(int id) { if (!otherPlayers.ContainsKey(id)) { if (id != myID) { otherPlayers.Add(id, new Player(new Image("@", ConsoleColor.Magenta))); return true; } else { return false; } } return true; } public static void RemoveOtherPlayer(int id) { otherPlayers.Remove(id); } public static void Update() { Input.HandleKeys(); switch (mode) { case GameMode.Chat: Graphics.SetStatus("Chat: " + Input.enteringString, true); break; } timecount += (float)UPDATE_INTERVAL / 1000f; //Graphics.status = Convert.ToString(timecount); if(client != null) client.DoUpdate(); } } }