363 lines
9.6 KiB
C
363 lines
9.6 KiB
C
/*
|
|
* Empire - A multi-player, client/server Internet based war game.
|
|
* Copyright (C) 1986-2004, Dave Pare, Jeff Bailey, Thomas Ruschak,
|
|
* Ken Stevens, Steve McClure
|
|
*
|
|
* This program 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
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* 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
|
|
*
|
|
* ---
|
|
*
|
|
* 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.
|
|
*
|
|
* ---
|
|
*
|
|
* move.c: Move something somewhere.
|
|
*
|
|
* Known contributors to this file:
|
|
*
|
|
*/
|
|
|
|
#include "misc.h"
|
|
#include "player.h"
|
|
#include "sect.h"
|
|
#include "item.h"
|
|
#include "file.h"
|
|
#include "xy.h"
|
|
#include "path.h"
|
|
#include "nat.h"
|
|
#include "map.h"
|
|
#include "nsc.h"
|
|
#include "damage.h"
|
|
#include "prototypes.h"
|
|
|
|
static int move_map(s_char *what, coord curx, coord cury, s_char *arg);
|
|
|
|
int
|
|
move_ground(s_char *what, struct sctstr *start, struct sctstr *end,
|
|
double weight, s_char *path,
|
|
int (*map)(s_char *, coord, coord, s_char *), int exploring,
|
|
int *dam)
|
|
{
|
|
struct sctstr sect, ending_sect;
|
|
struct sctstr next, dsect;
|
|
coord curx, cury, oldx, oldy;
|
|
coord tmpx, tmpy;
|
|
coord dx, dy;
|
|
s_char *movstr;
|
|
double sect_mcost;
|
|
double total_mcost;
|
|
double mv_cost;
|
|
double mobility = (double)start->sct_mobil;
|
|
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];
|
|
|
|
*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)) {
|
|
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);
|
|
strncpy(bpath, path, sizeof(bpath));
|
|
path = bpath;
|
|
}
|
|
if ((total_mcost * weight) > mobility) {
|
|
pr("Not enough mobility to go all the way. Nothing moved.\n");
|
|
return -1;
|
|
}
|
|
}
|
|
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 == 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);
|
|
strncpy(bpath, movstr, sizeof(bpath));
|
|
movstr = bpath;
|
|
}
|
|
}
|
|
}
|
|
if (movstr == 0 || *movstr == 0) {
|
|
buf2[0] = dirch[DIR_STOP];
|
|
buf2[1] = 0;
|
|
movstr = buf2;
|
|
}
|
|
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,
|
|
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_ROAD);
|
|
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 = tmpx;
|
|
cury = tmpy;
|
|
if (cury != start->sct_y)
|
|
out = 1;
|
|
if (curx != start->sct_x)
|
|
out = 1;
|
|
|
|
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 (chance(total_mcost - intcost))
|
|
intcost++;
|
|
return intcost;
|
|
}
|
|
|
|
|
|
/*ARGSUSED*/
|
|
static int
|
|
move_map(s_char *what, coord curx, coord cury, s_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 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;
|
|
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 */
|
|
|
|
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++;
|
|
}
|
|
|
|
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 dam = 0;
|
|
|
|
getsect(x, y, §);
|
|
if (sect.sct_mines > 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;
|
|
}
|