// 01 basic setup // rogue at its simplest and most readable // player can move around dungeon, bump into walls, // pick up gold and items, kill monsters, and // use the stairs // random bits of level, monsters, gold, and items // placed randomly in the dungeon // help screen shows how to deal with fullscreen // commands like inventory and discoveries using System; class Program { static THING player = new THING(); static bool found_amulet = false; static Random random = new Random(); static void Main(string[] args) { Console.WindowWidth = Console.BufferWidth = 80; Console.WindowHeight = Console.BufferHeight = 25; Console.Title = "steelgolem rogue - 01 basic setup"; CONSOLE.clear(); dungeon_level = 1; new_level(); update_status(); while (true) { // put cursor under player to highlight CONSOLE.move_cursor(player.x, player.y); char key_ch = CONSOLE.read_key(); switch(key_ch) { case '?': show_help(); break; case 'h': move_player(-1, 0); break; case 'j': move_player(0, +1); break; case 'k': move_player(0, -1); break; case 'l': move_player(+1, 0); break; case 'y': move_player(-1, -1); break; case 'u': move_player(+1, -1); break; case 'b': move_player(-1, +1); break; case 'n': move_player(+1, +1); break; case '>': if (player.under_ch == '%') { if (found_amulet && dungeon_level == 1) win_game(); if (found_amulet) dungeon_level--; else dungeon_level++; new_level(); update_status(); } else { if (found_amulet) set_message("there is no way up"); else set_message("there is no way down"); } break; case (char)18: // ^R set_message(last_message); break; case 'Q': Environment.Exit(0); break; } } } #region dungeon level static int dungeon_level; static void new_level() { CONSOLE.clear(); // add some random level bits for (int c = 0; c < 80; c++) { int x = random.Next(80); int y = 1 + random.Next(23); char ch = "-|.+#"[random.Next(5)]; CONSOLE.put_char(x, y, ch); } // add some gold for (int c = 0; c < 9; c++) { int x = random.Next(80); int y = 1 + random.Next(23); CONSOLE.put_char(x, y, '*'); } // add some items for (int c = 0; c < 9; c++) { int x = random.Next(80); int y = 1 + random.Next(23); char ch = ":!?)]=/"[random.Next(7)]; CONSOLE.put_char(x, y, ch); } // add some monsters for (int c = 0; c < 9; c++) { int x = random.Next(80); int y = 1 + random.Next(23); char ch = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"[random.Next(26)]; CONSOLE.put_char(x, y, ch); } // add the amulet if (dungeon_level >= 26) { int x = random.Next(80); int y = 1 + random.Next(23); CONSOLE.put_char(x, y, ','); } // add the stairs int stairs_x = random.Next(80); int stairs_y = 1 + random.Next(23); CONSOLE.put_char(stairs_x, stairs_y, '%'); // place the player player.x = random.Next(80); player.y = 1 + random.Next(23); player.under_ch = ' '; player.draw(); } #endregion // dungeon level #region commands static void show_help() { string[] help_text = new string[] { "? show help", "h move left", "j move down", "k move up", "l move right", "y move up & left", "u move up & right", "b move down & left", "n move down & right", "> use stairs", "^R repeat last message", "Q quit game", }; CONSOLE.back_up_buffer(); CONSOLE.clear(); for (int h = 0; h < help_text.Length; h++) CONSOLE.write_string(0, h, help_text[h]); CONSOLE.write_string(0, 24, "[press any key]"); CONSOLE.read_key(); CONSOLE.restore_buffer(); } static void move_player(int dx, int dy) { clear_message(); int dest_x = player.x + dx; int dest_y = player.y + dy; char dest_ch = CONSOLE.get_char(dest_x, dest_y); // walls stop movement if (is_wall(dest_ch)) return; // fight monster if (is_monster(dest_ch)) { CONSOLE.put_char(dest_x, dest_y, ' '); set_message("defeated " + get_name(dest_ch)); return; } player.erase(); player.get_eraser(dest_x, dest_y); player.x = dest_x; player.y = dest_y; player.draw(); // pick up gold if (dest_ch == '*') { player.under_ch = ' '; set_message("picked up gold"); } // pick up item if (is_item(dest_ch)) { player.under_ch = ' '; set_message("picked up " + get_name(dest_ch)); if (dest_ch == ',') found_amulet = true; } } #endregion // commands #region helper functions static bool is_wall(char ch) { return "-|".Contains(ch.ToString()); } static bool is_monster(char ch) { return char.IsLetter(ch); } static bool is_item(char ch) { return ":!?)]=/,".Contains(ch.ToString()); } static string get_name(char dest_ch) { switch (dest_ch) { case 'A': return "giant ant"; case 'B': return "bat"; case 'C': return "centaur"; case 'D': return "dragon"; case 'E': return "floating eye"; case 'F': return "violet fungi"; case 'G': return "gnome"; case 'H': return "hobgoblin"; case 'I': return "invisible stalker"; case 'J': return "jackal"; case 'K': return "kobold"; case 'L': return "leprechaun"; case 'M': return "mimic"; case 'N': return "nymph"; case 'O': return "orc"; case 'P': return "purple worm"; case 'Q': return "quasit"; case 'R': return "rust monster"; case 'S': return "snake"; case 'T': return "troll"; case 'U': return "umber hulk"; case 'V': return "vampire"; case 'W': return "wraith"; case 'X': return "xorn"; case 'Y': return "yeti"; case 'Z': return "zombie"; case ':': return "food"; case '!': return "potion"; case '?': return "scroll"; case ')': return "weapon"; case ']': return "armor"; case '=': return "ring"; case '/': return "stick"; case ',': return "the amulet of yendor"; default: return null; } } static void update_status() { clear_status(); CONSOLE.write_string(0, 24, "level: " + dungeon_level); } #endregion // helper functions #region messages static string last_message = ""; static void set_message(string text) { CONSOLE.write_string(0, 0, text); last_message = text; } static void clear_message() { CONSOLE.cursor_off(); CONSOLE.write_string(0, 0, "".PadRight(80)); CONSOLE.cursor_on(); } static void clear_status() { CONSOLE.write_string(0, 24, "".PadRight(79)); } #endregion // messages #region game over static void win_game() { CONSOLE.clear(); CONSOLE.write_string("you win"); CONSOLE.read_key(); Environment.Exit(0); } #endregion // game over } class THING { public int x, y; public char under_ch; public void get_eraser(int x, int y) { this.under_ch = CONSOLE.get_char(x, y); } public void erase() { CONSOLE.put_char(this.x, this.y, this.under_ch); } public void draw() { CONSOLE.put_char(this.x, this.y, '@'); } } class CONSOLE { static char[,] buffer = new char[80, 25]; static int cursor_x, cursor_y; public static char get_char(int x, int y) { return buffer[x, y]; } public static void put_char(char ch) { buffer[cursor_x, cursor_y] = ch; cursor_x++; if (cursor_x == 80) { cursor_x = 0; cursor_y++; } Console.Write(ch); } public static void put_char(int x, int y, char ch) { move_cursor(x, y); put_char(ch); } public static void move_cursor(int x, int y) { cursor_x = x; cursor_y = y; Console.SetCursorPosition(x, y); } public static char read_key() { return Console.ReadKey(true).KeyChar; } public static void write_string(string text) { for (int c = 0; c < text.Length; c++) put_char(text[c]); } public static void write_string(int x, int y, string text) { move_cursor(x, y); write_string(text); } public static void cursor_on() { Console.CursorVisible = true; } public static void cursor_off() { Console.CursorVisible = false; } public static void clear() { for (int y = 0; y < 25; y++) for (int x = 0; x < 80; x++) buffer[x, y] = ' '; cursor_x = cursor_y = 0; Console.Clear(); } static char[,] old_buffer = new char[80, 25]; public static void back_up_buffer() { Array.Copy(CONSOLE.buffer, old_buffer, 80 * 25); } public static void restore_buffer() { Array.Copy(old_buffer, CONSOLE.buffer, 80 * 25); for (int y = 0; y < 25; y++) for (int x = 0; x < 80; x++) if (!(x == 79 && y == 24)) CONSOLE.put_char(x, y, CONSOLE.buffer[x, y]); } }