summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--crawl-ref/source/dat/des/branches/shoals.des9
-rw-r--r--crawl-ref/source/dgn-height.cc3
-rw-r--r--crawl-ref/source/dgn-shoals.cc140
-rw-r--r--crawl-ref/source/dgn-shoals.h2
-rw-r--r--crawl-ref/source/dungeon.cc100
-rw-r--r--crawl-ref/source/dungeon.h13
-rw-r--r--crawl-ref/source/maps.cc2
7 files changed, 227 insertions, 42 deletions
diff --git a/crawl-ref/source/dat/des/branches/shoals.des b/crawl-ref/source/dat/des/branches/shoals.des
index b47761857f..2c9e38dbdd 100644
--- a/crawl-ref/source/dat/des/branches/shoals.des
+++ b/crawl-ref/source/dat/des/branches/shoals.des
@@ -546,7 +546,7 @@ ENDMAP
# The hut itself may not contain Ilsuiw if she had other engagements.
NAME: shoal_ilsuiw
-TAGS: mini_float shoal_guardian
+TAGS: shoal_guardian
KMONS: 1 = Ilsuiw band, siren
KMONS: 2 = merfolk impaler / merfolk javelineer
SUBST: 3 = 33w
@@ -567,13 +567,12 @@ ENDMAP
# HangedMan's alternative Shoals:$
NAME: shoals_rune_alternative
-TAGS: shoal_rune_hangedman water_ok allow_dup transparent mini_float
+TAGS: shoal_rune_hangedman water_ok allow_dup transparent mini_float no_dump
KMONS: 12 = merfolk impaler / merfolk javelineer / merfolk aquamancer
KMONS: 3 = kraken / harpy band w:5
KMONS: d = siren / mermaid w:5
KITEM: d = barnacled rune of zot
KFEAT: 123 = w
-KFEAT: d = W
KPROP: d = no_tide
SHUFFLE: AB / AB / BA, CD / CD / DC
NSUBST: 2 = 2 = 22w / * = 22www, 0 = 2:0 / * = 00...
@@ -594,10 +593,8 @@ xxW...DC.x@
ENDMAP
NAME: shoals_rune_alternative_decoy
-TAGS: shoal_hut_hangedman water_ok allow_dup transparent mini_float
+TAGS: shoal_hut_hangedman water_ok allow_dup transparent mini_float no_dump
KMONS: 0 = 0
-KITEM: | = |
-KFEAT: | = W
SHUFFLE: AB / AB / BA, CD / CD / DC
NSUBST: 0 = 3:0 / * = 00...
SUBST: AC = x, B = w, D = .
diff --git a/crawl-ref/source/dgn-height.cc b/crawl-ref/source/dgn-height.cc
index a4390278d4..91092552ee 100644
--- a/crawl-ref/source/dgn-height.cc
+++ b/crawl-ref/source/dgn-height.cc
@@ -56,6 +56,9 @@ void dgn_island_centred_at(const coord_def &c,
void dgn_smooth_height_at(coord_def c, int radius, int max_height)
{
+ if (!in_bounds(c))
+ return;
+
const int height = dgn_height_at(c);
if (max_height != DGN_UNDEFINED_HEIGHT && height > max_height)
return;
diff --git a/crawl-ref/source/dgn-shoals.cc b/crawl-ref/source/dgn-shoals.cc
index fae08d79b0..0447ff0f69 100644
--- a/crawl-ref/source/dgn-shoals.cc
+++ b/crawl-ref/source/dgn-shoals.cc
@@ -8,6 +8,7 @@
#include "dgn-shoals.h"
#include "dgn-height.h"
#include "env.h"
+#include "flood_find.h"
#include "fprop.h"
#include "items.h"
#include "itemprop.h"
@@ -220,6 +221,22 @@ static void _shoals_apply_level()
grd(*ri) = _shoals_feature_at(*ri);
}
+static void _shoals_postbuild_apply_level()
+{
+ for (rectangle_iterator ri(1); ri; ++ri)
+ {
+ if (!map_masked(*ri, MMT_VAULT))
+ {
+ const dungeon_feature_type feat = grd(*ri);
+ if (feat_is_water(feat) || feat == DNGN_ROCK_WALL
+ || feat == DNGN_STONE_WALL || feat == DNGN_FLOOR)
+ {
+ grd(*ri) = _shoals_feature_at(*ri);
+ }
+ }
+ }
+}
+
// Returns all points in deep water with an adjacent square in shallow water.
static vector<coord_def> _shoals_water_depth_change_points()
{
@@ -288,22 +305,23 @@ static void _shoals_furniture(int margin)
static void _shoals_deepen_edges()
{
- const int edge = 2;
+ const int edge = 1;
+ const int deepen_by = 1000;
// Water of the edge of the screen is too deep to be exposed by tides.
for (int y = 1; y < GYM - 2; ++y)
{
for (int x = 1; x <= edge; ++x)
{
- dgn_height_at(coord_def(x, y)) -= 800;
- dgn_height_at(coord_def(GXM - 1 - x, y)) -= 800;
+ dgn_height_at(coord_def(x, y)) -= deepen_by;
+ dgn_height_at(coord_def(GXM - 1 - x, y)) -= deepen_by;
}
}
for (int x = 1; x < GXM - 2; ++x)
{
for (int y = 1; y <= edge; ++y)
{
- dgn_height_at(coord_def(x, y)) -= 800;
- dgn_height_at(coord_def(x, GYM - 1 - y)) -= 800;
+ dgn_height_at(coord_def(x, y)) -= deepen_by;
+ dgn_height_at(coord_def(x, GYM - 1 - y)) -= deepen_by;
}
}
}
@@ -700,6 +718,118 @@ void shoals_postprocess_level()
shoals_apply_tides(0, true, false);
}
+static void _shoals_clamp_height_at(const coord_def &c,
+ int clamp_height = SHT_ROCK - 1)
+{
+ if (!in_bounds(c))
+ return;
+
+ if (dgn_height_at(c) > clamp_height)
+ dgn_height_at(c) = clamp_height;
+}
+
+static void _shoals_connect_smooth_height_at(const coord_def &c)
+{
+ if (map_bounds_with_margin(c, 3))
+ dgn_smooth_height_at(c, 1);
+}
+
+static void _shoals_connecting_point_smooth(const coord_def &c, int radius)
+{
+ for (int dy = 0; dy < radius; ++dy)
+ {
+ for (int dx = 0; dx < radius; ++dx)
+ {
+ _shoals_connect_smooth_height_at(c + coord_def(dy, dx));
+ if (dy)
+ _shoals_connect_smooth_height_at(c + coord_def(-dy, dx));
+ if (dx)
+ _shoals_connect_smooth_height_at(c + coord_def(dy, -dx));
+ if (dx && dy)
+ _shoals_connect_smooth_height_at(c + coord_def(-dy, -dx));
+ }
+ }
+}
+
+static void _shoals_connecting_point_clamp_height(
+ const coord_def &c, int radius)
+{
+ if (!in_bounds(c))
+ return;
+
+ for (rectangle_iterator ri(c - coord_def(radius, radius),
+ c + coord_def(radius, radius)); ri; ++ri)
+ {
+ _shoals_clamp_height_at(*ri);
+ }
+
+ const int min_height_threshold = (SHT_SHALLOW_WATER + SHT_FLOOR) / 2;
+ if (dgn_height_at(c) < min_height_threshold)
+ dgn_height_at(c) = min_height_threshold;
+}
+
+bool dgn_shoals_connect_point(const coord_def &point,
+ bool (*overwriteable)(dungeon_feature_type))
+{
+ flood_find<feature_grid, coord_predicate> ff(env.grid, in_bounds, true,
+ false);
+ ff.add_feat(DNGN_FLOOR);
+
+ const coord_def target = ff.find_first_from(point, env.level_map_mask);
+ if (!in_bounds(target))
+ return false;
+
+ const vector<coord_def> track =
+ dgn_join_the_dots_pathfind(point, target, MMT_VAULT);
+
+ if (!track.empty())
+ {
+ const int n_points = 15;
+ const int radius = 4;
+
+ for (vector<coord_def>::const_iterator i = track.begin();
+ i != track.end(); ++i)
+ {
+ int height = 0, npoints = 0;
+ for (radius_iterator ri(*i, radius, C_POINTY); ri; ++ri)
+ {
+ if (in_bounds(*ri))
+ {
+ height += dgn_height_at(*ri);
+ ++npoints;
+ }
+ }
+
+ const int target_height = SHT_FLOOR;
+ if (height < target_height)
+ {
+ const int elevation_change = target_height - height;
+ const int elevation_change_per_dot =
+ max(1, elevation_change / n_points + 1);
+
+ dgn_island_centred_at(*i, n_points, radius,
+ int_range(elevation_change_per_dot,
+ elevation_change_per_dot + 20),
+ 3);
+ }
+ }
+
+ for (int i = track.size() - 1; i >= 0; --i)
+ {
+ const coord_def &p(track[i]);
+ _shoals_connecting_point_smooth(p, radius + 2);
+ }
+ for (int i = track.size() - 1; i >= 0; --i)
+ {
+ const coord_def &p(track[i]);
+ _shoals_connecting_point_clamp_height(p, radius + 2);
+ }
+
+ _shoals_postbuild_apply_level();
+ }
+ return !track.empty();
+}
+
static void _shoals_run_tide(int &tide, int &acc)
{
// If someone is calling the tide, the tide velocity is clamped high.
diff --git a/crawl-ref/source/dgn-shoals.h b/crawl-ref/source/dgn-shoals.h
index 24e17da41a..62c04ecd3f 100644
--- a/crawl-ref/source/dgn-shoals.h
+++ b/crawl-ref/source/dgn-shoals.h
@@ -3,6 +3,8 @@
void dgn_build_shoals_level();
void dgn_shoals_generate_flora();
+bool dgn_shoals_connect_point(const coord_def &point,
+ bool (*overwriteable)(dungeon_feature_type));
void shoals_postprocess_level();
void shoals_apply_tides(int turns_elapsed, bool force,
bool incremental_tide);
diff --git a/crawl-ref/source/dungeon.cc b/crawl-ref/source/dungeon.cc
index 2e4b6d8f8b..00ea7ced85 100644
--- a/crawl-ref/source/dungeon.cc
+++ b/crawl-ref/source/dungeon.cc
@@ -117,7 +117,9 @@ static void _add_plant_clumps(int frequency = 10, int clump_density = 12,
static void _pick_float_exits(vault_placement &place,
vector<coord_def> &targets);
-static bool _connect_spotty(const coord_def& from);
+static bool _feat_is_wall_floor_liquid(dungeon_feature_type);
+static bool _connect_spotty(const coord_def& from,
+ bool (*overwriteable)(dungeon_feature_type) = NULL);
static bool _connect_vault_exit(const coord_def& exit);
// ITEM & SHOP FUNCTIONS
@@ -2259,7 +2261,7 @@ static void _build_dungeon_level(dungeon_feature_type dest_stairs_type)
const unsigned nvaults = env.level_vaults.size();
// Any further vaults must make sure not to disrupt level layout.
- dgn_check_connectivity = !player_in_branch(BRANCH_SHOALS);
+ dgn_check_connectivity = true;
if (player_in_branch(BRANCH_MAIN_DUNGEON)
&& !crawl_state.game_is_tutorial())
@@ -3966,8 +3968,7 @@ _build_vault_impl(const map_def *vault,
if (!make_no_exits)
{
const bool spotty = player_in_branch(BRANCH_ORCISH_MINES)
- || player_in_branch(BRANCH_SLIME_PITS)
- || player_in_branch(BRANCH_SHOALS);
+ || player_in_branch(BRANCH_SLIME_PITS);
place.connect(spotty);
}
@@ -5003,10 +5004,16 @@ static void _jtd_init_surrounds(coord_set &coords, uint32_t mapmask,
}
}
-static bool _join_the_dots_pathfind(coord_set &coords,
- const coord_def &from, const coord_def &to,
- uint32_t mapmask)
+// Resets travel_point_distance
+vector<coord_def> dgn_join_the_dots_pathfind(const coord_def &from,
+ const coord_def &to,
+ uint32_t mapmask)
{
+ memset(travel_point_distance, 0, sizeof(travel_distance_grid_t));
+ const coord_comparator comp(to);
+ coord_set coords(comp);
+
+ vector<coord_def> path;
coord_def curr = from;
while (true)
{
@@ -5026,36 +5033,44 @@ static bool _join_the_dots_pathfind(coord_set &coords,
}
if (curr != to)
- return false;
+ return path;
while (curr != from)
{
if (!map_masked(curr, mapmask))
- {
- grd(curr) = DNGN_FLOOR;
- dgn_height_set_at(curr);
- }
+ path.push_back(curr);
const int dist = travel_point_distance[curr.x][curr.y];
ASSERT(dist < 0 && dist != -1000);
curr += coord_def(-dist / 4 - 2, (-dist % 4) - 2);
}
if (!map_masked(curr, mapmask))
- grd(curr) = DNGN_FLOOR;
+ path.push_back(curr);
- return true;
+ return path;
}
bool join_the_dots(const coord_def &from, const coord_def &to,
- uint32_t mapmask)
+ uint32_t mapmask,
+ bool (*overwriteable)(dungeon_feature_type))
{
- memset(travel_point_distance, 0, sizeof(travel_distance_grid_t));
+ if (!overwriteable)
+ overwriteable = _feat_is_wall_floor_liquid;
- const coord_comparator comp(to);
- coord_set coords(comp);
- const bool found = _join_the_dots_pathfind(coords, from, to, mapmask);
+ const vector<coord_def> path =
+ dgn_join_the_dots_pathfind(from, to, mapmask);
- return found;
+ for (vector<coord_def>::const_iterator i = path.begin(); i != path.end();
+ ++i)
+ {
+ if (!map_masked(*i, mapmask) && overwriteable(grd(*i)))
+ {
+ grd(*i) = DNGN_FLOOR;
+ dgn_height_set_at(*i);
+ }
+ }
+
+ return !path.empty() || from == to;
}
static dungeon_feature_type _pick_temple_altar(vault_placement &place)
@@ -5449,17 +5464,28 @@ static bool _spotty_seed_ok(const coord_def& p)
&& p.x < GXM - margin && p.y < GYM - margin);
}
+static bool _feat_is_wall_floor_liquid(dungeon_feature_type feat)
+{
+ return (feat_is_water(feat) || feat_is_lava(feat) || feat_is_wall(feat)
+ || feat == DNGN_FLOOR);
+}
+
// Connect vault exit "from" to dungeon floor by growing a spotty chamber.
// This tries to be like _spotty_level, but probably isn't quite.
// It might be better to aim for a more open connection -- currently
// it stops pretty much as soon as connectivity is attained.
-static bool _connect_spotty(const coord_def& from)
+set<coord_def>
+dgn_spotty_connect_path(const coord_def& from,
+ bool (*overwriteable)(dungeon_feature_type))
{
set<coord_def> flatten;
set<coord_def> border;
set<coord_def>::const_iterator it;
bool success = false;
+ if (!overwriteable)
+ overwriteable = _feat_is_wall_floor_liquid;
+
for (adjacent_iterator ai(from); ai; ++ai)
if (!map_masked(*ai, MMT_VAULT) && _spotty_seed_ok(*ai))
border.insert(*ai);
@@ -5483,11 +5509,8 @@ static bool _connect_spotty(const coord_def& from)
if (grd(*ai) == DNGN_FLOOR)
success = true; // Through, but let's remove the others, too.
- if ((grd(*ai) != DNGN_ROCK_WALL && grd(*ai) != DNGN_SLIMY_WALL)
- || flatten.find(*ai) != flatten.end())
- {
+ if (!overwriteable(grd(*ai)) || flatten.find(*ai) != flatten.end())
continue;
- }
flatten.insert(*ai);
for (adjacent_iterator bi(*ai); bi; ++bi)
@@ -5502,16 +5525,29 @@ static bool _connect_spotty(const coord_def& from)
}
}
- if (success)
+ if (!success)
+ flatten.clear();
+
+ return flatten;
+}
+
+static bool _connect_spotty(const coord_def& from,
+ bool (*overwriteable)(dungeon_feature_type))
+{
+ const set<coord_def> spotty_path =
+ dgn_spotty_connect_path(from, overwriteable);
+
+ if (!spotty_path.empty())
{
- for (it = flatten.begin(); it != flatten.end(); ++it)
+ for (set<coord_def>::const_iterator it = spotty_path.begin();
+ it != spotty_path.end(); ++it)
{
grd(*it) = DNGN_FLOOR;
dgn_height_set_at(*it);
}
}
- return success;
+ return !spotty_path.empty();
}
bool place_specific_trap(const coord_def& where, trap_type spec_type, int charges)
@@ -6442,9 +6478,15 @@ void vault_placement::connect(bool spotty) const
for (vector<coord_def>::const_iterator i = exits.begin();
i != exits.end(); ++i)
{
- if (spotty && _connect_spotty(*i))
+ if (spotty && _connect_spotty(*i, _feat_is_wall_floor_liquid))
continue;
+ if (player_in_branch(BRANCH_SHOALS) &&
+ dgn_shoals_connect_point(*i, _feat_is_wall_floor_liquid))
+ {
+ continue;
+ }
+
if (!_connect_vault_exit(*i))
dprf("Warning: failed to connect vault exit (%d;%d).", i->x, i->y);
}
diff --git a/crawl-ref/source/dungeon.h b/crawl-ref/source/dungeon.h
index 298072e80a..3f485aac26 100644
--- a/crawl-ref/source/dungeon.h
+++ b/crawl-ref/source/dungeon.h
@@ -285,7 +285,18 @@ string dump_vault_maps();
bool dgn_square_travel_ok(const coord_def &c);
-bool join_the_dots(const coord_def &from, const coord_def &to, unsigned mmask);
+set<coord_def> dgn_spotty_connect_path(
+ const coord_def& from,
+ bool (*overwriteable)(dungeon_feature_type) = NULL);
+
+// Resets travel_point_distance!
+vector<coord_def> dgn_join_the_dots_pathfind(const coord_def &from,
+ const coord_def &to,
+ uint32_t mapmask);
+
+bool join_the_dots(const coord_def &from, const coord_def &to,
+ unsigned mmask,
+ bool (*overwriteable)(dungeon_feature_type) = NULL);
int count_feature_in_box(int x0, int y0, int x1, int y1,
dungeon_feature_type feat);
bool door_vetoed(const coord_def pos);
diff --git a/crawl-ref/source/maps.cc b/crawl-ref/source/maps.cc
index cbf04210ec..a2f6df14cf 100644
--- a/crawl-ref/source/maps.cc
+++ b/crawl-ref/source/maps.cc
@@ -508,7 +508,7 @@ static coord_def _find_minivault_place(
// [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;
+ const int margin = MAPGEN_BORDER * 2 + 1;
// Find a target area which can be safely overwritten.
for (int tries = 0; tries < 600; ++tries)