summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorharanp <haranp@c06c8d41-db1a-0410-9941-cceddc491573>2006-10-31 17:21:06 +0000
committerharanp <haranp@c06c8d41-db1a-0410-9941-cceddc491573>2006-10-31 17:21:06 +0000
commita9a42e796f70733df88a447e53a0042307c27280 (patch)
tree23ee7c4fe767de76580463fcc78148ac5dfc81c7
parent8b12954db4d6af0e6a2d1a1c2efaaec95d9d166f (diff)
downloadcrawl-ref-a9a42e796f70733df88a447e53a0042307c27280.tar.gz
crawl-ref-a9a42e796f70733df88a447e53a0042307c27280.zip
Rewritten the beam code. Much cleaner now, I hope. Bugs are quite likely.
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/branches/stone_soup@314 c06c8d41-db1a-0410-9941-cceddc491573
-rw-r--r--crawl-ref/source/beam.cc345
-rw-r--r--crawl-ref/source/externs.h17
-rw-r--r--crawl-ref/source/view.cc228
-rw-r--r--crawl-ref/source/view.h8
4 files changed, 265 insertions, 333 deletions
diff --git a/crawl-ref/source/beam.cc b/crawl-ref/source/beam.cc
index c144c41535..644e0bf981 100644
--- a/crawl-ref/source/beam.cc
+++ b/crawl-ref/source/beam.cc
@@ -75,10 +75,6 @@ static bool isBouncy(struct bolt &beam);
static void beam_drop_object( struct bolt &beam, item_def *item, int x, int y );
static bool beam_term_on_target(struct bolt &beam);
static void beam_explodes(struct bolt &beam, int x, int y);
-static int bounce(int &step1, int &step2, int w1, int w2, int &n1, int &n2,
- int l1, int l2, int &t1, int &t2, bool topBlocked, bool sideBlocked);
-static bool fuzzyLine(int nx, int ny, int &tx, int &ty, int lx, int ly,
- int stepx, int stepy, bool roundX, bool roundY);
static int affect_wall(struct bolt &beam, int x, int y);
static int affect_place_clouds(struct bolt &beam, int x, int y);
static void affect_place_explosion_clouds(struct bolt &beam, int x, int y);
@@ -1217,17 +1213,9 @@ static void zappy( char z_type, int power, struct bolt &pbolt )
void fire_beam( struct bolt &pbolt, item_def *item )
{
- int dx, dy; // total delta between source & target
- int lx, ly; // last affected x,y
- int stepx, stepy; // x,y increment - FP
- int wx, wy; // 'working' x,y - FP
bool beamTerminate; // has beam been 'stopped' by something?
- int nx, ny; // test(new) x,y - FP
int tx, ty; // test(new) x,y - integer
- bool roundX, roundY; // which to round?
int rangeRemaining;
- bool fuzzyOK; // fuzzification resulted in OK move
- bool sideBlocked, topBlocked, random_beam;
#if DEBUG_DIAGNOSTICS
if (pbolt.flavour != BEAM_LINE_OF_SIGHT)
@@ -1246,47 +1234,22 @@ void fire_beam( struct bolt &pbolt, item_def *item )
#endif
// init
- pbolt.aimed_at_feet = false;
+ pbolt.aimed_at_feet =
+ (pbolt.target_x == pbolt.source_x) &&
+ (pbolt.target_y == pbolt.source_y);
pbolt.msg_generated = false;
- roundY = false;
- roundX = false;
- // first, calculate beam step
- dx = pbolt.target_x - pbolt.source_x;
- dy = pbolt.target_y - pbolt.source_y;
+ ray_def ray;
- // check for aim at feet
- if (dx == 0 && dy == 0)
- {
- pbolt.aimed_at_feet = true;
- stepx = 0;
- stepy = 0;
- tx = pbolt.source_x;
- ty = pbolt.source_y;
- }
- else
- {
- if (abs(dx) >= abs(dy))
- {
- stepx = (dx > 0) ? 100 : -100;
- stepy = 100 * dy / (abs(dx));
- roundY = true;
- }
- else
- {
- stepy = (dy > 0) ? 100 : -100;
- stepx = 100 * dx / (abs(dy));
- roundX = true;
- }
- }
+ find_ray( pbolt.source_x, pbolt.source_y, pbolt.target_x, pbolt.target_y,
+ true, ray);
+
+ if ( !pbolt.aimed_at_feet )
+ ray.advance();
// give chance for beam to affect one cell even if aimed_at_feet.
beamTerminate = false;
- // setup working coords
- lx = pbolt.source_x;
- wx = 100 * lx;
- ly = pbolt.source_y;
- wy = 100 * ly;
+
// setup range
rangeRemaining = pbolt.range;
if (pbolt.rangeMax > pbolt.range)
@@ -1304,34 +1267,10 @@ void fire_beam( struct bolt &pbolt, item_def *item )
oldValue = setBuffering(false);
#endif
- // cannot use source_x, source_y, target_x, target_y during
- // step algorithm due to bouncing.
-
- // now, one step at a time, try to move towards target.
while(!beamTerminate)
{
- nx = wx + stepx;
- ny = wy + stepy;
-
- if (roundY)
- {
- tx = nx / 100;
- ty = (ny + 50) / 100;
- }
- if (roundX)
- {
- ty = ny / 100;
- tx = (nx + 50) / 100;
- }
-
- // check that tx, ty are valid. If not, set to last
- // x,y and break.
- if (tx < 0 || tx >= GXM || ty < 0 || ty >= GYM)
- {
- tx = lx;
- ty = ly;
- break;
- }
+ tx = ray.x();
+ ty = ray.y();
// see if tx, ty is blocked by something
if (grid_is_solid(grd[tx][ty]))
@@ -1350,78 +1289,43 @@ void fire_beam( struct bolt &pbolt, item_def *item )
}
else
{
- // BEGIN fuzzy line algorithm
- fuzzyOK = fuzzyLine(nx,ny,tx,ty,lx,ly,stepx,stepy,roundX,roundY);
- if (!fuzzyOK)
- {
- // BEGIN bounce case
- if (!isBouncy(pbolt))
- {
- tx = lx;
- ty = ly;
- break; // breaks from line tracing
- }
-
- sideBlocked = false;
- topBlocked = false;
- // BOUNCE -- guaranteed to return reasonable tx, ty.
- // if it doesn't, we'll quit in the next if stmt anyway.
- if (roundY)
- {
- if (grid_is_solid(grd[lx + stepx / 100][ly]))
- sideBlocked = true;
-
- if (dy != 0)
- {
- if (grid_is_solid(grd[lx][ly + (stepy>0?1:-1)]))
- topBlocked = true;
- }
+ // BEGIN bounce case
+ if (!isBouncy(pbolt)) {
+ ray.regress();
+ tx = ray.x();
+ ty = ray.y();
+ break; // breaks from line tracing
+ }
- rangeRemaining -= bounce(stepx, stepy, wx, wy, nx, ny,
- lx, ly, tx, ty, topBlocked, sideBlocked);
- }
- else
- {
- if (grid_is_solid(grd[lx][ly + stepy / 100]))
- sideBlocked = true;
+ // bounce
+ do {
+ ray.regress();
+ ray.advance_and_bounce();
+ --rangeRemaining;
+ } while ( rangeRemaining > 0 &&
+ grid_is_solid(grd[ray.x()][ray.y()]) );
- if (dx != 0)
- {
- if (grid_is_solid(grd[lx + (stepx>0?1:-1)][ly]))
- topBlocked = true;
- }
+ if (rangeRemaining < 1)
+ break;
+ tx = ray.x();
+ ty = ray.y();
- rangeRemaining -= bounce(stepy, stepx, wy, wx, ny, nx,
- ly, lx, ty, tx, topBlocked, sideBlocked);
- }
- // END bounce case - range check
- if (rangeRemaining < 1)
- {
- tx = lx;
- ty = ly;
- break;
- }
- }
} // end else - beam doesn't affect walls
} // endif - is tx, ty wall?
// at this point, if grd[tx][ty] is still a wall, we
// couldn't find any path: bouncy, fuzzy, or not - so break.
if (grid_is_solid(grd[tx][ty]))
- {
- tx = lx;
- ty = ly;
break;
- }
-
+
// check for "target termination"
// occurs when beam can be targetted at empty
// cell (e.g. a mage wants an explosion to happen
// between two monsters)
- // in this case, don't affect the cell - players
- // /monsters have no chance to dodge or block such
- // a beam, and we want to avoid silly messages.
+ // in this case, don't affect the cell - players and
+ // monsters have no chance to dodge or block such
+ // a beam, and we want to avoid silly messages.
if (tx == pbolt.target_x && ty == pbolt.target_y)
beamTerminate = beam_term_on_target(pbolt);
@@ -1431,7 +1335,7 @@ void fire_beam( struct bolt &pbolt, item_def *item )
if (!beamTerminate || !pbolt.is_explosion)
{
// random beams: randomize before affect
- random_beam = false;
+ bool random_beam = false;
if (pbolt.flavour == BEAM_RANDOM)
{
random_beam = true;
@@ -1493,14 +1397,7 @@ void fire_beam( struct bolt &pbolt, item_def *item )
}
}
-
- // set some stuff up for the next iteration
- lx = tx;
- ly = ty;
-
- wx = nx;
- wy = ny;
-
+ ray.advance();
} // end- while !beamTerminate
// the beam has finished, and terminated at tx, ty
@@ -2290,8 +2187,6 @@ void fire_tracer(struct monsters *monster, struct bolt &pbolt)
bool check_line_of_sight( int sx, int sy, int tx, int ty )
{
- struct bolt pbolt;
-
const int dist = grid_distance( sx, sy, tx, ty );
// can always see one square away
@@ -2301,42 +2196,11 @@ bool check_line_of_sight( int sx, int sy, int tx, int ty )
// currently we limit the range to 8
if (dist > MONSTER_LOS_RANGE)
return (false);
-
- // Redirect player centered LoS to the old method (using display table)...
- // note that this assumes that viewwindow() has been called if needed
- // before we get here (ie this won't work very well if this function gets
- // called between moving the player and updating the display).
- if (sx == you.x_pos && sy == you.y_pos)
- return (see_grid( tx, ty ));
- else if (tx == you.x_pos && ty == you.y_pos)
- return (see_grid( sx, sy ));
-
- // Okay, no easy way... set up a LoS beam between the points
- pbolt.flavour = BEAM_LINE_OF_SIGHT;
- pbolt.is_tracer = true;
- pbolt.source_x = sx;
- pbolt.source_y = sy;
- pbolt.target_x = tx;
- pbolt.target_y = ty;
- pbolt.range = MONSTER_LOS_RANGE;
- pbolt.rangeMax = MONSTER_LOS_RANGE;
-
- // setting these just to be safe:
- pbolt.hit = 0;
- pbolt.type = 0;
- pbolt.damage = dice_def( 0, 1 );
- pbolt.colour = BLACK;
- pbolt.is_beam = true;
-
- // init tracer variables (used to tell if we "hit" the target)
- pbolt.foe_count = pbolt.fr_count = 0;
- pbolt.foe_power = pbolt.fr_power = 0;
-
- // fire!
- fire_beam( pbolt );
-
- // got to target?
- return (pbolt.foe_count == 1);
+
+ // Note that we are guaranteed to be within the player LOS range.
+ // Thus find_ray_path() is enough. If this ever changes, we can
+ // create the appropriate beam and advance it manually.
+ return ( find_ray_path(sx, sy, tx, ty) != 0 );
}
/*
@@ -2354,7 +2218,7 @@ void mimic_alert(struct monsters *mimic)
static bool isBouncy(struct bolt &beam)
{
- // at present, only non-enchantment eletrcical beams bounce.
+ // at present, only non-enchantment electrical beams bounce.
if (beam.name[0] != '0' && beam.flavour == BEAM_ELECTRICITY)
return (true);
@@ -2542,131 +2406,6 @@ static void beam_drop_object( struct bolt &beam, item_def *item, int x, int y )
#define B_VERT 2
#define B_BOTH 3
-static int bounce(int &step1, int &step2, int w1, int w2, int &n1, int &n2,
- int l1, int l2, int &t1, int &t2, bool topBlocked, bool sideBlocked)
-{
- int bounceType = 0;
- int bounceCount = 1;
-
- if (topBlocked) bounceType = B_HORZ;
- if (sideBlocked) bounceType = B_VERT;
- if (topBlocked && sideBlocked)
- {
- // check for veritcal bounce only
- if ((w2 + step2 - 50)/100 == (w2 - 50)/100)
- bounceType = B_VERT;
- else
- bounceType = B_BOTH;
- }
-
- switch (bounceType)
- {
- case B_VERT: // easiest
- n1 = w1;
- n2 = w2 + step2;
- step1 = -step1;
- t1 = n1 / 100;
- t2 = (n2 + 50)/100;
- // check top
- if (t2 != n2/100 && topBlocked)
- t2 = n2/100;
- break;
- case B_HORZ: // a little tricky
- if (step2 > 0)
- n2 = (100 + 200*(w2/100)) - (w2 + step2);
- else
- n2 = (100 + 200*((w2 - 50)/100)) - (w2 + step2);
- n1 = w1 + step1;
- t1 = n1 /100;
- t2 = (n2 + 50) / 100;
- step2 = -step2;
- break;
- case B_BOTH:
- // vertical:
- n1 = w1;
- t1 = l1;
- t2 = l2;
- // horizontal:
- if (step2 > 0)
- n2 = (100 + 200*(w2/100)) - (w2 + step2);
- else
- n2 = (100 + 200*((w2 - 50)/100)) - (w2 + step2);
- // reverse both directions
- step1 =- step1;
- step2 =- step2;
- bounceCount = 2;
- break;
- default:
- bounceCount = 0;
- break;
- }
-
- return (bounceCount);
-}
-
-static bool fuzzyLine(int nx, int ny, int &tx, int &ty, int lx, int ly,
- int stepx, int stepy, bool roundX, bool roundY)
-{
- bool fuzzyOK = false;
- int fx, fy; // fuzzy x,y
-
- // BEGIN fuzzy line algorithm
- fx = tx;
- fy = ty;
- if (roundY)
- {
- // try up
- fy = (ny + 100) / 100;
- // check for monotonic
- if (fy != ty && ((stepy>0 && fy >= ly)
- || (stepy<0 && fy <= ly)))
- fuzzyOK = true;
- // see if up try is blocked
- if (fuzzyOK && grid_is_solid(grd[tx][fy]))
- fuzzyOK = false;
-
- // try down
- if (!fuzzyOK)
- fy = ny / 100;
- // check for monotonic
- if (fy != ty && ((stepy>0 && fy >= ly)
- || (stepy<0 && fy <= ly)))
- fuzzyOK = true;
- if (fuzzyOK && grid_is_solid(grd[tx][fy]))
- fuzzyOK = false;
- }
- if (roundX)
- {
- // try up
- fx = (nx + 100) / 100;
- // check for monotonic
- if (fx != tx && ((stepx>0 && fx >= lx)
- || (stepx<0 && fx <= lx)))
- fuzzyOK = true;
- // see if up try is blocked
- if (fuzzyOK && grid_is_solid(grd[fx][ty]))
- fuzzyOK = false;
-
- // try down
- if (!fuzzyOK)
- fx = nx / 100;
- // check for monotonic
- if (fx != tx && ((stepx>0 && fx >= lx)
- || (stepx<0 && fx <= lx)))
- fuzzyOK = true;
- if (fuzzyOK && grid_is_solid(grd[fx][ty]))
- fuzzyOK = false;
- }
- // END fuzzy line algorithm
-
- if (fuzzyOK)
- {
- tx = fx;
- ty = fy;
- }
-
- return (fuzzyOK);
-}
// affects a single cell.
// returns the amount of extra range 'used up' by this beam
diff --git a/crawl-ref/source/externs.h b/crawl-ref/source/externs.h
index fe1bb9deec..e7030de959 100644
--- a/crawl-ref/source/externs.h
+++ b/crawl-ref/source/externs.h
@@ -191,6 +191,23 @@ struct bolt
bolt();
};
+struct ray_def
+{
+ double accx;
+ double accy;
+ double slope;
+ // Quadrant 1: down-right
+ // Quadrant 2: down-left
+ // Quadrant 3: up-left
+ // Quadrant 4: up-right
+ int quadrant;
+
+ int x() const { return (int)(accx); }
+ int y() const { return (int)(accy); }
+ int advance(); // returns the direction taken (0,1,2)
+ void advance_and_bounce();
+ void regress();
+};
struct run_check_dir
{
diff --git a/crawl-ref/source/view.cc b/crawl-ref/source/view.cc
index f95eb02d69..6fe43b18b7 100644
--- a/crawl-ref/source/view.cc
+++ b/crawl-ref/source/view.cc
@@ -979,6 +979,7 @@ unsigned long* dead_rays = NULL;
std::vector<short> ray_coord_x;
std::vector<short> ray_coord_y;
std::vector<int> raylengths;
+std::vector<ray_def> fullrays;
void setLOSRadius(int newLR)
{
@@ -997,18 +998,22 @@ bool double_is_zero( const double x )
return (x > -EPSILON_VALUE) && (x < EPSILON_VALUE);
}
-static void find_next_intercept(double* accx, double* accy, const double slope)
+// note that slope must be nonnegative!
+// returns 0 if the advance was in x, 1 if it was in y, 2 if it was
+// the diagonal
+static int find_next_intercept(double* accx, double* accy, const double slope)
{
+
// handle perpendiculars
if ( double_is_zero(slope) )
{
*accx += 1.0;
- return;
+ return 0;
}
if ( slope > 100.0 )
{
*accy += 1.0;
- return;
+ return 1;
}
const double xtarget = (double)((int)(*accx) + 1);
@@ -1021,26 +1026,103 @@ static void find_next_intercept(double* accx, double* accy, const double slope)
if ( double_is_zero( distdiff ) ) {
// move somewhat away from the corner
if ( slope > 1.0 ) {
- *accx = xtarget + 0.5 / slope;
- *accy = ytarget + 0.5;
+ *accx = xtarget + EPSILON_VALUE * 2;
+ *accy = ytarget + EPSILON_VALUE * 2 * slope;
}
else {
- *accx = xtarget + 0.5;
- *accy = ytarget + 0.5 * slope;
+ *accx = xtarget + EPSILON_VALUE * 2 / slope;
+ *accy = ytarget + EPSILON_VALUE * 2;
}
- return;
+ return 2;
}
double traveldist;
- if ( distdiff > 0.0 )
+ int rc = -1;
+ if ( distdiff > 0.0 ) {
traveldist = ydistance / slope;
- else
+ rc = 1;
+ }
+ else {
traveldist = xdistance;
+ rc = 0;
+ }
traveldist += EPSILON_VALUE * 10.0;
*accx += traveldist;
*accy += traveldist * slope;
+ return rc;
+}
+
+void ray_def::advance_and_bounce()
+{
+ // 0 = down-right, 1 = down-left, 2 = up-left, 3 = up-right
+ int bouncequad[4][3] = {
+ { 1, 3, 2 }, { 0, 2, 3 }, { 3, 1, 0 }, { 2, 0, 1 }
+ };
+ int oldx = x(), oldy = y();
+ int rc = advance();
+ int newx = x(), newy = y();
+ ASSERT( grid_is_solid(grd[newx][newy]) );
+ if ( double_is_zero(slope) || slope > 100.0 )
+ quadrant = bouncequad[quadrant][2];
+ else if ( rc != 2 )
+ quadrant = bouncequad[quadrant][rc];
+ else
+ {
+ ASSERT( (oldx != newx) && (oldy != newy) );
+ bool blocked_x = grid_is_solid(grd[oldx][newy]);
+ bool blocked_y = grid_is_solid(grd[newx][oldy]);
+ if ( blocked_x && blocked_y )
+ quadrant = bouncequad[quadrant][rc];
+ else if ( blocked_x )
+ quadrant = bouncequad[quadrant][1];
+ else
+ quadrant = bouncequad[quadrant][0];
+ }
+ advance();
+}
+
+void ray_def::regress()
+{
+ int opp_quadrant[4] = { 2, 3, 0, 1 };
+ quadrant = opp_quadrant[quadrant];
+ advance();
+ quadrant = opp_quadrant[quadrant];
+}
+
+int ray_def::advance()
+{
+ int rc;
+ switch ( quadrant )
+ {
+ case 0:
+ // going down-right
+ rc = find_next_intercept( &accx, &accy, slope );
+ return rc;
+ case 1:
+ // going down-left
+ accx = 100.0 - EPSILON_VALUE/10.0 - accx;
+ rc = find_next_intercept( &accx, &accy, slope );
+ accx = 100.0 - EPSILON_VALUE/10.0 - accx;
+ return rc;
+ case 2:
+ // going up-left
+ accx = 100.0 - EPSILON_VALUE/10.0 - accx;
+ accy = 100.0 - EPSILON_VALUE/10.0 - accy;
+ rc = find_next_intercept( &accx, &accy, slope );
+ accx = 100.0 - EPSILON_VALUE/10.0 - accx;
+ accy = 100.0 - EPSILON_VALUE/10.0 - accy;
+ return rc;
+ case 3:
+ // going up-right
+ accy = 100.0 - EPSILON_VALUE/10.0 - accy;
+ rc = find_next_intercept( &accx, &accy, slope );
+ accy = 100.0 - EPSILON_VALUE/10.0 - accy;
+ return rc;
+ default:
+ return -1;
+ }
}
// Shoot a ray from the given start point (accx, accy) with the given
@@ -1116,8 +1198,15 @@ static bool register_ray( double accx, double accy, double slope )
ray_coord_x.push_back(xpos[i]);
ray_coord_y.push_back(ypos[i]);
}
+
// register the fullray
raylengths.push_back(raylen);
+ ray_def ray;
+ ray.accx = accx;
+ ray.accy = accy;
+ ray.slope = slope;
+ ray.quadrant = 0;
+ fullrays.push_back(ray);
return true;
}
@@ -1191,6 +1280,11 @@ void raycast()
int xangle, yangle;
+ // register perpendiculars FIRST, to make them top choice
+ // when selecting beams
+ register_ray( 0.5, 0.5, 1000.0 );
+ register_ray( 0.5, 0.5, 0.0 );
+
// For a slope of M = y/x, every x we move on the X axis means
// that we move y on the y axis. We want to look at the resolution
// of x/y: in that case, every step on the X axis means an increase
@@ -1218,14 +1312,91 @@ void raycast()
}
}
- // register perpendiculars
- register_ray( 0.5, 0.5, 1000.0 );
- register_ray( 0.5, 0.5, 0.0 );
-
// Now create the appropriate blockrays array
create_blockrays();
}
+static void set_ray_quadrant( ray_def& ray, int sx, int sy, int tx, int ty )
+{
+ if ( tx >= sx && ty >= sy )
+ ray.quadrant = 0;
+ else if ( tx < sx && ty >= sy )
+ ray.quadrant = 1;
+ else if ( tx < sx && ty < sy )
+ ray.quadrant = 2;
+ else if ( tx >= sx && ty < sy )
+ ray.quadrant = 3;
+ else
+ mpr("Bad ray quadrant!", MSGCH_DIAGNOSTICS);
+}
+
+
+// Find a nonblocked ray from sx, sy to tx, ty. Return false if no
+// such ray could be found, otherwise return true and fill ray
+// appropriately.
+// If allow_fallback is true, fall back to a center-to-center ray
+// if range is too great or all rays are blocked.
+bool find_ray( int sourcex, int sourcey, int targetx, int targety,
+ bool allow_fallback, ray_def& ray )
+{
+
+ int cellray, inray;
+ const int signx = ((targetx - sourcex >= 0) ? 1 : -1);
+ const int signy = ((targety - sourcey >= 0) ? 1 : -1);
+ const int absx = signx * (targetx - sourcex);
+ const int absy = signy * (targety - sourcey);
+ int cur_offset = 0;
+ for ( unsigned int fullray = 0; fullray < fullrays.size();
+ cur_offset += raylengths[fullray++] ) {
+
+ for ( cellray = 0; cellray < raylengths[fullray]; ++cellray )
+ {
+ if ( ray_coord_x[cellray + cur_offset] == absx &&
+ ray_coord_y[cellray + cur_offset] == absy ) {
+
+ // check if we're blocked so far
+ bool blocked = false;
+ for ( inray = 0; inray < cellray; ++inray ) {
+ if (grid_is_solid(grd[sourcex + signx * ray_coord_x[inray + cur_offset]][sourcey + signy * ray_coord_y[inray + cur_offset]]))
+ {
+ blocked = true;
+ break;
+ }
+ }
+
+ if ( !blocked )
+ {
+ // success!
+ ray = fullrays[fullray];
+ if ( sourcex > targetx )
+ ray.accx = 1.0 - ray.accx;
+ if ( sourcey > targety )
+ ray.accy = 1.0 - ray.accy;
+ ray.accx += sourcex;
+ ray.accy += sourcey;
+ set_ray_quadrant(ray, sourcex, sourcey, targetx, targety);
+ return true;
+ }
+ }
+ }
+ }
+ if ( allow_fallback ) {
+ ray.accx = sourcex + 0.5;
+ ray.accy = sourcey + 0.5;
+ if ( targetx == sourcex )
+ ray.slope = 10000.0;
+ else {
+ ray.slope = targety - sourcey;
+ ray.slope /= targetx - sourcex;
+ if ( ray.slope < 0 )
+ ray.slope = -ray.slope;
+ }
+ set_ray_quadrant(ray, sourcex, sourcey, targetx, targety);
+ return true;
+ }
+ return false;
+}
+
// Find a ray from sourcex, sourcey to targetx, targety.
//
// Return the maximum length of the ray (until it leaves LOS), and the
@@ -1236,15 +1407,17 @@ void raycast()
// The assumption is that targetx, targety is within LOS of sourcex, sourcey.
// Therefore, we simply look at all the rays until we hit one which
// passes through targetx, targety and is nonblocked.
+//
+// If we can't find any path, we return 0.
int find_ray_path( int sourcex, int sourcey,
int targetx, int targety,
- int xpos[], int ypos[] )
+ int* xpos, int* ypos, bool just_check )
{
int cellray, inray;
- const int signx = (targetx >= 0 ? 1 : -1);
- const int signy = (targety >= 0 ? 1 : -1);
- const int absx = signx * targetx;
- const int absy = signy * targety;
+ const int signx = ((targetx - sourcex >= 0) ? 1 : -1);
+ const int signy = ((targety - sourcey >= 0) ? 1 : -1);
+ const int absx = signx * (targetx - sourcex);
+ const int absy = signy * (targety - sourcey);
int cur_offset = 0;
for ( unsigned int fullray = 0; fullray < raylengths.size();
cur_offset += raylengths[fullray++] ) {
@@ -1267,21 +1440,22 @@ int find_ray_path( int sourcex, int sourcey,
if ( !blocked )
{
// success!
- for ( inray = 0; inray <= cellray; ++inray )
+ if (!just_check)
{
- xpos[inray] = sourcex +
- signx * ray_coord_x[inray + cur_offset];
- ypos[inray] = sourcey +
- signy * ray_coord_y[inray + cur_offset];
+ // write out the ray
+ for ( inray = 0; inray <= cellray; ++inray )
+ {
+ xpos[inray] = sourcex +
+ signx * ray_coord_x[inray + cur_offset];
+ ypos[inray] = sourcey +
+ signy * ray_coord_y[inray + cur_offset];
+ }
}
return cellray + 1;
}
}
}
}
-//#ifdef DEBUG_DIAGNOSTICS
- mpr("Oops! Couldn't find a ray!", MSGCH_DIAGNOSTICS);
-//#endif
return 0;
}
diff --git a/crawl-ref/source/view.h b/crawl-ref/source/view.h
index fffd7d6eee..2fac2d8b39 100644
--- a/crawl-ref/source/view.h
+++ b/crawl-ref/source/view.h
@@ -135,12 +135,14 @@ std::string screenshot(bool fullscreen = false);
unsigned char get_sightmap_char(int feature);
unsigned char get_magicmap_char(int feature);
-int find_ray_path( int sourcex, int sourcey,
- int targetx, int targety,
- int xpos[], int ypos[] );
+int find_ray_path(int sourcex, int sourcey, int targetx, int targety,
+ int* xpos = NULL, int* ypos = NULL, bool just_check = true);
void viewwindow(bool draw_it, bool do_updates);
+bool find_ray( int sourcex, int sourcey, int targetx, int targety,
+ bool allow_fallback, ray_def& ray );
+
#if defined(WIN32CONSOLE) || defined(DOS)
unsigned short dos_brand( unsigned short colour,
unsigned brand = CHATTR_REVERSE);