SteelGolem

02 uncovering the map in rogue

Apr 1st, 2021 (edited)
728
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 20.27 KB | None | 0 0
  1. // 02 uncover map
  2.  
  3. // hide everything on the map and uncover it as the player roams
  4. // makes 3x3 rooms with 1 gold pile and 1 monster each
  5. // lit rooms light up when player walks in
  6. // can discover traps
  7.  
  8. using System;
  9. using System.Collections.Generic;
  10.  
  11. class Program
  12. {
  13.     static List<ITEM> items_on_floor;
  14.  
  15.     static List<THING> monsters;
  16.  
  17.     static THING player = new THING();
  18.  
  19.     static bool found_amulet = false;
  20.  
  21.     static Random random = new Random();
  22.  
  23.     static void Main(string[] args)
  24.     {
  25.         Console.WindowWidth = Console.BufferWidth = 80;
  26.         Console.WindowHeight = Console.BufferHeight = 25;
  27.         Console.Title = "steelgolem rogue - 02 uncover map";
  28.  
  29.         CONSOLE.clear();
  30.  
  31.         dungeon_level = 1;
  32.         new_level();
  33.  
  34.         update_status();
  35.  
  36.         while (true)
  37.         {
  38.             // put cursor under player to highlight
  39.             CONSOLE.move_cursor(player.x, player.y);
  40.  
  41.             char key_ch = CONSOLE.read_key();
  42.  
  43.             switch (key_ch)
  44.             {
  45.                 case '?': show_help(); break;
  46.  
  47.                 case 'h': move_player(-1, 0); break;
  48.                 case 'j': move_player(0, +1); break;
  49.                 case 'k': move_player(0, -1); break;
  50.                 case 'l': move_player(+1, 0); break;
  51.                 case 'y': move_player(-1, -1); break;
  52.                 case 'u': move_player(+1, -1); break;
  53.                 case 'b': move_player(-1, +1); break;
  54.                 case 'n': move_player(+1, +1); break;
  55.  
  56.                 case '>':
  57.                     if (dungeon_map[player.x, player.y] == '%')
  58.                     {
  59.                         if (found_amulet && dungeon_level == 1)
  60.                             win_game();
  61.  
  62.                         if (found_amulet) dungeon_level--;
  63.                         else dungeon_level++;
  64.  
  65.                         new_level();
  66.                         update_status();
  67.                     }
  68.                     else
  69.                     {
  70.                         if (found_amulet) set_message("there is no way up");
  71.                         else set_message("there is no way down");
  72.                     }
  73.                     break;
  74.  
  75.                 case (char)18: // ^R
  76.                     set_message(last_message);
  77.                     break;
  78.  
  79.                 case 'Q':
  80.                     Environment.Exit(0);
  81.                     break;
  82.             }
  83.         }
  84.     }
  85.  
  86.     #region dungeon level
  87.  
  88.     static int dungeon_level;
  89.  
  90.     static char[,] dungeon_map = new char[80, 25];
  91.  
  92.     static ROOM[,] rooms;
  93.  
  94.     const int room_max_w = 80 / 3;
  95.     const int room_max_h = 23 / 3;
  96.  
  97.     static List<TRAP> traps;
  98.  
  99.     static void new_level()
  100.     {
  101.         items_on_floor = new List<ITEM>();
  102.  
  103.         monsters = new List<THING>();
  104.  
  105.         traps = new List<TRAP>();
  106.  
  107.         for (int y = 0; y < 25; y++)
  108.             for (int x = 0; x < 80; x++)
  109.                 dungeon_map[x, y] = ' ';
  110.  
  111.         CONSOLE.clear();
  112.  
  113.         // add 3x3 rooms
  114.         rooms = new ROOM[3, 3];
  115.         for (int ry = 0; ry < 3; ry++)
  116.         {
  117.             for (int rx = 0; rx < 3; rx++)
  118.             {
  119.                 ROOM room = new ROOM();
  120.                 room.w = 4 + random.Next(room_max_w - 4);
  121.                 room.h = 4 + random.Next(room_max_h - 4);
  122.                 room.x = rx * room_max_w +
  123.                     random.Next(room_max_w - room.w);
  124.                 room.y = 1 + ry * room_max_h +
  125.                     random.Next(room_max_h - room.h);
  126.                 if (random.Next(100) < 50)
  127.                     room.is_lit = true;
  128.                 rooms[rx, ry] = room;
  129.  
  130.                 room.draw_on_map();
  131.                 // one door at the bottom
  132.                 dungeon_map[room.x + room.w / 2, room.y + room.h - 1] = '+';
  133.             }
  134.         }
  135.  
  136.         // add some random level bits
  137.         for (int c = 0; c < 80; c++)
  138.         {
  139.             int x = random.Next(80);
  140.             int y = 1 + random.Next(23);
  141.             char ch = "-|.+#"[random.Next(5)];
  142.             dungeon_map[x, y] = ch;
  143.         }
  144.  
  145.         // add some traps
  146.         for (int t = 0; t < 9; t++)
  147.         {
  148.             TRAP trap = new TRAP();
  149.             do
  150.             {
  151.                 ROOM room = get_random_room();
  152.                 room.set_random_pos(trap);
  153.             }
  154.             while (dungeon_map[trap.x, trap.y] != '.');
  155.             trap.ch = ">{$}~`"[random.Next(6)];
  156.             dungeon_map[trap.x, trap.y] = trap.ch;
  157.             traps.Add(trap);
  158.         }
  159.  
  160.         // add some gold
  161.         for (int ry = 0; ry < 3; ry++)
  162.         {
  163.             for (int rx = 0; rx < 3; rx++)
  164.             {
  165.                 ROOM room = rooms[rx, ry];
  166.                 ITEM item = new ITEM();
  167.                 do room.set_random_pos(item);
  168.                 while (dungeon_map[item.x, item.y] != '.');
  169.                 item.ch = '*';
  170.                 items_on_floor.Add(item);
  171.             }
  172.         }
  173.  
  174.         // add some items
  175.         for (int c = 0; c < 9; c++)
  176.         {
  177.             ITEM item = new ITEM();
  178.             do
  179.             {
  180.                 ROOM room = get_random_room();
  181.                 room.set_random_pos(item);
  182.             }
  183.             while (dungeon_map[item.x, item.y] != '.');
  184.             item.ch = ":!?)]=/"[random.Next(7)];
  185.             items_on_floor.Add(item);
  186.         }
  187.  
  188.         // add some monsters
  189.         for (int ry = 0; ry < 3; ry++)
  190.         {
  191.             for (int rx = 0; rx < 3; rx++)
  192.             {
  193.                 ROOM room = rooms[rx, ry];
  194.                 THING monster = new THING();
  195.                 do room.set_random_pos(monster);
  196.                 while (dungeon_map[monster.x, monster.y] != '.');
  197.                 monster.ch = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"[random.Next(26)];
  198.                 monsters.Add(monster);
  199.             }
  200.         }
  201.  
  202.         // add the amulet
  203.         if (dungeon_level >= 26)
  204.         {
  205.             ITEM item = new ITEM();
  206.             do
  207.             {
  208.                 ROOM room = get_random_room();
  209.                 room.set_random_pos(item);
  210.             }
  211.             while (dungeon_map[item.x, item.y] != '.');
  212.             item.ch = ',';
  213.             items_on_floor.Add(item);
  214.         }
  215.  
  216.         // add the stairs
  217.         int stairs_x = -1, stairs_y = -1;
  218.         do
  219.         {
  220.             ROOM room = get_random_room();
  221.             room.set_random_pos(ref stairs_x, ref stairs_y);
  222.         }
  223.         while (dungeon_map[stairs_x, stairs_y] != '.');
  224.         dungeon_map[stairs_x, stairs_y] = '%';
  225.  
  226.         // place the player
  227.         do
  228.         {
  229.             ROOM room = get_random_room();
  230.             room.set_random_pos(player);
  231.         }
  232.         while (dungeon_map[player.x, player.y] != '.');
  233.         draw_what_player_can_see();
  234.     }
  235.  
  236.     static ROOM get_random_room()
  237.     {
  238.         return rooms[random.Next(3), random.Next(3)];
  239.     }
  240.  
  241.     class ROOM
  242.     {
  243.         public int x, y, w, h;
  244.         public bool is_lit;
  245.  
  246.         public void draw_on_map()
  247.         {
  248.             for (int y = 0; y < this.h; y++)
  249.                 for (int x = 0; x < this.w; x++)
  250.                     dungeon_map[this.x + x, this.y + y] = '.';
  251.  
  252.             for (int y = 0; y < this.h; y++)
  253.             {
  254.                 dungeon_map[this.x, this.y + y] = '|';
  255.                 dungeon_map[this.x + this.w - 1, this.y + y] = '|';
  256.             }
  257.  
  258.             for (int x = 0; x < this.w; x++)
  259.             {
  260.                 dungeon_map[this.x + x, this.y] = '-';
  261.                 dungeon_map[this.x + x, this.y + this.h - 1] = '-';
  262.             }
  263.         }
  264.  
  265.         public void set_random_pos(ref int x, ref int y)
  266.         {
  267.             x = this.x + 1 + random.Next(this.w - 2);
  268.             y = this.y + 1 + random.Next(this.h - 2);
  269.         }
  270.  
  271.         public void set_random_pos(ITEM item)
  272.         {
  273.             set_random_pos(ref item.x, ref item.y);
  274.         }
  275.  
  276.         public void set_random_pos(THING thing)
  277.         {
  278.             set_random_pos(ref thing.x, ref thing.y);
  279.         }
  280.  
  281.         public void set_random_pos(TRAP trap)
  282.         {
  283.             set_random_pos(ref trap.x, ref trap.y);
  284.         }
  285.     }
  286.  
  287.     class TRAP
  288.     {
  289.         public int x, y;
  290.         public char ch;
  291.         public bool found;
  292.     }
  293.  
  294.     #endregion // dungeon level
  295.  
  296.     #region commands
  297.  
  298.     static void show_help()
  299.     {
  300.         string[] help_text = new string[]
  301.         {
  302.             "?    show help",
  303.             "h    move left",
  304.             "j    move down",
  305.             "k    move up",
  306.             "l    move right",
  307.             "y    move up & left",
  308.             "u    move up & right",
  309.             "b    move down & left",
  310.             "n    move down & right",
  311.             ">    use stairs",
  312.             "^R   repeat last message",
  313.             "Q    quit game",
  314.         };
  315.  
  316.         CONSOLE.back_up_buffer();
  317.  
  318.         CONSOLE.clear();
  319.  
  320.         for (int h = 0; h < help_text.Length; h++)
  321.             CONSOLE.write_string(0, h, help_text[h]);
  322.  
  323.         CONSOLE.write_string(0, 24, "[press any key]");
  324.  
  325.         CONSOLE.read_key();
  326.  
  327.         CONSOLE.restore_buffer();
  328.     }
  329.  
  330.     static void move_player(int dx, int dy)
  331.     {
  332.         clear_message();
  333.  
  334.         int dest_x = player.x + dx;
  335.         int dest_y = player.y + dy;
  336.         char map_ch = dungeon_map[dest_x, dest_y];
  337.  
  338.         // walls stop movement
  339.         if (is_wall(map_ch))
  340.             return;
  341.  
  342.         // fight monster
  343.         for (int m = monsters.Count - 1; m >= 0; m--)
  344.         {
  345.             THING monster = monsters[m];
  346.  
  347.             if (dest_x == monster.x && dest_y == monster.y)
  348.             {
  349.                 monsters.Remove(monster);
  350.  
  351.                 draw_what_player_can_see();
  352.  
  353.                 set_message("defeated " + get_name(monster.ch));
  354.  
  355.                 return;
  356.             }
  357.         }
  358.  
  359.         erase_what_player_cant_see();
  360.  
  361.         player.x = dest_x;
  362.         player.y = dest_y;
  363.  
  364.         draw_what_player_can_see();
  365.  
  366.         // pick up item
  367.         for (int i = items_on_floor.Count - 1; i >= 0; i--)
  368.         {
  369.             ITEM item = items_on_floor[i];
  370.  
  371.             if (dest_x == item.x && dest_y == item.y)
  372.             {
  373.                 if (player.items.Count == 23)
  374.                 {
  375.                     set_message("no room in inventory");
  376.                     return;
  377.                 }
  378.  
  379.                 set_message("picked up " + get_name(item.ch));
  380.  
  381.                 items_on_floor.Remove(item);
  382.  
  383.                 player.items.Add(item);
  384.  
  385.                 if (item.ch == ',')
  386.                     found_amulet = true;
  387.             }
  388.         }
  389.  
  390.         // get trapped
  391.         for (int t = 0; t < traps.Count; t++)
  392.         {
  393.             TRAP trap = traps[t];
  394.  
  395.             if (dest_x == trap.x && dest_y == trap.y)
  396.             {
  397.                 trap.found = true;
  398.                 string message = "found ";
  399.                 switch (trap.ch)
  400.                 {
  401.                     case '>': message += "trap door"; break;
  402.                     case '{': message += "arrow trap"; break;
  403.                     case '$': message += "sleep trap"; break;
  404.                     case '}': message += "bear trap"; break;
  405.                     case '~': message += "teleport trap"; break;
  406.                     case '`': message += "dart trap"; break;
  407.                 }
  408.                 set_message(message);
  409.             }
  410.         }
  411.     }
  412.  
  413.     static void draw_what_player_can_see()
  414.     {
  415.         ROOM room = null;
  416.  
  417.         // without this line, we redraw the room and
  418.         //      everything in it every time we move
  419.         //      (is this actually perfectly fine?)
  420.         //if (dungeon_map[player.x, player.y] == '+')
  421.         room = get_room_at(player.x, player.y);
  422.  
  423.         if (room != null && room.is_lit)
  424.         {
  425.             for (int ry = 0; ry < room.h; ry++)
  426.             {
  427.                 for (int rx = 0; rx < room.w; rx++)
  428.                 {
  429.                     int x = room.x + rx;
  430.                     int y = room.y + ry;
  431.                     if (">{$}~`".Contains(dungeon_map[x, y].ToString()))
  432.                     {
  433.                         TRAP trap = get_trap_at(x, y);
  434.                         if (trap.found)
  435.                             CONSOLE.put_char(x, y, '^');
  436.                         else
  437.                             CONSOLE.put_char(x, y, '.');
  438.                     }
  439.                     else
  440.                         CONSOLE.put_char(x, y, dungeon_map[x, y]);
  441.                 }
  442.             }
  443.  
  444.             for (int i = 0; i < items_on_floor.Count; i++)
  445.             {
  446.                 ITEM item = items_on_floor[i];
  447.                 if (get_room_at(item.x, item.y) == room)
  448.                     CONSOLE.put_char(item.x, item.y, item.ch);
  449.             }
  450.  
  451.             for (int m = 0; m < monsters.Count; m++)
  452.             {
  453.                 THING monster = monsters[m];
  454.                 if (get_room_at(monster.x, monster.y) == room)
  455.                     CONSOLE.put_char(monster.x, monster.y, monster.ch);
  456.             }
  457.  
  458.             CONSOLE.put_char(player.x, player.y, '@');
  459.         }
  460.  
  461.         // 3x3 area around player
  462.         for (int dy = -1; dy <= +1; dy++)
  463.         {
  464.             for (int dx = -1; dx <= +1; dx++)
  465.             {
  466.                 int x = player.x + dx;
  467.                 int y = player.y + dy;
  468.  
  469.                 if (x < 0 || x >= 80 || y < 0 || y >= 25) continue;
  470.  
  471.                 CONSOLE.put_char(x, y, dungeon_map[x, y]);
  472.  
  473.                 if (">{$}~`".Contains(dungeon_map[x, y].ToString()))
  474.                 {
  475.                     TRAP trap = get_trap_at(x, y);
  476.                     if (trap.found)
  477.                         CONSOLE.put_char(x, y, '^');
  478.                     else
  479.                         CONSOLE.put_char(x, y, '.');
  480.                 }
  481.  
  482.                 for (int i = 0; i < items_on_floor.Count; i++)
  483.                     if (x == items_on_floor[i].x &&
  484.                         y == items_on_floor[i].y)
  485.                         CONSOLE.put_char(x, y, items_on_floor[i].ch);
  486.  
  487.                 for (int m = 0; m < monsters.Count; m++)
  488.                     if (x == monsters[m].x &&
  489.                         y == monsters[m].y)
  490.                         CONSOLE.put_char(x, y, monsters[m].ch);
  491.             }
  492.         }
  493.  
  494.         CONSOLE.put_char(player.x, player.y, '@');
  495.     }
  496.  
  497.     static void erase_what_player_cant_see()
  498.     {
  499.         ROOM room = get_room_at(player.x, player.y);
  500.  
  501.         if (room != null && room.is_lit)
  502.             return;
  503.  
  504.         // 3x3 area around player
  505.         for (int dy = -1; dy <= +1; dy++)
  506.         {
  507.             for (int dx = -1; dx <= +1; dx++)
  508.             {
  509.                 int x = player.x + dx;
  510.                 int y = player.y + dy;
  511.  
  512.                 if (x < 0 || x >= 80 || y < 0 || y >= 25) continue;
  513.  
  514.                 char ch = CONSOLE.get_char(x, y);
  515.  
  516.                 if (!"-|+#%^".Contains(ch.ToString()))
  517.                     CONSOLE.put_char(x, y, ' ');
  518.             }
  519.         }
  520.     }
  521.  
  522.     static ROOM get_room_at(int x, int y)
  523.     {
  524.         for (int ry = 0; ry < 3; ry++)
  525.         {
  526.             for (int rx = 0; rx < 3; rx++)
  527.             {
  528.                 ROOM room = rooms[rx, ry];
  529.                 if (x >= room.x && x < room.x + room.w &&
  530.                     y >= room.y && y < room.y + room.h)
  531.                     return rooms[rx, ry];
  532.             }
  533.         }
  534.         return null;
  535.     }
  536.  
  537.     static TRAP get_trap_at(int x, int y)
  538.     {
  539.         for (int t = 0; t < traps.Count; t++)
  540.             if (x == traps[t].x && y == traps[t].y)
  541.                 return traps[t];
  542.  
  543.         return null;
  544.     }
  545.  
  546.     #endregion // commands
  547.  
  548.     #region helper functions
  549.  
  550.     static bool is_wall(char ch)
  551.     {
  552.         return "-|".Contains(ch.ToString());
  553.     }
  554.  
  555.     static string get_name(char dest_ch)
  556.     {
  557.         switch (dest_ch)
  558.         {
  559.             case 'A': return "giant ant";
  560.             case 'B': return "bat";
  561.             case 'C': return "centaur";
  562.             case 'D': return "dragon";
  563.             case 'E': return "floating eye";
  564.             case 'F': return "violet fungi";
  565.             case 'G': return "gnome";
  566.             case 'H': return "hobgoblin";
  567.             case 'I': return "invisible stalker";
  568.             case 'J': return "jackal";
  569.             case 'K': return "kobold";
  570.             case 'L': return "leprechaun";
  571.             case 'M': return "mimic";
  572.             case 'N': return "nymph";
  573.             case 'O': return "orc";
  574.             case 'P': return "purple worm";
  575.             case 'Q': return "quasit";
  576.             case 'R': return "rust monster";
  577.             case 'S': return "snake";
  578.             case 'T': return "troll";
  579.             case 'U': return "umber hulk";
  580.             case 'V': return "vampire";
  581.             case 'W': return "wraith";
  582.             case 'X': return "xorn";
  583.             case 'Y': return "yeti";
  584.             case 'Z': return "zombie";
  585.  
  586.             case '*': return "gold";
  587.  
  588.             case ':': return "food";
  589.             case '!': return "potion";
  590.             case '?': return "scroll";
  591.             case ')': return "weapon";
  592.             case ']': return "armor";
  593.             case '=': return "ring";
  594.             case '/': return "stick";
  595.             case ',': return "the amulet of yendor";
  596.  
  597.             default: return null;
  598.         }
  599.     }
  600.  
  601.     static void update_status()
  602.     {
  603.         clear_status();
  604.  
  605.         CONSOLE.write_string(0, 24, "level: " + dungeon_level);
  606.     }
  607.  
  608.     #endregion // helper functions
  609.  
  610.     #region messages
  611.  
  612.     static string last_message = "";
  613.  
  614.     static void set_message(string text)
  615.     {
  616.         CONSOLE.write_string(0, 0, text);
  617.         last_message = text;
  618.     }
  619.  
  620.     static void clear_message()
  621.     {
  622.         CONSOLE.cursor_off();
  623.         CONSOLE.write_string(0, 0, "".PadRight(80));
  624.         CONSOLE.cursor_on();
  625.     }
  626.  
  627.     static void clear_status()
  628.     {
  629.         CONSOLE.write_string(0, 24, "".PadRight(79));
  630.     }
  631.  
  632.     #endregion // messages
  633.  
  634.     #region game over
  635.  
  636.     static void win_game()
  637.     {
  638.         CONSOLE.clear();
  639.  
  640.         CONSOLE.write_string("you win");
  641.  
  642.         CONSOLE.read_key();
  643.  
  644.         Environment.Exit(0);
  645.     }
  646.  
  647.     #endregion // game over
  648.  
  649.     // THING must be in Program for access to dungeon_map[]
  650.     class THING
  651.     {
  652.         public int x, y;
  653.         public char ch;
  654.         public List<ITEM> items = new List<ITEM>();
  655.     }
  656. }
  657.  
  658. class ITEM
  659. {
  660.     public int x;
  661.     public int y;
  662.     public char ch;
  663. }
  664.  
  665. class CONSOLE
  666. {
  667.     static char[,] buffer = new char[80, 25];
  668.  
  669.     static int cursor_x, cursor_y;
  670.  
  671.     public static char get_char(int x, int y)
  672.     {
  673.         return buffer[x, y];
  674.     }
  675.  
  676.     public static void put_char(char ch)
  677.     {
  678.         buffer[cursor_x, cursor_y] = ch;
  679.         cursor_x++;
  680.         if (cursor_x == 80)
  681.         {
  682.             cursor_x = 0;
  683.             cursor_y++;
  684.         }
  685.  
  686.         Console.Write(ch);
  687.     }
  688.  
  689.     public static void put_char(int x, int y, char ch)
  690.     {
  691.         move_cursor(x, y);
  692.         put_char(ch);
  693.     }
  694.  
  695.     public static void move_cursor(int x, int y)
  696.     {
  697.         cursor_x = x;
  698.         cursor_y = y;
  699.  
  700.         Console.SetCursorPosition(x, y);
  701.     }
  702.  
  703.     public static char read_key()
  704.     {
  705.         return Console.ReadKey(true).KeyChar;
  706.     }
  707.  
  708.     public static void write_string(string text)
  709.     {
  710.         for (int c = 0; c < text.Length; c++)
  711.             put_char(text[c]);
  712.     }
  713.  
  714.     public static void write_string(int x, int y, string text)
  715.     {
  716.         move_cursor(x, y);
  717.         write_string(text);
  718.     }
  719.  
  720.     public static void cursor_on()
  721.     {
  722.         Console.CursorVisible = true;
  723.     }
  724.  
  725.     public static void cursor_off()
  726.     {
  727.         Console.CursorVisible = false;
  728.     }
  729.  
  730.     public static void clear()
  731.     {
  732.         for (int y = 0; y < 25; y++)
  733.             for (int x = 0; x < 80; x++)
  734.                 buffer[x, y] = ' ';
  735.         cursor_x = cursor_y = 0;
  736.  
  737.         Console.Clear();
  738.     }
  739.  
  740.     static char[,] old_buffer = new char[80, 25];
  741.  
  742.     public static void back_up_buffer()
  743.     {
  744.         Array.Copy(CONSOLE.buffer, old_buffer, 80 * 25);
  745.     }
  746.  
  747.     public static void restore_buffer()
  748.     {
  749.         Array.Copy(old_buffer, CONSOLE.buffer, 80 * 25);
  750.  
  751.         for (int y = 0; y < 25; y++)
  752.             for (int x = 0; x < 80; x++)
  753.                 if (!(x == 79 && y == 24))
  754.                     CONSOLE.put_char(x, y, CONSOLE.buffer[x, y]);
  755.     }
  756. }
  757.  
Add Comment
Please, Sign In to add comment