From 199d107c9f40413126a31fcc843f5c54608bc73c Mon Sep 17 00:00:00 2001 From: dshaligram Date: Sun, 29 Jul 2007 17:10:16 +0000 Subject: &L can place encompass levels, and is more aggressive about overwriting existing dungeon features. Dungeon features of importance - such as stairs, shops, and altars - and map markers are shifted out of the way, to the nearest free floor square. git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@1947 c06c8d41-db1a-0410-9941-cceddc491573 --- crawl-ref/source/dungeon.cc | 51 ++++++++++++++++--- crawl-ref/source/mapmark.cc | 21 ++++++++ crawl-ref/source/mapmark.h | 1 + crawl-ref/source/maps.cc | 5 +- crawl-ref/source/misc.cc | 116 +++++++++++++++++++++++++++++++++---------- crawl-ref/source/shopping.cc | 2 +- crawl-ref/source/shopping.h | 2 +- 7 files changed, 158 insertions(+), 40 deletions(-) (limited to 'crawl-ref/source') diff --git a/crawl-ref/source/dungeon.cc b/crawl-ref/source/dungeon.cc index 58a2870d98..937482cb7a 100644 --- a/crawl-ref/source/dungeon.cc +++ b/crawl-ref/source/dungeon.cc @@ -55,6 +55,7 @@ #include "notes.h" #include "player.h" #include "randart.h" +#include "spells3.h" #include "spl-book.h" #include "stuff.h" #include "tags.h" @@ -2880,6 +2881,9 @@ static bool safe_minivault_place(int v1x, int v1y, const vault_placement &place, bool clobber) { + if (clobber) + return (true); + const bool water_ok = place.map.has_tag("water_ok"); const std::vector &lines = place.map.map.get_lines(); for (int vx = v1x; vx < v1x + place.width; vx++) @@ -2893,20 +2897,16 @@ static bool safe_minivault_place(int v1x, int v1y, return (false); const dungeon_feature_type dfeat = grd[vx][vy]; - + if ((dfeat != DNGN_FLOOR && dfeat != DNGN_ROCK_WALL && dfeat != DNGN_CLOSED_DOOR && dfeat != DNGN_SECRET_DOOR && (!water_ok || (dfeat != DNGN_DEEP_WATER - && dfeat != DNGN_SHALLOW_WATER)) - && (!clobber - || (!grid_is_solid(dfeat) && dfeat != DNGN_LAVA - && !grid_is_watery(dfeat)))) - || (!clobber - && (igrd[vx][vy] != NON_ITEM - || mgrd[vx][vy] != NON_MONSTER))) + && dfeat != DNGN_SHALLOW_WATER))) + || igrd[vx][vy] != NON_ITEM + || mgrd[vx][vy] != NON_MONSTER) { return (false); } @@ -3419,6 +3419,9 @@ static dungeon_feature_type dgn_find_rune_subst_tags(const std::string &tags) } // Places a map on the current level (minivault or regular vault). +// +// NOTE: encompass maps will destroy the existing level! +// // generating_level: If true, assumes that this is in the middle of normal // level generation, and does not link items or handle // changing terrain. @@ -3429,6 +3432,26 @@ bool dgn_place_map(int map, bool generating_level, bool clobber) { const map_def *mdef = map_by_index(map); bool did_map = false; + bool fixup = false; + + if (mdef->orient == MAP_ENCOMPASS && !generating_level) + { + if (clobber) + { + // For encompass maps, clear the entire level. + generating_level = true; + fixup = true; + reset_level(); + dungeon_events.clear(); + } + else + { + mprf(MSGCH_DIAGNOSTICS, + "Cannot generate encompass map '%s' without clobber=true", + mdef->name.c_str()); + return (false); + } + } if (mdef->is_minivault()) did_map = @@ -3460,6 +3483,18 @@ bool dgn_place_map(int map, bool generating_level, bool clobber) } } } + + if (fixup) + { + link_items(); + env_activate_markers(); + + // Force teleport to place the player somewhere sane. + you_teleport_now(false, false); + } + + if (fixup || !generating_level) + setup_environment_effects(); return (did_map); } diff --git a/crawl-ref/source/mapmark.cc b/crawl-ref/source/mapmark.cc index 2f2dc84a6b..191466f9e2 100644 --- a/crawl-ref/source/mapmark.cc +++ b/crawl-ref/source/mapmark.cc @@ -421,6 +421,27 @@ map_marker *env_find_marker(const coord_def &c, map_marker_type type) return (NULL); } +void env_move_markers(const coord_def &from, const coord_def &to) +{ + std::pair + els = env.markers.equal_range(from); + + std::list markers; + for (dgn_marker_map::iterator i = els.first; i != els.second; ) + { + dgn_marker_map::iterator curr = i++; + markers.push_back(curr->second); + env.markers.erase(curr); + } + + for (std::list::iterator i = markers.begin(); + i != markers.end(); ++i) + { + (*i)->pos = to; + env_add_marker(*i); + } +} + std::vector env_get_markers(const coord_def &c) { std::pair diff --git a/crawl-ref/source/mapmark.h b/crawl-ref/source/mapmark.h index dc18f77946..49983e8017 100644 --- a/crawl-ref/source/mapmark.h +++ b/crawl-ref/source/mapmark.h @@ -109,5 +109,6 @@ std::vector env_get_markers(const coord_def &c); void env_clear_markers(); std::string env_property_at(const coord_def &c, map_marker_type, const std::string &key); +void env_move_markers(const coord_def &from, const coord_def &to); #endif diff --git a/crawl-ref/source/maps.cc b/crawl-ref/source/maps.cc index 8599c2efe2..859e6fe211 100644 --- a/crawl-ref/source/maps.cc +++ b/crawl-ref/source/maps.cc @@ -161,7 +161,7 @@ static bool bad_map_place(const map_def &map, int sx, int sy, int width, int height, bool check_place, bool clobber) { - if (!check_place) + if (!check_place || clobber) return (false); const std::vector &lines = map.map.get_lines(); @@ -175,8 +175,7 @@ static bool bad_map_place(const map_def &map, if (dgn_map_mask[x][y]) return (true); - if (!clobber - && (igrd[x][y] != NON_ITEM || mgrd[x][y] != NON_MONSTER)) + if (igrd[x][y] != NON_ITEM || mgrd[x][y] != NON_MONSTER) return (true); const dungeon_feature_type grid = grd[x][y]; diff --git a/crawl-ref/source/misc.cc b/crawl-ref/source/misc.cc index 328f46617d..372dbebb84 100644 --- a/crawl-ref/source/misc.cc +++ b/crawl-ref/source/misc.cc @@ -451,49 +451,110 @@ void search_around( bool only_adjacent ) return; } // end search_around() -static bool dgn_shift_item_around(const coord_def &pos, item_def &item) +static coord_def dgn_find_nearest_square( + const coord_def &pos, + bool (*acceptable)(const coord_def &), + bool (*traversable)(const coord_def &) = NULL) { - std::list points; - for (int yi = -1; yi <= 1; ++yi) + memset(travel_point_distance, 0, sizeof(travel_distance_grid_t)); + + std::list points[2]; + int iter = 0; + points[iter].push_back(pos); + + while (!points[iter].empty()) { - for (int xi = -1; xi <= 1; ++xi) + for (std::list::iterator i = points[iter].begin(); + i != points[iter].end(); ++i) { - if (!xi && !yi) - continue; + const coord_def &p = *i; - const coord_def np(pos.x + xi, pos.y + yi); - if (!in_bounds(np) || travel_point_distance[np.x][np.y]) - continue; + if (p != pos && acceptable(p)) + return (p); + + travel_point_distance[p.x][p.y] = 1; + for (int yi = -1; yi <= 1; ++yi) + { + for (int xi = -1; xi <= 1; ++xi) + { + if (!xi && !yi) + continue; - travel_point_distance[np.x][np.y] = 1; + const coord_def np = p + coord_def(xi, yi); + if (!in_bounds(np) || travel_point_distance[np.x][np.y]) + continue; - const dungeon_feature_type feat = grd(np); - if (!grid_is_solid(feat) && !grid_destroys_items(feat)) - { - int index = item.index(); - move_item_to_grid(&index, np.x, np.y); - return (true); + if (traversable && !traversable(np)) + continue; + + points[!iter].push_back(np); + } } - - points.push_back(np); } + + points[iter].clear(); + iter = !iter; } - for (std::list::iterator i = points.begin(); i != points.end(); - ++i) + return (coord_def()); +} + +static bool item_safe_square(const coord_def &pos) +{ + const dungeon_feature_type feat = grd(pos); + return (is_traversable(feat) && !grid_destroys_items(feat)); +} + +// Moves an item on the floor to the nearest adjacent floor-space. +static bool dgn_shift_item(const coord_def &pos, item_def &item) +{ + const coord_def np = dgn_find_nearest_square(pos, item_safe_square); + if (in_bounds(np) && np != pos) { - if (dgn_shift_item_around(*i, item)) - return (true); + int index = item.index(); + move_item_to_grid(&index, np.x, np.y); + return (true); } return (false); } -// Moves an item on the floor to the nearest adjacent floor-space. -static bool dgn_shift_item(const coord_def &pos, item_def &item) +static bool is_critical_feature(dungeon_feature_type feat) { - memset(travel_point_distance, 0, sizeof(travel_distance_grid_t)); - travel_point_distance[pos.x][pos.y] = 0; - return (dgn_shift_item_around(pos, item)); + return (grid_stair_direction(feat) != CMD_NO_CMD + || grid_altar_god(feat) != GOD_NO_GOD); +} + +static bool is_feature_shift_target(const coord_def &pos) +{ + return (grd(pos) == DNGN_FLOOR); +} + +static bool dgn_shift_feature(const coord_def &pos) +{ + const dungeon_feature_type dfeat = grd(pos); + if (!is_critical_feature(dfeat) && !env_find_marker(pos, MAT_ANY)) + return (false); + + const coord_def dest = + dgn_find_nearest_square(pos, is_feature_shift_target); + if (in_bounds(dest) && dest != pos) + { + grd(dest) = dfeat; + + if (dfeat == DNGN_ENTER_SHOP) + { + if (shop_struct *s = get_shop(pos.x, pos.y)) + { + s->x = dest.x; + s->y = dest.y; + } + } + env_move_markers(pos, dest); + + if (see_grid(dest) && is_notable_terrain(dfeat)) + seen_notable_thing(dfeat, dest.x, dest.y); + } + return (true); } static void dgn_check_terrain_items(const coord_def &pos) @@ -541,6 +602,7 @@ void dungeon_terrain_changed(const coord_def &pos, { if (nfeat != DNGN_UNSEEN) { + dgn_shift_feature(pos); unnotice_feature(level_pos(level_id::current(), pos)); grd(pos) = nfeat; if (is_notable_terrain(nfeat) && see_grid(pos)) diff --git a/crawl-ref/source/shopping.cc b/crawl-ref/source/shopping.cc index fce0a7cab6..9873fcec93 100644 --- a/crawl-ref/source/shopping.cc +++ b/crawl-ref/source/shopping.cc @@ -1485,7 +1485,7 @@ void shop() redraw_screen(); } // end shop() -const shop_struct *get_shop(int sx, int sy) +shop_struct *get_shop(int sx, int sy) { if (grd[sx][sy] != DNGN_ENTER_SHOP) return (NULL); diff --git a/crawl-ref/source/shopping.h b/crawl-ref/source/shopping.h index b558fed97b..f91e14a111 100644 --- a/crawl-ref/source/shopping.h +++ b/crawl-ref/source/shopping.h @@ -24,7 +24,7 @@ int randart_value( const item_def &item ); unsigned int item_value( item_def item, bool ident = false ); void shop(); -const shop_struct *get_shop(int sx, int sy); +shop_struct *get_shop(int sx, int sy); std::string shop_name(int sx, int sy); std::string shop_name(int sx, int sy, bool add_stop); -- cgit v1.2.3-54-g00ecf