--- /dev/null
+/*! \file dungeon.cc
+ * \brief "dungeon"-like level generators i.e. made of rooms
+ */
+
+/* Copyright 2014 Martin Read
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "obumbrata.hh"
+#include "objects.hh"
+#include "monsters.hh"
+#include "mapgen.hh"
+
+#define DBASH_ROOMS_WIDE (3)
+#define DBASH_ROOMS_HIGH (3)
+/*! \brief Number of rooms on a "dungeonbash"-style level */
+#define DBASH_ROOMS (DBASH_ROOMS_WIDE * DBASH_ROOMS_HIGH)
+/*! \brief Maximum number of corridors on a dungeonbash-style level
+ *
+ * This value corresponds to the situation where every adjacent pair of
+ * rooms is connected. */
+#define DBASH_CORRIDORS ((DBASH_ROOMS_WIDE - 1) * DBASH_ROOMS_HIGH + \
+ (DBASH_ROOMS_HIGH - 1) * DBASH_ROOMS_WIDE)
+/*! \brief Room generated first */
+#define DBASH_ORIGIN_ROOM (4)
+
+struct Dbash_room
+{
+ Coord inner_tl;
+ Coord inner_br;
+ Coord exit_positions[4];
+};
+
+struct Dbash_corridor
+{
+ Coord endpoints[2];
+};
+
+struct Dbash_layout_data
+{
+ Level_layout id;
+ int32_t exit_room;
+ int32_t entry_room;
+ uint16_t connectivity[DBASH_ROOMS];
+ Dbash_room rooms[DBASH_ROOMS];
+ Dbash_corridor corridors[DBASH_CORRIDORS];
+ void *next_layout_data;
+};
+
+static void excavate_normal_room(Level *l, Coord inner_tl, Coord inner_br, uint32_t region)
+{
+ Coord pos;
+ // Initial pass: make the room interior all floor.
+ for (pos.y = inner_tl.y; pos.y <= inner_br.y; ++pos.y)
+ {
+ for (pos.x = inner_tl.x; pos.x <= inner_br.x; ++pos.x)
+ {
+ l->set_terrain_at(pos, FLOOR);
+ l->set_region_at(pos, region);
+ }
+ }
+}
+
+static void draw_pillar_row(Level *l, Coord end1, Coord end2, Terrain t)
+{
+ Offset delta = end2 - end1;
+ Offset step = mysign(delta) * 2;
+}
+
+#define PILLARS_WEST 0x00000001u
+#define PILLARS_EAST 0x00000002u
+#define PILLARS_NORTH 0x00000004u
+#define PILLARS_SOUTH 0x00000008u
+#define PILLARS_INNER_MASK 0x000000f0u
+#define PILLARS_EMPTY 0u
+#define PILLARS_ALL 1u
+#define PILLARS_EW_AVENUE 2u
+#define PILLARS_NS_AVENUE 3u
+#define PILLARS_CROSSED_AVENUE 4u
+#define PILLARS_INNER_SHIFT 4u
+
+static void excavate_pillar_room(Level *l, Coord inner_tl, Coord inner_br, uint32_t region, uint32_t pillar_pattern)
+{
+ Offset delta = inner_br - inner_tl;
+ if ((delta.y | delta.x) & 1)
+ {
+ throw Obumb_levgen_excep("Awkward dimensions for pillar room");
+ }
+ excavate_normal_room(l, inner_tl, inner_br, region);
+ /* Second pass: What pattern of pillars?
+ *
+ * Low 4 bits: Do we have the "ring" pillars?
+ * Next 4 bits: Choice of interior pattern from:
+ * 0 = no interior pillars
+ * 1 = all interior pillars
+ * 2 = east-west avenue of pillars
+ * 3 = north-south avenue of pillars
+ * 4 = crossed avenues of pillars
+ */
+ Coord end1;
+ Coord end2;
+ if (pillar_pattern & PILLARS_EAST)
+ {
+ end1.y = inner_tl.y + 1;
+ end1.x = end2.x = inner_br.x - 1;
+ end2.y = inner_br.y - 1;
+ draw_pillar_row(l, end1, end2, MASONRY_WALL);
+ }
+ if (pillar_pattern & PILLARS_WEST)
+ {
+ end1.y = inner_tl.y + 1;
+ end1.x = end2.x = inner_tl.x + 1;
+ end2.y = inner_br.y - 1;
+ draw_pillar_row(l, end1, end2, MASONRY_WALL);
+ }
+ if (pillar_pattern & PILLARS_NORTH)
+ {
+ end1.y = end2.y = inner_tl.y + 1;
+ end2.x = inner_tl.x + 1;
+ end2.x = inner_br.x - 1;
+ draw_pillar_row(l, end1, end2, MASONRY_WALL);
+ }
+ if (pillar_pattern & PILLARS_SOUTH)
+ {
+ end1.y = end2.y = inner_tl.y + 1;
+ end2.x = inner_tl.x + 1;
+ end2.x = inner_br.x - 1;
+ draw_pillar_row(l, end1, end2, MASONRY_WALL);
+ }
+ switch ((pillar_pattern >> 4) & 0xf)
+ {
+ default:
+ // TODO emit debug
+ case PILLARS_EMPTY:
+ break;
+ case PILLARS_ALL:
+ end1.x = inner_tl.x;
+ end2.x = inner_tl.x;
+ for (end1.y = end2.y = inner_tl.y + 1;
+ end1.y < inner_br.y; (end1.y += 2), (end2.y += 2))
+ {
+ draw_pillar_row(l, end1, end2, MASONRY_WALL);
+ }
+ break;
+ case PILLARS_EW_AVENUE:
+ if (delta.y > 2)
+ {
+ end1.y = end2.y = (inner_tl.y + inner_br.y) / 2 - 1;
+ end1.x = inner_tl.x + 1;
+ end2.x = inner_br.x - 1;
+ draw_pillar_row(l, end1, end2, MASONRY_WALL);
+ end1.y = end2.y = (inner_tl.y + inner_br.y) / 2 + 1;
+ draw_pillar_row(l, end1, end2, MASONRY_WALL);
+ }
+ break;
+ case PILLARS_NS_AVENUE:
+ if (delta.x > 2)
+ {
+
+ end1.x = end2.x = (inner_tl.x + inner_br.x) / 2 - 1;
+ end1.y = inner_tl.y + 1;
+ end2.y = inner_br.y - 1;
+ draw_pillar_row(l, end1, end2, MASONRY_WALL);
+ end1.y = end2.y = (inner_tl.y + inner_br.y) / 2 + 1;
+ draw_pillar_row(l, end1, end2, MASONRY_WALL);
+ }
+ break;
+ case PILLARS_CROSSED_AVENUE:
+ end1.y = end2.y = (inner_tl.y + inner_br.y) / 2 - 1;
+ end1.x = inner_tl.x + 1;
+ end2.x = inner_br.x - 1;
+ draw_pillar_row(l, end1, end2, MASONRY_WALL);
+ end1.y = end2.y = (inner_tl.y + inner_br.y) / 2 + 1;
+ draw_pillar_row(l, end1, end2, MASONRY_WALL);
+ end1.x = end2.x = (inner_tl.x + inner_br.x) / 2 - 1;
+ end1.y = inner_tl.y + 1;
+ end2.y = inner_br.y - 1;
+ draw_pillar_row(l, end1, end2, MASONRY_WALL);
+ end1.y = end2.y = (inner_tl.y + inner_br.y) / 2 + 1;
+ draw_pillar_row(l, end1, end2, MASONRY_WALL);
+ break;
+ }
+}
+
+/*! \brief Excavate a dungeonbash-style level
+ *
+ * Levels in Martin's Dungeon Bash had nine rooms in a 3x3 grid. This function
+ * reproduces that structure.
+ */
+void build_level_dungeonbash(Level *l)
+{
+ Coord tl;
+ Coord br;
+ int ysize; // internal y-size of room we're about to build
+ int xsize; // internal x-size of room we're about to build
+ Dbash_layout_data *layout_data = new Dbash_layout_data;
+ Dbash_room *rptr;
+ layout_data->id = LAYOUT_DUNGEONBASH;
+ l->layout_data = layout_data;
+ layout_data->entry_room = zero_die(9);
+ do
+ {
+ layout_data->exit_room = zero_die(9);
+ } while (layout_data->exit_room == layout_data->entry_room);
+ /* Go with the standard 3x3 chunk set. */
+ initialize_chunks(l, GUIDE_EDGE_CHUNKS, GUIDE_EDGE_CHUNKS, true);
+ /* Build the centre room. */
+ ysize = 3 + zero_die(6);
+ xsize = 3 + zero_die(6);
+ tl.y = (GUIDE_EDGE_CHUNKS / 2) - (ysize / 2);
+ br.y = tl.y + (ysize - 1);
+ tl.x = (GUIDE_EDGE_CHUNKS / 2) - (xsize / 2);
+ br.x = tl.x + (xsize - 1);
+ rptr = layout_data->rooms + DBASH_ORIGIN_ROOM;
+ rptr->inner_tl = tl;
+ rptr->inner_br = br;
+ /* Centre room is either plain, or ring pillars with crossed avenues. */
+ if (zero_die(2))
+ {
+ excavate_pillar_room(l, rptr->inner_tl, rptr->inner_br,
+ DBASH_ORIGIN_ROOM, 0x4f);
+ }
+ else
+ {
+ excavate_normal_room(l, rptr->inner_tl, rptr->inner_br,
+ DBASH_ORIGIN_ROOM);
+ }
+ /* Other rooms are plain for now. */
+ for (int i = 0; i < DBASH_ROOMS; ++i)
+ {
+ if (i == DBASH_ORIGIN_ROOM)
+ {
+ continue;
+ }
+ }
+}
+
+/*! \brief Excavate a "claustrophobia" level
+ *
+ * "Claustrophobia" levels
+ *
+ * \todo Implement.
+ */
+void build_level_claustrophobia(Level *l)
+{
+}
+
+/* dungeon.cc */
+// vim:cindent:ts=8:sw=4:expandtab