SteelGolem icon

02 uncovering the map in rogue

SteelGolem | PRO | 04/03/21 08:42:27 PM UTC (Edited) | 0 ⭐ | 1018 👁️ | Never ⏰ | []
C# |

20.27 KB

|

None

|

0 👍

/

0 👎

// 02 uncover map
 
// hide everything on the map and uncover it as the player roams
// makes 3x3 rooms with 1 gold pile and 1 monster each
// lit rooms light up when player walks in
// can discover traps
 
using System;
using System.Collections.Generic;
 
class Program
{
    static List<ITEM> items_on_floor;
 
    static List<THING> monsters;
 
    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 - 02 uncover map";
 
        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 (dungeon_map[player.x, player.y] == '%')
                    {
                        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 char[,] dungeon_map = new char[80, 25];
 
    static ROOM[,] rooms;
 
    const int room_max_w = 80 / 3;
    const int room_max_h = 23 / 3;
 
    static List<TRAP> traps;
 
    static void new_level()
    {
        items_on_floor = new List<ITEM>();
 
        monsters = new List<THING>();
 
        traps = new List<TRAP>();
 
        for (int y = 0; y < 25; y++)
            for (int x = 0; x < 80; x++)
                dungeon_map[x, y] = ' ';
 
        CONSOLE.clear();
 
        // add 3x3 rooms
        rooms = new ROOM[3, 3];
        for (int ry = 0; ry < 3; ry++)
        {
            for (int rx = 0; rx < 3; rx++)
            {
                ROOM room = new ROOM();
                room.w = 4 + random.Next(room_max_w - 4);
                room.h = 4 + random.Next(room_max_h - 4);
                room.x = rx * room_max_w +
                    random.Next(room_max_w - room.w);
                room.y = 1 + ry * room_max_h +
                    random.Next(room_max_h - room.h);
                if (random.Next(100) < 50)
                    room.is_lit = true;
                rooms[rx, ry] = room;
 
                room.draw_on_map();
                // one door at the bottom
                dungeon_map[room.x + room.w / 2, room.y + room.h - 1] = '+';
            }
        }
 
        // 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)];
            dungeon_map[x, y] = ch;
        }
 
        // add some traps
        for (int t = 0; t < 9; t++)
        {
            TRAP trap = new TRAP();
            do
            {
                ROOM room = get_random_room();
                room.set_random_pos(trap);
            }
            while (dungeon_map[trap.x, trap.y] != '.');
            trap.ch = ">{$}~`"[random.Next(6)];
            dungeon_map[trap.x, trap.y] = trap.ch;
            traps.Add(trap);
        }
 
        // add some gold
        for (int ry = 0; ry < 3; ry++)
        {
            for (int rx = 0; rx < 3; rx++)
            {
                ROOM room = rooms[rx, ry];
                ITEM item = new ITEM();
                do room.set_random_pos(item);
                while (dungeon_map[item.x, item.y] != '.');
                item.ch = '*';
                items_on_floor.Add(item);
            }
        }
 
        // add some items
        for (int c = 0; c < 9; c++)
        {
            ITEM item = new ITEM();
            do
            {
                ROOM room = get_random_room();
                room.set_random_pos(item);
            }
            while (dungeon_map[item.x, item.y] != '.');
            item.ch = ":!?)]=/"[random.Next(7)];
            items_on_floor.Add(item);
        }
 
        // add some monsters
        for (int ry = 0; ry < 3; ry++)
        {
            for (int rx = 0; rx < 3; rx++)
            {
                ROOM room = rooms[rx, ry];
                THING monster = new THING();
                do room.set_random_pos(monster);
                while (dungeon_map[monster.x, monster.y] != '.');
                monster.ch = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"[random.Next(26)];
                monsters.Add(monster);
            }
        }
 
        // add the amulet
        if (dungeon_level >= 26)
        {
            ITEM item = new ITEM();
            do
            {
                ROOM room = get_random_room();
                room.set_random_pos(item);
            }
            while (dungeon_map[item.x, item.y] != '.');
            item.ch = ',';
            items_on_floor.Add(item);
        }
 
        // add the stairs
        int stairs_x = -1, stairs_y = -1;
        do
        {
            ROOM room = get_random_room();
            room.set_random_pos(ref stairs_x, ref stairs_y);
        }
        while (dungeon_map[stairs_x, stairs_y] != '.');
        dungeon_map[stairs_x, stairs_y] = '%';
 
        // place the player
        do
        {
            ROOM room = get_random_room();
            room.set_random_pos(player);
        }
        while (dungeon_map[player.x, player.y] != '.');
        draw_what_player_can_see();
    }
 
    static ROOM get_random_room()
    {
        return rooms[random.Next(3), random.Next(3)];
    }
 
    class ROOM
    {
        public int x, y, w, h;
        public bool is_lit;
 
        public void draw_on_map()
        {
            for (int y = 0; y < this.h; y++)
                for (int x = 0; x < this.w; x++)
                    dungeon_map[this.x + x, this.y + y] = '.';
 
            for (int y = 0; y < this.h; y++)
            {
                dungeon_map[this.x, this.y + y] = '|';
                dungeon_map[this.x + this.w - 1, this.y + y] = '|';
            }
 
            for (int x = 0; x < this.w; x++)
            {
                dungeon_map[this.x + x, this.y] = '-';
                dungeon_map[this.x + x, this.y + this.h - 1] = '-';
            }
        }
 
        public void set_random_pos(ref int x, ref int y)
        {
            x = this.x + 1 + random.Next(this.w - 2);
            y = this.y + 1 + random.Next(this.h - 2);
        }
 
        public void set_random_pos(ITEM item)
        {
            set_random_pos(ref item.x, ref item.y);
        }
 
        public void set_random_pos(THING thing)
        {
            set_random_pos(ref thing.x, ref thing.y);
        }
 
        public void set_random_pos(TRAP trap)
        {
            set_random_pos(ref trap.x, ref trap.y);
        }
    }
 
    class TRAP
    {
        public int x, y;
        public char ch;
        public bool found;
    }
 
    #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 map_ch = dungeon_map[dest_x, dest_y];
 
        // walls stop movement
        if (is_wall(map_ch))
            return;
 
        // fight monster
        for (int m = monsters.Count - 1; m >= 0; m--)
        {
            THING monster = monsters[m];
 
            if (dest_x == monster.x && dest_y == monster.y)
            {
                monsters.Remove(monster);
 
                draw_what_player_can_see();
 
                set_message("defeated " + get_name(monster.ch));
 
                return;
            }
        }
 
        erase_what_player_cant_see();
 
        player.x = dest_x;
        player.y = dest_y;
 
        draw_what_player_can_see();
 
        // pick up item
        for (int i = items_on_floor.Count - 1; i >= 0; i--)
        {
            ITEM item = items_on_floor[i];
 
            if (dest_x == item.x && dest_y == item.y)
            {
                if (player.items.Count == 23)
                {
                    set_message("no room in inventory");
                    return;
                }
 
                set_message("picked up " + get_name(item.ch));
 
                items_on_floor.Remove(item);
 
                player.items.Add(item);
 
                if (item.ch == ',')
                    found_amulet = true;
            }
        }
 
        // get trapped
        for (int t = 0; t < traps.Count; t++)
        {
            TRAP trap = traps[t];
 
            if (dest_x == trap.x && dest_y == trap.y)
            {
                trap.found = true;
                string message = "found ";
                switch (trap.ch)
                {
                    case '>': message += "trap door"; break;
                    case '{': message += "arrow trap"; break;
                    case '$': message += "sleep trap"; break;
                    case '}': message += "bear trap"; break;
                    case '~': message += "teleport trap"; break;
                    case '`': message += "dart trap"; break;
                }
                set_message(message);
            }
        }
    }
 
    static void draw_what_player_can_see()
    {
        ROOM room = null;
 
        // without this line, we redraw the room and 
        //      everything in it every time we move
        //      (is this actually perfectly fine?)
        //if (dungeon_map[player.x, player.y] == '+')
        room = get_room_at(player.x, player.y);
 
        if (room != null && room.is_lit)
        {
            for (int ry = 0; ry < room.h; ry++)
            {
                for (int rx = 0; rx < room.w; rx++)
                {
                    int x = room.x + rx;
                    int y = room.y + ry;
                    if (">{$}~`".Contains(dungeon_map[x, y].ToString()))
                    {
                        TRAP trap = get_trap_at(x, y);
                        if (trap.found)
                            CONSOLE.put_char(x, y, '^');
                        else
                            CONSOLE.put_char(x, y, '.');
                    }
                    else
                        CONSOLE.put_char(x, y, dungeon_map[x, y]);
                }
            }
 
            for (int i = 0; i < items_on_floor.Count; i++)
            {
                ITEM item = items_on_floor[i];
                if (get_room_at(item.x, item.y) == room)
                    CONSOLE.put_char(item.x, item.y, item.ch);
            }
 
            for (int m = 0; m < monsters.Count; m++)
            {
                THING monster = monsters[m];
                if (get_room_at(monster.x, monster.y) == room)
                    CONSOLE.put_char(monster.x, monster.y, monster.ch);
            }
 
            CONSOLE.put_char(player.x, player.y, '@');
        }
 
        // 3x3 area around player
        for (int dy = -1; dy <= +1; dy++)
        {
            for (int dx = -1; dx <= +1; dx++)
            {
                int x = player.x + dx;
                int y = player.y + dy;
 
                if (x < 0 || x >= 80 || y < 0 || y >= 25) continue;
 
                CONSOLE.put_char(x, y, dungeon_map[x, y]);
 
                if (">{$}~`".Contains(dungeon_map[x, y].ToString()))
                {
                    TRAP trap = get_trap_at(x, y);
                    if (trap.found)
                        CONSOLE.put_char(x, y, '^');
                    else
                        CONSOLE.put_char(x, y, '.');
                }
 
                for (int i = 0; i < items_on_floor.Count; i++)
                    if (x == items_on_floor[i].x &&
                        y == items_on_floor[i].y)
                        CONSOLE.put_char(x, y, items_on_floor[i].ch);
 
                for (int m = 0; m < monsters.Count; m++)
                    if (x == monsters[m].x &&
                        y == monsters[m].y)
                        CONSOLE.put_char(x, y, monsters[m].ch);
            }
        }
 
        CONSOLE.put_char(player.x, player.y, '@');
    }
 
    static void erase_what_player_cant_see()
    {
        ROOM room = get_room_at(player.x, player.y);
 
        if (room != null && room.is_lit)
            return;
 
        // 3x3 area around player
        for (int dy = -1; dy <= +1; dy++)
        {
            for (int dx = -1; dx <= +1; dx++)
            {
                int x = player.x + dx;
                int y = player.y + dy;
 
                if (x < 0 || x >= 80 || y < 0 || y >= 25) continue;
 
                char ch = CONSOLE.get_char(x, y);
 
                if (!"-|+#%^".Contains(ch.ToString()))
                    CONSOLE.put_char(x, y, ' ');
            }
        }
    }
 
    static ROOM get_room_at(int x, int y)
    {
        for (int ry = 0; ry < 3; ry++)
        {
            for (int rx = 0; rx < 3; rx++)
            {
                ROOM room = rooms[rx, ry];
                if (x >= room.x && x < room.x + room.w &&
                    y >= room.y && y < room.y + room.h)
                    return rooms[rx, ry];
            }
        }
        return null;
    }
 
    static TRAP get_trap_at(int x, int y)
    {
        for (int t = 0; t < traps.Count; t++)
            if (x == traps[t].x && y == traps[t].y)
                return traps[t];
 
        return null;
    }
 
    #endregion // commands
 
    #region helper functions
 
    static bool is_wall(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 "gold";
 
            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
 
    // THING must be in Program for access to dungeon_map[]
    class THING
    {
        public int x, y;
        public char ch;
        public List<ITEM> items = new List<ITEM>();
    }
}
 
class ITEM
{
    public int x;
    public int y;
    public char ch;
}
 
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]);
    }
}
 

Comments