]> git.pond.sub.org Git - empserver/blobdiff - src/lib/subs/maps.c
Update copyright notice
[empserver] / src / lib / subs / maps.c
index c9c2e8c163a2825c3a5d02fecc34736ddb0e8388..1d1aa0359f9cc4c107326bd096932c5364d8cb42 100644 (file)
@@ -1,11 +1,11 @@
 /*
  *  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-2015, 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,
@@ -14,8 +14,7 @@
  *  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"
 
-static int draw_map(int, char, int, struct nstr_sect *);
+/* 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 (map_flags & MAP_BMAP_REVERT)
+       return revert_bmap(&ns);
+    return draw_map(origin, map_flags, &ns);
+}
 
-    if (!snxtsct(&ns, arg)) {
-       if (unit_map(unit_type, atoi(arg), &ns, &origin))
+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;
+       }
+    }
+    return RET_OK;
+}
+
+static void
+warn_deprecated_arg(char *what, char *arg, char *use)
+{
+    pr("%s '%s' is deprecated and will go away in a future release.\n"
+       "Use %s instead.\n",
+       what, arg, use);
+}
+
+static int
+parse_map_flags(int bmap, char *str)
+{
+    int map_flags;
+    char *p;
+    int tflags = 0;
+    char *tp = NULL;
+
+    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;
     }
-    for (b = map_flags_arg; b && *b; b++) {
-       switch (*b) {
+
+    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;
@@ -98,26 +178,50 @@ do_map(int bmap, int unit_type, char *arg, char *map_flags_arg)
        case 't':
            if (bmap != 'b')
                goto bad_flag;
-           bmap = 't';
-           *(b + 1) = 0;
+           map_flags |= MAP_ALT;
+           /*
+            * Flags following 't' used to be ignored.  That breaks
+            * perfectly sensible "ts".  Try to continue, but save
+            * state for when a bad flag is found.
+            */
+           if (!tflags) {
+               tflags = map_flags;
+               tp = p;
+           }
            break;
        case 'r':
-           if (bmap != 'b')
+           if (bmap != 'b' || tflags)
                goto bad_flag;
-           bmap = 'r';
-           *(b + 1) = 0;
-           break;
+           warn_deprecated_arg("Map flag", "r", "argument 'revert'");
+           return MAP_BMAP_REVERT;
        default:
        bad_flag:
-           pr("Bad flag %c!\n", *b);
-           break;
+           if (tflags) {
+               /* ignore bad flags following 't' */
+               warn_deprecated_arg("Argument", tp, "map flag 't'");
+               return tflags;
+           }
+           pr("Bad flag %c!\n", *p);
+           return -1;
        }
     }
-    return draw_map(bmap, origin, map_flags, &ns);
+
+    return map_flags;
 }
 
 static int
-draw_map(int bmap, char origin, int map_flags, struct nstr_sect *nsp)
+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;
@@ -147,17 +251,13 @@ draw_map(int bmap, char origin, int map_flags, struct nstr_sect *nsp)
        }
     }
     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);
@@ -169,51 +269,13 @@ draw_map(int bmap, char origin, int map_flags, struct nstr_sect *nsp)
     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[nsp->id]))
-                   wmap[nsp->dy][nsp->dx] = c;
-           }
-           break;
-       case 't':
-           while (bmnxtsct(nsp) && !player->aborted) {
-               if (0 != (c = player->map[nsp->id]))
-                   wmap[nsp->dy][nsp->dx] = c;
-           }
-           break;
-       case 'r':
-           while (bmnxtsct(nsp) && !player->aborted) {
-               player->bmap[nsp->id] =
-                   player->map[nsp->id];
-               if (0 != (c = player->bmap[nsp->id]))
-                   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, &sect) && !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;
@@ -221,21 +283,23 @@ draw_map(int bmap, char origin, int map_flags, struct nstr_sect *nsp)
        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, &sect) && !player->aborted) {
+
+       while (nxtsct(nsp, &sect)) {
            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) {
@@ -264,13 +328,7 @@ draw_map(int bmap, char origin, int map_flags, struct nstr_sect *nsp)
        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, &sect) && !player->aborted) {
-           if (!player->god && !emp_getbit(nsp->x, nsp->y, bitmap))
-               continue;
+       while (nxtsct(nsp, &sect)) {
            if (sect.sct_own == player->cnum)
                 wmap[nsp->dy][nsp->dx] |= 0x80;
        }
@@ -282,7 +340,7 @@ draw_map(int bmap, char origin, int map_flags, struct nstr_sect *nsp)
 
        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;
     }
@@ -321,7 +379,6 @@ bmnxtsct(struct nstr_sect *np)
        np->id = sctoff(np->x, np->y);
        return 1;
     }
-    /*NOTREACHED*/
 }
 
 /*
@@ -344,17 +401,16 @@ static int
 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 RET_FAIL;
+       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';
@@ -363,40 +419,48 @@ unit_map(int unit_type, int uid, struct nstr_sect *nsp, char *originp)
        *originp = *name;
     }
 
-    range.lx = xnorm(unit.gen.x - 10);
-    range.hx = xnorm(unit.gen.x + 10);
-    range.ly = ynorm(unit.gen.y - 5);
-    range.hy = ynorm(unit.gen.y + 5);
+    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;
     }
-    player->condarg = NULL;
-    return do_map(bmap, unit_type, arg, map_flag_arg);
+
+    if (map_flags & MAP_BMAP_REVERT)
+       return revert_bmap(&ns);
+    return draw_map(origin, map_flags, &ns);
 }
 
 int
@@ -426,6 +490,9 @@ share_bmap(natid from, natid to, struct nstr_sect *ns, char des,
     char todes;
     char from_des = *from_name;
 
+    if (from == to)
+       return 0;
+
     if (isalpha(from_des))
        from_des &= ~0x20;