los_param got a new opacity_monmove to help. The change compiles and the game runs, but I'm unsure how to test monster pathfinding. Please tell me if anything went wrong!
Removes mon-los.{cc,h}, so I'm afraid I may have broken the non-Unix builds again.
RG4JTNTDB35PSDT3N3IBNBCPSSZLWL4K7DRTOD73OEDRB4I5MTCAC IOYLVGTLPFTKADPHYIWMXXD64HCW7UMR2P44M7K26ZLLEDBVMJQQC UL7XFKMUX3WIU4O2LZANK4ECJ654UZPDBFGNXUEYZYOLKBYBCG6AC ACZYEIX7WMPIIODKCATBCUE626AJ4ZGGBOMVC6BGXM27EQU2RECAC TZNURHCLTLE3A55EPNU66BU6NX7LOBA7EFG4NAJJBUKZLOAEFU4AC DTLSPUE47XI4YC3QWKTBWJOWBU52GXPGXFEEBG374I4JAYVM7KZAC K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC UCEAWJ4I6AEFR64SSUFQSX6Q62JGLMJQ5BOO5MQSV3XIE7KAS6CQC YKVVFNKT2M5WG2KBURRTOJG23BJVI6WUBP5JOGYPHQBS4RNGFGWQC 22ORIULMB2NHLFZNJFK2AF275Q6XBKOBE4ZRMOADY64VK5FAUUSQC H7AOW4T4Q7AKOXREMK6ZXN3GK6A4I24ICE6VTROMJ5Y3LX47TSDAC P5TRGRH7XMQSPCZKM5IEEO34TY6WMLGHHX7BU6Y453JFRXLUR2VQC LHYTGOCNDWX3CVD2HSQ6LAYC6NLKKI6ZKKNWZ5IQWP6YP5PQEVWQC ZJMTMMZBCXHCPFHBTI2PL3Q4XTJQUWMMHCCG6JDIEDMJYCC33TFQC BR42OZ3CHR5F5MKPBUOPRG3EXIEQRRRWD5L54BTZQRDXV6VBLATQC MQ62OAMLGJVRW2QIL4PAZRAU6PC52ZVGY2FCOBIY6IWGQIHMU5CAC PVHG5SLN34UM4FRF5YJZOG4EN22Q5LZ5MNUHYZFWAXWIB5K4RZ2AC AL7EYY4HB7JNEFGDB6NVVHCVVUYYKUJKC4UFH4T7XUT3P5NT4NAAC 2EBEWIV4YHXXAFR4GG2GMZJ2K77NK762HNQ77CZLHI3LDVGX7RJAC NWWSJFJEA23B64WF4AT7K7KNFUMK3I22L4RCDSIMEI3XJL3KS2CQC DRH5HH762ZIS2R6NCKQYD3XO2P6RDNS6N4XEULIEQPNMB46HEDFQC #ifndef MON_LOS_H/** File: mon-los.cc* Summary: Monster line-of-sight.*/#define MON_LOS_H#define _monster_los_LSIZE (2 * LOS_RADIUS + 1)// This class can be used to fill the entire surroundings (los_range)// of a monster or other position with seen/unseen values, so as to be able// to compare several positions within this range.class monster_los{public:monster_los();virtual ~monster_los();// public methodsvoid set_monster(monsters *mon);void set_los_centre(int x, int y);void set_los_centre(const coord_def& p) { this->set_los_centre(p.x, p.y); }void set_los_range(int r);void fill_los_field(void);bool in_sight(int x, int y);bool in_sight(const coord_def& p) { return this->in_sight(p.x, p.y); }protected:// protected methodscoord_def pos_to_index(coord_def &p);coord_def index_to_pos(coord_def &i);void set_los_value(int x, int y, bool blocked, bool override = false);int get_los_value(int x, int y);bool is_blocked(int x, int y);bool is_unknown(int x, int y);void check_los_beam(int dx, int dy);// The (fixed) size of the array.static const int LSIZE;static const int L_VISIBLE;static const int L_UNKNOWN;static const int L_BLOCKED;// The centre of our los field.int gridx, gridy;// Habitat checks etc. should be done for this monster.// Usually the monster whose LOS we're trying to calculate// (if mon->x == gridx, mon->y == gridy).// Else, any monster trying to move around within this los field.monsters *mons;// Range may never be greater than LOS_RADIUS!int range;// The array to store the LOS values.int los_field[_monster_los_LSIZE][_monster_los_LSIZE];};#endif
/** File: mon-los.cc* Summary: Monster line-of-sight.*/#include "AppHdr.h"REVISION("$Rev$");#include "mon-los.h"#include "los.h"#include "ray.h"#include "stuff.h"// Static class members must be initialised outside of the class// declaration, or gcc won't define them in view.o and we'll get a// linking error.const int monster_los::LSIZE = _monster_los_LSIZE;const int monster_los::L_VISIBLE = 1;const int monster_los::L_UNKNOWN = 0;const int monster_los::L_BLOCKED = -1;/////////////////////////////////////////////////////////////////////////////// monster_losmonster_los::monster_los(): gridx(0), gridy(0), mons(), range(LOS_RADIUS), los_field(){}monster_los::~monster_los(){}void monster_los::set_monster(monsters *mon){mons = mon;set_los_centre(mon->pos());}void monster_los::set_los_centre(int x, int y){if (!in_bounds(x, y))return;gridx = x;gridy = y;}void monster_los::set_los_range(int r){ASSERT (r >= 1 && r <= LOS_RADIUS);range = r;}coord_def monster_los::pos_to_index(coord_def &p){int ix = LOS_RADIUS + p.x - gridx;int iy = LOS_RADIUS + p.y - gridy;ASSERT(ix >= 0 && ix < LSIZE);ASSERT(iy >= 0 && iy < LSIZE);return (coord_def(ix, iy));}coord_def monster_los::index_to_pos(coord_def &i){int px = i.x + gridx - LOS_RADIUS;int py = i.y + gridy - LOS_RADIUS;ASSERT(in_bounds(px, py));return (coord_def(px, py));}void monster_los::set_los_value(int x, int y, bool blocked, bool override){if (!override && !is_unknown(x,y))return;coord_def c(x,y);coord_def lpos = pos_to_index(c);int value = (blocked ? L_BLOCKED : L_VISIBLE);if (value != los_field[lpos.x][lpos.y])los_field[lpos.x][lpos.y] = value;}int monster_los::get_los_value(int x, int y){// Too far away -> definitely out of sight!return (L_BLOCKED);coord_def c(x,y);coord_def lpos = pos_to_index(c);return (los_field[lpos.x][lpos.y]);}bool monster_los::in_sight(int x, int y){// Is the path to (x,y) clear?return (get_los_value(x,y) == L_VISIBLE);}bool monster_los::is_blocked(int x, int y){// Is the path to (x,y) blocked?return (get_los_value(x, y) == L_BLOCKED);}bool monster_los::is_unknown(int x, int y){return (get_los_value(x, y) == L_UNKNOWN);}static bool _blocks_movement_sight(monsters *mon, dungeon_feature_type feat){if (feat < DNGN_MINMOVE)return (true);if (!mon) // No monster defined?return (false);if (!mon->can_pass_through_feat(feat))return (true);return (false);}void monster_los::fill_los_field(){int pos_x, pos_y;for (int k = 1; k <= range; k++)for (int i = -1; i <= 1; i++)for (int j = -1; j <= 1; j++){if (i == 0 && j == 0) // Ignore centre grid.continue;pos_x = gridx + k*i;pos_y = gridy + k*j;if (!in_bounds(pos_x, pos_y))continue;if (!_blocks_movement_sight(mons, grd[pos_x][pos_y]))set_los_value(pos_x, pos_y, false);else{set_los_value(pos_x, pos_y, true);// Check all beam potentially going through a blocked grid.check_los_beam(pos_x, pos_y);}}}// (cx, cy) is the centre point// (dx, dy) is the target we're aiming *through*// target1 and target2 are targets we'll be aiming *at* to fire through (dx,dy)static bool _set_beam_target(int cx, int cy, int dx, int dy,int &target1_x, int &target1_y,int &target2_x, int &target2_y,int range){const int xdist = dx - cx;const int ydist = dy - cy;if (xdist == 0 && ydist == 0)return (false); // Nothing to be done.if (xdist <= -range || xdist >= range|| ydist <= -range || ydist >= range){// Grids on the edge of a monster's LOS don't block sight any further.return (false);}/** The following code divides the field into eights of different directions.** \ NW | NE /* \ | /* WN \ | / EN* ----------------* WS / | \ ES* / | \* / SW | SE \** target1_x and target1_y mark the base line target, so the base beam ends* on the diagonal line closest to the target (or on one of the straight* lines if cx == dx or dx == dy).** target2_x and target2_y then mark the second target our beam finder should* cycle through. It'll always be target2_x = dx or target2_y = dy, the other* being on the edge of LOS, which one depending on the quadrant.** The beam finder can then cycle from the nearest corner (target1) to the* second edge target closest to (dx,dy).*/if (xdist == 0){target1_x = cx;target1_y = (ydist > 0 ? cy + range: cy - range);target2_x = target1_x;target2_y = target1_y;}else if (ydist == 0){target1_x = (xdist > 0 ? cx + range: cx - range);target1_y = cy;target2_x = target1_x;target2_y = target1_y;}else if (xdist < 0 && ydist < 0 || xdist > 0 && ydist > 0){if (xdist < 0){target1_x = cx - range;target1_y = cy - range;}else{target1_x = cx + range;target1_y = cy + range;}if (xdist == ydist){target2_x = target1_x;target2_y = target1_y;}else{if (xdist < 0) // both are negative (upper left corner){if (dx > dy){target2_x = dx;target2_y = cy - range;}else{target2_x = cx - range;target2_y = dy;}}else // both are positive (lower right corner){if (dx > dy){target2_x = cx + range;target2_y = dy;}else{target2_x = dx;target2_y = cy + range;}}}}else if (xdist < 0 && ydist > 0 || xdist > 0 && ydist < 0){if (xdist < 0) // lower left corner{target1_x = cx - range;target1_y = cy + range;}else // upper right corner{target1_x = cx + range;target1_y = cy - range;}if (xdist == -ydist){target2_x = target1_x;target2_y = target1_y;}else{if (xdist < 0) // ydist > 0{if (-xdist > ydist){target2_x = cx - range;target2_y = dy;}else{target2_x = dx;target2_y = cy + range;}}else // xdist > 0, ydist < 0{if (-xdist > ydist){target2_x = dx;target2_y = cy - range;}else{target2_x = cx + range;target2_y = dy;}}}}else{// Everything should have been handled above.ASSERT(false);}return (true);}void monster_los::check_los_beam(int dx, int dy){ray_def ray;int target1_x = 0, target1_y = 0, target2_x = 0, target2_y = 0;if (!_set_beam_target(gridx, gridy, dx, dy, target1_x, target1_y,target2_x, target2_y, range)){// Nothing to be done.return;}if (target1_x > target2_x || target1_y > target2_y){// Swap the two targets so our loop will work correctly.int help = target1_x;target1_x = target2_x;target2_x = help;help = target1_y;target1_y = target2_y;target2_y = help;}const int max_dist = range;int dist;bool blocked = false;for (int tx = target1_x; tx <= target2_x; tx++)for (int ty = target1_y; ty <= target2_y; ty++){// If (tx, ty) lies outside the level boundaries, there's nothing// that shooting a ray into that direction could bring us, esp.// as earlier grids in the ray will already have been handled, and// out of bounds grids are simply skipped in any LoS check.if (!map_bounds(tx, ty))continue;// Already calculated a beam to (tx, ty), don't do so again.if (!is_unknown(tx, ty))continue;dist = 0;if (ray.x() == gridx && ray.y() == gridy)ray.advance(true);while (dist++ <= max_dist){// The ray brings us out of bounds of the level map.// Since we're always shooting outwards there's nothing more// to look at in that direction, and we can break the loop.if (!map_bounds(ray.x(), ray.y()))break;if (blocked){// Earlier grid blocks this beam, set to blocked if// unknown, but don't overwrite visible grids.set_los_value(ray.x(), ray.y(), true);}else if (_blocks_movement_sight(mons, grd[ray.x()][ray.y()])){set_los_value(ray.x(), ray.y(), true);// The rest of the beam will now be blocked.blocked = true;}else{// Allow overriding in case another beam has marked this// field as blocked, because we've found a solution where// that isn't the case.set_los_value(ray.x(), ray.y(), false, true);}if (ray.x() == tx && ray.y() == ty)break;ray.advance(true);}}}fallback_ray(coord_def(gridx, gridy), coord_def(tx, ty), ray);if (!find_ray(coord_def(gridx, gridy), coord_def(tx, ty), ray))if (distance(x, y, gridx, gridy) > get_los_radius_sq())
monster_los patrol;// Set monster to make monster_los respect habitat restrictions.patrol.set_monster(mon);patrol.set_los_centre(mon->patrol_point);patrol.set_los_range(rad);patrol.fill_los_field();
env_show_grid patrol;losight(patrol, mon->patrol_point, opacity_monmove(*mon), bounds_radius(rad));
static bounds_radius_sq bds_deflos = bounds_radius_sq(LOS_RADIUS_SQ);static bounds_radius_sq bds_maxlos = bounds_radius_sq(LOS_MAX_RADIUS_SQ);
// LOS bounded by fixed radius.struct bounds_radius : bounds_radius_sq{bounds_radius(int r): bounds_radius_sq(r * r + 1){}};