summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source/files.cc
diff options
context:
space:
mode:
authorharanp <haranp@c06c8d41-db1a-0410-9941-cceddc491573>2007-04-25 10:06:09 +0000
committerharanp <haranp@c06c8d41-db1a-0410-9941-cceddc491573>2007-04-25 10:06:09 +0000
commite11f6ceb8c6fcd91d774303208ae1818428524db (patch)
tree9bb2235e632cc924b6fd30adf36b2f0dde5af663 /crawl-ref/source/files.cc
parent367e8413d532c0acf61a4c258f7482cf9f994eaa (diff)
downloadcrawl-ref-e11f6ceb8c6fcd91d774303208ae1818428524db.tar.gz
crawl-ref-e11f6ceb8c6fcd91d774303208ae1818428524db.zip
load() cleanups.
Rock stairs now take you to the closest stair distance-wise. This invalidates the interlevel travel cache. git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@1365 c06c8d41-db1a-0410-9941-cceddc491573
Diffstat (limited to 'crawl-ref/source/files.cc')
-rw-r--r--crawl-ref/source/files.cc611
1 files changed, 347 insertions, 264 deletions
diff --git a/crawl-ref/source/files.cc b/crawl-ref/source/files.cc
index 6d7d3028ac..8e4a3f4d33 100644
--- a/crawl-ref/source/files.cc
+++ b/crawl-ref/source/files.cc
@@ -542,15 +542,335 @@ bool travel_load_map( char branch, int absdepth )
return true;
}
-void load( int stair_taken, int load_mode, bool was_a_labyrinth,
- int old_level, branch_type where_were_you2 )
+static coord_def find_nearby_stair(int stair_to_find, bool find_closest)
{
- int j = 0;
- int i = 0, count_x = 0, count_y = 0;
+ // scan around the player's position first
+ int basex = you.x_pos;
+ int basey = you.y_pos;
- std::vector<follower> followers;
+ // 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 && 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?)
+ for (int i = 0; i < MAX_MONSTERS; i++)
+ {
+ if (menv[i].type == -1)
+ continue;
+
+ for (int j = 0; j < NUM_MONSTER_SLOTS; j++)
+ {
+ if (menv[i].inv[j] == NON_ITEM)
+ continue;
+
+ // items carried by monsters shouldn't be linked
+ if (mitm[menv[i].inv[j]].link != NON_ITEM)
+ mitm[menv[i].inv[j]].link = NON_ITEM;
+ }
+ }
+}
+
+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;
+
+ // Order is important here:
+ if (you.level_type == LEVEL_DUNGEON
+ && old_branch == BRANCH_VESTIBULE_OF_HELL
+ && stair_taken == DNGN_STONE_STAIRS_UP_I)
+ {
+ // leaving hell - look for entry portal first
+ stair_taken = DNGN_ENTER_HELL;
+ find_first = false;
+ }
+ else if (stair_taken == DNGN_EXIT_PANDEMONIUM)
+ {
+ stair_taken = DNGN_ENTER_PANDEMONIUM;
+ find_first = false;
+ }
+ else if (stair_taken == DNGN_EXIT_ABYSS)
+ {
+ stair_taken = DNGN_ENTER_ABYSS;
+ find_first = false;
+ }
+ else if (stair_taken == DNGN_ENTER_HELL
+ || stair_taken == DNGN_ENTER_LABYRINTH)
+ {
+ // the vestibule and labyrith always start from this stair
+ stair_taken = DNGN_STONE_STAIRS_UP_I;
+ }
+ else if (stair_taken >= DNGN_STONE_STAIRS_DOWN_I
+ && stair_taken <= DNGN_ROCK_STAIRS_DOWN)
+ {
+ // look for coresponding up stair
+ stair_taken += (DNGN_STONE_STAIRS_UP_I - DNGN_STONE_STAIRS_DOWN_I);
+ }
+ else if (stair_taken >= DNGN_STONE_STAIRS_UP_I
+ && stair_taken <= DNGN_ROCK_STAIRS_UP)
+ {
+ // look for coresponding down stair
+ stair_taken += (DNGN_STONE_STAIRS_DOWN_I - DNGN_STONE_STAIRS_UP_I);
+ }
+ 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);
+ }
+ 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);
+ }
+ else if (stair_taken >= DNGN_ENTER_DIS
+ && stair_taken <= DNGN_TRANSIT_PANDEMONIUM)
+ {
+ // when entering a hell or pandemonium
+ stair_taken = DNGN_STONE_STAIRS_UP_I;
+ }
+ else // Note: stair_taken can equal things like DNGN_FLOOR
+ {
+ // just find a nice empty square
+ stair_taken = DNGN_FLOOR;
+ find_first = false;
+ }
+
+ const coord_def where_to_go = find_nearby_stair(stair_taken, find_first);
+ you.x_pos = where_to_go.x;
+ you.y_pos = where_to_go.y;
+}
+
+static void close_level_gates()
+{
+ for ( int i = 0; i < GXM; ++i )
+ {
+ for ( int j = 0; j < GYM; ++j )
+ {
+ if (you.char_direction == DIR_ASCENDING
+ && you.level_type != LEVEL_PANDEMONIUM)
+ {
+ if (grd[i][j] == DNGN_ENTER_HELL
+ || grd[i][j] == DNGN_ENTER_ABYSS
+ || grd[i][j] == DNGN_ENTER_PANDEMONIUM)
+ {
+ grd[i][j] = DNGN_STONE_ARCH;
+ }
+ }
+ }
+ }
+}
+
+static void clear_env_map()
+{
+ for (int i = 0; i < GXM; i++)
+ {
+ for (int j = 0; j < GYM; j++)
+ {
+ env.map[i][j] = 0;
+ env.map_col[i][j].clear();
+ }
+ }
+}
- int val;
+static void clear_clouds()
+{
+ for (int i = 0; i < GXM; i++)
+ for (int j = 0; j < GYM; j++)
+ env.cgrid[i][j] = EMPTY_CLOUD;
+}
+
+static void grab_followers(std::vector<follower>& followers)
+{
+ for (int i = you.x_pos - 1; i < you.x_pos + 2; i++)
+ {
+ for (int j = you.y_pos - 1; j < you.y_pos + 2; j++)
+ {
+ if (i == you.x_pos && j == you.y_pos)
+ continue;
+
+ if (mgrd[i][j] == NON_MONSTER)
+ continue;
+
+ monsters *fmenv = &menv[mgrd[i][j]];
+
+ if (fmenv->type == MONS_PLAYER_GHOST
+ && fmenv->hit_points < fmenv->max_hit_points / 2)
+ {
+ mpr("The ghost fades into the shadows.");
+ monster_teleport(fmenv, true);
+ continue;
+ }
+
+ // monster has to be already tagged in order to follow:
+ if (!testbits( fmenv->flags, MF_TAKING_STAIRS ))
+ continue;
+
+#if DEBUG_DIAGNOSTICS
+ mprf( "%s is following.", ptr_monam( fmenv, DESC_CAP_THE ) );
+#endif
+
+ follower f(*fmenv);
+ followers.push_back(f);
+ fmenv->destroy_inventory();
+ monster_cleanup(fmenv);
+ }
+ }
+}
+
+void load( int stair_taken, load_mode_type load_mode, bool was_a_labyrinth,
+ int old_level, branch_type old_branch )
+{
+ std::vector<follower> followers;
bool just_created_level = false;
@@ -576,6 +896,7 @@ void load( int stair_taken, int load_mode, bool was_a_labyrinth,
// Don't delete clouds just because the player saved and restarted.
if (load_mode != LOAD_RESTART_GAME)
{
+ // XXX XXX FIXME shouldn't this just go into clear_clouds()?
for (int clouty = 0; clouty < MAX_CLOUDS; ++clouty)
delete_cloud( clouty );
@@ -585,44 +906,10 @@ void load( int stair_taken, int load_mode, bool was_a_labyrinth,
// This block is to grab followers and save the old level to disk.
if (load_mode == LOAD_ENTER_LEVEL)
{
- // grab followers
- for (count_x = you.x_pos - 1; count_x < you.x_pos + 2; count_x++)
- {
- for (count_y = you.y_pos - 1; count_y < you.y_pos + 2; count_y++)
- {
- if (count_x == you.x_pos && count_y == you.y_pos)
- continue;
-
- if (mgrd[count_x][count_y] == NON_MONSTER)
- continue;
-
- monsters *fmenv = &menv[mgrd[count_x][count_y]];
-
- if (fmenv->type == MONS_PLAYER_GHOST
- && fmenv->hit_points < fmenv->max_hit_points / 2)
- {
- mpr("The ghost fades into the shadows.");
- monster_teleport(fmenv, true);
- continue;
- }
-
- // monster has to be already tagged in order to follow:
- if (!testbits( fmenv->flags, MF_TAKING_STAIRS ))
- continue;
-
-#if DEBUG_DIAGNOSTICS
- mprf( "%s is following.", ptr_monam( fmenv, DESC_CAP_THE ) );
-#endif
-
- follower f(*fmenv);
- followers.push_back(f);
- fmenv->destroy_inventory();
- monster_cleanup(fmenv);
- }
- } // end of grabbing followers
+ grab_followers(followers);
if (!was_a_labyrinth)
- save_level( old_level, LEVEL_DUNGEON, where_were_you2 );
+ save_level( old_level, LEVEL_DUNGEON, old_branch );
was_a_labyrinth = false;
}
@@ -673,188 +960,19 @@ void load( int stair_taken, int load_mode, bool was_a_labyrinth,
}
// closes all the gates if you're on the way out
- for (i = 0; i < GXM; i++)
- {
- for (j = 0; j < GYM; j++)
- {
- if (just_created_level)
- {
- env.map[i][j] = 0;
- env.map_col[i][j].clear();
- }
+ if (you.char_direction == DIR_ASCENDING &&
+ you.level_type != LEVEL_PANDEMONIUM)
+ close_level_gates();
- if (you.char_direction == DIR_ASCENDING
- && you.level_type != LEVEL_PANDEMONIUM)
- {
- if (grd[i][j] == DNGN_ENTER_HELL
- || grd[i][j] == DNGN_ENTER_ABYSS
- || grd[i][j] == DNGN_ENTER_PANDEMONIUM)
- {
- grd[i][j] = DNGN_STONE_ARCH;
- }
- }
+ if (just_created_level)
+ clear_env_map();
- if (load_mode != LOAD_RESTART_GAME)
- env.cgrid[i][j] = EMPTY_CLOUD;
- }
- }
+ if (load_mode != LOAD_RESTART_GAME)
+ clear_clouds();
- // This next block is for cases where we want to look for a stairs
- // to place the player.
if (load_mode != LOAD_RESTART_GAME && you.level_type != LEVEL_ABYSS)
{
- bool find_first = true;
-
- // Order is important here:
- if (you.level_type == LEVEL_DUNGEON
- && where_were_you2 == BRANCH_VESTIBULE_OF_HELL
- && stair_taken == DNGN_STONE_STAIRS_UP_I)
- {
- // leaving hell - look for entry portal first
- stair_taken = DNGN_ENTER_HELL;
- find_first = false;
- }
- else if (stair_taken == DNGN_EXIT_PANDEMONIUM)
- {
- stair_taken = DNGN_ENTER_PANDEMONIUM;
- find_first = false;
- }
- else if (stair_taken == DNGN_EXIT_ABYSS)
- {
- stair_taken = DNGN_ENTER_ABYSS;
- find_first = false;
- }
- else if (stair_taken == DNGN_ENTER_HELL
- || stair_taken == DNGN_ENTER_LABYRINTH)
- {
- // the vestibule and labyrith always start from this stair
- stair_taken = DNGN_STONE_STAIRS_UP_I;
- }
- else if (stair_taken >= DNGN_STONE_STAIRS_DOWN_I
- && stair_taken <= DNGN_ROCK_STAIRS_DOWN)
- {
- // look for coresponding up stair
- stair_taken += (DNGN_STONE_STAIRS_UP_I - DNGN_STONE_STAIRS_DOWN_I);
- }
- else if (stair_taken >= DNGN_STONE_STAIRS_UP_I
- && stair_taken <= DNGN_ROCK_STAIRS_UP)
- {
- // look for coresponding down stair
- stair_taken += (DNGN_STONE_STAIRS_DOWN_I - DNGN_STONE_STAIRS_UP_I);
- }
- 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);
- }
- 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);
- }
- else if (stair_taken >= DNGN_ENTER_DIS
- && stair_taken <= DNGN_TRANSIT_PANDEMONIUM)
- {
- // when entering a hell or pandemonium
- stair_taken = DNGN_STONE_STAIRS_UP_I;
- }
- else // Note: stair_taken can equal things like DNGN_FLOOR
- {
- // just find a nice empty square
- stair_taken = DNGN_FLOOR;
- find_first = false;
- }
-
- int found = 0;
- int x_pos = 0, y_pos = 0;
-
- // Start by looking for the expected entry point:
- for (count_x = 0; count_x < GXM; count_x++)
- {
- for (count_y = 0; count_y < GYM; count_y++)
- {
- if (grd[count_x][count_y] == stair_taken)
- {
- found++;
- if (one_chance_in( found ))
- {
- x_pos = count_x;
- y_pos = count_y;
- }
-
- if (find_first)
- goto found_stair; // double break
- }
- }
- }
-
-found_stair:
- if (!found)
- {
- // See if we can find a stairway in the "right" direction:
- for (count_x = 0; count_x < GXM; count_x++)
- {
- for (count_y = 0; count_y < GYM; count_y++)
- {
- if (stair_taken <= DNGN_ROCK_STAIRS_DOWN)
- {
- // looking for any down stairs
- if (grd[count_x][count_y] >= DNGN_STONE_STAIRS_DOWN_I
- && grd[count_x][count_y] <= DNGN_ROCK_STAIRS_DOWN)
- {
- found++;
- if (one_chance_in( found ))
- {
- x_pos = count_x;
- y_pos = count_y;
- }
- }
- }
- else
- {
- // looking for any up stairs
- if (grd[count_x][count_y] >= DNGN_STONE_STAIRS_UP_I
- && grd[count_x][count_y] <= DNGN_ROCK_STAIRS_UP)
- {
- found++;
- if (one_chance_in( found ))
- {
- x_pos = count_x;
- y_pos = count_y;
- }
- }
- }
- }
- }
-
- if (!found)
- {
- // Still not found? Look for any clear terrain:
- for (count_x = 0; count_x < GXM; count_x++)
- {
- for (count_y = 0; count_y < GYM; count_y++)
- {
- if (grd[count_x][count_y] >= DNGN_FLOOR)
- {
- found++;
- if (one_chance_in( found ))
- {
- x_pos = count_x;
- y_pos = count_y;
- }
- }
- }
- }
- }
- }
-
- // If still not found, the level is very buggy.
- ASSERT( found );
-
- you.x_pos = x_pos;
- you.y_pos = y_pos;
+ place_player_on_stair(old_branch, stair_taken);
}
else if (load_mode != LOAD_RESTART_GAME && you.level_type == LEVEL_ABYSS)
{
@@ -868,7 +986,7 @@ found_stair:
// actually "move" the followers if applicable
if ((you.level_type == LEVEL_DUNGEON
- || you.level_type == LEVEL_PANDEMONIUM)
+ || you.level_type == LEVEL_PANDEMONIUM)
&& load_mode == LOAD_ENTER_LEVEL)
{
while (!followers.empty())
@@ -884,47 +1002,11 @@ found_stair:
redraw_all();
- // Sanity forcing of monster inventory items (required?)
- for (i = 0; i < MAX_MONSTERS; i++)
- {
- if (menv[i].type == -1)
- continue;
-
- for (j = 0; j < NUM_MONSTER_SLOTS; j++)
- {
- if (menv[i].inv[j] == NON_ITEM)
- continue;
-
- /* items carried by monsters shouldn't be linked */
- if (mitm[menv[i].inv[j]].link != NON_ITEM)
- mitm[menv[i].inv[j]].link = NON_ITEM;
- }
- }
+ sanity_test_monster_inventory();
// Translate stairs for pandemonium levels:
if (you.level_type == LEVEL_PANDEMONIUM)
- {
- for (count_x = 0; count_x < GXM; count_x++)
- {
- for (count_y = 0; count_y < GYM; count_y++)
- {
- if (grd[count_x][count_y] >= DNGN_STONE_STAIRS_UP_I
- && grd[count_x][count_y] <= DNGN_ROCK_STAIRS_UP)
- {
- if (one_chance_in( you.mutation[MUT_PANDEMONIUM] ? 5 : 50 ))
- grd[count_x][count_y] = DNGN_EXIT_PANDEMONIUM;
- else
- grd[count_x][count_y] = DNGN_FLOOR;
- }
-
- if (grd[count_x][count_y] >= DNGN_ENTER_LABYRINTH
- && grd[count_x][count_y] <= DNGN_ROCK_STAIRS_DOWN)
- {
- grd[count_x][count_y] = DNGN_TRANSIT_PANDEMONIUM;
- }
- }
- }
- }
+ fixup_pandemonium_stairs();
// Things to update for player entering level
if (load_mode == LOAD_ENTER_LEVEL)
@@ -934,21 +1016,22 @@ found_stair:
update_level( you.elapsed_time - env.elapsed_time );
// Centaurs have difficulty with stairs
- val = ((you.species != SP_CENTAUR) ? player_movement_speed() : 15);
+ int timeval = ((you.species != SP_CENTAUR) ? player_movement_speed()
+ : 15);
// new levels have less wary monsters:
if (just_created_level)
- val /= 2;
+ timeval /= 2;
- val -= (stepdown_value( check_stealth(), 50, 50, 150, 150 ) / 10);
+ timeval -= (stepdown_value( check_stealth(), 50, 50, 150, 150 ) / 10);
#if DEBUG_DIAGNOSTICS
- mprf(MSGCH_DIAGNOSTICS, "arrival time: %d", val );
+ mprf(MSGCH_DIAGNOSTICS, "arrival time: %d", timeval );
#endif
- if (val > 0)
+ if (timeval > 0)
{
- you.time_taken = val;
+ you.time_taken = timeval;
handle_monsters();
}
}