summaryrefslogtreecommitdiff
path: root/src/gen_maze.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/gen_maze.c')
-rw-r--r--src/gen_maze.c297
1 files changed, 297 insertions, 0 deletions
diff --git a/src/gen_maze.c b/src/gen_maze.c
new file mode 100644
index 00000000..03941f01
--- /dev/null
+++ b/src/gen_maze.c
@@ -0,0 +1,297 @@
+/*
+ * Maze dungeon generator
+ */
+
+/*
+ * Copyright (c) 2003 DarkGod. And somebody who posted the algorith on
+ * rec.games.roguelike.development. I can't remember teh name :( please mail me
+ *
+ * This software may be copied and distributed for educational, research, and
+ * not for profit purposes provided that this copyright and statement are
+ * included in all such copies.
+ */
+
+#include "angband.h"
+
+/*
+ * If we wasted static memory for this, it would look like:
+ *
+ * static char maze[(MAX_HGT / 2) + 2][(MAX_WID / 2) + 2];
+ */
+typedef signed char maze_row[(MAX_WID / 2) + 2];
+
+void dig(maze_row *maze, int y, int x, int d)
+{
+ int k;
+ int dy = 0, dx = 0;
+
+ /*
+ * first, open the wall of the new cell
+ * in the direction we come from.
+ */
+ switch (d)
+ {
+ case 0:
+ {
+ maze[y][x] |= 4;
+ break;
+ }
+
+ case 1:
+ {
+ maze[y][x] |= 8;
+ break;
+ }
+
+ case 2:
+ {
+ maze[y][x] |= 1;
+ break;
+ }
+
+ case 3:
+ {
+ maze[y][x] |= 2;
+ break;
+ }
+ }
+
+ /*
+ * try to chage direction, here 50% times.
+ * with smaller values (say 25%) the maze
+ * is made of long straight corridors. with
+ * greaters values (say 75%) the maze is
+ * very "turny".
+ */
+ if (rand_range(1, 100) < 50) d = rand_range(0, 3);
+
+ for (k = 1; k <= 4; k++)
+ {
+ switch (d)
+ {
+ case 0:
+ {
+ dy = 0;
+ dx = 1;
+ break;
+ }
+
+ case 1:
+ {
+ dy = -1;
+ dx = 0;
+ break;
+ }
+
+ case 2:
+ {
+ dy = 0;
+ dx = -1;
+ break;
+ }
+
+ case 3:
+ {
+ dy = 1;
+ dx = 0;
+ break;
+ }
+ }
+
+ if (maze[y + dy][x + dx] == 0)
+ {
+ /*
+ * now, open the wall of the new cell
+ * in the direction we go to.
+ */
+ switch (d)
+ {
+ case 0:
+ {
+ maze[y][x] |= 1;
+ break;
+ }
+
+ case 1:
+ {
+ maze[y][x] |= 2;
+ break;
+ }
+
+ case 2:
+ {
+ maze[y][x] |= 4;
+ break;
+ }
+
+ case 3:
+ {
+ maze[y][x] |= 8;
+ break;
+ }
+ }
+
+ dig(maze, y + dy, x + dx, d);
+ }
+
+ d = (d + 1) % 4;
+ }
+}
+
+
+bool level_generate_maze(cptr name)
+{
+ int i, j, d;
+ int y, dy = 0;
+ int x, dx = 0;
+ int m_1 = 0, m_2 = 0;
+ maze_row *maze;
+
+ /* unused */
+ name = name;
+
+ /* Allocate temporary memory */
+ C_MAKE(maze, (MAX_HGT / 2) + 2, maze_row);
+
+ /*
+ * the empty maze is:
+ *
+ * -1 -1 ... -1 -1
+ * -1 0 0 -1
+ * . .
+ * . .
+ * -1 0 0 -1
+ * -1 -1 ... -1 -1
+ *
+ * -1 are so-called "sentinel value".
+ * 0 are empty cells.
+ *
+ * walls are not represented, only cells.
+ * at the end of the algorithm each cell
+ * contains a value that is bit mask
+ * representing surrounding walls:
+ *
+ * bit #1
+ *
+ * +------+
+ * | |
+ * bit #2 | | bit #0
+ * | |
+ * +------+
+ *
+ * bit #3
+ *
+ * d is the direction you are digging
+ * to. d value is the bit number:
+ * d=0 --> go east
+ * d=1 --> go north
+ * etc
+ *
+ * you need only 4 bits per cell.
+ * this gives you a very compact
+ * maze representation.
+ *
+ */
+ for (j = 0; j <= (cur_hgt / 2) + 1; j++)
+ {
+ for (i = 0; i <= (cur_wid / 2) + 1; i++)
+ {
+ maze[j][i] = -1;
+ }
+ }
+
+ for (j = 1; j <= (cur_hgt / 2); j++)
+ {
+ for (i = 1; i <= (cur_wid / 2); i++)
+ {
+ maze[j][i] = 0;
+ }
+ }
+
+ y = rand_range(1, (cur_hgt / 2));
+ x = rand_range(1, (cur_wid / 2));
+ d = rand_range(0, 3);
+
+ dig(maze, y, x, d);
+
+ maze[y][x] = 0;
+
+ for (d = 0; d <= 3; d++)
+ {
+ switch (d)
+ {
+ case 0:
+ {
+ dy = 0;
+ dx = 1;
+ m_1 = 1;
+ m_2 = 4;
+ break;
+ }
+
+ case 1:
+ {
+ dy = -1;
+ dx = 0;
+ m_1 = 2;
+ m_2 = 8;
+ break;
+ }
+
+ case 2:
+ {
+ dy = 0;
+ dx = -1;
+ m_1 = 4;
+ m_2 = 1;
+ break;
+ }
+
+ case 3:
+ {
+ dy = 1;
+ dx = 0;
+ m_1 = 8;
+ m_2 = 2;
+ break;
+ }
+ }
+
+ if ((maze[y + dy][x + dx] != -1) &&
+ ((maze[y + dy][x + dx] & m_2) != 0))
+ {
+ maze[y][x] |= m_1;
+ }
+ }
+
+ /* Translate the maze bit array into a real dungeon map -- DG */
+ for (j = 1; j <= (cur_hgt / 2) - 2; j++)
+ {
+ for (i = 1; i <= (cur_wid / 2) - 2; i++)
+ {
+ if (maze[j][i])
+ {
+ place_floor(j * 2, i * 2);
+ }
+
+ if (maze[j][i] & 1)
+ {
+ place_floor(j * 2, i * 2 + 1);
+ }
+
+ if (maze[j][i] & 8)
+ {
+ place_floor(j * 2 + 1, i * 2);
+ }
+ }
+ }
+
+ /* Free temporary memory */
+ C_FREE(maze, (MAX_HGT / 2) + 2, maze_row);
+
+ /* Determine the character location */
+ if (!new_player_spot(get_branch()))
+ return FALSE;
+
+ return TRUE;
+}