autonav: Remove the feature
The autonavigation feature has issues: * Autonavigation orders are executed at the update. Crafty players can use them to get around the update window. * Usability is poor: - The order command is overly complex, not least because it can do five different things: clear, suspend, resume, declare route, set cargo levels. - Unlike every other command involving movement, order does not let you specify routes, only destination sectors. - Setting cargo levels can silently swap start and end point of a circular route, because "this keeps the load_it() procedure happy". Maybe it does, but it surely keeps players confused. - Setting "start" cargo levels actually sets the "end" levels, and vice versa. Has always been broken that way. - Predicting what exactly autonavigation will do at the update isn't easy. * The info pages documenting it amount to almost 400 non-blank lines formatted. They claim only merchant ships can be given orders. This is wrong. Unlikely to be the only error. * Few players use it, and its workings at the update a fairly opaque. Makes it a nice hidey-hole for bugs. Here are two: - Unlike the scuttle command, autonavigation happily scuttles trade ships while they're on the trading block. - Unlike the load command, autonavigation can load in friendly and allied sectors. * It's more than 700 lines of rather crufty code nobody wants to touch. Thanks to a big effort in Empire 2, it shares code with the navigation command. It still duplicates load code. The sharing complicates fixing the bugs demonstrated by navi-march-test. Reviewing, fixing and testing this mess isn't worth the opportunity cost. Remove it instead. Drop commands order, qorder and sorder. Drop ship selectors xstart, xend, ystart, yend, cargostart, cargoend, amtstart, amtend, autonav. xdump ship sheds almost half its columns. struct shpstr shrinks, on my system from 200 to 160 bytes. Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
This commit is contained in:
parent
a4e519c377
commit
48e656c057
37 changed files with 306 additions and 1764 deletions
|
@ -1,330 +0,0 @@
|
|||
/*
|
||||
* Empire - A multi-player, client/server Internet based war game.
|
||||
* Copyright (C) 1986-2014, Dave Pare, Jeff Bailey, Thomas Ruschak,
|
||||
* Ken Stevens, Steve McClure, Markus Armbruster
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* ---
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* ---
|
||||
*
|
||||
* nav_ship.c: Navigate ships and such
|
||||
*
|
||||
* Known contributors to this file:
|
||||
* Chad Zabel, 1994
|
||||
* Ken Stevens, 1995
|
||||
* Markus Armbruster, 2004-2011
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "nsc.h"
|
||||
#include "path.h"
|
||||
#include "update.h"
|
||||
#include "empobj.h"
|
||||
#include "unit.h"
|
||||
|
||||
static void swap(struct shpstr *);
|
||||
|
||||
static void
|
||||
scuttle_it(struct shpstr *sp)
|
||||
{
|
||||
struct sctstr *sectp;
|
||||
|
||||
sp->shp_autonav &= ~AN_SCUTTLE;
|
||||
if (!(sectp = getsectp(sp->shp_x, sp->shp_y))) {
|
||||
wu(0, 0, "bad sector (%d,%d) ship %d\n",
|
||||
sp->shp_x, sp->shp_y, sp->shp_uid);
|
||||
return;
|
||||
}
|
||||
if (CANT_HAPPEN(!(mchr[sp->shp_type].m_flags & M_TRADE)))
|
||||
return;
|
||||
if (!scuttle_tradeship(sp, 0)) {
|
||||
wu(0, sp->shp_own,
|
||||
"%s doesn't pay here! Not scuttled.\n", prship(sp));
|
||||
return;
|
||||
}
|
||||
wu(0, sp->shp_own, "Scuttling %s in sector %s\n",
|
||||
prship(sp), xyas(sp->shp_x, sp->shp_y, sp->shp_own));
|
||||
if (sectp->sct_own == sp->shp_own)
|
||||
unit_drop_cargo((struct empobj *)sp, sectp->sct_own);
|
||||
sp->shp_effic = 0;
|
||||
putship(sp->shp_uid, sp);
|
||||
}
|
||||
|
||||
static void
|
||||
nav_check_atdest(struct shpstr *sp)
|
||||
{
|
||||
if ((sp->shp_x == sp->shp_destx[0]) && (sp->shp_y == sp->shp_desty[0])) {
|
||||
if ((sp->shp_destx[0] == sp->shp_destx[1]) &&
|
||||
(sp->shp_desty[0] == sp->shp_desty[1])) {
|
||||
|
||||
/* End of road */
|
||||
|
||||
sp->shp_autonav &= ~AN_AUTONAV;
|
||||
wu(0, sp->shp_own, "%s arrived at %s, finished\n",
|
||||
prship(sp), xyas(sp->shp_x, sp->shp_y, sp->shp_own));
|
||||
if (sp->shp_autonav & AN_SCUTTLE) {
|
||||
scuttle_it(sp);
|
||||
}
|
||||
} else {
|
||||
/* unload all cargo */
|
||||
unload_it(sp);
|
||||
wu(0, sp->shp_own, "%s arrived at %s\n",
|
||||
prship(sp), xyas(sp->shp_x, sp->shp_y, sp->shp_own));
|
||||
/* Swap */
|
||||
swap(sp);
|
||||
}
|
||||
} else
|
||||
sp->shp_autonav &= ~AN_LOADING;
|
||||
}
|
||||
|
||||
/* flip the 2 fields that deal with autonav movement. */
|
||||
/* CZ 6/1/94 */
|
||||
|
||||
static void
|
||||
swap(struct shpstr *sp)
|
||||
{
|
||||
coord tcord;
|
||||
i_type tcomm[TMAX];
|
||||
short lev[TMAX];
|
||||
int i;
|
||||
|
||||
tcord = sp->shp_destx[0];
|
||||
sp->shp_destx[0] = sp->shp_destx[1];
|
||||
sp->shp_destx[1] = tcord;
|
||||
tcord = sp->shp_desty[0];
|
||||
sp->shp_desty[0] = sp->shp_desty[1];
|
||||
sp->shp_desty[1] = tcord;
|
||||
|
||||
for (i = 0; i < TMAX; ++i) {
|
||||
lev[i] = sp->shp_lstart[i];
|
||||
tcomm[i] = sp->shp_tstart[i];
|
||||
}
|
||||
|
||||
for (i = 0; i < TMAX; ++i) {
|
||||
sp->shp_lstart[i] = sp->shp_lend[i];
|
||||
sp->shp_tstart[i] = sp->shp_tend[i];
|
||||
}
|
||||
|
||||
for (i = 0; i < TMAX; ++i) {
|
||||
sp->shp_lend[i] = lev[i];
|
||||
sp->shp_tend[i] = tcomm[i];
|
||||
}
|
||||
|
||||
/* set load bit */
|
||||
sp->shp_autonav |= AN_LOADING;
|
||||
}
|
||||
|
||||
/* New Autonav code.
|
||||
* Chad Zabel
|
||||
* 6-1-94
|
||||
*/
|
||||
|
||||
static int
|
||||
nav_loadship(struct shpstr *sp)
|
||||
{
|
||||
struct sctstr *sectp;
|
||||
int i, didsomething[TMAX], rel;
|
||||
|
||||
for (i = 0; i < TMAX; i++)
|
||||
didsomething[i] = 0;
|
||||
|
||||
/* Turn off the loading flag.
|
||||
* if any of the loads fail on the ship
|
||||
* it will be turned back on.
|
||||
*/
|
||||
|
||||
sp->shp_autonav &= ~AN_LOADING;
|
||||
|
||||
if (!(sectp = getsectp(sp->shp_x, sp->shp_y)))
|
||||
return 0; /* safety */
|
||||
|
||||
rel = relations_with(sectp->sct_own, sp->shp_own);
|
||||
|
||||
/* loop through each field for that ship */
|
||||
for (i = 0; i < TMAX; ++i) {
|
||||
/* check and see if the data fields have been set. */
|
||||
|
||||
if (sp->shp_tend[i] == I_NONE || sp->shp_lend[i] == 0) {
|
||||
/* nothing to do move on. */
|
||||
didsomething[i] = 1;
|
||||
continue;
|
||||
}
|
||||
if (sectp->sct_own == 0) {
|
||||
/* either sea or deity harbor */
|
||||
didsomething[i] = 1;
|
||||
continue;
|
||||
}
|
||||
if (!sect_has_dock(sectp)) {
|
||||
/* we can only load in harbors */
|
||||
didsomething[i] = 1;
|
||||
continue;
|
||||
}
|
||||
if (rel >= FRIENDLY)
|
||||
didsomething[i] = load_it(sp, sectp, i);
|
||||
}
|
||||
|
||||
/* check for any unsucessful loads */
|
||||
/* if we have any return 0 to stop */
|
||||
/* the nav_ship loop. */
|
||||
|
||||
for (i = 0; i < TMAX; i++) {
|
||||
if (didsomething[i] == 0)
|
||||
return 0;
|
||||
}
|
||||
/* All loads were succesful */
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
nav_load_ship_at_sea(struct shpstr *sp)
|
||||
{
|
||||
int i;
|
||||
int n_items;
|
||||
int max_amt, item_amt;
|
||||
struct mchrstr *mcp;
|
||||
struct sctstr *sectp;
|
||||
struct check_list_st {
|
||||
long cap;
|
||||
i_type item;
|
||||
} check_list[] = {{M_FOOD, I_FOOD}, {M_OIL, I_OIL}};
|
||||
|
||||
n_items = sizeof(check_list) / sizeof(check_list[0]);
|
||||
|
||||
mcp = &mchr[(int)sp->shp_type];
|
||||
sectp = getsectp(sp->shp_x, sp->shp_y);
|
||||
for (i = 0; i < n_items; i++) {
|
||||
if (mcp->m_flags & check_list[i].cap) {
|
||||
item_amt = sp->shp_item[check_list[i].item];
|
||||
max_amt = mcp->m_item[check_list[i].item];
|
||||
if (item_amt < max_amt && sectp->sct_type == SCT_WATER)
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* new autonav code.
|
||||
*
|
||||
* 1. Try and move to the next sector/harbor given by the player.
|
||||
* 2. Once we reach a harbor try and load all cargo holds for that ship.
|
||||
* 3. If the ship reaches its max levels set by the player try to use
|
||||
* up all mobility getting to the next harbor.
|
||||
* Continue to loop until the ship runs out of mobility, a load fails,
|
||||
* the ship gets sunk (forts,ect..), the ship hits a mine.
|
||||
*
|
||||
* Questions, bugs (fixes) , or new ideas should be directed at
|
||||
* Chad Zabel.
|
||||
* 6-1-94
|
||||
* Modified to use shp_nav by Ken Stevens 1995
|
||||
*/
|
||||
int
|
||||
nav_ship(struct shpstr *sp)
|
||||
{
|
||||
char *cp;
|
||||
int stopping;
|
||||
int quit;
|
||||
int didsomething = 0;
|
||||
char buf[1024];
|
||||
struct emp_qelem ship_list;
|
||||
struct emp_qelem *qp, *newqp;
|
||||
struct ulist *mlp;
|
||||
int dummyint;
|
||||
double dummydouble;
|
||||
int dir;
|
||||
|
||||
/* just return if no autonaving to do for this ship */
|
||||
if (!(sp->shp_autonav & AN_AUTONAV) || (sp->shp_autonav & AN_STANDBY))
|
||||
return 0;
|
||||
|
||||
/* Make a list of one ships so we can use the navi.c code */
|
||||
emp_initque(&ship_list);
|
||||
mlp = shp_insque(sp, &ship_list);
|
||||
ef_mark_fresh(EF_SHIP, &mlp->unit.ship);
|
||||
|
||||
do {
|
||||
if ((sp->shp_mobil > 0) && (!(sp->shp_autonav & AN_LOADING)) &&
|
||||
(!(sp->shp_autonav & AN_STANDBY))) {
|
||||
shp_nav(&ship_list, &dummydouble, &dummydouble, &dummyint,
|
||||
sp->shp_own);
|
||||
if (QEMPTY(&ship_list))
|
||||
return 0;
|
||||
|
||||
if (path_find(sp->shp_x, sp->shp_y,
|
||||
sp->shp_destx[0], sp->shp_desty[0],
|
||||
sp->shp_own, MOB_SAIL) < 0) {
|
||||
wu(0, sp->shp_own,
|
||||
"%s bad path, ship put on standby\n", prship(sp));
|
||||
sp->shp_autonav |= AN_STANDBY;
|
||||
putship(sp->shp_uid, sp);
|
||||
|
||||
/* We need to free the ship list */
|
||||
qp = ship_list.q_forw;
|
||||
while (qp != &ship_list) {
|
||||
newqp = qp->q_forw;
|
||||
emp_remque(qp);
|
||||
free(qp);
|
||||
qp = newqp;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
path_find_route(buf, sizeof(buf), sp->shp_x, sp->shp_y,
|
||||
sp->shp_destx[0], sp->shp_desty[0]);
|
||||
stopping = 0;
|
||||
|
||||
cp = buf;
|
||||
while (*cp && !stopping && sp->shp_own && mlp->mobil > 0.0) {
|
||||
dir = diridx(*cp++);
|
||||
stopping |= shp_nav_one_sector(&ship_list, dir,
|
||||
sp->shp_own, 0);
|
||||
}
|
||||
|
||||
/* Ship not sunk */
|
||||
if (sp->shp_own)
|
||||
nav_check_atdest(sp);
|
||||
}
|
||||
|
||||
quit = 0; /* stop loop */
|
||||
|
||||
/* Try to load the ship */
|
||||
if (sp->shp_autonav & AN_LOADING) {
|
||||
didsomething = nav_loadship(sp);
|
||||
if (didsomething)
|
||||
quit = 1;
|
||||
}
|
||||
/* special case for fishing boats and oil derricks */
|
||||
if (nav_load_ship_at_sea(sp))
|
||||
quit = 0;
|
||||
/* reset flag and check if we can move. */
|
||||
|
||||
} while (quit); /* end loop */
|
||||
|
||||
putship(sp->shp_uid, sp);
|
||||
|
||||
/* We need to free the ship list (just in case) */
|
||||
qp = ship_list.q_forw;
|
||||
while (qp != &ship_list) {
|
||||
newqp = qp->q_forw;
|
||||
emp_remque(qp);
|
||||
free(qp);
|
||||
qp = newqp;
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -1,175 +0,0 @@
|
|||
/*
|
||||
* Empire - A multi-player, client/server Internet based war game.
|
||||
* Copyright (C) 1986-2014, Dave Pare, Jeff Bailey, Thomas Ruschak,
|
||||
* Ken Stevens, Steve McClure, Markus Armbruster
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* ---
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* ---
|
||||
*
|
||||
* nav_util.c: Utilities for autonav and sail
|
||||
*
|
||||
* Known contributors to this file:
|
||||
*
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "item.h"
|
||||
#include "nsc.h"
|
||||
#include "plague.h"
|
||||
#include "ship.h"
|
||||
#include "update.h"
|
||||
|
||||
/* load a specific ship given its
|
||||
* location and what field to modify.
|
||||
* new autonav code
|
||||
* Chad Zabel 6/1/94
|
||||
*/
|
||||
int
|
||||
load_it(struct shpstr *sp, struct sctstr *psect, int i)
|
||||
{
|
||||
int shipown, amount, ship_amt, sect_amt;
|
||||
int abs_max, max_amt, transfer;
|
||||
i_type comm;
|
||||
struct mchrstr *vship;
|
||||
|
||||
amount = sp->shp_lend[i];
|
||||
shipown = sp->shp_own;
|
||||
comm = sp->shp_tend[i];
|
||||
if (CANT_HAPPEN(comm <= I_NONE || comm > I_MAX))
|
||||
return 0;
|
||||
|
||||
ship_amt = sp->shp_item[comm];
|
||||
sect_amt = psect->sct_item[comm];
|
||||
|
||||
/* check for disloyal civilians */
|
||||
if (psect->sct_oldown != shipown && comm == I_CIVIL) {
|
||||
wu(0, shipown,
|
||||
"Ship #%d - unable to load disloyal civilians at %s.",
|
||||
sp->shp_uid, xyas(psect->sct_x, psect->sct_y, shipown));
|
||||
return 0;
|
||||
}
|
||||
if (comm == I_CIVIL || comm == I_MILIT)
|
||||
sect_amt--; /* leave 1 civ or mil to hold the sector. */
|
||||
vship = &mchr[(int)sp->shp_type];
|
||||
abs_max = max_amt = vship->m_item[comm];
|
||||
|
||||
if (!abs_max)
|
||||
return 0; /* can't load the ship, skip to the end. */
|
||||
|
||||
max_amt = MIN(sect_amt, max_amt - ship_amt);
|
||||
if (max_amt <= 0 && (ship_amt != abs_max)) {
|
||||
sp->shp_autonav |= AN_LOADING;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
transfer = amount - ship_amt;
|
||||
if (transfer > sect_amt) { /* not enough in the */
|
||||
transfer = sect_amt; /* sector to fill the */
|
||||
sp->shp_autonav |= AN_LOADING; /* ship, set load flag */
|
||||
}
|
||||
if (ship_amt + transfer > abs_max) /* Do not load more */
|
||||
transfer = abs_max - ship_amt; /* then the max alowed */
|
||||
/* on the ship. */
|
||||
|
||||
if (transfer <= 0)
|
||||
return 0; /* nothing to move */
|
||||
|
||||
|
||||
sp->shp_item[comm] = ship_amt + transfer;
|
||||
if (comm == I_CIVIL || comm == I_MILIT)
|
||||
sect_amt++; /*adjustment */
|
||||
psect->sct_item[comm] = sect_amt - transfer;
|
||||
|
||||
/* deal with the plague */
|
||||
if (psect->sct_pstage == PLG_INFECT && sp->shp_pstage == PLG_HEALTHY)
|
||||
sp->shp_pstage = PLG_EXPOSED;
|
||||
if (sp->shp_pstage == PLG_INFECT && psect->sct_pstage == PLG_HEALTHY)
|
||||
psect->sct_pstage = PLG_EXPOSED;
|
||||
|
||||
return 1; /* we did someloading return 1 to keep */
|
||||
/* our loop happy in nav_ship() */
|
||||
|
||||
}
|
||||
|
||||
/* unload_it
|
||||
* A guess alot of this looks like load_it but because of its location
|
||||
* in the autonav code I had to split the 2 procedures up.
|
||||
* unload_it dumps all the goods from the ship to the harbor.
|
||||
* ONLY goods in the trade fields will be unloaded.
|
||||
* new autonav code
|
||||
* Chad Zabel 6/1/94
|
||||
*/
|
||||
void
|
||||
unload_it(struct shpstr *sp)
|
||||
{
|
||||
struct sctstr *sectp;
|
||||
int i;
|
||||
int landowner;
|
||||
int shipown;
|
||||
i_type comm;
|
||||
int sect_amt;
|
||||
int ship_amt;
|
||||
int max_amt;
|
||||
|
||||
sectp = getsectp(sp->shp_x, sp->shp_y);
|
||||
|
||||
landowner = sectp->sct_own;
|
||||
shipown = sp->shp_own;
|
||||
|
||||
for (i = 0; i < TMAX; ++i) {
|
||||
if (sp->shp_tend[i] == I_NONE || sp->shp_lend[i] == 0)
|
||||
continue;
|
||||
if (landowner == 0)
|
||||
continue;
|
||||
if (sectp->sct_type != SCT_HARBR)
|
||||
continue;
|
||||
|
||||
comm = sp->shp_tend[i];
|
||||
if (CANT_HAPPEN(comm <= I_NONE || comm > I_MAX))
|
||||
continue;
|
||||
ship_amt = sp->shp_item[comm];
|
||||
sect_amt = sectp->sct_item[comm];
|
||||
|
||||
/* check for disloyal civilians */
|
||||
if (sectp->sct_oldown != shipown && comm == I_CIVIL) {
|
||||
wu(0, sp->shp_own,
|
||||
"Ship #%d - unable to unload civilians into a disloyal sector at %s.",
|
||||
sp->shp_uid, xyas(sectp->sct_x, sectp->sct_y, sp->shp_own));
|
||||
continue;
|
||||
}
|
||||
if (comm == I_CIVIL)
|
||||
ship_amt--; /* This leaves 1 civs on board the ship */
|
||||
|
||||
max_amt = MIN(ship_amt, ITEM_MAX - sect_amt);
|
||||
if (max_amt <= 0)
|
||||
continue;
|
||||
|
||||
sp->shp_item[comm] = ship_amt - max_amt;
|
||||
sectp->sct_item[comm] = sect_amt + max_amt;
|
||||
|
||||
if (sectp->sct_pstage == PLG_INFECT && sp->shp_pstage == PLG_HEALTHY)
|
||||
sp->shp_pstage = PLG_EXPOSED;
|
||||
if (sp->shp_pstage == PLG_INFECT && sectp->sct_pstage == PLG_HEALTHY)
|
||||
sectp->sct_pstage = PLG_EXPOSED;
|
||||
}
|
||||
}
|
|
@ -75,8 +75,6 @@ prod_ship(int etus, int natnum, struct bp *bp, int build)
|
|||
np = getnatp(sp->shp_own);
|
||||
start_money = np->nat_money;
|
||||
upd_ship(sp, etus, np, bp, build);
|
||||
if (build && !player->simulation) /* make sure to only autonav once */
|
||||
nav_ship(sp); /* autonav the ship */
|
||||
sea_money[sp->shp_own] += np->nat_money - start_money;
|
||||
if (!build || np->nat_money != start_money)
|
||||
k++;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue