]> git.pond.sub.org Git - empserver/blobdiff - src/lib/subs/move.c
Fix 'm' in path argument of explore, move, transport
[empserver] / src / lib / subs / move.c
index 770aab6e0c2e7808ac6ec7259c46118cd5030423..0d7de92ac88a2ee2df0de2b4c86d44d3476b418e 100644 (file)
@@ -1,11 +1,11 @@
 /*
  *  Empire - A multi-player, client/server Internet based war game.
- *  Copyright (C) 1986-2000, Dave Pare, Jeff Bailey, Thomas Ruschak,
- *                           Ken Stevens, Steve McClure
+ *  Copyright (C) 1986-2011, 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.
  *
  *  ---
  *
  *  move.c: Move something somewhere.
- * 
+ *
  *  Known contributors to this file:
- *     
+ *     Markus Armbruster, 2004-2011
  */
 
-#include "misc.h"
-#include "player.h"
-#include "var.h"
-#include "sect.h"
-#include "item.h"
+#include <config.h>
+
+#include <ctype.h>
+#include "damage.h"
 #include "file.h"
-#include "deity.h"
-#include "xy.h"
-#include "path.h"
-#include "nat.h"
 #include "map.h"
 #include "nsc.h"
-#include "damage.h"
+#include "path.h"
+#include "player.h"
 #include "prototypes.h"
+#include "sect.h"
 
-extern int move_map(s_char *what, coord curx, coord cury, s_char *arg);
+static int move_map(coord curx, coord cury, char *arg);
 
 int
-move_ground(s_char *what, struct sctstr *start, struct sctstr *end,
-           double mobility, double weight, s_char *path,
-           int (*map) (s_char *, coord, coord, s_char *), int exploring,
-           int *dam)
-
-
-                               /* RESULT */
+move_ground(struct sctstr *start, struct sctstr *end,
+           double weight, char *path,
+           int (*map)(coord, coord, char *, char *),
+           int exploring, int *dam)
 {
-    struct sctstr sect, ending_sect;
-    struct sctstr next, dsect;
-    int vec[I_MAX + 1];
+    struct sctstr sect;
+    struct sctstr next;
     coord curx, cury, oldx, oldy;
     coord tmpx, tmpy;
     coord dx, dy;
-    s_char *movstr, *BestLandPath(s_char *, struct sctstr *,
-                                 struct sctstr *, double *, int);
+    char *movstr;
     double sect_mcost;
     double total_mcost;
     double mv_cost;
+    size_t len;
+    double mobility = start->sct_mobil;
     int dir;
+    char scanspace[1024];
+    char *argp[128];
     int intcost;
-    int takedam = (*dam), out = 0;
-    s_char bpath[512];
-    s_char buf2[512];
-    s_char prompt[128];
-    s_char buf[1024];
+    int takedam = *dam;
+    int out = 0;
+    char prompt[128];
+    char buf[1024];
 
+    *end = *start;
     if (mobility <= 0.0)
        return -1;
     *dam = 0;
-    if (path && sarg_xy(path, &dx, &dy) && getsect(dx, dy, &ending_sect)) {
-       if ((ending_sect.sct_x == start->sct_x) &&
-           (ending_sect.sct_y == start->sct_y)) {
+    if (path && sarg_xy(path, &dx, &dy)) {
+       if (dx == start->sct_x && dy == start->sct_y) {
            pr("Start sector is ending sector!\n");
            return -1;
        }
        pr("Looking for best path to %s\n", path);
-       path =
-           BestLandPath(buf2, start, &ending_sect, &total_mcost,
-                        MOB_ROAD);
-       if (exploring && (path != (s_char *)0)) /* take off the 'h' */
-           *(path + strlen(path) - 1) = '\0';
-       if (path == (s_char *)0)
+       total_mcost = path_find(start->sct_x, start->sct_y, dx, dy,
+                               player->cnum, MOB_MOVE);
+       path = NULL;
+       if (total_mcost < 0)
            pr("No owned path exists!\n");
        else {
-           pr("Using best path '%s', movement cost %1.3f\n",
-              path, total_mcost);
-           bzero(bpath, 512);
-           bcopy(path, bpath, strlen(path));
-           path = bpath;
-       }
-       if ((total_mcost * weight) > mobility) {
-           pr("Not enough mobility to go all the way. Nothing moved.\n");
-           *end = *start;
-           return -1;
+           len = path_find_route(buf, sizeof(buf),
+                                 start->sct_x, start->sct_y, dx, dy);
+           if (!exploring) {
+               if (len < sizeof(buf))
+                   strcpy(buf + len, "h");
+               len++;
+           }
+           if (len >= sizeof(buf))
+               pr("Can't handle path to %s, it's too long, sorry.\n",
+                  xyas(dx, dy, player->cnum));
+           else {
+               path = buf;
+               pr("Using best path '%s', movement cost %1.3f\n",
+                  path, total_mcost);
+               if (total_mcost * weight > mobility) {
+                   pr("Not enough mobility to go all the way."
+                      " Nothing moved.\n");
+                   return -1;
+               }
+           }
        }
     }
     movstr = path;
-    tmpx = start->sct_x;
-    curx = tmpx;
-    tmpy = start->sct_y;
-    cury = tmpy;
+    curx = start->sct_x;
+    cury = start->sct_y;
     total_mcost = 0.0;
     if (getsect(curx, cury, &sect) < 0) {
        logerror("move_path: getsect %d,%d", curx, cury);
        return -1;
     }
     for (;;) {
-       tmpx = curx;
-       tmpy = cury;
        oldx = curx;
        oldy = cury;
-       if (movstr == 0 || *movstr == 0) {
+       if (!movstr || *movstr == 0) {
            if (exploring) {
-               map(what, curx, cury, (s_char *)0);
+               map(curx, cury, NULL, NULL);
            } else {
-               move_map(what, curx, cury, (s_char *)0);
+               move_map(curx, cury, NULL);
            }
            sprintf(prompt, "<%.1f: %c %s> ", mobility,
                    dchr[sect.sct_type].d_mnem,
@@ -133,51 +131,65 @@ move_ground(s_char *what, struct sctstr *start, struct sctstr *end,
            movstr = getstring(prompt, buf);
        }
        if (movstr && sarg_xy(movstr, &dx, &dy)) {
-           if (getsect(dx, dy, &dsect)) {
-               movstr =
-                   BestLandPath(buf2, &sect, &dsect, &mv_cost, MOB_ROAD);
-           } else {
-               pr("Invalid destination sector!\n");
-               movstr = (s_char *)0;
-           }
-
-           if (movstr == (s_char *)0) {
+           mv_cost = path_find(sect.sct_x, sect.sct_y, dx, dy,
+                               player->cnum, MOB_MOVE);
+           if (mv_cost < 0) {
                pr("Can't get to %s from here!\n",
                   xyas(dx, dy, player->cnum));
-               movstr = (s_char *)0;
+               movstr = NULL;
            } else {
-               if ((mv_cost * weight) > mobility) {
-                   pr("Not enough mobility to go all the way. Nothing moved.\n");
-                   movstr = (s_char *)0;
+               len = path_find_route(buf, sizeof(buf),
+                                     sect.sct_x, sect.sct_y, dx, dy);
+               if (len < sizeof(buf))
+                   strcpy(buf + len, "h");
+               len++;
+               if (len >= sizeof(buf)) {
+                   pr("Can't handle path to %s, it's too long, sorry.\n",
+                      xyas(dx, dy, player->cnum));
+                   movstr = NULL;
                } else {
-                   pr("Using best path '%s', movement cost %1.3f\n",
-                      movstr, mv_cost);
-                   bzero(bpath, 512);
-                   bcopy(movstr, bpath, strlen(movstr));
-                   movstr = bpath;
+                   if ((mv_cost * weight) > mobility) {
+                       pr("Not enough mobility to go all the way. Nothing moved.\n");
+                       movstr = NULL;
+                   } else {
+                       movstr = buf;
+                       pr("Using best path '%s', movement cost %1.3f\n",
+                          movstr, mv_cost);
+                   }
                }
            }
        }
-       if (movstr == 0 || *movstr == 0)
-           movstr = dirch;
+       if (!movstr || *movstr == 0) {
+           buf[0] = dirch[DIR_STOP];
+           buf[1] = 0;
+           movstr = buf;
+       }
        if ((dir = chkdir(*movstr, DIR_STOP, DIR_MAP)) < 0) {
            pr("\"%c\" is not legal...", *movstr);
            direrr("'%c' to stop ", "'%c' to view ", "& '%c' to map\n");
            *movstr = 0;
            continue;
        }
-       movstr++;
        if (dir == DIR_MAP) {
+           parse(movstr, scanspace, argp, NULL, NULL, NULL);
+           if (argp[0][1]) {
+               pr("Use of '%c' without a space before its argument is deprecated.\n"
+                  "Support for it will go away in a future release\n",
+                  *movstr);
+               argp[2] = argp[1];
+               argp[1] = argp[0] + 1;
+           }
            if (!exploring)
-               map(what, curx, cury, movstr + 1);
+               map(curx, cury, argp[1], argp[2]);
            *movstr = 0;
            continue;
-       } else if (dir == DIR_STOP)
+       }
+       movstr++;
+       if (dir == DIR_STOP)
            break;
-       else if (dir == DIR_VIEW) {
+       if (dir == DIR_VIEW) {
            pr("%d%% %s with %d civilians.\n", sect.sct_effic,
-              dchr[sect.sct_type].d_name,
-              getvar(V_CIVIL, (s_char *)&sect, EF_SECTOR));
+              dchr[sect.sct_type].d_name, sect.sct_item[I_CIVIL]);
            continue;
        }
        /*
@@ -185,8 +197,8 @@ move_ground(s_char *what, struct sctstr *start, struct sctstr *end,
         * next sector.  Mobility, terrain,
         * or ownership may prevent us.
         */
-       tmpx += diroff[dir][0];
-       tmpy += diroff[dir][1];
+       tmpx = curx + diroff[dir][0];
+       tmpy = cury + diroff[dir][1];
        if (getsect(tmpx, tmpy, &next) < 0) {
            pr("You can't go there...\n");
            *movstr = 0;
@@ -196,17 +208,14 @@ move_ground(s_char *what, struct sctstr *start, struct sctstr *end,
            if ((next.sct_type == SCT_SANCT) &&
                (next.sct_own != player->cnum)) {
                pr("Converts, huh?\n");
-               *end = next;
-               intcost = (int)total_mcost;
-               if (chance(total_mcost - intcost))
-                   intcost++;
-               return intcost;
+               *movstr = 0;
+               continue;
            }
-           getvec(VT_ITEM, vec, (s_char *)&next, EF_SECTOR);
-           sect_mcost = sector_mcost(&next, MOB_ROAD);
-           if ((!player->owner && (!exploring ||
-                                   (vec[I_MILIT] || vec[I_CIVIL]))) ||
-               sect_mcost == -1.0) {
+           sect_mcost = sector_mcost(&next, MOB_MOVE);
+           if ((!player->owner && (!exploring
+                                   || next.sct_item[I_MILIT]
+                                   || next.sct_item[I_CIVIL]))
+               || sect_mcost == -1.0) {
                /* already-owned, or prohibited terrain */
                pr("You can't go there...\n");
                *movstr = 0;
@@ -222,8 +231,8 @@ move_ground(s_char *what, struct sctstr *start, struct sctstr *end,
            mobility -= sect_mcost;
            total_mcost += sect_mcost;
        }
-       curx = tmpx;
-       cury = tmpy;
+       curx = next.sct_x;
+       cury = next.sct_y;
        if (cury != start->sct_y)
            out = 1;
        if (curx != start->sct_x)
@@ -240,8 +249,8 @@ move_ground(s_char *what, struct sctstr *start, struct sctstr *end,
         */
        if (takedam && chance(weight / 100.0) &&
            ((curx != oldx) || (cury != oldy)))
-           (*dam) +=
-               ground_interdict(curx, cury, player->cnum, "commodities");
+           *dam += ground_interdict(curx, cury, player->cnum,
+                                    "commodities");
        if (*dam >= 100)
            break;
     }
@@ -260,33 +269,19 @@ move_ground(s_char *what, struct sctstr *start, struct sctstr *end,
 
 
 /*ARGSUSED*/
-int
-move_map(s_char *what, coord curx, coord cury, s_char *arg)
+static int
+move_map(coord curx, coord cury, char *arg)
 {
     struct nstr_sect ns;
-    struct natstr *np;
     struct sctstr sect;
-    coord rel_x, rel_y;
-    s_char range[128];
-    s_char view[7];
+    char view[7];
     int i;
-    int vec[I_MAX + 1];
     int changed = 0;
 
-    np = getnatp(player->cnum);
-    rel_x = xrel(np, curx);
-    rel_y = yrel(np, cury);
-    sprintf(range, "%d:%d,%d:%d", rel_x - 2, rel_x + 2, rel_y - 1,
-           rel_y + 1);
-    player->condarg = 0;
-    /* This is necessary, otherwise move_map would attempt to pay */
-    /* attention to the conditional arguments left behind by such */
-    /* a command as "tran p -1,-1 ?eff=100".. It'd then only see  */
-    /* 100% efficienct sects, and get all screwed up         --ts */
-    if (!snxtsct(&ns, range))
-       return RET_FAIL;
+    snxtsct_dist(&ns, curx, cury, 1);
     i = 0;
     while (i < 7 && nxtsct(&ns, &sect)) {
+       /* Nasty: this relies on the iteration order */
        view[i] = dchr[sect.sct_type].d_mnem;
        switch (sect.sct_type) {
        case SCT_WATER:
@@ -307,13 +302,13 @@ move_map(s_char *what, coord curx, coord cury, s_char *arg)
        writemap(player->cnum);
     if (!getsect(curx, cury, &sect))
        return RET_FAIL;
-    getvec(VT_ITEM, vec, (s_char *)&sect, EF_SECTOR);
     pr("    %c %c      eff   mob   civ  mil   uw food  work  avail\n",
        view[0], view[1]);
     pr("   %c %c %c     %3d   %3d  %4d %4d %4d %4d   %3d   %3d\n",
        view[2], view[3], view[4],
-       sect.sct_effic, sect.sct_mobil, vec[I_CIVIL], vec[I_MILIT],
-       vec[I_UW], vec[I_FOOD], sect.sct_work, sect.sct_avail);
+       sect.sct_effic, sect.sct_mobil,
+       sect.sct_item[I_CIVIL], sect.sct_item[I_MILIT], sect.sct_item[I_UW],
+       sect.sct_item[I_FOOD], sect.sct_work, sect.sct_avail);
     pr("    %c %c\n", view[5], view[6]);
     return RET_OK;
 }
@@ -322,29 +317,15 @@ int
 fly_map(coord curx, coord cury)
 {
     struct nstr_sect ns;
-    struct natstr *np;
     struct sctstr sect;
-    coord rel_x, rel_y;
-    s_char view[7];
+    char view[7];
     int i;
-    s_char range[128];
 
-    np = getnatp(player->cnum);
-    rel_x = xrel(np, curx);
-    rel_y = yrel(np, cury);
-    sprintf(range, "%d:%d,%d:%d", rel_x - 2, rel_x + 2, rel_y - 1,
-           rel_y + 1);
-    player->condarg = 0;
-    /* This is necessary, otherwise move_map would attempt to pay */
-    /* attention to the conditional arguments left behind by such */
-    /* a command as "tran p -1,-1 ?eff=100".. It'd then only see  */
-    /* 100% efficienct sects, and get all screwed up         --ts */
-
-    if (!snxtsct(&ns, range))
-       return RET_FAIL;
+    snxtsct_dist(&ns, curx, cury, 1);
     i = 0;
     while (i < 7 && nxtsct(&ns, &sect)) {
-       if (!(view[i] = player->bmap[sctoff(ns.x, ns.y)]))
+       /* Nasty: this relies on the iteration order */
+       if (!(view[i] = player->bmap[sect.sct_uid]))
            view[i] = ' ';
        i++;
     }
@@ -359,20 +340,17 @@ int
 check_lmines(coord x, coord y, double weight)
 {
     struct sctstr sect;
-    int mines;
     int dam = 0;
 
     getsect(x, y, &sect);
-    mines = getvar(V_MINE, (s_char *)&sect, EF_SECTOR);
-    if (mines > 0 &&
+    if (SCT_LANDMINES(&sect) > 0 &&
        sect.sct_oldown != player->cnum &&
-       chance(DMINE_LHITCHANCE(mines)) && chance(weight / 100.0)) {
+       chance(DMINE_LHITCHANCE(sect.sct_mines)) && chance(weight / 100.0)) {
        pr_beep();
        pr("Blammo! Landmines detected! in %s  ",
           xyas(sect.sct_x, sect.sct_y, player->cnum));
        dam = roll(20);
-       --mines;
-       putvar(V_MINE, mines, (s_char *)&sect, EF_SECTOR);
+       --sect.sct_mines;
        putsect(&sect);
        pr("%d damage sustained.\n", dam);
     }