using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace mmoRL { public static class Graphics { public static Image[,] backBuffer = new Image[70, 23]; public static string status = "Press H for help."; public static string statusBuffer = ""; public static void Initialize() { for (int i = 0; i < 70; i++) { for (int ii = 0; ii < 23; ii++) { backBuffer[i, ii] = new Image(" "); } } } //------------------------------ public static void SetStatus(string msg, bool force = false) { bool immediate = true; if (MainClass.map != null) { if (MainClass.map.turnBased && !force) immediate = false; } if (statusBuffer != "") statusBuffer += " "; statusBuffer += msg; if (statusBuffer.Length > 70) statusBuffer = statusBuffer.Substring(statusBuffer.Length - 70); if (!immediate) { status = statusBuffer; while (status.Length < 70) status += " "; } else { status = statusBuffer; while (status.Length < 70) status += " "; statusBuffer = ""; } } //------------------------------ public static void Draw() { //Copy backbuffer for comparison Image[,] oldBackBuffer = new Image[70, 23]; for (int iy = 0; iy < 23; iy++) { for (int ix = 0; ix < 70; ix++) { oldBackBuffer[ix, iy] = backBuffer[ix, iy]; } } if (MainClass.mode == GameMode.IntroScreen) { for (int i = 0; i < 15; i++) { BufferString(0, i, " "); } BufferString(8, 4, "####################################", ConsoleColor.DarkYellow); for (int i = 5; i < 16; i++) { BufferString(8, i, "# #", ConsoleColor.DarkYellow); } BufferString(8, 16, "####################################", ConsoleColor.DarkYellow); //BufferString(20, 5, "-----"); BufferString(21, 6, "mmoRL", ConsoleColor.White); //BufferString(20, 7, "-----"); BufferString(20, 9, "by VDZ"); BufferString(13, 11, "Server: " + MainClass.host + ":" + MainClass.port + ""); BufferString(14, 13, "Press ENTER to start."); BufferString(12, 14, "Press S to change server."); } else if (MainClass.mode == GameMode.Connecting) { } else if (MainClass.mode == GameMode.KeyEntry) { for (int i = 0; i < 15; i++) { BufferString(0, i, " "); } BufferString(8, 4, "#########################################", ConsoleColor.DarkGreen); for (int i = 5; i < 16; i++) { BufferString(8, i, "# #", ConsoleColor.DarkGreen); } BufferString(8, 16, "#########################################", ConsoleColor.DarkGreen); BufferString(15, 6, "Welcome to mmoRL!"); BufferString(10, 8, "Please enter a key to start playing:"); BufferString(23, 10, " "); BufferString(23, 10, Input.enteringString); BufferString(10, 12, "(A key is like a password, allowing"); BufferString(10, 13, " you to log in to your character. If"); BufferString(10, 14, " you are playing for the first time,"); BufferString(10, 15, " just enter a new key.)"); BufferString(3, 18, "NOTE: Keys are sent and stored in plaintext."); BufferString(3, 19, " Don't use one of your passwords as your key."); } else if (MainClass.mode == GameMode.NameEntry) { for (int i = 0; i < 15; i++) { BufferString(0, i, " "); } //BufferString(10, 1, "(Server: " + MainClass.host + ":" + MainClass.port + ")"); //BufferString(5, 2, "(Press enter without entering name to change.)"); BufferString(8, 4, "####################################", ConsoleColor.White); for (int i = 5; i < 12; i++) { BufferString(8, i, "# #", ConsoleColor.White); } BufferString(8, 12, "####################################", ConsoleColor.White); BufferString(15, 6, "NEW CHARACTER"); BufferString(9, 8, "Please enter your name to begin:"); BufferString(23, 10, " "); BufferString(23, 10, Input.enteringString); if (MainClass.failedName) { BufferString(3, 14, "Name is already in use (or belongs to a dead character).", ConsoleColor.Red); } } else if (MainClass.mode == GameMode.ServerChange) { for (int i = 0; i < 15; i++) { BufferString(0, i, " "); } BufferString(8, 4, "########################################", ConsoleColor.Red); for (int i = 5; i < 14; i++) { BufferString(8, i, "# #", ConsoleColor.Red); } BufferString(8, 14, "########################################", ConsoleColor.Red); BufferString(15, 6, "Changing server"); BufferString(10, 8, "Please enter the IP or hostname."); BufferString(10, 9, "Optionally, specify a port with ':'."); BufferString(10, 10, "Example: 'vdzserver.org:51525'"); BufferString(23, 12, " "); BufferString(23, 12, Input.enteringString); } else { //Dead people don't see shit if (!MainClass.dead) { //Draw world for (int iy = 0; iy < 15; iy++) { for (int ix = 0; ix < 70; ix++) { if (MainClass.map != null && !Menu.active) { if (MainClass.map.objects[ix, iy].id != 0) { BufferImage(ix, iy, MainClass.map.objects[ix, iy].image); } else BufferImage(ix, iy, MainClass.map.tiles[ix, iy].image); } else BufferString(ix, iy, " "); } } //Draw items if (MainClass.map != null && !Menu.active) { for (int i = 0; i < MainClass.map.items.Count; i++) { Item item = MainClass.map.items[i]; BufferImage(item.x, item.y, item.image); } } //Draw monsters if (MainClass.map != null && !Menu.active) { for (int i = 0; i < MainClass.map.monsters.Count; i++) { Monster monster = MainClass.map.monsters[i]; BufferImage(monster.x, monster.y, monster.image); } } //Draw loading screen if no map is present if (MainClass.map == null) { BufferString(28, 7, " L O A D I N G ", ConsoleColor.Red); } if (!Menu.active) { //Draw player BufferImage(MainClass.player.x, MainClass.player.y, MainClass.player.image); //Draw other players foreach (KeyValuePair kp in MainClass.otherPlayers) { if (kp.Value.location == MainClass.player.location) { Image toPrint = new Image(kp.Value.image.character, kp.Value.image.color); if (MainClass.partyMembers.Contains(kp.Value.name)) toPrint.color = ConsoleColor.Blue; BufferImage(kp.Value.x, kp.Value.y, toPrint); } } } } //Display YOU ARE DEAD if (MainClass.dead) { for (int iy = 0; iy < 15; iy++) { for (int ix = 0; ix < 70; ix++) { BufferString(ix, iy, " "); } } string deadstring1 = "Y O U A R E D E A D"; string deadstring2 = "-----------------------"; BufferString(35 - (int)(Math.Floor((float)deadstring1.Length / 2f)), 7, deadstring1, ConsoleColor.Red); BufferString(35 - (int)(Math.Floor((float)deadstring2.Length / 2f)), 8, deadstring2, ConsoleColor.Red); } //Town access entry if (MainClass.mode == GameMode.TownEntry) { BufferString(13, 4, "############################################", ConsoleColor.Green); for (int i = 5; i < 12; i++) { BufferString(13, i, "# #", ConsoleColor.Green); } BufferString(13, 12, "############################################", ConsoleColor.Green); BufferString(30, 6, "VISITING TOWN"); BufferString(14, 8, "Please enter the key of the area to visit:"); BufferString(28, 10, " "); BufferString(28, 10, Input.enteringString); } if (Menu.active) BufferMenu(); //Print status BufferString(0, 15, "----------------------------------------------------------------------", ConsoleColor.DarkGray); BufferString(0, 16, status); BufferString(0, 17, "----------------------------------------------------------------------", ConsoleColor.DarkGray); //Print stats ConsoleColor hpColor = ConsoleColor.Green; float hpPerc = (float)MainClass.player.HP / (float)MainClass.player.maxHP; if (hpPerc < 0.6f) hpColor = ConsoleColor.DarkYellow; if (hpPerc < 0.25f) hpColor = ConsoleColor.Red; BufferString(2, 15, "HP: " + MainClass.player.HP + "/" + MainClass.player.maxHP, hpColor); string expString = "EXP: " + MainClass.player.experience; BufferString(68 - expString.Length, 15, expString, ConsoleColor.White); //Print 'waiting for party members...' if (MainClass.waitingForPartyMembers) { BufferString(5, 17, "*WAITING FOR PARTY MEMBERS...*", ConsoleColor.Red); } //Print chat int chatStartValue = MainClass.chatLines.Count - 5; //for (int i = chatStartValue; i < chatStartValue + 6; i++) for (int i = 0; i < 5; i++) { if (i + chatStartValue < MainClass.chatLines.Count && i + chatStartValue > -1) { string[] text = MainClass.chatLines[i + chatStartValue].Split(new string[] { "@" }, StringSplitOptions.None); int curpos = 0; for (int ii = 0; ii < text.Length; ii++) { string part = text[ii]; if (part.Length > 0) { ConsoleColor color = ConsoleColor.Gray; if (ii > 0) { color = HexToColor(part.Substring(0, 1)); part = part.Substring(1); } BufferString(curpos, 18 + i, part, color); curpos += part.Length; } } for (int ii = curpos; ii < 70; ii++) BufferString(ii, 18 + i, " "); } } } //Print screen for (int iy = 0; iy < 23; iy++) { for (int ix = 0; ix < 70; ix++) { if (!backBuffer[ix, iy].IsSame(oldBackBuffer[ix, iy])) PrintGraphic(ix, iy, backBuffer[ix, iy]); } } if (MainClass.mode == GameMode.Looking || MainClass.mode == GameMode.InviteParty) { Console.CursorLeft = MainClass.lookX; Console.CursorTop = MainClass.lookY; } else { Console.CursorLeft = 69; Console.CursorTop = 22; } } public static void BufferImage(int x, int y, Image graphic) { backBuffer[x, y] = graphic; } public static void BufferString(int x, int y, string text, ConsoleColor color = ConsoleColor.Gray) { char[] letters = text.ToCharArray(); for (int i = 0; i < text.Length; i++) { int tx = x + i; if (tx > -1 && tx < 70) { if (y > -1 && y < 23) { backBuffer[tx, y] = new Image(Convert.ToString(letters[i]), color); } } } } public static void PrintGraphic(int x, int y, Image graphic) { Console.CursorLeft = x; Console.CursorTop = y; Console.ForegroundColor = graphic.color; Console.Write(graphic.character); } public static void ClearStatusBuffer() { statusBuffer = ""; //SetStatus("", true); } //------ public static void BufferMenu() { string[] pre = Menu.preText.Split(new string[] { "\n" }, StringSplitOptions.RemoveEmptyEntries); string[] post = Menu.postText.Split(new string[] { "\n" }, StringSplitOptions.RemoveEmptyEntries); StringBuilder emptySB = new StringBuilder(""); for (int i = 0; i < Menu.optionPrefix.Length; i++) emptySB.Append(" "); string emptyPrefix = emptySB.ToString(); int posX = 0; int posY = 0; for (int i = 0; i < pre.Length; i++) { BufferString(posX, posY, pre[i]); posY++; } if (Menu.offset > 0) { BufferString(posX, posY, "(...)"); posY++; } int number = 0; for (int i = 0; i < Menu.numberOfOptions; i++) { if (Menu.offset + i < Menu.options.Count) { string toPrint = Menu.options[i + Menu.offset].description; if (Menu.options[Menu.offset + i].result != -2) { toPrint = Menu.optionPrefix + toPrint; } else { toPrint = emptyPrefix + toPrint; } toPrint = toPrint.Replace("$i", Menu.NumberToLetter(number)); string realPrint = toPrint.Replace("$pic", " "); int maxLineLength = 70; if (realPrint.Length > maxLineLength) //Scrolling { Menu.options[i + Menu.offset].scrollPosition++; if (realPrint.Length - Menu.options[i + Menu.offset].scrollPosition < maxLineLength - 20) { Menu.options[i + Menu.offset].scrollPosition = -20; } int scrollOffset = 0; if (realPrint.Length - Menu.options[i + Menu.offset].scrollPosition < maxLineLength) { scrollOffset = realPrint.Length - maxLineLength; } else if (Menu.options[i + Menu.offset].scrollPosition >= 0) { scrollOffset = Menu.options[i + Menu.offset].scrollPosition; } realPrint = realPrint.Substring(scrollOffset); } BufferString(posX, posY, realPrint, Menu.options[i + Menu.offset].color); if (toPrint.Contains("$pic") && toPrint.IndexOf("$pic") >= Menu.options[i + Menu.offset].scrollPosition) { int menuItemResult = Menu.options[i + Menu.offset].result; if (menuItemResult != -2) { switch (MainClass.mode) { case GameMode.Inventory: case GameMode.DropItem: BufferImage(posX + toPrint.IndexOf("$pic"), posY, MainClass.inventory[i + Menu.offset].image); break; case GameMode.Crafting: BufferImage(posX + toPrint.IndexOf("$pic"), posY, Crafting.recipes[menuItemResult].result.image); break; } } } posY++; if (Menu.options[Menu.offset + i].result != -2) number++; } } if (Menu.options.Count > Menu.offset + Menu.numberOfOptions) { BufferString(posX, posY, "(...)"); posY++; } for (int i = 0; i < post.Length; i++) { BufferString(posX, posY, post[i]); posY++; } } //------ public static ConsoleColor HexToColor(string hex) { switch (hex) { case "0": return ConsoleColor.White; case "1": return ConsoleColor.Black; case "2": return ConsoleColor.DarkBlue; case "3": return ConsoleColor.DarkGreen; case "4": return ConsoleColor.Red; case "5": return ConsoleColor.DarkRed; case "6": return ConsoleColor.DarkCyan; case "b": return ConsoleColor.Blue; } return ConsoleColor.Gray; } } }