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
SW3RLYFNRT3IJBK6LYKHKP2J2YDU7SXQWAJZX7U6S7ICYW43OMNQC W5VEC2PBIM5DMU5233HOWAZUEPTGWJRZZIA3H35YYQQW6BTP6XUAC YCL3W2PFE6ILTGBFODCSXNPDIA46KVSZP2TI7HDMYAOEJT65RIEAC K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC SDLKLUNFGVKDS55DDJZCBAVIB7NL3RRYPTACAY65SCUQKV6APFSAC RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC 7KWDC7XFNMBLSUO2HISIROBINZBX5T67LJEEXTAORXW2YZ7VWFGAC D27U7RT2C77NEUBP6JCSQJ2DRCJVHOXUO2PFZ45VFYMEVMKI4TSAC 5UVDIVD4NSXA52U4QMQIVST3GSZJ2A2YZK3RUEXKPM43YVQ7LI5AC void load( int stair_taken, int load_mode, bool was_a_labyrinth,int old_level, branch_type where_were_you2 )
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 matchfor (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*ydiffconst 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 directionfor (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);elsegood_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 linkedif (mitm[menv[i].inv[j]].link != NON_ITEM)mitm[menv[i].inv[j]].link = NON_ITEM;}}}static void fixup_pandemonium_stairs()
int j = 0;int i = 0, count_x = 0, count_y = 0;
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;elsegrd[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 firststair_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 stairstair_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 stairstair_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 stairstair_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 leavingstair_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 enteringstair_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 pandemoniumstair_taken = DNGN_STONE_STAIRS_UP_I;}else // Note: stair_taken can equal things like DNGN_FLOOR{// just find a nice empty squarestair_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();}}}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_DIAGNOSTICSmprf( "%s is following.", ptr_monam( fmenv, DESC_CAP_THE ) );#endiffollower f(*fmenv);followers.push_back(f);fmenv->destroy_inventory();monster_cleanup(fmenv);}}}
// grab followersfor (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;
grab_followers(followers);
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_DIAGNOSTICSmprf( "%s is following.", ptr_monam( fmenv, DESC_CAP_THE ) );#endiffollower f(*fmenv);followers.push_back(f);fmenv->destroy_inventory();monster_cleanup(fmenv);}} // end of grabbing followers
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();
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 firststair_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 stairstair_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 stairstair_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 stairstair_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 leavingstair_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 enteringstair_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 pandemoniumstair_taken = DNGN_STONE_STAIRS_UP_I;}else // Note: stair_taken can equal things like DNGN_FLOOR{// just find a nice empty squarestair_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 stairsif (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 stairsif (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);
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();
{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;elsegrd[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();