diff options
author | dshaligram <dshaligram@c06c8d41-db1a-0410-9941-cceddc491573> | 2007-06-21 19:20:47 +0000 |
---|---|---|
committer | dshaligram <dshaligram@c06c8d41-db1a-0410-9941-cceddc491573> | 2007-06-21 19:20:47 +0000 |
commit | a1792c303b15abc726cf833a3b2658ce38b0a2ac (patch) | |
tree | 4b72e80e49683fde434b5d115dd819572c2c4cbc | |
parent | 9181a73f6feb5a62a5ff98e4a3db447ef1220db1 (diff) | |
download | crawl-ref-a1792c303b15abc726cf833a3b2658ce38b0a2ac.tar.gz crawl-ref-a1792c303b15abc726cf833a3b2658ce38b0a2ac.zip |
Allow minivaults tagged "lab" to be used for labyrinth exits.
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@1616 c06c8d41-db1a-0410-9941-cceddc491573
-rw-r--r-- | crawl-ref/source/dat/entry.des | 1 | ||||
-rw-r--r-- | crawl-ref/source/dat/vaults.des | 45 | ||||
-rw-r--r-- | crawl-ref/source/dungeon.cc | 273 | ||||
-rw-r--r-- | crawl-ref/source/dungeon.h | 1 | ||||
-rw-r--r-- | crawl-ref/source/maps.cc | 3 |
5 files changed, 228 insertions, 95 deletions
diff --git a/crawl-ref/source/dat/entry.des b/crawl-ref/source/dat/entry.des index 2f295a99f7..e58e952d02 100644 --- a/crawl-ref/source/dat/entry.des +++ b/crawl-ref/source/dat/entry.des @@ -4481,7 +4481,6 @@ TAGS: entry FLAGS: no_rotate no_hmirror ORIENT: float SHUFFLE: ({[<, 1234567 -CHANCE: 10000 MONS: giant gecko/giant iguana/giant lizard/giant newt/gila monster/komodo dragon MONS: hog/jackal/wolf/hound/war dog MONS: giant cockroach/giant ant/butterfly/killer bee/bumbleebee/redback/giant mite diff --git a/crawl-ref/source/dat/vaults.des b/crawl-ref/source/dat/vaults.des index 97e53cbde9..7b4a7cd4d1 100644 --- a/crawl-ref/source/dat/vaults.des +++ b/crawl-ref/source/dat/vaults.des @@ -2342,6 +2342,51 @@ MAP ............ ENDMAP +############################################################################# +# Labyrinth minivaults +############################################################################# +# One layer of floor space *must* surround the minivault, or the player could +# be trapped in the labyrinth (the dummy is exempt from this requirement). +# +# You can use the "generate_loot" tag to indicate that you're not explicitly +# placing the loot and that the dungeon builder should generate random loot +# (on the upstair). Note that this is not the default, and if you neither use +# this tag nor provide loot in the map definition, the player will be +# disappointed. +# +# You *must* place the minotaur(s) yourself! +############################################################################# +# Dummy balancer + +NAME: labyrinth_0 +TAGS: lab dummy +CHANCE: 20 + +MAP +x +ENDMAP + +############################################################################# +# A simple lair. + +NAME: labyrinth_1 +TAGS: lab generate_loot no_pool_fixup +MONS: minotaur +SHUFFLE: def +SUBST: d=^, e=^, f=. + +MAP +......... +.ccccccc. +.cwwwwwc. +.cww<wwc. +.cwdefwc. +.ccc1ccc. +.c.....c. +.ccc+ccc. +......... +ENDMAP + ############################################################################ # Minivaults specific to particular branches ############################################################################ diff --git a/crawl-ref/source/dungeon.cc b/crawl-ref/source/dungeon.cc index 9c493a765d..295e13308f 100644 --- a/crawl-ref/source/dungeon.cc +++ b/crawl-ref/source/dungeon.cc @@ -90,7 +90,8 @@ static bool make_box(int room_x1, int room_y1, int room_x2, int room_y2, dungeon_feature_type avoid=DNGN_UNSEEN); static void replace_area(int sx, int sy, int ex, int ey, dungeon_feature_type replace, - dungeon_feature_type feature); + dungeon_feature_type feature, + const dgn_region_list &forbidden = dgn_region_list()); static builder_rc_type builder_by_type(int level_number, char level_type); static builder_rc_type builder_by_branch(int level_number); static builder_rc_type builder_normal(int level_number, char level_type, spec_room &s); @@ -169,7 +170,7 @@ static void jelly_pit(int level_number, spec_room &sr); static bool build_secondary_vault(int level_number, int vault, int rune_subst = -1); static bool build_vaults(int level_number, int vault_number, int rune_subst = -1, bool build_only = false); -static void build_minivaults(int level_number, int force_vault); +static bool build_minivaults(int level_number, int force_vault); static int vault_grid( vault_placement &, int level_number, int vx, int vy, int altar_count, FixedVector < object_class_type, 7 > &acq_item_class, @@ -2547,7 +2548,68 @@ static void beehive(spec_room &sr) mons_place( MONS_QUEEN_BEE, BEH_SLEEP, MHITNOT, true, queenx, queeny ); } // end beehive() -static void build_minivaults(int level_number, int force_vault) +static bool safe_minivault_place(int v1x, int v1y, + const vault_placement &place) +{ + for (int vx = v1x; vx < v1x + place.width; vx++) + { + for (int vy = v1y; vy < v1y + place.height; vy++) + { + if ((grd[vx][vy] != DNGN_FLOOR + && grd[vx][vy] != DNGN_ROCK_WALL + && grd[vx][vy] != DNGN_CLOSED_DOOR + && grd[vx][vy] != DNGN_SECRET_DOOR) + || igrd[vx][vy] != NON_ITEM + || mgrd[vx][vy] != NON_MONSTER) + { + return (false); + } + } + } + return (true); +} + +static bool connected_minivault_place(int v1x, int v1y, + const vault_placement &place) +{ + /* must not be completely isolated: */ + for (int vx = v1x; vx < v1x + place.width; vx++) + { + // if (vx != v1x && vx != v1x + 12) continue; + for (int vy = v1y; vy < v1y + place.height; vy++) + { + if (grd[vx][vy] == DNGN_FLOOR + || grd[vx][vy] == DNGN_CLOSED_DOOR + || grd[vx][vy] == DNGN_SECRET_DOOR) + return (true); + } + } + return (false); +} + +static bool find_minivault_place(const vault_placement &place, + int &v1x, int &v1y) +{ + // [ds] The margin around the edges of the map where the minivault + // won't be placed. Purely arbitrary as far as I can see. + const int margin = MAPGEN_BORDER * 2; + + /* find a target area which can be safely overwritten: */ + for (int tries = 0; tries < 600; ++tries) + { + v1x = random_range( margin, GXM - margin - place.width ); + v1y = random_range( margin, GYM - margin - place.height ); + + if (!safe_minivault_place( v1x, v1y, place )) + continue; + + if (connected_minivault_place(v1x, v1y, place)) + return (true); + } + return (false); +} + +static bool build_minivaults(int level_number, int force_vault) { // for some weird reason can't put a vault on level 1, because monster equip // isn't generated. @@ -2568,62 +2630,17 @@ static void build_minivaults(int level_number, int force_vault) vault_placement place; vault_main(vgrid, place, force_vault); - level_vaults.push_back(place); - int vx, vy; int v1x, v1y; - // [ds] The margin around the edges of the map where the minivault won't be - // placed. Purely arbitrary as far as I can see. - const int margin = 12; - - /* find a target area which can be safely overwritten: */ - while(1) - { - v1x = random_range( margin, GXM - margin - place.width ); - v1y = random_range( margin, GYM - margin - place.height ); - - for (vx = v1x; vx < v1x + place.width; vx++) - { - for (vy = v1y; vy < v1y + place.height; vy++) - { - // [ds] An escape hatch to keep from hanging forever looking - // for a good place. - if (one_chance_in(2000)) - return; - - if ((grd[vx][vy] != DNGN_FLOOR - && grd[vx][vy] != DNGN_ROCK_WALL - && grd[vx][vy] != DNGN_CLOSED_DOOR - && grd[vx][vy] != DNGN_SECRET_DOOR) - || igrd[vx][vy] != NON_ITEM - || mgrd[vx][vy] != NON_MONSTER) - { - goto out_of_check; - } - } - } - - /* must not be completely isolated: */ - for (vx = v1x; vx < v1x + place.width; vx++) - { - // if (vx != v1x && vx != v1x + 12) continue; - for (vy = v1y; vy < v1y + place.height; vy++) - { - if (grd[vx][vy] == DNGN_FLOOR - || grd[vx][vy] == DNGN_CLOSED_DOOR - || grd[vx][vy] == DNGN_SECRET_DOOR) - goto break_out; - } - } - - out_of_check: - continue; - - break_out: - break; - } + if (!find_minivault_place(place, v1x, v1y)) + return (false); + place.x = v1x; + place.y = v1y; + + level_vaults.push_back(place); + for (vx = v1x; vx < v1x + place.width; vx++) { for (vy = v1y; vy < v1y + place.height; vy++) @@ -2667,6 +2684,8 @@ static void build_minivaults(int level_number, int force_vault) if (place.map.has_tag("no_pool_fixup")) no_pool_fixup_zones.push_back( dgn_region( place.x, place.y, place.width, place.height ) ); + + return (true); } // end build_minivaults() static void build_rooms(const dgn_region_list &excluded, @@ -3545,12 +3564,12 @@ static int vault_grid( vault_placement &place, static void replace_area( int sx, int sy, int ex, int ey, dungeon_feature_type replace, - dungeon_feature_type feature) + dungeon_feature_type feature, const dgn_region_list &forbidden) { int x,y; for(x=sx; x<=ex; x++) for(y=sy; y<=ey; y++) - if (grd[x][y] == replace) + if (grd[x][y] == replace && unforbidden(coord_def(x, y), forbidden)) grd[x][y] = feature; } @@ -4668,7 +4687,9 @@ static bool octa_room(spec_room &sr, int oblique_max, return true; } // end octa_room() -static void find_maze_neighbours(const coord_def &c, coord_list &ns) +static void find_maze_neighbours(const coord_def &c, + const dgn_region ®ion, + coord_list &ns) { std::vector<coord_def> coords; @@ -4680,11 +4701,8 @@ static void find_maze_neighbours(const coord_def &c, coord_list &ns) continue; const coord_def cp(c.x + xi, c.y + yi); - if (cp.x >= MAPGEN_BORDER * 3 && cp.x < GXM - MAPGEN_BORDER * 3 - && cp.y >= MAPGEN_BORDER * 3 && cp.y < GYM - MAPGEN_BORDER * 3) - { + if (region.contains(cp)) coords.push_back(cp); - } } } @@ -4696,47 +4714,38 @@ static void find_maze_neighbours(const coord_def &c, coord_list &ns) } } -static void labyrinth_maze_recurse(const coord_def &c) +static void labyrinth_maze_recurse(const coord_def &c, const dgn_region &where) { coord_list neighbours; - find_maze_neighbours(c, neighbours); + find_maze_neighbours(c, where, neighbours); coord_list deferred; for (coord_list::iterator i = neighbours.begin(); i != neighbours.end(); ++i) { const coord_def &nc = *i; - - if (grd(nc) == DNGN_ROCK_WALL) - { - grd(nc) = DNGN_FLOOR; - grd(c + (nc - c) / 2) = DNGN_FLOOR; - - if (!one_chance_in(3)) - labyrinth_maze_recurse(nc); - else - deferred.push_back(nc); - } + if (grd(nc) != DNGN_ROCK_WALL) + continue; + + grd(nc) = DNGN_FLOOR; + grd(c + (nc - c) / 2) = DNGN_FLOOR; + + if (!one_chance_in(5)) + labyrinth_maze_recurse(nc, where); + else + deferred.push_back(nc); } for (coord_list::iterator i = deferred.begin(); i != deferred.end(); ++i) - labyrinth_maze_recurse(*i); -} - -static coord_def random_point_in_lab() -{ - return coord_def( random_range(MAPGEN_BORDER * 3, - GXM - MAPGEN_BORDER * 3 - 1), - random_range(MAPGEN_BORDER * 3, - GYM - MAPGEN_BORDER * 3 - 1) ); + labyrinth_maze_recurse(*i, where); } -static void labyrinth_build_maze(coord_def &e) +static void labyrinth_build_maze(coord_def &e, const dgn_region &lab) { - labyrinth_maze_recurse(random_point_in_lab()); + labyrinth_maze_recurse(lab.random_point(), lab); do - e = random_point_in_lab(); + e = lab.random_point(); while (grd(e) != DNGN_FLOOR); } @@ -4777,19 +4786,90 @@ static void labyrinth_place_exit(const coord_def &end) grd(end) = DNGN_ROCK_STAIRS_UP; } +static void init_minivault_placement(int vault, vault_placement &place) +{ + map_type vgrid; + vault_main(vgrid, place, vault); +} + +static void labyrinth_dimension_adjust(int delta, int &ds, int &dw) +{ + if (delta > MAPGEN_BORDER) + delta = MAPGEN_BORDER; + + if (delta) + { + if (delta & 1) + ++delta; + + ds -= delta; + dw += delta * 2; + } +} + static void labyrinth_level(int level_number) { + dgn_region lab = + dgn_region::absolute( MAPGEN_BORDER * 5 / 2, MAPGEN_BORDER * 5 / 2, + GXM - MAPGEN_BORDER * 5 / 2 - 1, + GYM - MAPGEN_BORDER * 5 / 2 - 1 ); + + // First decide if we're going to use a Lab minivault. + int vault = random_map_for_tag("lab", true, false); + vault_placement place; + if (vault != -1) + { + init_minivault_placement(vault, place); + + int ex = place.width / 4, ey = place.height / 4; + + labyrinth_dimension_adjust(ex, lab.pos.x, lab.size.x); + labyrinth_dimension_adjust(ey, lab.pos.y, lab.size.y); + } + coord_def end; - labyrinth_build_maze(end); - labyrinth_place_exit(end); - link_items(); + labyrinth_build_maze(end, lab); - // turn rock walls into undiggable stone or metal: + if (vault == -1 || !build_minivaults(level_number, vault)) + { + vault = -1; + labyrinth_place_exit(end); + } + else + { + const vault_placement &rplace = *(level_vaults.end() - 1); + if (rplace.map.has_tag("generate_loot")) + { + for (int y = rplace.y; y <= rplace.y + rplace.height - 1; ++y) + { + for (int x = rplace.x; x <= rplace.x + rplace.height - 1; ++x) + { + if (grd[x][y] == DNGN_ROCK_STAIRS_UP) + { + labyrinth_place_items(coord_def(x, y)); + break; + } + } + } + } + place.x = rplace.x; + place.y = rplace.y; + place.width = rplace.width; + place.height = rplace.height; + } + + // turn rock walls into undiggable stone or metal: dungeon_feature_type wall_xform = ((random2(50) > 10) ? DNGN_STONE_WALL // 78.0% : DNGN_METAL_WALL); // 22.0% - replace_area(0,0,GXM-1,GYM-1,DNGN_ROCK_WALL,wall_xform); + dgn_region_list vaults; + vaults.push_back( + dgn_region(place.x, place.y, place.width, place.height)); + + replace_area(0, 0, GXM - 1, GYM - 1, DNGN_ROCK_WALL, wall_xform, vaults); + + link_items(); #ifdef OBSOLETE_LABYRINTH @@ -6039,9 +6119,14 @@ bool dgn_region::overlaps_any(const dgn_region_list ®ions) const coord_def dgn_region::random_edge_point() const { return random2(size.x + size.y) < size.x? - coord_def( random_range( pos.x, pos.x + size.x - 1 ), + coord_def( pos.x + random2(size.x), coinflip()? pos.y : pos.y + size.y - 1 ) : coord_def( coinflip()? pos.x : pos.x + size.x - 1, - random_range( pos.y, pos.y + size.y - 1 ) ); + pos.y + random2(size.y) ); +} + +coord_def dgn_region::random_point() const +{ + return coord_def( pos.x + random2(size.x), pos.y + random2(size.y) ); } diff --git a/crawl-ref/source/dungeon.h b/crawl-ref/source/dungeon.h index 1cd926125b..f46106a3ed 100644 --- a/crawl-ref/source/dungeon.h +++ b/crawl-ref/source/dungeon.h @@ -50,6 +50,7 @@ struct dgn_region } coord_def random_edge_point() const; + coord_def random_point() const; static dgn_region absolute(int left, int top, int right, int bottom) { diff --git a/crawl-ref/source/maps.cc b/crawl-ref/source/maps.cc index 8d9342175c..7c1ff8421f 100644 --- a/crawl-ref/source/maps.cc +++ b/crawl-ref/source/maps.cc @@ -329,6 +329,9 @@ int random_map_for_tag(const std::string &tag, } } + if (mapindex != -1 && vdefs[mapindex].has_tag("dummy")) + mapindex = -1; + #ifdef DEBUG_DIAGNOSTICS if (mapindex != -1) mprf(MSGCH_DIAGNOSTICS, "Found map %s tagged '%s'", |