Removed DOS_TERM, PLAIN_TERM special casery - all platforms get PLAIN_TERM.
Better end-of-greedy-explore reporting for items on traps (Erik).
Cleaned up find_travel_pos - moved guts of travel pathfinding to travel_pathfind class.
Miscellaneous other stuff.
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@882 c06c8d41-db1a-0410-9941-cceddc491573
RC6L3CIBLJEH4GWRFD7UQNGI6PZT74FRUVOYHSAN2XCC74NZUASQC CAGCTYIUYWDHQAJOLVLKOEV5HG6K5ZG7IDHONLIG6BDNCWZJAK4AC PGTE3JC4J5U536IJTCJFXTUOSRE73JXZJINWAGCANOQOCGC7J6AAC V6S33CAMTUXXDETG654VX2K4DA25DI6KFBTKPM2EGFDIBMAU4TJAC LEF6VQNLRIJXXWQFODNMZZZFYJXHYAXD4O5UNBHBS4RHMAVF6IFQC WREARQBLQW4ZLVXTPQTVPSXJVKPWQGE2JSIZYTJ5AJ55WREI72OAC LXLUKS5CKXBUSVV3QTZ4SM7NWSY6JFQEBHUBQW2VUEU5DOL3RRLAC 4EWXDZSMYTEINQRUL4OHRUZVWMKCWEPYVJVGENQPBWUYU37SP63QC GCIZIUXO5TYROKDUYB3HAY7H7MRDTJNM7HR7DGSH7KXDIZC2LCDAC JM6GKZ6VMX6FNVOZIDXIV22HGX7YESMIFZFE6EEQVCMFJIEA3FNAC RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC SDLKLUNFGVKDS55DDJZCBAVIB7NL3RRYPTACAY65SCUQKV6APFSAC AJJ6D6JRV6ZAZOAUHYUM2IQG42V6PBALOD4KEMNKSVVAOJXAUCPQC Y66ZAXN24E3HLIBOSW4OXUTQ4X4PRGNJII4KVDQH4GQJVA6GO3NAC 547JREUJXTZNYVGHNNAET5F5O5JYYGNTDQB6ABZNT7YX5EY64OHAC IPXXB4VRVZWOU5DKQ5ZTD37LS3QNK2R6APNZUO672YEEJT6OFAYQC 3YK4G4IQBXW63HPGU5WRTV6L2FCMKAK4DOTCHFK2FNSB5B3Y3PVQC TJISAZK5RWKXIIC5UTQNY4KT3UX3ASGBUQQNWZ7ZDULPRYFRZXQQC Q2XXRX5KFUHUQC6VJ7BMLZ6FWEUTXLUUHCIC2GS5DRGZ4VAALUIAC VIFRP3HZEONFR6PQRYZYM3YUEJOQ7T4F5CZY4MN4YJMB23FMU7XAC MSQI3TH6T62JAXQGLL52QZCWAMC372TGB6ZNNRDGUGMJKBNNV2VAC Z262AMUK447BTC7MVOPQQ3NZTQXQOE5JODNHXN3IU7WL4ABSW5YQC 5UVDIVD4NSXA52U4QMQIVST3GSZJ2A2YZK3RUEXKPM43YVQ7LI5AC MWHMD65QP6UKXO6Q4ZVEAMXY563AJ6KH7J6UEZOB5CRPPSRB762QC SH6NU4H5TG4O7CRXRHZ7MDHABZLWWXQ77NJDBHI7KCVHXHQYK46QC 5ASC3STDYCNLZFEBN6UTMUCGDETHBR2OCBZCF5VIAZ5RRWLOTDYQC LAMIVDKY7LO5ONX5Z273ZCCEA5UBENOJD5VWNE4AK2EXGFED6BFQC NXVPOFYKJFWQWKVPQUMWH2Y2KJEZX44BUOBFJ4JD4KFGPEGYHG4QC 43ZTEB57FU7KE5EVMYWZONNVJBZCGF3JEAJZIY25LC4LGE65PG5QC BUUPPUTWFL2NTMFJWP7LKDXON74CX47E37WDAZ3QI4N55UOUQTXAC 22RFWMSJGG26Z2MQEEXGKVTFSTLREHQIG46WYOTMDRKI5YVMRNVAC #if defined(DOS_TERM)// DOS functions like gettext() and puttext() can only// work with arrays of characters, not shorts.typedef unsigned char screen_buffer_t;#else
// If we've a waypoint on the current square, *and* the square is// a normal floor square with nothing on it, show the waypoint// number.
// If we've a waypoint on the current square, *and* the// square is a normal floor square with nothing on it,// show the waypoint number.
// Handles travel and explore floodfill pathfinding. Does not do interlevel// travel pathfinding directly (but is used internally by interlevel travel).// * All coordinates are grid coords.// * Do not reuse one travel_pathfind for different runmodes.class travel_pathfind{public:travel_pathfind();
int level_distance(level_id first, level_id second);
// Finds travel direction or explore target.const coord_def pathfind(run_mode_type rt);// For flood-fills (explore), sets starting (seed) square.void set_floodseed(const coord_def &seed, bool double_flood = false);// For regular travel, set starting point (usually the character's current// position) and destination.void set_src_dst(const coord_def &src, const coord_def &dst);// Request that the point distance array be annotated with magic numbers for// excludes and waypoints.void set_annotate_map(bool annotate);// Sets the travel_distance_grid_t to use instead of travel_point_distance.void set_distance_grid(travel_distance_grid_t distgrid);// Set feature vector to use; if non-NULL, also sets annotate_map to true.void set_feature_vector(std::vector<coord_def> *features);// The next square to go to to move towards the travel destination. Return// value is undefined if pathfind was not called with RMODE_TRAVEL.const coord_def travel_move() const;// Square to go to for (greedy) explore. Return value is undefined if// pathfind was not called with RMODE_EXPLORE or RMODE_EXPLORE_GREEDY.const coord_def explore_target() const;// Nearest greed-inducing square. Return value is undefined if// pathfind was not called with RMODE_EXPLORE_GREEDY.const coord_def greedy_square() const;// Nearest unexplored territory. Return value is undefined if// pathfind was not called with RMODE_EXPLORE or// RMODE_EXPLORE_GREEDY.const coord_def unexplored_square() const;private:bool is_greed_inducing_square(const coord_def &c) const;bool path_examine_point(const coord_def &c);bool path_flood(const coord_def &c, const coord_def &dc);bool square_slows_movement(const coord_def &c);void check_square_greed(const coord_def &c);
bool can_travel_to(const level_id &lid);bool can_travel_interlevel();bool prompt_stop_explore(int es_why);
private:static const int UNFOUND_DIST = -10000;static const int INFINITE_DIST = 10000;private:run_mode_type runmode;// Where pathfinding starts, and the destination. Note that dest is not// relevant for explore!coord_def start, dest;// This is the square adjacent to the starting position to move// along the shortest path to the destination. Does *not* apply// for explore!coord_def next_travel_move;// True if flooding outwards from start square for explore.bool floodout, double_flood;// Set true in the second part of a double floodfill to completely ignore// hostile squares.bool ignore_hostile;// If true, use magic numbers in point distance array which can be// used to colour the level-map.bool annotate_map;// Stashes on this level (needed for greedy explore and to populate the// feature vector with stashes on the X level-map).const LevelStashes *ls;// Are we greedy exploring?bool need_for_greed;// Targets for explore and greedy explore.coord_def unexplored_place, greedy_place;// How far from player's location unexplored_place and greedy_place are.int unexplored_dist, greedy_dist;const int *refdist;// For double-floods, the points to restart floodfill from at the end of// the first flood.std::vector<coord_def> reseed_points;std::vector<coord_def> *features;travel_distance_col *point_distance;// How many points are we currently considering? We start off with just one// point, and spread outwards like a flood-filler.int points;// How many points we'll consider next iteration.int next_iter_points;// How far we've traveled from (start_x, start_y), in moves (a diagonal move// is no longer than an orthogonal move).int traveled_distance;
}// Determines if the level is fully explored. Clobbers you.run_x/y.static bool fully_explored(){const int oldrun = you.running;if (!you.running.is_explore())you.running = RMODE_EXPLORE;// Do a second floodfill to check if the level is fully explored.// Note we're passing in a features vector to force find_travel_pos to// reseed past traps/deep water/lava. Icky.std::vector<coord_def> features_dummy;find_travel_pos(you.x_pos, you.y_pos, NULL, NULL, &features_dummy);you.running = oldrun;return !(you.running.x > 0 && you.running.y > 0);
extern short point_distance[GXM][GYM];// We have to set the point_distance array if the level map is// to be properly coloured. The caller isn't going to do it because// we say this square is inaccessible, so in a horrible hack, we// do it ourselves. Ecch.point_distance[x][y] = ignore_hostile? -42 : 42;return false;
return (false);
// Could not pick up interesting items because of hostile terrain. Note// that this and EST_PARTLY_EXPLORED are not mutually exclusive.EST_GREED_UNFULFILLED = 2};// Determines if the level is fully explored.static int find_explore_status(const travel_pathfind &tp){int explore_status = 0;const coord_def greed = tp.greedy_square();if (greed.x || greed.y)explore_status |= EST_GREED_UNFULFILLED;const coord_def unexplored = tp.unexplored_square();if (unexplored.x || unexplored.y)explore_status |= EST_PARTLY_EXPLORED;return (explore_status);}static void explore_find_target_square(){travel_pathfind tp;tp.set_floodseed(coord_def(you.x_pos, you.y_pos), true);coord_def whereto =tp.pathfind( static_cast<run_mode_type>(you.running.runmode) );if (whereto.x || whereto.y){// Make sure this is a square that is reachable, since we asked// travel_pathfind to give us even unreachable squares.if (travel_point_distance[whereto.x][whereto.y] <= 0)whereto.reset();}if (whereto.x || whereto.y){you.running.x = whereto.x;you.running.y = whereto.y;}else{// No place to go? Report to the player.const int estatus = find_explore_status(tp);if (!estatus)mpr("Done exploring.");else{std::vector<std::string> inacc;if (estatus & EST_GREED_UNFULFILLED)inacc.push_back("items");if (estatus & EST_PARTLY_EXPLORED)inacc.push_back("places");mprf("Partly explored, can't reach some %s.",comma_separated_line(inacc.begin(),inacc.end()).c_str());}stop_running();}}
you.running.x = 0;find_travel_pos(you.x_pos, you.y_pos, NULL, NULL);// No place to go?if (!you.running.x){// Do fully_explored() *before* stop_running!if (fully_explored())mpr("Done exploring.");elsempr("Partly explored, some areas are inaccessible.");stop_running();}
explore_find_target_square();
}/////////////////////////////////////////////////////////////////////////////// travel_pathfindFixedVector<coord_def, GXM * GYM> travel_pathfind::circumference[2];const int travel_pathfind::UNFOUND_DIST;const int travel_pathfind::INFINITE_DIST;travel_pathfind::travel_pathfind(): runmode(RMODE_NOT_RUNNING), start(), dest(), next_travel_move(),floodout(false), double_flood(false), ignore_hostile(false),annotate_map(false), ls(NULL), need_for_greed(false),unexplored_place(), greedy_place(), unexplored_dist(0),greedy_dist(0), refdist(NULL), reseed_points(),features(NULL), point_distance(travel_point_distance),points(0), next_iter_points(0), traveled_distance(0),circ_index(0){
static bool is_greed_inducing_square(const LevelStashes *ls, int x, int y)
bool travel_pathfind::is_greed_inducing_square(const coord_def &c) const{return (ls && ls->needs_visit(c.x, c.y));}void travel_pathfind::set_src_dst(const coord_def &src, const coord_def &dst){// Yes, this is backwards - for travel, we always start from the destination// and search outwards for the starting position.start = dst;dest = src;floodout = double_flood = false;}void travel_pathfind::set_floodseed(const coord_def &seed, bool dblflood){start = seed;dest.reset();floodout = true;double_flood = dblflood;}void travel_pathfind::set_annotate_map(bool annotate){annotate_map = annotate;}void travel_pathfind::set_distance_grid(travel_distance_grid_t grid){point_distance = grid;}void travel_pathfind::set_feature_vector(std::vector<coord_def> *feats){features = feats;if (features){double_flood = true;annotate_map = true;}}const coord_def travel_pathfind::travel_move() const{return (next_travel_move);}const coord_def travel_pathfind::explore_target() const{if (unexplored_dist != UNFOUND_DIST && greedy_dist != UNFOUND_DIST)return (unexplored_dist < greedy_dist? unexplored_place : greedy_place);else if (unexplored_dist != UNFOUND_DIST)return (unexplored_place);else if (greedy_dist != UNFOUND_DIST)return (greedy_place);return coord_def(0, 0);}const coord_def travel_pathfind::greedy_square() const{return (greedy_place);}const coord_def travel_pathfind::unexplored_square() const
init_terrain_check();int start_x = you.running.x, start_y = you.running.y;int dest_x = youx, dest_y = youy;bool floodout = false;unsigned char feature;const LevelStashes *lev = stashes.find_current_level();const bool need_for_greed =you.running == RMODE_EXPLORE_GREEDY && can_autopickup();
if (rmode == RMODE_INTERLEVEL)rmode = RMODE_TRAVEL;runmode = rmode;
// For greedy explore, keep track of the closest unexplored// territory and the closest greedy square.int e_x = 0, e_y = 0; // Unexploredint i_x = 0, i_y = 0; // Square with interesting item.// Use these weird defaults to handle negative item greeds.int ex_dist = -10000, ix_dist = -10000;
// Check whether species or levitation permits travel through terrain such// as deep water.init_terrain_check();
// Normally we start from the destination and floodfill outwards, looking// for the character's current position. If we're merely trying to populate// the point_distance array (or exploring), we'll want to start from the// character's current position and fill outwardsif (!move_x || !move_y){start_x = youx;start_y = youy;
need_for_greed =(rmode == RMODE_EXPLORE_GREEDY && can_autopickup());
floodout = true;}
next_travel_move.reset();// For greedy explore, keep track of the closest unexplored territory and// the closest greedy square. Exploring to the nearest (unexplored / greedy)// square is easier, but it produces unintuitive explore behaviour where// grabbing items is not favoured over simple exploring.//// Greedy explore instead uses the explore_item_greed option to weight// greedy explore towards grabbing items over exploring. An// explore_item_greed set to 10, for instance, forces explore to prefer// items that are less than 10 squares farther away from the player than the// nearest unmapped square. Negative explore_item_greed values force greedy// explore to favour unexplored territory over picking up items. For the// most natural greedy explore behaviour, explore_item_greed should be set// to 10 or more.//unexplored_place = greedy_place = coord_def(0, 0);unexplored_dist = greedy_dist = UNFOUND_DIST;
// Abort run if we're trying to go someplace evilif (dest_x != -1 && !is_travel_ok(start_x, start_y, false) &&!is_trap(start_x, start_y))
refdist = Options.explore_item_greed > 0? &unexplored_dist: &greedy_dist;// Abort run if we're trying to go someplace evil. Travel to traps is// specifically allowed here if the player insists on it.if (!floodout&& !is_travel_ok(start.x, start.y, false)&& !is_trap(start.x, start.y)) // The player likes pain
// Abort run if we're going nowhere.if (start_x == dest_x && start_y == dest_y){you.running = RMODE_NOT_RUNNING;return ;}
// Nothing to do?if (!floodout && start == dest)return (start);
// The circumference points of the floodfilled area, for this iteration// and the next (this iteration's points being circ_index amd the next one's// being !circ_index).static FixedVector<coord_def, GXM * GYM> circumference[2];// Coordinates of all discovered traps. If we're exploring instead of// travelling, we'll reseed from these points after we've explored the mapstd::vector<coord_def> trap_seeds;// When set to true, the travel code ignores features, traps and hostile// terrain, and simply tries to map contiguous floorspace. Will only be set// to true if we're exploring, instead of travelling.bool ignore_hostile = false;
int x = circumference[circ_index][i].x,y = circumference[circ_index][i].y;// (x,y) is a known (explored) location - we never put unknown// points in the circumference vector, so we don't need to examine// the map array, just the grid array.feature = grd[x][y];// If this is a feature that'll take time to travel past, we// simulate that extra turn by taking this feature next turn,// thereby artificially increasing traveled_distance.//// Note: I don't know how slow walking through shallow water and// opening closed doors is - right now it's considered to have// the cost of two normal moves.int feat_cost = feature_traverse_cost(feature);if (feat_cost > 1&& point_distance[x][y] > traveled_distance - feat_cost)
if (path_examine_point(circumference[circ_index][i]))
// For each point, we look at all surrounding points. Take them// orthogonals first so that the travel path doesn't zigzag all over// the map. Note the (dir = 1) is intentional assignment.for (int dir = 0; dir < 8; (dir += 2) == 8 && (dir = 1))
if (next_iter_points == 0){// Don't reseed unless we've found no target for explore, OR// we're doing map annotation or feature tracking.if ((runmode == RMODE_EXPLORE || runmode == RMODE_EXPLORE_GREEDY)&& double_flood&& !ignore_hostile&& !features&& !annotate_map&& (unexplored_dist != UNFOUND_DIST|| greedy_dist != UNFOUND_DIST))
if (floodout && you.running.is_explore()){if (!is_player_mapped(envf)){if (!need_for_greed){you.running.x = x;you.running.y = y;return;}
if (double_flood&& !ignore_hostile&& !reseed_points.empty()){// Reseed herefor (unsigned i = 0, size = reseed_points.size(); i < size; ++i)circumference[!circ_index][i] = reseed_points[i];next_iter_points = reseed_points.size();ignore_hostile = true;}}} // for ( ; points > 0 ...
if (ex_dist == -10000){e_x = x;e_y = y;ex_dist =traveled_distance + Options.explore_item_greed;}}else if (need_for_greed&& ix_dist == -10000&& is_greed_inducing_square(lev, dx, dy)&& is_travel_ok(dx, dy, ignore_hostile)){i_x = dx;i_y = dy;ix_dist = traveled_distance + 1;}
if (features && floodout){for (int i = 0, size = curr_excludes.size(); i < size; ++i){const coord_def &exc = curr_excludes[i];// An exclude - wherever it is - is always a feature.if (std::find(features->begin(), features->end(), exc)== features->end())features->push_back(exc);
// Short-circuit if we can.if (need_for_greed){const int refdist =Options.explore_item_greed > 0? ex_dist: ix_dist;if (refdist != -10000&& traveled_distance > refdist){if (Options.explore_item_greed > 0)ix_dist = 10000;elseex_dist = 10000;}}// ex_dist/ix_dist are only ever set in// greedy-explore so this check implies// greedy-explore.if (ex_dist != -10000 && ix_dist != -10000){if (ex_dist < ix_dist){you.running.x = e_x;you.running.y = e_y;}else{you.running.x = i_x;you.running.y = i_y;}return;}}
fill_exclude_radius(exc);}}
if ((dx != dest_x || dy != dest_y)&& !is_travel_ok(dx, dy, ignore_hostile)){// This point is not okay to travel on, but if this is a// trap, we'll want to put it on the feature vector anyway.if (is_reseedable(dx, dy)&& !point_distance[dx][dy]&& (dx != start_x || dy != start_y)){if (features){const coord_def c(dx, dy);if (is_trap(dx, dy) || is_exclude_root(dx, dy))features->push_back(c);trap_seeds.push_back(c);}
return (rmode == RMODE_TRAVEL? travel_move(): explore_target());}
// Appropriate mystic number. Nobody else should check// this number, since this square is unsafe for travel.point_distance[dx][dy] =is_exclude_root(dx, dy)? PD_EXCLUDED :is_excluded(dx, dy) ? PD_EXCLUDED_RADIUS :PD_TRAP;}continue;}
bool travel_pathfind::square_slows_movement(const coord_def &c){// c is a known (explored) location - we never put unknown points in the// circumference vector, so we don't need to examine the map array, just the// grid array.const int feature = grd(c);
if (dx == dest_x && dy == dest_y){// Hallelujah, we're home!if (is_safe_move(x, y) && move_x && move_y){*move_x = sgn(x - dest_x);*move_y = sgn(y - dest_y);}return ;}else if (!point_distance[dx][dy]){// This point is going to be on the agenda for the next// iterationcircumference[!circ_index][next_iter_points].x = dx;circumference[!circ_index][next_iter_points].y = dy;next_iter_points++;
// If this is a feature that'll take time to travel past, we simulate that// extra turn by taking this feature next turn, thereby artificially// increasing traveled_distance.//// Walking through shallow water and opening closed doors is considered to// have the cost of two normal moves for travel purposes.const int feat_cost = feature_traverse_cost(feature);if (feat_cost > 1&& point_distance[c.x][c.y] > traveled_distance - feat_cost){circumference[!circ_index][next_iter_points++] = c;return (true);}
// Negative distances here so that show_map can colour// the map differently for these squares.if (ignore_hostile){point_distance[dx][dy] = -point_distance[dx][dy];if (is_exclude_root(dx, dy))point_distance[dx][dy] = PD_EXCLUDED;else if (is_excluded(dx, dy))point_distance[dx][dy] = PD_EXCLUDED_RADIUS;}
void travel_pathfind::check_square_greed(const coord_def &c){if (greedy_dist == UNFOUND_DIST&& is_greed_inducing_square(c)&& is_travel_ok(c.x, c.y, ignore_hostile)){greedy_place = c;greedy_dist = traveled_distance;}}
feature = grd[dx][dy];if (features && !ignore_hostile&& ((feature != DNGN_FLOOR&& feature != DNGN_SHALLOW_WATER&& feature != DNGN_DEEP_WATER&& feature != DNGN_LAVA)|| is_waypoint(dx, dy)|| is_stash(lev, dx, dy))&& (dx != start_x || dy != start_y)){const coord_def c(dx, dy);features->push_back(c);}
bool travel_pathfind::path_flood(const coord_def &c, const coord_def &dc){if (!in_bounds(dc))return (false);
if (features && is_exclude_root(dx, dy) && dx != start_x&& dy != start_y){const coord_def c(dx, dy);features->push_back(c);}}} // for (dir = 0; dir < 8 ...} // for (i = 0; i < points ...
if (floodout&& (runmode == RMODE_EXPLORE || runmode == RMODE_EXPLORE_GREEDY)){if (!is_terrain_seen(dc)){if (!need_for_greed){// Found explore target!unexplored_place = c;unexplored_dist = traveled_distance;return (true);}if (unexplored_dist == UNFOUND_DIST){unexplored_place = c;unexplored_dist =traveled_distance + Options.explore_item_greed;}}
if (!next_iter_points && features && !move_x && !ignore_hostile&& trap_seeds.size())
// Short-circuit if we can. If traveled_distance (the current// distance from the center of the floodfill) is greater// than the adjusted distance to the nearest greedy explore// target, we have a target. Note the adjusted distance is// the distance with explore_item_greed applied (if// explore_item_greed > 0, it is added to the distance to// unexplored terrain, if explore_item_greed < 0, it is// added to the distance to interesting items.//// We never short-circuit if ignore_hostile is true. This is// important so we don't need to do multiple floods to work out// whether explore is complete.if (need_for_greed&& !ignore_hostile&& *refdist != UNFOUND_DIST&& traveled_distance > *refdist)
// Reseed herefor (unsigned i = 0; i < trap_seeds.size(); ++i)circumference[!circ_index][i] = trap_seeds[i];next_iter_points = trap_seeds.size();ignore_hostile = true;
if (Options.explore_item_greed > 0)greedy_dist = INFINITE_DIST;elseunexplored_dist = INFINITE_DIST;
for (int i = 0, size = curr_excludes.size(); i < size; ++i)
// This point is not okay to travel on, but if this is a// trap, we'll want to put it on the feature vector anyway.if (is_reseedable(dc.x, dc.y)&& !point_distance[dc.x][dc.y]&& dc != start)
const coord_def &exc = curr_excludes[i];// An exclude - wherever it is - is always a feature.if (std::find(features->begin(), features->end(), exc)== features->end())features->push_back(exc);
if (features &&(is_trap(dc.x, dc.y) || is_exclude_root(dc.x, dc.y))){features->push_back(dc);}
fill_exclude_radius(exc);
if (double_flood)reseed_points.push_back(dc);// Appropriate mystic number. Nobody else should check// this number, since this square is unsafe for travel.point_distance[dc.x][dc.y] =is_exclude_root(dc.x, dc.y)? PD_EXCLUDED :is_excluded(dc.x, dc.y) ? PD_EXCLUDED_RADIUS :PD_TRAP;
if (ix_dist != -10000)
// This point is going to be on the agenda for the next// iterationcircumference[!circ_index][next_iter_points++] = dc;point_distance[dc.x][dc.y] = traveled_distance;// Negative distances here so that show_map can colour// the map differently for these squares.if (ignore_hostile)
you.running.x = e_x;you.running.y = e_y;
if (features && !ignore_hostile){const int feature = grd(dc);if (((feature != DNGN_FLOOR&& feature != DNGN_SHALLOW_WATER&& feature != DNGN_DEEP_WATER&& feature != DNGN_LAVA)|| is_waypoint(dc.x, dc.y)|| is_stash(ls, dc.x, dc.y))&& dc != start){features->push_back(dc);}}if (features && dc != start && is_exclude_root(dc.x, dc.y))features->push_back(dc);}return (false);}bool travel_pathfind::path_examine_point(const coord_def &c){if (square_slows_movement(c))return (false);// Greedy explore check should happen on (x,y), not (dx,dy) as for// regular explore.if (need_for_greed)check_square_greed(c);// For each point, we look at all surrounding points. Take them orthogonals// first so that the travel path doesn't zigzag all over the map. Note the// (dir = 1) is intentional assignment.for (int dir = 0; dir < 8; (dir += 2) == 8 && (dir = 1)){if (path_flood(c, c + Compass[dir]))return (true);}return (false);}/////////////////////////////////////////////////////////////////////////////void find_travel_pos(int youx, int youy,char *move_x, char *move_y,std::vector<coord_def>* features){travel_pathfind tp;if (move_x && move_y)tp.set_src_dst(coord_def(youx, youy),coord_def(you.running.x, you.running.y));elsetp.set_floodseed(coord_def(youx, youy));tp.set_feature_vector(features);run_mode_type rmode = move_x && move_y? RMODE_TRAVEL : RMODE_NOT_RUNNING;const coord_def dest = tp.pathfind( rmode );if (dest.x == 0 && dest.y == 0){if (move_x && move_y)you.running = RMODE_NOT_RUNNING;
* This function relies on the point_distance array being correctly populated* with a floodout call to find_travel_pos starting from the player's location.
* This function relies on the travel_point_distance array being correctly* populated with a floodout call to find_travel_pos starting from the player's* location.
#ifdef USE_SYSTEM_RANDcf_setseed();#endif}#ifdef USE_SYSTEM_RANDint random2(int max){#ifdef USE_NEW_RANDOM//return (int) ((((float) max) * rand()) / RAND_MAX); - this is bad!// Uses FP, so is horribly slow on computers without coprocessors.// Taken from comp.lang.c FAQ. May have problems as max approaches// RAND_MAX, but this is rather unlikely.// We've used rand() rather than random() for the portability, I think.if (max < 1 || max >= RAND_MAX)return 0;elsereturn (int) rand() / (RAND_MAX / max + 1);#elseif (max < 1)return 0;return rand() % max;#endif
// I got to thinking a bit more about how much people talk// about RNGs and RLs and also about the issue of performance// when it comes to Crawl's RNG ... turning to *Numerical// Recipies in C* (Chapter 7-4, page 298), I hit upon what// struck me as a fine solution.// You can read all the details about this function (pretty// much stolen shamelessly from NRinC) elsewhere, but having// tested it out myself I think it satisfies Crawl's incessant// need to decide things on a 50-50 flip of the coin. No call// to random2() required -- along with all that wonderful math// and type casting -- and only a single variable its pointer,// and some bitwise operations to randomly generate 1s and 0s!// No parameter passing, nothing. Too good to be true, but it// works as long as cfseed is not set to absolute zero when it// is initialized ... good for 2**n-1 random bits before the// pattern repeats (n = long's bitlength on your platform).// It also avoids problems with poor implementations of rand()// on some platforms in regards to low-order bits ... a big// problem if one is only looking for a 1 or a 0 with random2()!// Talk about a hard sell! Anyway, it returns bool, so please// use appropriately -- I set it to bool to prevent such// tomfoolery, as I think that pure RNG and quickly grabbing// either a value of 1 or 0 should be separated where possible// to lower overhead in Crawl ... at least until it assembles// itself into something a bit more orderly :P 16jan2000 {dlb}// NB(1): cfseed is defined atop stuff.cc// NB(2): IB(foo) and MASK are defined somewhere in defines.h// NB(3): the function assumes that cf_setseed() has been called// beforehand - the call is presently made in acr::initialise()// right after srandom() and srand() are called (note also// that cf_setseed() requires rand() - random2 returns int// but a long can't hurt there).bool coinflip(void){extern unsigned long cfseed; // defined atop stuff.ccunsigned long *ptr_cfseed = &cfseed;if (*ptr_cfseed & IB18){*ptr_cfseed = ((*ptr_cfseed ^ MASK) << 1) | IB1;return true;}else{*ptr_cfseed <<= 1;return false;}} // end coinflip()// cf_setseed should only be called but once in all of Crawl!!! {dlb}void cf_setseed(void){extern unsigned long cfseed; // defined atop stuff.ccunsigned long *ptr_cfseed = &cfseed;do{// using rand() here makes these predictable -- bwr*ptr_cfseed = rand();}while (*ptr_cfseed == 0);}static std::stack<long> rng_states;void push_rng_state(){// XXX: Does this even work? randart.cc uses it, but I can't find anything// that says this will restore the RNG to its original state. Anyway, we're// now using MT with a deterministic push/pop.rng_states.push(rand());}void pop_rng_state(){if (!rng_states.empty()){seed_rng(rng_states.top());rng_states.pop();}}unsigned long random_int( void ){return rand();}#else // USE_SYSTEM_RAND
}// takes rectangle (x1,y1)-(x2,y2) and shifts it somewhere randomly in boundsvoid random_place_rectangle( int &x1, int &y1, int &x2, int &y2, bool excl ){const unsigned int dx = abs( x2 - x1 );const unsigned int dy = abs( y2 - y1 );x1 = X_BOUND_1 + random2( X_WIDTH - dx - 2 * excl ) + excl;y1 = Y_BOUND_1 + random2( Y_WIDTH - dy - 2 * excl ) + excl;x2 = x1 + dx;y2 = y1 + dy;}// returns true if point (px,py) is in rectangle (rx1, ry1) - (rx2, ry2)bool in_rectangle( int px, int py, int rx1, int ry1, int rx2, int ry2,bool excl ){ASSERT( rx1 < rx2 - 1 && ry1 < ry2 - 1 );if (excl){rx1++;rx2--;ry1++;ry2--;}return (px >= rx1 && px <= rx2 && py >= ry1 && py <= ry2);
// XXX: this can be done better// returns true if rectables a and b overlapbool rectangles_overlap( int ax1, int ay1, int ax2, int ay2,int bx1, int by1, int bx2, int by2,bool excl ){ASSERT( ax1 < ax2 - 1 && ay1 < ay2 - 1 );ASSERT( bx1 < bx2 - 1 && by1 < by2 - 1 );if (excl){ax1++;ax2--;ay1++;ay2--;}return (in_rectangle( ax1, ay1, bx1, by1, bx2, by2, excl )|| in_rectangle( ax1, ay2, bx1, by1, bx2, by2, excl )|| in_rectangle( ax2, ay1, bx1, by1, bx2, by2, excl )|| in_rectangle( ax2, ay2, bx1, by1, bx2, by2, excl ));}
branches[BRANCH_ECUMENICAL_TEMPLE].startdepth = 3 + random2(4);branches[BRANCH_ORCISH_MINES].startdepth = 5 + random2(6);branches[BRANCH_ELVEN_HALLS].startdepth = coinflip() ? 4 : 3;branches[BRANCH_LAIR].startdepth = 7 + random2(6);branches[BRANCH_HIVE].startdepth = 10 + random2(6);branches[BRANCH_SLIME_PITS].startdepth = 3 + random2(4);branches[BRANCH_SWAMP].startdepth = 2 + random2(6);branches[BRANCH_SNAKE_PIT].startdepth = coinflip() ? 7 : 6;branches[BRANCH_VAULTS].startdepth = 13 + random2(6);branches[BRANCH_CRYPT].startdepth = 2 + random2(3);branches[BRANCH_HALL_OF_BLADES].startdepth = 4;branches[BRANCH_TOMB].startdepth = coinflip() ? 3 : 2;
branches[BRANCH_ECUMENICAL_TEMPLE].startdepth = random_range(4, 7);branches[BRANCH_ORCISH_MINES].startdepth = random_range(6, 11);branches[BRANCH_ELVEN_HALLS].startdepth = random_range(3, 4);branches[BRANCH_LAIR].startdepth = random_range(8, 13);branches[BRANCH_HIVE].startdepth = random_range(11, 16);branches[BRANCH_SLIME_PITS].startdepth = random_range(3, 9);branches[BRANCH_SWAMP].startdepth = random_range(2, 7);branches[BRANCH_SNAKE_PIT].startdepth = random_range(3, 8);branches[BRANCH_VAULTS].startdepth = random_range(14, 19);branches[BRANCH_CRYPT].startdepth = random_range(2, 4);branches[BRANCH_HALL_OF_BLADES].startdepth = random_range(4, 6);branches[BRANCH_TOMB].startdepth = random_range(2, 3);
New_Message_Count++;
// Prompt lines are presumably shown to / seen by the player accompanied// by a request for input, which should do the equivalent of a more(); to// save annoyance, don't bump New_Message_Count for prompts.if (channel != MSGCH_PROMPT)New_Message_Count++;
MCHMOD = 2755INSTALLDIR := /usr/games
# If you have lex and yacc, set DOYACC to y (lowercase y).DOYACC := y# Permissions to set on the game executable.MCHMOD := 2755# Permissions to set on the save directory.MCHMOD_SAVEDIR := 775# The user:group to install the game as.INSTALL_UGRP := games:gamesINSTALLDIR := /usr/games
#endif#else#define getch_with_command_macros() getch()#define getchm(x) getch()#define flush_input_buffer(XXX) ;#define macro_buf_add(x)#define is_userfunction(x) false#define get_userfunction(x) NULL#define call_userfunction(x)