Rework code dealing with struct range fixing many bugs

Change struct range from exclusive to inclusive upper bounds, for
consistency with struct realmstr and the area syntax.  Also fix many
bugs.

real()'s conversion from struct range's exclusive upper bounds to
struct realmstr's inclusive upper bounds could underflow and store -1
in the realms file.  Harmless, because its users didn't mind:
list_realm() and nstr_exec_val() convert back to relative coordinates,
and sarg_getrange() is only used by sarg_area(), which happened to
undo the damage.  The change to inclusive upper bounds gets rid of the
broken conversion.

xyinrange() incorrectly treated the upper bound as inclusive, unless
the bounds were equal.  Impact:

* nxtitem() and nxtitemp() cases NS_AREA and NS_DIST attempted to hack
  around xyinrange()'s lossage(!), but screwed up: sectors on the
  lower bound of of a range spanning the the whole world were skipped.
  This affected all command arguments that support area or distance
  syntax for items.  In sufficiently small worlds, it could also make
  radar miss satellites and ships, sonar miss ships, satellite miss
  ships and land units, nuclear detonations miss ships, planes, land
  units and nukes, automatic supply miss ship and land unit supply
  sources, ships and land units fail to return fire, ships fail to
  fire support.

* draw_map() could draw units sitting just right or just below of the
  mapped area.  No effect, as these parts of the map weren't actually
  shown.

xydist_range() produced an inclusive upper bound when it decided that
the range covers everything in that dimension (which it didn't get
quite right either).  This could make snxtsct_dist() and
snxtitem_dist() initialize the iterator with an incorrect upper bound.
Similar impact as the xyinrange() / nxtitem() lossage.

border() could print the hundreds line unnecessarily.

snxtsct() and snxtsct_all() screwed up for odd WORLD_Y: they failed to
include (WORLD_Y - 1) / 2 in the y-range.  This affected all command
arguments that support "*" syntax for sectors, plus add ... c, power
n, and break.

snxtsct_all() failed to normalize the bounds (presumed harmless).

There were a few correct, but somewhat unclean uses of struct range
with inclusive upper bounds:

* nat_reset() used one internally.

* pathrange() worked with inclusive upper bounds internally, but
  corrected to exclusive upper bounds before passing the range out.

* sarg_getrange() worked with inclusive upper bounds.  Its only caller
  sarg_area() corrected that to exclusive upper bounds.

The change to inclusive upper bounds cleans this up.

unit_map() and xysize_range() had no issues (isn't that amazing?), but
need to be updated for the changed struct range semantics.
This commit is contained in:
Markus Armbruster 2008-08-17 17:44:00 -04:00
parent 1ec0dc976a
commit 68f7c0ceda
10 changed files with 34 additions and 54 deletions

View file

@ -48,12 +48,9 @@
(((y) < 0) ? (WORLD_Y - 1 - ((-(y) - 1) % WORLD_Y)) : ((y) % WORLD_Y)) (((y) < 0) ? (WORLD_Y - 1 - ((-(y) - 1) % WORLD_Y)) : ((y) % WORLD_Y))
struct range { struct range {
coord lx; /* low-range x,y */ coord lx, ly; /* low-range x,y (inclusive) */
coord ly; coord hx, hy; /* high-range x,y (inclusive) */
coord hx; /* high-range x,y */ int width, height;
coord hy;
int width; /* range width, height */
int height;
}; };
extern char *xyas(coord x, coord y, natid country); extern char *xyas(coord x, coord y, natid country);

View file

@ -86,9 +86,9 @@ real(void)
return RET_SYN; return RET_SYN;
getrealm(curr, natp->nat_cnum, &realm); getrealm(curr, natp->nat_cnum, &realm);
realm.r_xl = abs.lx; realm.r_xl = abs.lx;
realm.r_xh = abs.hx - 1; realm.r_xh = abs.hx;
realm.r_yl = abs.ly; realm.r_yl = abs.ly;
realm.r_yh = abs.hy - 1; realm.r_yh = abs.hy;
putrealm(&realm); putrealm(&realm);
list_realm(curr, natp); list_realm(curr, natp);
} }

View file

@ -183,7 +183,7 @@ ynorm(coord y)
int int
xyinrange(coord x, coord y, struct range *rp) xyinrange(coord x, coord y, struct range *rp)
{ {
if (rp->lx < rp->hx) { if (rp->lx <= rp->hx) {
/* xrange doesn't wrap */ /* xrange doesn't wrap */
if (x < rp->lx || x > rp->hx) if (x < rp->lx || x > rp->hx)
return 0; return 0;
@ -191,7 +191,7 @@ xyinrange(coord x, coord y, struct range *rp)
if (x < rp->lx && x > rp->hx) if (x < rp->lx && x > rp->hx)
return 0; return 0;
} }
if (rp->ly < rp->hy) { if (rp->ly <= rp->hy) {
/* yrange doesn't wrap */ /* yrange doesn't wrap */
if (y < rp->ly || y > rp->hy) if (y < rp->ly || y > rp->hy)
return 0; return 0;

View file

@ -68,7 +68,7 @@ border(struct range *rp, char *prefstr, char *sep)
int posi, n, x; int posi, n, x;
if ((WORLD_X / 2) >= 100) { if ((WORLD_X / 2) >= 100) {
if (rp->lx + rp->width > 99 || rp->hx - rp->width < -99) { if (rp->lx + rp->width > 100 || rp->hx - rp->width < -100) {
/* /*
* hundreds * hundreds
*/ */

View file

@ -366,9 +366,9 @@ unit_map(int unit_type, int uid, struct nstr_sect *nsp, char *originp)
} }
range.lx = xnorm(unit.gen.x - 10); range.lx = xnorm(unit.gen.x - 10);
range.hx = xnorm(unit.gen.x + 11); range.hx = xnorm(unit.gen.x + 10);
range.ly = ynorm(unit.gen.y - 5); range.ly = ynorm(unit.gen.y - 5);
range.hy = ynorm(unit.gen.y + 6); range.hy = ynorm(unit.gen.y + 5);
xysize_range(&range); xysize_range(&range);
snxtsct_area(nsp, &range); snxtsct_area(nsp, &range);
return RET_OK; return RET_OK;

View file

@ -87,8 +87,6 @@ nxtitem(struct nstr_item *np, void *ptr)
return 0; return 0;
if (!xyinrange(gp->x, gp->y, &np->range)) if (!xyinrange(gp->x, gp->y, &np->range))
selected = 0; selected = 0;
if (gp->x == np->range.hx || gp->y == np->range.hy)
selected = 0;
break; break;
case NS_XY: case NS_XY:
if (CANT_HAPPEN(!(ef_flags(np->type) & EFF_XY))) if (CANT_HAPPEN(!(ef_flags(np->type) & EFF_XY)))

View file

@ -243,8 +243,6 @@ pathrange(coord cx, coord cy, char *pp, int border, struct range *range)
range->hx = cx; range->hx = cx;
range->ly = cy; range->ly = cy;
range->hy = cy; range->hy = cy;
range->width = 0;
range->height = 0;
for (; *pp; pp++) { for (; *pp; pp++) {
dir = diridx(*pp); dir = diridx(*pp);
if (dir == DIR_STOP) if (dir == DIR_STOP)
@ -262,7 +260,7 @@ pathrange(coord cx, coord cy, char *pp, int border, struct range *range)
} }
range->lx = xnorm(range->lx - border * 2); range->lx = xnorm(range->lx - border * 2);
range->ly = ynorm(range->ly - border); range->ly = ynorm(range->ly - border);
range->hx = xnorm(range->hx + border * 2 + 1); range->hx = xnorm(range->hx + border * 2);
range->hy = ynorm(range->hy + border + 1); range->hy = ynorm(range->hy + border);
xysize_range(range); xysize_range(range);
} }

View file

@ -165,13 +165,6 @@ sarg_area(char *str, struct range *rp)
{ {
if (!sarg_getrange(str, rp)) if (!sarg_getrange(str, rp))
return 0; return 0;
rp->hx += 1;
if (rp->hx >= WORLD_X)
rp->hx = 0;
rp->hy += 1;
if (rp->hy >= WORLD_Y)
rp->hy = 0;
xysize_range(rp);
return 1; return 1;
} }

View file

@ -83,8 +83,8 @@ snxtsct(struct nstr_sect *np, char *str)
natp = getnatp(player->cnum); natp = getnatp(player->cnum);
range.lx = xabs(natp, -WORLD_X / 2); range.lx = xabs(natp, -WORLD_X / 2);
range.ly = yabs(natp, -WORLD_Y / 2); range.ly = yabs(natp, -WORLD_Y / 2);
range.hx = xabs(natp, WORLD_X / 2); range.hx = xnorm(range.lx + WORLD_X - 1);
range.hy = yabs(natp, WORLD_Y / 2); range.hy = ynorm(range.ly + WORLD_Y - 1);
xysize_range(&range); xysize_range(&range);
snxtsct_area(np, &range); snxtsct_area(np, &range);
break; break;
@ -104,10 +104,10 @@ snxtsct_all(struct nstr_sect *np)
{ {
struct range worldrange; struct range worldrange;
worldrange.lx = -WORLD_X / 2; worldrange.lx = 0;
worldrange.ly = -WORLD_Y / 2; worldrange.ly = 0;
worldrange.hx = WORLD_X / 2; worldrange.hx = WORLD_X - 1;
worldrange.hy = WORLD_Y / 2; worldrange.hy = WORLD_Y - 1;
xysize_range(&worldrange); xysize_range(&worldrange);
snxtsct_area(np, &worldrange); snxtsct_area(np, &worldrange);
} }
@ -156,44 +156,40 @@ snxtsct_dist(struct nstr_sect *np, coord cx, coord cy, int dist)
void void
xysize_range(struct range *rp) xysize_range(struct range *rp)
{ {
if (rp->lx >= rp->hx) if (rp->lx > rp->hx)
rp->width = WORLD_X + rp->hx - rp->lx; rp->width = WORLD_X + rp->hx + 1 - rp->lx;
else else
rp->width = rp->hx - rp->lx; rp->width = rp->hx + 1 - rp->lx;
if (CANT_HAPPEN(rp->width > WORLD_X)) if (CANT_HAPPEN(rp->width > WORLD_X))
rp->width = WORLD_X; rp->width = WORLD_X;
if (rp->ly >= rp->hy) if (rp->ly > rp->hy)
rp->height = WORLD_Y + rp->hy - rp->ly; rp->height = WORLD_Y + rp->hy + 1 - rp->ly;
else else
rp->height = rp->hy - rp->ly; rp->height = rp->hy + 1 - rp->ly;
if (CANT_HAPPEN(rp->height > WORLD_Y)) if (CANT_HAPPEN(rp->height > WORLD_Y))
rp->height = WORLD_Y; rp->height = WORLD_Y;
} }
/* This is called also called in snxtitem.c */
void void
xydist_range(coord x, coord y, int dist, struct range *rp) xydist_range(coord x, coord y, int dist, struct range *rp)
{ {
if (dist < WORLD_X / 4) { if (4 * dist + 1 < WORLD_X) {
rp->lx = xnorm((coord)(x - 2 * dist)); rp->lx = xnorm(x - 2 * dist);
rp->hx = xnorm((coord)(x + 2 * dist) + 1); rp->hx = xnorm(x + 2 * dist);
rp->width = 4 * dist + 1; rp->width = 4 * dist + 1;
} else { } else {
/* Range is larger than the world */ rp->lx = xnorm(x - WORLD_X / 2);
/* Make sure we get lx in the right place. */ rp->hx = xnorm(rp->lx + WORLD_X - 1);
rp->lx = xnorm((coord)(x - WORLD_X / 2));
rp->hx = xnorm((coord)(rp->lx + WORLD_X - 1));
rp->width = WORLD_X; rp->width = WORLD_X;
} }
if (dist < WORLD_Y / 2) { if (2 * dist + 1 < WORLD_Y) {
rp->ly = ynorm((coord)(y - dist)); rp->ly = ynorm(y - dist);
rp->hy = ynorm((coord)(y + dist) + 1); rp->hy = ynorm(y + dist);
rp->height = 2 * dist + 1; rp->height = 2 * dist + 1;
} else { } else {
/* Range is larger than the world */ rp->ly = ynorm(y - WORLD_Y / 2);
rp->ly = ynorm((coord)(y - WORLD_Y / 2)); rp->hy = ynorm(rp->ly + WORLD_Y - 1);
rp->hy = ynorm((coord)(rp->ly + WORLD_Y - 1));
rp->height = WORLD_Y; rp->height = WORLD_Y;
} }
} }

View file

@ -82,8 +82,6 @@ nxtitemp(struct nstr_item *np)
return 0; return 0;
if (!xyinrange(gp->x, gp->y, &np->range)) if (!xyinrange(gp->x, gp->y, &np->range))
selected = 0; selected = 0;
if (gp->x == np->range.hx || gp->y == np->range.hy)
selected = 0;
break; break;
case NS_XY: case NS_XY:
if (CANT_HAPPEN(!(ef_flags(np->type) & EFF_XY))) if (CANT_HAPPEN(!(ef_flags(np->type) & EFF_XY)))