diff options
author | dshaligram <dshaligram@c06c8d41-db1a-0410-9941-cceddc491573> | 2007-07-18 16:31:53 +0000 |
---|---|---|
committer | dshaligram <dshaligram@c06c8d41-db1a-0410-9941-cceddc491573> | 2007-07-18 16:31:53 +0000 |
commit | 280290a5fabe951a68d53c09f6c92c1172b27454 (patch) | |
tree | 780f4274f2548cd1a475682b95eab93acc428a25 /crawl-ref | |
parent | 1d98e2f42503bee2a5ed1842db732f6a6b03884d (diff) | |
download | crawl-ref-280290a5fabe951a68d53c09f6c92c1172b27454.tar.gz crawl-ref-280290a5fabe951a68d53c09f6c92c1172b27454.zip |
[1754412] New rock stair behaviour: rock stairs take you to the nearest
point on the target level that is connected to at least one stone stair.
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@1893 c06c8d41-db1a-0410-9941-cceddc491573
Diffstat (limited to 'crawl-ref')
-rw-r--r-- | crawl-ref/source/dungeon.cc | 263 | ||||
-rw-r--r-- | crawl-ref/source/dungeon.h | 1 | ||||
-rw-r--r-- | crawl-ref/source/files.cc | 175 | ||||
-rw-r--r-- | crawl-ref/source/misc.cc | 16 | ||||
-rw-r--r-- | crawl-ref/source/misc.h | 1 | ||||
-rw-r--r-- | crawl-ref/source/travel.cc | 39 | ||||
-rw-r--r-- | crawl-ref/source/travel.h | 3 |
7 files changed, 291 insertions, 207 deletions
diff --git a/crawl-ref/source/dungeon.cc b/crawl-ref/source/dungeon.cc index 7d5e24b3a6..a93c75773f 100644 --- a/crawl-ref/source/dungeon.cc +++ b/crawl-ref/source/dungeon.cc @@ -180,7 +180,6 @@ static void chequerboard(spec_room &sr, dungeon_feature_type target, dungeon_feature_type floor2); static void roguey_level(int level_number, spec_room &sr); static void morgue(spec_room &sr); -static void dgn_fill_zone(const coord_def &c, int zone); // SPECIAL ROOM BUILDERS static void special_room(int level_number, spec_room &sr); @@ -290,12 +289,43 @@ bool builder(int level_number, int level_type) return (false); } -static inline bool dgn_grid_is_isolating(const dungeon_feature_type grid) +static inline bool dgn_grid_is_passable(dungeon_feature_type grid) { // Rock wall check is superfluous, but is the most common case. - return (grid == DNGN_ROCK_WALL - || (grid_is_solid(grid) && grid != DNGN_CLOSED_DOOR - && grid != DNGN_SECRET_DOOR)); + return !(grid == DNGN_ROCK_WALL + || (grid_is_solid(grid) && grid != DNGN_CLOSED_DOOR + && grid != DNGN_SECRET_DOOR)); +} + +static inline void dgn_point_record_stub(const coord_def &) { } + +template <class point_record> +static void dgn_fill_zone( + const coord_def &c, int zone, point_record &prec, + bool (*passable)(dungeon_feature_type) = dgn_grid_is_passable) +{ + // No bounds checks, assuming the level has at least one layer of + // rock border. + travel_point_distance[c.x][c.y] = zone; + for (int yi = -1; yi <= 1; ++yi) + { + for (int xi = -1; xi <= 1; ++xi) + { + if (!xi && !yi) + continue; + + const coord_def cp(c.x + xi, c.y + yi); + if (travel_point_distance[cp.x][cp.y] + || dgn_map_mask(cp) + || !passable(grd(cp))) + { + continue; + } + + prec(cp); + dgn_fill_zone(cp, zone, prec); + } + } } // Counts the number of mutually unreachable areas in the map, @@ -338,37 +368,36 @@ static int dgn_count_disconnected_zones() if (travel_point_distance[x][y] || dgn_map_mask[x][y]) continue; - if (dgn_grid_is_isolating(grd[x][y])) + if (!dgn_grid_is_passable(grd[x][y])) continue; - dgn_fill_zone(coord_def(x, y), ++nzones); + dgn_fill_zone(coord_def(x, y), ++nzones, dgn_point_record_stub); } } return (nzones); } -static void dgn_fill_zone(const coord_def &c, int zone) +static void fixup_pandemonium_stairs() { - // No bounds checks, assuming the level has at least one layer of - // rock border. - travel_point_distance[c.x][c.y] = zone; - for (int yi = -1; yi <= 1; ++yi) + for (int i = 0; i < GXM; i++) { - for (int xi = -1; xi <= 1; ++xi) + for (int j = 0; j < GYM; j++) { - if (!xi && !yi) - continue; - - const coord_def cp(c.x + xi, c.y + yi); - if (travel_point_distance[cp.x][cp.y] - || dgn_map_mask(cp) - || dgn_grid_is_isolating(grd(cp))) + if (grd[i][j] >= DNGN_STONE_STAIRS_UP_I + && grd[i][j] <= DNGN_ROCK_STAIRS_UP) { - continue; + if (one_chance_in( you.mutation[MUT_PANDEMONIUM] ? 5 : 50 )) + grd[i][j] = DNGN_EXIT_PANDEMONIUM; + else + grd[i][j] = DNGN_FLOOR; + } + + if (grd[i][j] >= DNGN_ENTER_LABYRINTH + && grd[i][j] <= DNGN_ROCK_STAIRS_DOWN) + { + grd[i][j] = DNGN_TRANSIT_PANDEMONIUM; } - - dgn_fill_zone(cp, zone); } } } @@ -733,6 +762,10 @@ static void build_dungeon_level(int level_number, int level_type) !player_in_branch(BRANCH_SWAMP) && !player_in_branch(BRANCH_SHOALS)) prepare_water( level_number ); + + // Translate stairs for pandemonium levels: + if (level_type == LEVEL_PANDEMONIUM) + fixup_pandemonium_stairs(); } // end builder() static void check_doors() @@ -6362,6 +6395,190 @@ static void build_lake(dungeon_feature_type lake_type) //mv } } // end lake() +struct nearest_point +{ + coord_def target; + coord_def nearest; + int distance; + + nearest_point(const coord_def &t) : target(t), nearest(), distance(-1) + { + } + void operator () (const coord_def &c) + { + if (grd(c) == DNGN_FLOOR) + { + const int ndist = (c - target).abs(); + if (distance == -1 || ndist < distance) + { + distance = ndist; + nearest = c; + } + } + } +}; + +// Fill travel_point_distance out from all stone stairs on the level. +static coord_def dgn_find_closest_to_stone_stairs() +{ + memset(travel_point_distance, 0, sizeof(travel_distance_grid_t)); + init_travel_terrain_check(false); + nearest_point np(you.pos()); + for (int y = 0; y < GYM; ++y) + for (int x = 0; x < GXM; ++x) + if (!travel_point_distance[x][y] && grid_is_stone_stair(grd[x][y])) + dgn_fill_zone(coord_def(x, y), 1, np, is_traversable); + return (np.nearest); +} + +coord_def dgn_find_nearby_stair(int stair_to_find, bool find_closest) +{ + if (stair_to_find == DNGN_ROCK_STAIRS_UP + || stair_to_find == DNGN_ROCK_STAIRS_DOWN) + { + const coord_def pos(dgn_find_closest_to_stone_stairs()); + if (in_bounds(pos)) + return (pos); + } + + // scan around the player's position first + int basex = you.x_pos; + int basey = you.y_pos; + + // check for illegal starting point + if ( !in_bounds(basex, basey) ) + { + basex = 0; + basey = 0; + } + + coord_def result; + + int found = 0; + int best_dist = 1 + GXM*GXM + GYM*GYM; + + // XXX These passes should be rewritten to use an iterator of STL + // algorithm of some kind. + + // First pass: look for an exact match + for (int xcode = 0; xcode < GXM; ++xcode ) + { + const int xsign = ((xcode % 2) ? 1 : -1); + const int xdiff = xsign * (xcode + 1)/2; + const int xpos = (basex + xdiff + GXM) % GXM; + + for (int ycode = 0; ycode < GYM; ++ycode) + { + const int ysign = ((ycode % 2) ? 1 : -1); + const int ydiff = ysign * (ycode + 1)/2; + const int ypos = (basey + ydiff + GYM) % GYM; + + // note that due to the wrapping above, we can't just use + // xdiff*xdiff + ydiff*ydiff + const int dist = (xpos-basex)*(xpos-basex) + + (ypos-basey)*(ypos-basey); + + if (grd[xpos][ypos] == stair_to_find) + { + found++; + if (find_closest) + { + if (dist < best_dist) + { + best_dist = dist; + result.x = xpos; + result.y = ypos; + } + } + else if (one_chance_in( found )) + { + result.x = xpos; + result.y = ypos; + } + } + } + } + + if ( found ) + return result; + + best_dist = 1 + GXM*GXM + GYM*GYM; + + // Second pass: find a staircase in the proper direction + for (int xcode = 0; xcode < GXM; ++xcode ) + { + const int xsign = ((xcode % 2) ? 1 : -1); + const int xdiff = xsign * (xcode + 1)/2; + const int xpos = (basex + xdiff + GXM) % GXM; + + for (int ycode = 0; ycode < GYM; ++ycode) + { + const int ysign = ((ycode % 2) ? 1 : -1); + const int ydiff = ysign * (ycode + 1)/2; + const int ypos = (basey + ydiff + GYM) % GYM; + + bool good_stair; + const int looking_at = grd[xpos][ypos]; + + if (stair_to_find <= DNGN_ROCK_STAIRS_DOWN ) + good_stair = + (looking_at >= DNGN_STONE_STAIRS_DOWN_I) && + (looking_at <= DNGN_ROCK_STAIRS_DOWN); + else + good_stair = + (looking_at >= DNGN_STONE_STAIRS_UP_I) && + (looking_at <= DNGN_ROCK_STAIRS_UP); + + const int dist = (xpos-basex)*(xpos-basex) + + (ypos-basey)*(ypos-basey); + + if ( good_stair ) + { + found++; + if (find_closest && dist < best_dist) + { + best_dist = dist; + result.x = xpos; + result.y = ypos; + } + else if (one_chance_in( found )) + { + result.x = xpos; + result.y = ypos; + } + } + } + } + + if ( found ) + return result; + + // Third pass: look for any clear terrain and abandon the idea of + // looking nearby now. This is used when taking transit Pandemonium gates, + // or landing in Labyrinths. Never land the PC inside a Pan or Lab vault. + // We can't check vaults for other levels because vault information is + // not saved, and the player can re-enter other levels. + for (int xpos = 0; xpos < GXM; xpos++) + { + for (int ypos = 0; ypos < GYM; ypos++) + { + if (grd[xpos][ypos] >= DNGN_FLOOR + && (you.level_type == LEVEL_DUNGEON + || unforbidden(coord_def(xpos, ypos), MMT_VAULT))) + { + found++; + if (one_chance_in( found )) + { + result.x = xpos; + result.y = ypos; + } + } + } + } + + ASSERT( found ); + return result; +} //////////////////////////////////////////////////////////////////// // dgn_region diff --git a/crawl-ref/source/dungeon.h b/crawl-ref/source/dungeon.h index 6ea27e147a..457705e4b3 100644 --- a/crawl-ref/source/dungeon.h +++ b/crawl-ref/source/dungeon.h @@ -117,6 +117,7 @@ bool place_specific_trap(int spec_x, int spec_y, trap_type spec_type); void place_spec_shop(int level_number, int shop_x, int shop_y, int force_s_type, bool representative = false); bool unforbidden(const coord_def &c, unsigned mask); +coord_def dgn_find_nearby_stair(int stair_to_find, bool find_closest); ////////////////////////////////////////////////////////////////////////// // Map markers diff --git a/crawl-ref/source/files.cc b/crawl-ref/source/files.cc index f8387f4775..6da990e5b8 100644 --- a/crawl-ref/source/files.cc +++ b/crawl-ref/source/files.cc @@ -619,142 +619,6 @@ bool travel_load_map( branch_type branch, int absdepth ) return true; } -static coord_def find_nearby_stair(int stair_to_find, bool find_closest) -{ - // scan around the player's position first - int basex = you.x_pos; - int basey = you.y_pos; - - // check for illegal starting point - if ( !in_bounds(basex, basey) ) - { - basex = 0; - basey = 0; - } - - coord_def result; - - int found = 0; - int best_dist = 1 + GXM*GXM + GYM*GYM; - - // XXX These passes should be rewritten to use an iterator of STL - // algorithm of some kind. - - // First pass: look for an exact match - for (int xcode = 0; xcode < GXM; ++xcode ) - { - const int xsign = ((xcode % 2) ? 1 : -1); - const int xdiff = xsign * (xcode + 1)/2; - const int xpos = (basex + xdiff + GXM) % GXM; - - for (int ycode = 0; ycode < GYM; ++ycode) - { - const int ysign = ((ycode % 2) ? 1 : -1); - const int ydiff = ysign * (ycode + 1)/2; - const int ypos = (basey + ydiff + GYM) % GYM; - - // note that due to the wrapping above, we can't just use - // xdiff*xdiff + ydiff*ydiff - const int dist = (xpos-basex)*(xpos-basex) + - (ypos-basey)*(ypos-basey); - - if (grd[xpos][ypos] == stair_to_find) - { - found++; - if (find_closest) - { - if (dist < best_dist) - { - best_dist = dist; - result.x = xpos; - result.y = ypos; - } - } - else if (one_chance_in( found )) - { - result.x = xpos; - result.y = ypos; - } - } - } - } - - if ( found ) - return result; - - best_dist = 1 + GXM*GXM + GYM*GYM; - - // Second pass: find a staircase in the proper direction - for (int xcode = 0; xcode < GXM; ++xcode ) - { - const int xsign = ((xcode % 2) ? 1 : -1); - const int xdiff = xsign * (xcode + 1)/2; - const int xpos = (basex + xdiff + GXM) % GXM; - - for (int ycode = 0; ycode < GYM; ++ycode) - { - const int ysign = ((ycode % 2) ? 1 : -1); - const int ydiff = ysign * (ycode + 1)/2; - const int ypos = (basey + ydiff + GYM) % GYM; - - bool good_stair; - const int looking_at = grd[xpos][ypos]; - - if (stair_to_find <= DNGN_ROCK_STAIRS_DOWN ) - good_stair = - (looking_at >= DNGN_STONE_STAIRS_DOWN_I) && - (looking_at <= DNGN_ROCK_STAIRS_DOWN); - else - good_stair = - (looking_at >= DNGN_STONE_STAIRS_UP_I) && - (looking_at <= DNGN_ROCK_STAIRS_UP); - - const int dist = (xpos-basex)*(xpos-basex) + - (ypos-basey)*(ypos-basey); - - if ( good_stair ) - { - found++; - if (find_closest && dist < best_dist) - { - best_dist = dist; - result.x = xpos; - result.y = ypos; - } - else if (one_chance_in( found )) - { - result.x = xpos; - result.y = ypos; - } - } - } - } - - if ( found ) - return result; - - // Third pass: look for any clear terrain (shouldn't happen). - // We abandon the idea of looking nearby now. - for (int xpos = 0; xpos < GXM; xpos++) - { - for (int ypos = 0; ypos < GYM; ypos++) - { - if (grd[xpos][ypos] >= DNGN_FLOOR) - { - found++; - if (one_chance_in( found )) - { - result.x = xpos; - result.y = ypos; - } - } - } - } - - ASSERT( found ); - return result; -} - static void sanity_test_monster_inventory() { // Sanity forcing of monster inventory items (required?) @@ -775,30 +639,6 @@ static void sanity_test_monster_inventory() } } -static void fixup_pandemonium_stairs() -{ - for (int i = 0; i < GXM; i++) - { - for (int j = 0; j < GYM; j++) - { - if (grd[i][j] >= DNGN_STONE_STAIRS_UP_I - && grd[i][j] <= DNGN_ROCK_STAIRS_UP) - { - if (one_chance_in( you.mutation[MUT_PANDEMONIUM] ? 5 : 50 )) - grd[i][j] = DNGN_EXIT_PANDEMONIUM; - else - grd[i][j] = DNGN_FLOOR; - } - - if (grd[i][j] >= DNGN_ENTER_LABYRINTH - && grd[i][j] <= DNGN_ROCK_STAIRS_DOWN) - { - grd[i][j] = DNGN_TRANSIT_PANDEMONIUM; - } - } - } -} - static void place_player_on_stair(branch_type old_branch, int stair_taken) { bool find_first = true; @@ -843,14 +683,16 @@ static void place_player_on_stair(branch_type old_branch, int stair_taken) else if (stair_taken >= DNGN_RETURN_FROM_ORCISH_MINES && stair_taken < 150) // 20 slots reserved { - // find entry point to subdungeon when leaving - stair_taken += (DNGN_ENTER_ORCISH_MINES - DNGN_RETURN_FROM_ORCISH_MINES); + // find entry point to subdungeon when leaving + stair_taken += (DNGN_ENTER_ORCISH_MINES + - DNGN_RETURN_FROM_ORCISH_MINES); } else if (stair_taken >= DNGN_ENTER_ORCISH_MINES && stair_taken < DNGN_RETURN_FROM_ORCISH_MINES) { // find exit staircase from subdungeon when entering - stair_taken += (DNGN_RETURN_FROM_ORCISH_MINES - DNGN_ENTER_ORCISH_MINES); + stair_taken += (DNGN_RETURN_FROM_ORCISH_MINES + - DNGN_ENTER_ORCISH_MINES); } else if (stair_taken >= DNGN_ENTER_DIS && stair_taken <= DNGN_TRANSIT_PANDEMONIUM) @@ -865,7 +707,8 @@ static void place_player_on_stair(branch_type old_branch, int stair_taken) find_first = false; } - const coord_def where_to_go = find_nearby_stair(stair_taken, find_first); + const coord_def where_to_go = + dgn_find_nearby_stair(stair_taken, find_first); you.moveto(where_to_go); } @@ -1070,10 +913,6 @@ bool load( dungeon_feature_type stair_taken, load_mode_type load_mode, sanity_test_monster_inventory(); - // Translate stairs for pandemonium levels: - if (you.level_type == LEVEL_PANDEMONIUM) - fixup_pandemonium_stairs(); - // Things to update for player entering level if (load_mode == LOAD_ENTER_LEVEL) { diff --git a/crawl-ref/source/misc.cc b/crawl-ref/source/misc.cc index 5040a38a88..0a83963b72 100644 --- a/crawl-ref/source/misc.cc +++ b/crawl-ref/source/misc.cc @@ -159,6 +159,22 @@ bool grid_is_wall( dungeon_feature_type grid ) || grid == DNGN_PERMAROCK_WALL); } +bool grid_is_stone_stair(dungeon_feature_type grid) +{ + switch (grid) + { + case DNGN_STONE_STAIRS_UP_I: + case DNGN_STONE_STAIRS_UP_II: + case DNGN_STONE_STAIRS_UP_III: + case DNGN_STONE_STAIRS_DOWN_I: + case DNGN_STONE_STAIRS_DOWN_II: + case DNGN_STONE_STAIRS_DOWN_III: + return (true); + default: + return (false); + } +} + bool grid_is_opaque( dungeon_feature_type grid ) { return (grid < MINSEE && grid != DNGN_ORCISH_IDOL); diff --git a/crawl-ref/source/misc.h b/crawl-ref/source/misc.h index ef6804cfab..46cc63cbf4 100644 --- a/crawl-ref/source/misc.h +++ b/crawl-ref/source/misc.h @@ -137,6 +137,7 @@ trap_type trap_type_at_xy(int x, int y); bool grid_is_wall(dungeon_feature_type grid); bool grid_is_opaque(dungeon_feature_type grid); bool grid_is_solid(dungeon_feature_type grid); +bool grid_is_stone_stair(dungeon_feature_type grid); bool grid_is_solid(int x, int y); bool grid_is_solid(const coord_def &c); bool grid_is_trap(dungeon_feature_type grid); diff --git a/crawl-ref/source/travel.cc b/crawl-ref/source/travel.cc index 130d74451c..b5c6b48b04 100644 --- a/crawl-ref/source/travel.cc +++ b/crawl-ref/source/travel.cc @@ -190,7 +190,7 @@ static const char *trap_name(int x, int y) /* * Returns true if the character can cross this dungeon feature. */ -bool is_traversable(int grid) +bool is_traversable(dungeon_feature_type grid) { return traversable_terrain[grid] == TRAVERSABLE; } @@ -380,7 +380,7 @@ bool is_travelsafe_square(int x, int y, bool ignore_hostile, if (!ignore_terrain_knowledge && !is_terrain_known(x, y)) return (false); - const int grid = grd[x][y]; + const dungeon_feature_type grid = grd[x][y]; // Special-case secret doors so that we don't run into awkwardness when // a monster opens a secret door without the hero seeing it, but the travel @@ -468,22 +468,31 @@ static void set_pass_feature(unsigned char grid, signed char pass) * Sets traversable terrain based on the character's role and whether or not he * has permanent levitation */ -static void init_terrain_check() +void init_travel_terrain_check(bool check_race_equip) { - // Swimmers get deep water. - signed char water = player_can_swim()? TRAVERSABLE : IMPASSABLE; + if (check_race_equip) + { + // Swimmers get deep water. + signed char water = player_can_swim()? TRAVERSABLE : IMPASSABLE; - // If the player has overridden deep water already, we'll respect that. - set_pass_feature(DNGN_DEEP_WATER, water); + // If the player has overridden deep water already, we'll respect that. + set_pass_feature(DNGN_DEEP_WATER, water); - // Permanently levitating players can cross most hostile terrain. - signed char trav = player_is_permalevitating()? - TRAVERSABLE : IMPASSABLE; + // Permanently levitating players can cross most hostile terrain. + signed char trav = player_is_permalevitating()? + TRAVERSABLE : IMPASSABLE; - if (water != TRAVERSABLE) - set_pass_feature(DNGN_DEEP_WATER, trav); - set_pass_feature(DNGN_LAVA, trav); - set_pass_feature(DNGN_TRAP_MECHANICAL, trav); + if (water != TRAVERSABLE) + set_pass_feature(DNGN_DEEP_WATER, trav); + set_pass_feature(DNGN_LAVA, trav); + set_pass_feature(DNGN_TRAP_MECHANICAL, trav); + } + else + { + set_pass_feature(DNGN_DEEP_WATER, IMPASSABLE); + set_pass_feature(DNGN_LAVA, IMPASSABLE); + set_pass_feature(DNGN_TRAP_MECHANICAL, IMPASSABLE); + } } void travel_init_new_level() @@ -1256,7 +1265,7 @@ const coord_def travel_pathfind::pathfind(run_mode_type rmode) // Check whether species or levitation permits travel through terrain such // as deep water. - init_terrain_check(); + init_travel_terrain_check(); need_for_greed = (rmode == RMODE_EXPLORE_GREEDY && can_autopickup()); diff --git a/crawl-ref/source/travel.h b/crawl-ref/source/travel.h index a2e5bc328a..7f234ca7da 100644 --- a/crawl-ref/source/travel.h +++ b/crawl-ref/source/travel.h @@ -23,6 +23,7 @@ * called from: initfile (what's a better place to initialise stuff?) * *********************************************************************** */ void initialise_travel(); +void init_travel_terrain_check(bool check_race_equip = true); void stop_running(void); void travel_init_new_level(); void cycle_exclude_radius(const coord_def &p); @@ -38,7 +39,7 @@ command_type stair_direction(dungeon_feature_type stair_feat); command_type direction_to_command( char x, char y ); bool is_resting( void ); bool can_travel_interlevel(); -bool is_traversable(int grid); +bool is_traversable(dungeon_feature_type grid); void find_travel_pos(int you_x, int you_y, char *move_x, char *move_y, std::vector<coord_def>* coords = NULL); |