/*
* 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-2013, 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 "chance.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];
- coord curx, cury, oldx, oldy;
- coord tmpx, tmpy;
- coord dx, dy;
- s_char *movstr, *BestLandPath(s_char *, struct sctstr *, struct sctstr *, double *, int);
- double sect_mcost;
- double total_mcost;
- double mv_cost;
- int dir;
- int intcost;
- int takedam = (*dam), out=0;
- s_char bpath[512];
- s_char buf2[512];
- s_char prompt[128];
- s_char buf[1024];
+ struct sctstr sect;
+ struct sctstr next;
+ coord curx, cury, oldx, oldy;
+ coord tmpx, tmpy;
+ coord dx, dy;
+ 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;
+ int out = 0;
+ char prompt[128];
+ char buf[1024];
- 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)){
- 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)
- 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;
+ *end = *start;
+ if (mobility <= 0.0)
+ return -1;
+ *dam = 0;
+ 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);
+ 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 {
+ 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;
}
- if ((total_mcost*weight) > mobility){
+ }
+ }
+ }
+ movstr = path;
+ curx = start->sct_x;
+ cury = start->sct_y;
+ total_mcost = 0.0;
+ if (getsect(curx, cury, §) < 0) {
+ logerror("move_path: getsect %d,%d", curx, cury);
+ return -1;
+ }
+ for (;;) {
+ oldx = curx;
+ oldy = cury;
+ if (!movstr || *movstr == 0) {
+ if (exploring) {
+ map(curx, cury, NULL, NULL);
+ } else {
+ move_map(curx, cury, NULL);
+ }
+ sprintf(prompt, "<%.1f: %c %s> ", mobility,
+ dchr[sect.sct_type].d_mnem,
+ xyas(sect.sct_x, sect.sct_y, player->cnum));
+ movstr = getstring(prompt, buf);
+ }
+ if (movstr && sarg_xy(movstr, &dx, &dy)) {
+ 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 = NULL;
+ } else {
+ 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 {
+ if ((mv_cost * weight) > mobility) {
pr("Not enough mobility to go all the way. Nothing moved.\n");
- *end = *start;
- return -1;
+ movstr = NULL;
+ } else {
+ movstr = buf;
+ pr("Using best path '%s', movement cost %1.3f\n",
+ movstr, mv_cost);
+ }
}
+ }
}
- movstr = path;
- tmpx = start->sct_x;
- curx = tmpx;
- tmpy = start->sct_y;
- cury = tmpy;
- total_mcost = 0.0;
- if (getsect(curx, cury, §) < 0) {
- logerror("move_path: getsect %d,%d", curx, cury);
- return -1;
+ if (!movstr || *movstr == 0) {
+ buf[0] = dirch[DIR_STOP];
+ buf[1] = 0;
+ movstr = buf;
}
- for (;;) {
- tmpx = curx;
- tmpy = cury;
- oldx = curx;
- oldy = cury;
- if (movstr == 0 || *movstr == 0) {
- if (exploring) {
- map(what, curx, cury, (s_char *)0); }
- else {
- move_map(what, curx, cury, (s_char *)0); }
- sprintf(prompt, "<%.1f: %c %s> ", mobility,
- dchr[sect.sct_type].d_mnem,
- xyas(sect.sct_x, sect.sct_y, player->cnum));
- movstr = getstring(prompt, buf);
- }
- if (movstr && sarg_xy(movstr, &dx, &dy)){
- if (getsect(dx,dy,&dsect)){
- movstr=BestLandPath(buf2,§,&dsect,&mv_cost,MOB_ROAD);
- }else{
- pr("Invalid destination sector!\n");
- movstr=(s_char *)0;
- }
-
- if (movstr == (s_char *)0){
- pr("Can't get to %s from here!\n",
- xyas(dx,dy,player->cnum));
- movstr=(s_char *)0;
- }else{
- if ((mv_cost*weight) > mobility){
- pr("Not enough mobility to go all the way. Nothing moved.\n");
- movstr = (s_char *)0;
- }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 (movstr == 0 || *movstr == 0)
- movstr = dirch;
- 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) {
- if (!exploring)
- map(what, curx, cury, movstr+1);
- *movstr = 0;
- continue;
- } else if (dir == DIR_STOP)
- break;
- else 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 *)§, EF_SECTOR));
- continue;
- }
- /*
- * now see if we can move into the
- * next sector. Mobility, terrain,
- * or ownership may prevent us.
- */
- tmpx += diroff[dir][0];
- tmpy += diroff[dir][1];
- if (getsect(tmpx, tmpy, &next) < 0) {
- pr("You can't go there...\n");
- *movstr = 0;
- continue;
- }
- if (!player->god) {
- 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;
- }
- 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) {
- /* already-owned, or prohibited terrain */
- pr("You can't go there...\n");
- *movstr = 0;
- continue;
- }
- sect_mcost *= weight;
- if (sect_mcost > mobility) {
- pr("Not enough mobility. ");
- pr("You can't go there...\n");
- *movstr = 0;
- continue;
- }
- mobility -= sect_mcost;
- total_mcost += sect_mcost;
- }
- curx = tmpx;
- cury = tmpy;
- if (cury != start->sct_y)
- out=1;
- if (curx != start->sct_x)
- out=1;
+ 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;
+ }
+ 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(curx, cury, argp[1], argp[2]);
+ *movstr = 0;
+ continue;
+ }
+ movstr++;
+ if (dir == DIR_STOP)
+ break;
+ if (dir == DIR_VIEW) {
+ pr("%d%% %s with %d civilians.\n", sect.sct_effic,
+ dchr[sect.sct_type].d_name, sect.sct_item[I_CIVIL]);
+ continue;
+ }
+ /*
+ * now see if we can move into the
+ * next sector. Mobility, terrain,
+ * or ownership may prevent us.
+ */
+ 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;
+ continue;
+ }
+ if (!player->god) {
+ if ((next.sct_type == SCT_SANCT) &&
+ (next.sct_own != player->cnum)) {
+ pr("Converts, huh?\n");
+ *movstr = 0;
+ continue;
+ }
+ 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;
+ continue;
+ }
+ sect_mcost *= weight;
+ if (sect_mcost > mobility) {
+ pr("Not enough mobility. ");
+ pr("You can't go there...\n");
+ *movstr = 0;
+ continue;
+ }
+ mobility -= sect_mcost;
+ total_mcost += sect_mcost;
+ }
+ curx = next.sct_x;
+ cury = next.sct_y;
+ if (cury != start->sct_y)
+ out = 1;
+ if (curx != start->sct_x)
+ out = 1;
- sect = next;
+ sect = next;
- if (takedam)
- *dam += check_lmines(sect.sct_x, sect.sct_y, weight);
- if (*dam >= 100)
- break;
- /*
- * Check and see if anyone will interdict us
- */
- if (takedam && chance(weight/100.0) &&
- ((curx != oldx) || (cury != oldy)))
- (*dam) += ground_interdict(curx,cury,player->cnum,"commodities");
- if (*dam >= 100)
- break;
- }
- *end = sect;
- intcost = (int) total_mcost;
- if (intcost < 0)
- return -1;
- if ((start->sct_x == end->sct_x) && (start->sct_y == end->sct_y) && !out)
- return -1;
+ if (takedam)
+ *dam += check_lmines(sect.sct_x, sect.sct_y, weight);
+ if (*dam >= 100)
+ break;
+ /*
+ * Check and see if anyone will interdict us
+ */
+ if (takedam && chance(weight / 100.0) &&
+ ((curx != oldx) || (cury != oldy)))
+ *dam += ground_interdict(curx, cury, player->cnum,
+ "commodities");
+ if (*dam >= 100)
+ break;
+ }
+ *end = sect;
+ intcost = (int)total_mcost;
+ if (intcost < 0)
+ return -1;
+ if ((start->sct_x == end->sct_x) && (start->sct_y == end->sct_y)
+ && !out)
+ return -1;
- if (chance(total_mcost - intcost))
- intcost++;
- return intcost;
+ if (chance(total_mcost - intcost))
+ intcost++;
+ return intcost;
}
/*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];
- 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;
- i = 0;
- while (i < 7 && nxtsct(&ns, §)) {
- view[i] = dchr[sect.sct_type].d_mnem;
- switch (sect.sct_type) {
- case SCT_WATER:
- case SCT_RURAL:
- case SCT_MOUNT:
- case SCT_WASTE:
- case SCT_PLAINS:
- break;
- default:
- if (sect.sct_own != player->cnum && !player->god)
- view[i] = '?';
- break;
- }
- changed += map_set(player->cnum, ns.x, ns.y, view[i], 0);
- i++;
- }
- if (changed)
- writemap(player->cnum);
- if (!getsect(curx, cury, §))
- return RET_FAIL;
- getvec(VT_ITEM, vec, (s_char *)§, 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);
- pr(" %c %c\n", view[5], view[6]);
- return RET_OK;
+ struct nstr_sect ns;
+ struct sctstr sect;
+ char view[7];
+ int i;
+ int changed = 0;
+
+ snxtsct_dist(&ns, curx, cury, 1);
+ i = 0;
+ while (i < 7 && nxtsct(&ns, §)) {
+ /* Nasty: this relies on the iteration order */
+ view[i] = dchr[sect.sct_type].d_mnem;
+ switch (sect.sct_type) {
+ case SCT_WATER:
+ case SCT_RURAL:
+ case SCT_MOUNT:
+ case SCT_WASTE:
+ case SCT_PLAINS:
+ break;
+ default:
+ if (sect.sct_own != player->cnum && !player->god)
+ view[i] = '?';
+ break;
+ }
+ changed += map_set(player->cnum, ns.x, ns.y, view[i], 0);
+ i++;
+ }
+ if (changed)
+ writemap(player->cnum);
+ if (!getsect(curx, cury, §))
+ return RET_FAIL;
+ 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,
+ 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;
}
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];
- 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 */
+ struct nstr_sect ns;
+ struct sctstr sect;
+ char view[7];
+ int i;
- if (!snxtsct(&ns, range))
- return RET_FAIL;
- i = 0;
- while (i < 7 && nxtsct(&ns, §)){
- if (!(view[i] = player->bmap[sctoff(ns.x, ns.y)]))
- view[i] = ' ';
- i++;
- }
+ snxtsct_dist(&ns, curx, cury, 1);
+ i = 0;
+ while (i < 7 && nxtsct(&ns, §)) {
+ /* Nasty: this relies on the iteration order */
+ if (!(view[i] = player->bmap[sect.sct_uid]))
+ view[i] = ' ';
+ i++;
+ }
- pr(" %c %c\n",view[0], view[1]);
- pr(" %c %c %c\n", view[2], view[3], view[4]);
- pr(" %c %c\n", view[5], view[6]);
- return RET_OK;
+ pr(" %c %c\n", view[0], view[1]);
+ pr(" %c %c %c\n", view[2], view[3], view[4]);
+ pr(" %c %c\n", view[5], view[6]);
+ return RET_OK;
}
int
check_lmines(coord x, coord y, double weight)
{
- struct sctstr sect;
- int mines;
- int dam = 0;
+ struct sctstr sect;
+ int dam = 0;
- getsect(x, y, §);
- mines = getvar(V_MINE, (s_char *)§, EF_SECTOR);
- if (mines > 0 &&
- sect.sct_oldown != player->cnum &&
- chance(DMINE_LHITCHANCE(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 *)§, EF_SECTOR);
- putsect(§);
- pr("%d damage sustained.\n", dam);
- }
- return dam;
+ getsect(x, y, §);
+ if (SCT_LANDMINES(§) > 0 &&
+ sect.sct_oldown != player->cnum &&
+ 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);
+ --sect.sct_mines;
+ putsect(§);
+ pr("%d damage sustained.\n", dam);
+ }
+ return dam;
}