]> git.pond.sub.org Git - empserver/blobdiff - src/lib/commands/retr.c
Update copyright notice
[empserver] / src / lib / commands / retr.c
index 8e6b2184cab61441804378f065c7cc0277303b88..abfbd5c7bff217a222bcb734b443d2155030fac4 100644 (file)
@@ -1,11 +1,11 @@
 /*
  *  Empire - A multi-player, client/server Internet based war game.
- *  Copyright (C) 1986-2006, Dave Pare, Jeff Bailey, Thomas Ruschak,
- *                           Ken Stevens, Steve McClure
+ *  Copyright (C) 1986-2018, 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/>.
  *
  *  ---
  *
- *  See the "LEGAL", "LICENSE", "CREDITS" and "README" files for all the
- *  related information and legal notices. It is expected that any future
- *  projects/authors will amend these files as needed.
+ *  See files README, COPYING and CREDITS in the root of the source
+ *  tree for related information and legal notices.  It is expected
+ *  that future projects/authors will amend these files as needed.
  *
  *  ---
  *
- *  retr.c: Set retreat conditionals for ships
- * 
+ *  retr.c: Set retreat conditionals for ships and land units
+ *
  *  Known contributors to this file:
  *     Ken Stevens, 1995
  *     Steve McClure, 2000
+ *     Markus Armbruster, 2008-2015
  */
 
 #include <config.h>
 
-#include "misc.h"
-#include "player.h"
-#include "retreat.h"
-#include "ship.h"
+#include <ctype.h>
+#include "commands.h"
+#include "empobj.h"
 #include "land.h"
-#include "nsc.h"
-#include "file.h"
 #include "path.h"
-#include "commands.h"
+#include "retreat.h"
+#include "ship.h"
+
+/*
+ * Retreat flag characters
+ * 'X' means flag is not available
+ * Must agree with RET_ defines.
+ */
+static char shp_rflagsc[] = "Xitshbdu";
+static char lnd_rflagsc[] = "XiXXhbXX";
+
+static int retreat(int);
+static int retreat_show(int, struct nstr_item *);
 
 int
 retr(void)
 {
-    s_char *pq, *fl;
-    int nships;
+    return retreat(EF_SHIP);
+}
+
+int
+lretr(void)
+{
+    return retreat(EF_LAND);
+}
+
+static int
+retreat(int type)
+{
+    char *pq, *fl;
+    int nunits;
     struct nstr_item ni;
-    struct shpstr ship;
-    int isfleet = 0;
-    int rflags = -2;
-    int zero;
-    unsigned int x;
-    s_char buf1[1024];
-    s_char buf2[1024];
+    union empobj_storage unit;
+    int i, rflags, ch, j;
+    char *rflagsc, *p;
+    char buf1[1024];
+    char buf2[1024];
 
-    if (!snxtitem(&ni, EF_SHIP, player->argp[1]))
+    if (CANT_HAPPEN(type != EF_LAND && type != EF_SHIP))
+       type = EF_SHIP;
+    rflagsc = type == EF_SHIP ? shp_rflagsc : lnd_rflagsc;
+
+    if (!snxtitem(&ni, type, player->argp[1], NULL))
        return RET_SYN;
-    nships = 0;
-    if (player->argp[1] != NULL)
-       if (isalpha(player->argp[1][0]))
-           isfleet = RET_GROUP;
-    if (player->argp[2] != NULL)
-       pq = getstarg(player->argp[2], "Retreat path? ", buf1);
-    else
-       pq = (s_char *)0;
 
-    if (pq != (s_char *)0) {
+    if (player->argp[1] && !player->argp[2]) {
+       pr("Omitting the second argument is deprecated and will cease to work in a\n"
+          "future release.  Please use '%s q' to query retreat orders.\n\n",
+          player->combuf);
+       pq = "q";
+    } else {
+       /*
+        * TODO getpath() or similar would be nice once the deprecated
+        * syntax is gone.
+        */
+       pq = getstarg(player->argp[2], "Retreat path, or q to query? ",
+                     buf1);
+       if (!pq || !*pq)
+           return RET_SYN;
+    }
+
+    if (*pq == 'q')
+       return retreat_show(type, &ni);
+
+    for (i = 0; i < RET_LEN - 1 && pq[i]; i++) {
+       if (chkdir(pq[i], DIR_STOP, DIR_LAST) < 0) {
+           pr("'%c' is not a valid direction...\n", pq[i]);
+           direrr(NULL, NULL, NULL);
+           return RET_SYN;
+       }
+    }
+    for (i--; i >= 0 && pq[i] == dirch[DIR_STOP]; i--)
+       pq[i] = 0;
+
+    rflags = 0;
+    if (*pq) {
+    again:
        fl = getstarg(player->argp[3],
-                     "Retreat conditions [i|t|s|h|b|d|u|c]? ", buf2);
+                     "Retreat conditions ('?' to list available ones)? ",
+                     buf2);
        if (!fl)
            return RET_SYN;
-       rflags = 0 | isfleet;
 
-       for (x = 0; x < strlen(fl); x++)
-           switch (*(fl + x)) {
-           case 'I':
-           case 'i':
-               rflags |= RET_INJURED;
+       for (i = 0; fl[i]; i++) {
+           ch = tolower(fl[i]);
+           if (ch == 'c') {
+               /* Deprecated, but keeping it around doesn't hurt */
+               *pq = 0;
                break;
-           case 'T':
-           case 't':
-               rflags |= RET_TORPED;
-               break;
-           case 'S':
-           case 's':
-               rflags |= RET_SONARED;
-               break;
-           case 'H':
-           case 'h':
-               rflags |= RET_HELPLESS;
-               break;
-           case 'B':
-           case 'b':
-               rflags |= RET_BOMBED;
-               break;
-           case 'D':
-           case 'd':
-               rflags |= RET_DCHRGED;
-               break;
-           case 'U':
-           case 'u':
-               rflags |= RET_BOARDED;
-               break;
-           case 'C':
-           case 'c':
-               rflags = -1;
-               break;
-           default:
-               pr("bad condition\n");
-               /* fall through */
-           case '?':
-               pr("i\tretreat when injured\n");
-               pr("t\tretreat when torped\n");
-               pr("s\tretreat when sonared\n");
-               pr("h\tretreat when helpless\n");
-               pr("b\tretreat when bombed\n");
-               pr("d\tretreat when depth-charged\n");
-               pr("u\tretreat when boarded\n");
            }
-       if (rflags == isfleet) {
-           pr("Must give retreat conditions!\n");
-           return RET_FAIL;
+           if (ch == '?' && !player->argp[3]) {
+               for (j = 1; rflagsc[j]; j++) {
+                   if (rflagsc[j] != 'X')
+                       pr("%c\tretreat when %s\n",
+                          rflagsc[j],
+                          symbol_by_value(1 << j, retreat_flags));
+               }
+               goto again;
+           }
+           p = strchr(rflagsc, ch);
+           if (!p) {
+               pr("Bad retreat condition '%c'\n", fl[i]);
+               return RET_SYN;
+           }
+           rflags |= 1 << (p - rflagsc);
        }
+       if (*pq && !rflags)
+           return RET_SYN;
+       if (ni.sel == NS_GROUP && ni.group)
+           rflags |= RET_GROUP;
+       if (!*pq)
+           rflags = 0;
     }
 
-    if (rflags == -1)
-       pq = (s_char *)0;
-
-    zero = (rflags == -1);
-    if (zero)
-       rflags = 0;
-
-    while (nxtitem(&ni, &ship)) {
-       if (!player->owner || ship.shp_own == 0)
+    nunits = 0;
+    while (nxtitem(&ni, &unit)) {
+       if (!player->owner || unit.gen.own == 0)
            continue;
-       if (zero)
-           memset(ship.shp_rpath, 0, sizeof(ship.shp_rpath));
-
-       if (pq != (s_char *)0) {
-           strncpy(ship.shp_rpath, pq, sizeof(ship.shp_rpath));
-           putship(ship.shp_uid, &ship);
-       }
-       if (rflags >= 0) {
-           ship.shp_rflags = rflags;
-           putship(ship.shp_uid, &ship);
+       if (type == EF_SHIP) {
+           strncpy(unit.ship.shp_rpath, pq, RET_LEN - 1);
+           unit.ship.shp_rflags = rflags;
+       } else {
+           strncpy(unit.land.lnd_rpath, pq, RET_LEN - 1);
+           unit.land.lnd_rflags = rflags;
        }
-       if (nships++ == 0) {
-           if (player->god)
-               pr("own ");
-           pr("shp#     ship type       x,y   fl path       as flt? flags\n");
-       }
-       if (player->god)
-           pr("%3d ", ship.shp_own);
-       pr("%4d ", ni.cur);
-       pr("%-16.16s ", mchr[(int)ship.shp_type].m_name);
-       prxy("%4d,%-4d ", ship.shp_x, ship.shp_y, player->cnum);
-       pr("%c", ship.shp_fleet);
-       pr(" %-11s", ship.shp_rpath);
-       if (ship.shp_rflags & RET_GROUP)
-           pr("Yes     ");
-       else
-           pr("        ");
-       if (ship.shp_rflags & RET_INJURED)
-           pr("I");
-       if (ship.shp_rflags & RET_TORPED)
-           pr("T");
-       if (ship.shp_rflags & RET_SONARED)
-           pr("S");
-       if (ship.shp_rflags & RET_HELPLESS)
-           pr("H");
-       if (ship.shp_rflags & RET_BOMBED)
-           pr("B");
-       if (ship.shp_rflags & RET_DCHRGED)
-           pr("D");
-       if (ship.shp_rflags & RET_BOARDED)
-           pr("U");
-       pr("\n");
+       put_empobj(type, unit.gen.uid, &unit);
+       nunits++;
     }
-    if (nships == 0) {
-       if (player->argp[1])
-           pr("%s: No ship(s)\n", player->argp[1]);
-       else
-           pr("%s: No ship(s)\n", "");
-       return RET_FAIL;
+    if (rflags) {
+       symbol_set_fmt(buf2, sizeof(buf2), rflags & ~RET_GROUP,
+                      retreat_flags, ", ", 0);
+       pr("%d %s%s ordered to retreat%s along path %s when %s\n",
+          nunits, ef_nameof_pretty(type), splur(nunits),
+          rflags & RET_GROUP ? " as group" : "", pq, buf2);
     } else
-       pr("%d ship%s\n", nships, splur(nships));
+       pr("%d %s%s ordered not to retreat\n",
+          nunits, ef_nameof_pretty(type), splur(nunits));
     return RET_OK;
 }
 
-int
-lretr(void)
+static int
+retreat_show(int type, struct nstr_item *np)
 {
-    s_char *pq, *fl;
+    char *rflagsc = type == EF_SHIP ? shp_rflagsc : lnd_rflagsc;
+    union empobj_storage unit;
     int nunits;
-    struct nstr_item ni;
-    struct lndstr land;
-    int isarmy = 0;
-    int rflags = -2;
-    int zero;
-    s_char buf1[1024];
-    s_char buf2[1024];
-    unsigned int x;
+    char *name, *rpath, *what;
+    int *rflagsp, rflags, i;
 
-    if (!snxtitem(&ni, EF_LAND, player->argp[1]))
-       return RET_SYN;
     nunits = 0;
-    if (player->argp[1] != NULL)
-       if (isalpha(player->argp[1][0]))
-           isarmy = RET_GROUP;
-    if (player->argp[2] != NULL)
-       pq = getstarg(player->argp[2], "Retreat path? ", buf1);
-    else
-       pq = (s_char *)0;
-    if (pq != (s_char *)0) {
-       fl = getstarg(player->argp[3], "Retreat conditions [i|h|b|c]? ",
-                     buf2);
-       if (!fl)
-           return RET_SYN;
-       rflags = 0 | isarmy;
-
-       for (x = 0; x < strlen(fl); x++)
-           switch (*(fl + x)) {
-           case 'I':
-           case 'i':
-               rflags |= RET_INJURED;
-               break;
-           case 'H':
-           case 'h':
-               rflags |= RET_HELPLESS;
-               break;
-           case 'B':
-           case 'b':
-               rflags |= RET_BOMBED;
-               break;
-           case 'C':
-           case 'c':
-               rflags = -1;
-               break;
-           default:
-               pr("bad condition\n");
-               /* fall through */
-           case '?':
-               pr("i\tretreat when injured\n");
-               pr("h\tretreat when helpless\n");
-               pr("b\tretreat when bombed\n");
-           }
-       if (rflags == isarmy) {
-           pr("Must give retreat conditions!\n");
-           return RET_FAIL;
-       }
-    }
-
-    if (rflags == -1)
-       pq = (s_char *)0;
-
-    zero = (rflags == -1);
-    if (zero)
-       rflags = 0;
-
-    while (nxtitem(&ni, &land)) {
-       if (!player->owner || land.lnd_own == 0)
+    while (nxtitem(np, &unit)) {
+       if (!player->owner || unit.gen.own == 0)
            continue;
-       if (zero)
-           memset(land.lnd_rpath, 0, sizeof(land.lnd_rpath));
-
-       if (pq != (s_char *)0) {
-           strncpy(land.lnd_rpath, pq, sizeof(land.lnd_rpath));
-           putland(land.lnd_uid, &land);
-       }
-       if (rflags >= 0) {
-           land.lnd_rflags = rflags;
-           putland(land.lnd_uid, &land);
-       }
-
-       if (nunits++ == 0) {
-           if (player->god)
-               pr("own ");
-           pr("lnd#     unit type       x,y   ar path       as army? flags\n");
+       if (type == EF_SHIP) {
+           if (nunits++ == 0) {
+               if (player->god)
+                   pr("own ");
+               pr("shp#     ship type       x,y   fl path       as flt?  flags\n");
+           }
+           name = mchr[unit.ship.shp_type].m_name;
+           rpath = unit.ship.shp_rpath;
+           rflagsp = &unit.ship.shp_rflags;
+       } else {
+           if (nunits++ == 0) {
+               if (player->god)
+                   pr("own ");
+               pr("lnd#     unit type       x,y   ar path       as army? flags\n");
+           }
+           name = lchr[unit.land.lnd_type].l_name;
+           rpath = unit.land.lnd_rpath;
+           rflagsp = &unit.land.lnd_rflags;
        }
        if (player->god)
-           pr("%3d ", land.lnd_own);
-       pr("%4d ", ni.cur);
-       pr("%-16.16s ", lchr[(int)land.lnd_type].l_name);
-       prxy("%4d,%-4d ", land.lnd_x, land.lnd_y, player->cnum);
-       pr("%c", land.lnd_army);
-       pr(" %-11s", land.lnd_rpath);
-       if (land.lnd_rflags & RET_GROUP)
+           pr("%3d ", unit.gen.own);
+       pr("%4d ", np->cur);
+       pr("%-16.16s ", name);
+       prxy("%4d,%-4d ", unit.gen.x, unit.gen.y);
+       pr("%1.1s", &unit.gen.group);
+       pr(" %-11s", rpath);
+       rflags = *rflagsp;
+       if (rflags & RET_GROUP)
            pr("Yes      ");
        else
            pr("         ");
-       if (land.lnd_rflags & RET_INJURED)
-           pr("I");
-       if (land.lnd_rflags & RET_TORPED)
-           pr("T");
-       if (land.lnd_rflags & RET_SONARED)
-           pr("S");
-       if (land.lnd_rflags & RET_HELPLESS)
-           pr("H");
-       if (land.lnd_rflags & RET_BOMBED)
-           pr("B");
-       if (land.lnd_rflags & RET_DCHRGED)
-           pr("D");
-       if (land.lnd_rflags & RET_BOARDED)
-           pr("U");
+       for (i = 1; rflagsc[i]; i++) {
+           if ((1 << i) & rflags) {
+               if (CANT_HAPPEN(rflagsc[i] == 'X'))
+                   continue;
+               pr("%c", rflagsc[i]);
+           }
+       }
        pr("\n");
     }
+    what = type == EF_SHIP ? "ship" : "unit";
     if (nunits == 0) {
        if (player->argp[1])
-           pr("%s: No unit(s)\n", player->argp[1]);
+           pr("%s: No %s(s)\n", player->argp[1], what);
        else
-           pr("%s: No unit(s)\n", "");
+           pr("%s: No %s(s)\n", "", what);
        return RET_FAIL;
-    }
-    pr("%d unit%s\n", nunits, splur(nunits));
+    } else
+       pr("%d %s%s\n", nunits, what, splur(nunits));
     return RET_OK;
 }