targeting (see 1725723):
Comments and suggestions welcome.
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@1511 c06c8d41-db1a-0410-9941-cceddc491573
GVCGKTH5IJ4VSQEIN4CRC7ZFVZW26JPIYNCPTO7GY66CSZZEW3ZQC
VYGSRD6AGPW3JDTKAMFIUEERMWNCV35SPWXH75XCX2SCMMR72RQQC
QKGDOYIYKE6B36ION5O2DRW65DWWPZMYNWJVH7LJJ7FPGGM2MYAQC
RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC
VD4KDTGHVKCN35AWREYB4TEOUMCTW7SAUPAMTMF5ABC7VBHVKP4AC
K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC
V4WGXVERZ34B7CEINV4D3ZYEKKT2TUIUYTOX5FSOX6B26U3DPVLQC
BNTPYSO6ECZ76CHHLDP3ASSPDSEUH4Y3E3LETKNXVWAWJRFL3YEQC
77H4BWWPPGLM3PLZH4QTAJRXIZTSDVNCOKZE223I437FN2UJ34RQC
5ASC3STDYCNLZFEBN6UTMUCGDETHBR2OCBZCF5VIAZ5RRWLOTDYQC
SDLKLUNFGVKDS55DDJZCBAVIB7NL3RRYPTACAY65SCUQKV6APFSAC
MSQI3TH6T62JAXQGLL52QZCWAMC372TGB6ZNNRDGUGMJKBNNV2VAC
RC6L3CIBLJEH4GWRFD7UQNGI6PZT74FRUVOYHSAN2XCC74NZUASQC
AOAJ6D3OKSELEYKAT55XCVU5LYJ7SMCZKC6DIEGLLB3TF2LEENWQC
FEGNPOJI2SALUA2PVIXIQ2CIXFLSXD7UB7CNUSAAKV4L3POXCRFQC
YAAJ6PTN6QUSWE52URI5AENOGD366FIHOIFUOXFUJLVZYE4OG6HQC
NQMXQ6OQVUSC7Y7F7IL252QW4A5JED224EECNHWAM4ZZYVNY745AC
JQ2PG3ZI7ISKGQ2BZYNIM2PEG4Z2EJHA4ZNKXEBVFBB6KDSHF7NAC
}
double ray_def::reflect(double p, double c) const
{
return (c + c - p);
}
double ray_def::reflect(bool rx, double oldx, double newx) const
{
if (rx? abs(slope) > 1.0 : abs(slope) < 1.0)
return (reflect(oldx, floor(oldx) + 0.5));
const int flnew = newx;
const int flold = oldx;
return (reflect(oldx,
flnew > flold? flnew :
flold > flnew? flold :
(newx + oldx) / 2));
}
void ray_def::set_reflect_point(const double oldx, const double oldy,
double *newx, double *newy,
bool blocked_x, bool blocked_y)
{
if (blocked_x == blocked_y)
{
// What to do?
*newx = oldx;
*newy = oldy;
return;
}
if (blocked_x)
{
ASSERT(int(oldy) != int(*newy));
*newy = oldy;
*newx = reflect(true, oldx, *newx);
}
else
{
ASSERT(int(oldx) != int(*newx));
*newx = oldx;
*newy = reflect(false, oldy, *newy);
}
int ray_def::advance()
int ray_def::advance_through(const coord_def &target)
{
return (advance(true, &target));
}
int ray_def::advance(bool shortest_possible, const coord_def *target)
{
if (!shortest_possible)
return (raw_advance());
// If we want to minimize the number of moves on the ray, look one
// step ahead and see if we can get a diagonal.
const coord_def old(accx, accy);
const int ret = raw_advance();
if (ret == 2 || (target && pos() == *target))
return (ret);
const double maccx = accx, maccy = accy;
if (raw_advance() != 2)
{
const coord_def second(accx, accy);
// If we can convert to a diagonal, do so.
if ((second - old).abs() == 2)
return (2);
}
// No diagonal, so roll back.
accx = maccx;
accy = maccy;
return (ret);
}
int ray_def::raw_advance()
if (grid_is_solid(
grd[sourcex
+ signx * ray_coord_x[inray + cur_offset]]
[sourcey
+ signy * ray_coord_y[inray + cur_offset]]))
const int xi = signx * ray_coord_x[inray + cur_offset];
const int yi = signy * ray_coord_y[inray + cur_offset];
if (grid_is_solid(grd[sourcex + xi][sourcey + yi]))
}
if (find_shortest)
{
c3 = coord_def(xi, yi);
// We've moved at least two steps if inray > 0.
if (inray)
{
// Check for a perpendicular corner on the ray and
// pretend that it's a diagonal.
if ((c3 - c1).abs() != 2)
++real_length;
else
{
// c2 was a dud move, pop it off
unaliased_ray.pop_back();
}
}
else
++real_length;
unaliased_ray.push_back(c3);
c1 = unaliased_ray[real_length - 1];
if ( !blocked )
int cimbalance = 0;
// If this ray is a candidate for shortest, calculate
// the imbalance. I'm defining 'imbalance' as the
// number of consecutive diagonal or orthogonal moves
// in the ray. This is a reasonable measure of deviation from
// the Bresenham line between our selected source and
// destination.
if (!blocked && find_shortest && shortest >= real_length)
{
int diags = 0, straights = 0;
for (int i = 1, size = unaliased_ray.size(); i < size;
++i)
{
const int dist =
(unaliased_ray[i] - unaliased_ray[i - 1]).abs();
if (dist == 2)
{
straights = 0;
if (++diags > cimbalance)
cimbalance = diags;
}
else
{
diags = 0;
if (++straights > cimbalance)
cimbalance = straights;
}
}
}
if ( !blocked
&& (!find_shortest
|| shortest > real_length
|| (shortest == real_length
&& imbalance > cimbalance)) )
int advance(); // returns the direction taken (0,1,2)
coord_def pos() const { return coord_def(accx, accy); }
// returns the direction taken (0,1,2)
int advance(bool shorten = false, const coord_def *p = NULL);
int advance_through(const coord_def &point);
void regress();
void regress(const coord_def &point);
private:
int raw_advance();
double reflect(bool x, double oldc, double newc) const;
double reflect(double x, double c) const;
void set_reflect_point(const double oldx, const double oldy,
double *newx, double *newy,
bool blocked_x, bool blocked_y);