/*
* Empire - A multi-player, client/server Internet based war game.
- * Copyright (C) 1986-2008, Dave Pare, Jeff Bailey, Thomas Ruschak,
- * Ken Stevens, Steve McClure
+ * Copyright (C) 1986-2016, Dave Pare, Jeff Bailey, Thomas Ruschak,
+ * Ken Stevens, Steve McClure, Markus Armbruster
*
- * This program is free software; you can redistribute it and/or modify
+ * Empire is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* ---
*
* ---
*
* maps.c: Map routines
- *
+ *
* Known contributors to this file:
* Ken Stevens, 1995
* Steve McClure, 1998
+ * Markus Armbruster, 2004-2011
* Ron Koenderink, 2006
*/
#include "file.h"
#include "land.h"
#include "map.h"
+#include "match.h"
#include "misc.h"
#include "nat.h"
#include "nsc.h"
-#include "nuke.h"
#include "optlist.h"
#include "plane.h"
#include "player.h"
#include "ship.h"
#include "xy.h"
+/* Flags for draw_map() */
+/* whether to put ships, planes, land units or nukes on the map */
+#define MAP_SHIP bit(0)
+#define MAP_PLANE bit(1)
+#define MAP_LAND bit(2)
+#define MAP_NUKE bit(3)
+#define MAP_ALL (MAP_SHIP | MAP_PLANE | MAP_LAND | MAP_NUKE)
+/* whether to highlight own sectors */
+#define MAP_HIGH bit(4)
+/* whether to draw a map or a bmap */
+#define MAP_BMAP bit(5)
+/* whether to draw an alternate map: newdes for map, true bmap for bmap */
+#define MAP_ALT bit(6)
+/* whether to revert bmap, internal to do_map() */
+#define MAP_BMAP_REVERT bit(7)
+
+static int parse_map_arg(int, char *, struct nstr_sect *, char *);
+static int parse_map_flags(int, char *);
+static int revert_bmap(struct nstr_sect *);
+static int draw_map(char, int, struct nstr_sect *);
static int bmnxtsct(struct nstr_sect *);
static char map_char(int, natid, int);
static int unit_map(int, int, struct nstr_sect *, char *);
+static void snxtsct_around(struct nstr_sect *, coord, coord);
int
-do_map(int bmap, int unit_type, char *arg, char *map_flags_arg)
+do_map(int bmap, int unit_type, char *arg1, char *arg2)
{
struct nstr_sect ns;
- char origin = '\0';
- char *b;
- int map_flags = 0;
+ char origin;
+ int res, map_flags;
+
+ res = parse_map_arg(unit_type, arg1, &ns, &origin);
+ if (res != RET_OK)
+ return res;
+
+ map_flags = parse_map_flags(bmap, arg2);
+ if (map_flags < 0)
+ return RET_SYN;
- if (!snxtsct(&ns, arg)) {
- if (unit_map(unit_type, atoi(arg), &ns, &origin))
+ if (map_flags & MAP_BMAP_REVERT)
+ return revert_bmap(&ns);
+ return draw_map(origin, map_flags, &ns);
+}
+
+static int
+parse_map_arg(int unit_type, char *arg,
+ struct nstr_sect *nsp, char *originp)
+{
+ switch (sarg_type(arg)) {
+ case NS_DIST:
+ case NS_AREA:
+ case NS_ALL:
+ if (!snxtsct(nsp, arg))
+ return RET_SYN;
+ *originp = 0;
+ break;
+ default:
+ if (unit_map(unit_type, atoi(arg), nsp, originp) < 0) {
+ pr("No such %s\n", ef_nameof(unit_type));
return RET_FAIL;
+ }
}
- for (b = map_flags_arg; b && *b; b++) {
- switch (*b) {
+ return RET_OK;
+}
+
+static int
+parse_map_flags(int bmap, char *str)
+{
+ int map_flags;
+ char *p;
+
+ switch (bmap) {
+ default: CANT_REACH();
+ /* fall through */
+ case 'b': map_flags = MAP_BMAP; break;
+ case 'n': map_flags = MAP_ALT; break;
+ case 0: map_flags = 0;
+ }
+
+ if (!str || !*str)
+ return map_flags;
+
+ /* special case "revert" */
+ if (bmap == 'b' && mineq(str, "revert") != ME_MISMATCH)
+ return MAP_BMAP_REVERT;
+
+ for (p = str; *p; p++) {
+ switch (*p) {
case 's':
case 'S':
map_flags |= MAP_SHIP;
case 't':
if (bmap != 'b')
goto bad_flag;
- bmap = 't';
- *(b + 1) = 0;
- break;
- case 'r':
- if (bmap != 'b')
- goto bad_flag;
- bmap = 'r';
- *(b + 1) = 0;
+ map_flags |= MAP_ALT;
break;
default:
bad_flag:
- pr("Bad flag %c!\n", *b);
- break;
+ pr("Bad flag %c!\n", *p);
+ return -1;
}
}
- return draw_map(bmap, origin, map_flags, &ns);
+
+ return map_flags;
}
-int
-draw_map(int bmap, char origin, int map_flags, struct nstr_sect *nsp)
+static int
+revert_bmap(struct nstr_sect *nsp)
+{
+ if (!confirm("Are you sure you want to revert your bmap? "))
+ return RET_FAIL;
+ while (bmnxtsct(nsp))
+ player->bmap[nsp->id] = player->map[nsp->id];
+ ef_write(EF_BMAP, player->cnum, player->bmap);
+ return RET_OK;
+}
+
+static int
+draw_map(char origin, int map_flags, struct nstr_sect *nsp)
{
struct natstr *np;
struct range range;
}
}
if (!bitmap)
- bitmap = malloc((WORLD_X * WORLD_Y) / 8);
+ bitmap = malloc((WORLD_SZ() + 7) / 8);
if (!wmapbuf || !wmap || !bitmap) {
pr("Memory error, tell the deity.\n");
logerror("malloc failed in draw_map\n");
return RET_FAIL;
}
- if (bmap == 'r') {
- if (!confirm("Are you sure you want to revert your bmap? "))
- return RET_OK;
- }
if (!(player->command->c_flags & C_MOD)) {
logerror("%s command needs C_MOD flag set",
player->command->c_form);
xyrelrange(np, &nsp->range, &range);
border(&range, " ", "");
blankfill(wmapbuf, &nsp->range, 1);
- if (bmap) {
- int c;
- switch (bmap) {
- default:
- CANT_REACH();
- bmap = 'b';
- /* fall through */
- case 'b':
- while (bmnxtsct(nsp) && !player->aborted) {
- if (0 != (c = player->bmap[sctoff(nsp->x, nsp->y)]))
- wmap[nsp->dy][nsp->dx] = c;
- }
- break;
- case 't':
- while (bmnxtsct(nsp) && !player->aborted) {
- if (0 != (c = player->map[sctoff(nsp->x, nsp->y)]))
- wmap[nsp->dy][nsp->dx] = c;
- }
- break;
- case 'r':
- while (bmnxtsct(nsp) && !player->aborted) {
- player->bmap[sctoff(nsp->x, nsp->y)] =
- player->map[sctoff(nsp->x, nsp->y)];
- if (0 != (c = player->bmap[sctoff(nsp->x, nsp->y)]))
- wmap[nsp->dy][nsp->dx] = c;
- }
- ef_write(EF_BMAP, player->cnum, player->bmap);
- break;
- case 'n':
- {
- struct sctstr sect;
- if (!player->god) {
- memset(bitmap, 0, (WORLD_X * WORLD_Y) / 8);
- bitinit2(nsp, bitmap, player->cnum);
- }
- while (nxtsct(nsp, §) && !player->aborted) {
- if (!player->god && !emp_getbit(nsp->x, nsp->y, bitmap))
- continue;
- wmap[nsp->dy][nsp->dx]
- = map_char(sect.sct_newtype, sect.sct_own,
- player->owner);
- }
- break;
- }
+ if (map_flags & MAP_BMAP) {
+ char *map = map_flags & MAP_ALT ? player->map : player->bmap;
+
+ while (bmnxtsct(nsp)) {
+ if (map[nsp->id])
+ wmap[nsp->dy][nsp->dx] = map[nsp->id];
}
} else {
struct sctstr sect;
int changed = 0;
if (!player->god) {
- memset(bitmap, 0, (WORLD_X * WORLD_Y) / 8);
+ memset(bitmap, 0, (WORLD_SZ() + 7) / 8);
bitinit2(nsp, bitmap, player->cnum);
}
- while (nxtsct(nsp, §) && !player->aborted) {
+
+ while (nxtsct(nsp, §)) {
if (!player->god && !emp_getbit(nsp->x, nsp->y, bitmap))
continue;
- mapch = map_char(sect.sct_type, sect.sct_own, player->owner);
+ mapch = map_char(map_flags & MAP_ALT
+ ? sect.sct_newtype : sect.sct_type,
+ sect.sct_own, player->owner);
wmap[nsp->dy][nsp->dx] = mapch;
- changed |= map_set(player->cnum, nsp->x, nsp->y, mapch, 0);
+ if (!(map_flags & MAP_ALT))
+ changed |= map_set(player->cnum, nsp->x, nsp->y, mapch, 0);
}
if (changed)
writemap(player->cnum);
}
- if (player->aborted)
- return RET_OK;
i = 0;
while (ef_mappable[i] != EF_BAD) {
if (map_flags & ef_unit_map[i]) {
- snxtitem_all(&ni, ef_mappable[i]);
+ snxtitem_area(&ni, ef_mappable[i], &nsp->range);
while (nxtitem(&ni, &unit)) {
if (unit.gen.own == 0)
continue;
if (unit.gen.own != player->cnum && !player->god)
continue;
- if (!xyinrange(unit.gen.x, unit.gen.y, &nsp->range))
- continue;
- x = xnorm(unit.gen.x - nsp->range.lx);
- y = ynorm(unit.gen.y - nsp->range.ly);
+ x = deltx(&nsp->range, unit.gen.x);
+ y = delty(&nsp->range, unit.gen.y);
if (ef_mappable[i] == EF_NUKE)
wmap[y][x] = 'N';
else {
- if ((name = emp_obj_chr_name(&unit.gen)) == NULL)
- return RET_FAIL;
+ name = empobj_chr_name(&unit.gen);
wmap[y][x] = *name & ~0x20;
}
}
struct sctstr sect;
snxtsct_rewind(nsp);
- if (!player->god) {
- memset(bitmap, 0, (WORLD_X * WORLD_Y) / 8);
- bitinit2(nsp, bitmap, player->cnum);
- }
- while (nxtsct(nsp, §) && !player->aborted) {
- if (!player->god && !emp_getbit(nsp->x, nsp->y, bitmap))
- continue;
+ while (nxtsct(nsp, §)) {
if (sect.sct_own == player->cnum)
wmap[nsp->dy][nsp->dx] |= 0x80;
}
yval = yrel(np, y);
wmap[i][nsp->range.width] = '\0';
- pr("%4d %s %-4d\n", yval, wmap[i], yval);
+ pr("%4d %s %d\n", yval, wmap[i], yval);
if (y >= WORLD_Y)
y -= WORLD_Y;
}
np->id = sctoff(np->x, np->y);
return 1;
}
- /*NOTREACHED*/
}
/*
- * Return character to use in maps for sector type TYPE owned by OWN.
- * If OWNER_OR_GOD, the map is for the sector's owner or a deity.
+ * Return character to use in maps for sector type @type owned by @own.
+ * If @owner_or_god, the map is for the sector's owner or a deity.
*/
static char
map_char(int type, natid own, int owner_or_god)
unit_map(int unit_type, int uid, struct nstr_sect *nsp, char *originp)
{
union empobj_storage unit;
- struct range range;
char *name;
+ if (CANT_HAPPEN((ef_flags(unit_type) & (EFF_OWNER | EFF_XY))
+ != (EFF_OWNER | EFF_XY)))
+ return -1;
+
if (!get_empobj(unit_type, uid, &unit))
- return RET_FAIL;
+ return -1;
if (!player->owner || unit.gen.own == 0)
- return RET_FAIL;
+ return -1;
if (unit_type == EF_NUKE)
*originp = 'n';
else {
- if ((name = emp_obj_chr_name(&unit.gen)) == NULL)
- return RET_FAIL;
+ name = empobj_chr_name(&unit.gen);
*originp = *name;
}
- range.lx = xnorm(unit.gen.x - 10);
- range.hx = xnorm(unit.gen.x + 11);
- range.ly = ynorm(unit.gen.y - 5);
- range.hy = ynorm(unit.gen.y + 6);
+ snxtsct_around(nsp, unit.gen.x, unit.gen.y);
+ return 0;
+}
+
+static void
+snxtsct_around(struct nstr_sect *nsp, coord x, coord y)
+{
+ struct range range;
+
+ range.lx = xnorm(x - 10);
+ range.hx = xnorm(x + 10);
+ range.ly = ynorm(y - 5);
+ range.hy = ynorm(y + 5);
xysize_range(&range);
snxtsct_area(nsp, &range);
- return RET_OK;
}
int
display_region_map(int bmap, int unit_type, coord curx, coord cury,
- char *arg)
+ char *arg1, char *arg2)
{
- char coordinates[80];
- char *map_flag_arg;
-
- if (!arg || !*arg) {
- struct natstr *np;
-
- np = getnatp(player->cnum);
- sprintf(coordinates, "%d:%d,%d:%d",
- xrel(np, curx - 10), xrel(np, curx + 11),
- yrel(np, cury - 5), yrel(np, cury + 6));
- arg = coordinates;
- map_flag_arg = NULL;
+ struct nstr_sect ns;
+ char origin;
+ int res, map_flags;
+
+ if (arg1 && *arg1) {
+ res = parse_map_arg(unit_type, arg1, &ns, &origin);
+ if (res != RET_OK)
+ return res;
+
+ map_flags = parse_map_flags(bmap, arg2);
+ if (map_flags < 0)
+ return RET_SYN;
} else {
- map_flag_arg = strchr(arg, ' ');
- if (map_flag_arg != NULL) {
- *map_flag_arg++ = '\0';
- while (isspace(*map_flag_arg)) map_flag_arg++;
+ snxtsct_around(&ns, curx, cury);
+ map_flags = 0;
+ origin = 0;
+ }
+
+ if (map_flags & MAP_BMAP_REVERT)
+ return revert_bmap(&ns);
+ return draw_map(origin, map_flags, &ns);
+}
+
+int
+nav_map(int x, int y, int show_designations)
+{
+ char *ptr;
+ struct nstr_sect ns;
+ struct sctstr sect;
+ int i;
+ /* Note this is not re-entrant anyway, so we keep the buffers
+ around */
+ static char *wmapbuf = NULL;
+ static char **wmap = NULL;
+ int changed = 0;
+
+ if (!wmapbuf)
+ wmapbuf = malloc(WORLD_Y * MAPWIDTH(1));
+ if (!wmap) {
+ wmap = malloc(WORLD_Y * sizeof(*wmap));
+ if (wmap && wmapbuf) {
+ for (i = 0; i < WORLD_Y; i++)
+ wmap[i] = &wmapbuf[MAPWIDTH(1) * i];
+ } else if (wmap) {
+ free(wmap);
+ wmap = NULL;
}
}
- player->condarg = NULL;
- return do_map(bmap, unit_type, arg, map_flag_arg);
+ if (!wmapbuf || !wmap) {
+ pr("Memory error, tell the deity.\n");
+ logerror("malloc failed in navi\n");
+ return RET_FAIL;
+ }
+ snxtsct_dist(&ns, x, y, 1);
+ blankfill(wmapbuf, &ns.range, 1);
+ while (nxtsct(&ns, §)) {
+ ptr = &wmap[ns.dy][ns.dx];
+ *ptr = dchr[sect.sct_type].d_mnem;
+ if (!show_designations &&
+ sect.sct_own != player->cnum &&
+ sect.sct_type != SCT_WATER &&
+ sect.sct_type != SCT_BSPAN && sect.sct_type != SCT_HARBR)
+ *ptr = '?';
+ changed += map_set(player->cnum, sect.sct_x, sect.sct_y, *ptr, 0);
+ /*
+ * We do it this way so that 'x' and 'X'
+ * bdesignations will show up. This can
+ * be used to mark mined sectors. So, the
+ * player will see the current des, UNLESS
+ * they've marked the sector 'x' or 'X',
+ * in which case they'll see that.
+ * --ts
+ */
+ *ptr = player->bmap[sect.sct_uid];
+ }
+ if (changed)
+ writemap(player->cnum);
+ for (i = 0; i < ns.range.height; i++)
+ pr("%s\n", wmap[i]);
+ return RET_OK;
}
int
char todes;
char from_des = *from_name;
+ if (from == to)
+ return 0;
+
if (isalpha(from_des))
from_des &= ~0x20;
while (nxtsct(ns, §)) {
- if (!(fromdes = from_bmap[sctoff(ns->x, ns->y)]))
+ if (!(fromdes = from_bmap[sect.sct_uid]))
continue;
- todes = to_bmap[sctoff(ns->x, ns->y)];
+ todes = to_bmap[sect.sct_uid];
if (todes &&
todes != '?' &&
todes != '.' && todes != ' ' && todes != from_des)