navigate: Require all ships to start in the same sector

The capability to navigate ships spread over several sectors is
obscure and rarely useful.  Accidental use is probably more frequent
than intentional use.  Issues:

* Interactive prompts show only the flagship's position, and give no
  clue that some ships are actually elsewhere.

* Path finding is supported only when all navigating ships are in
  the same sector.

* Interdiction becomes rather complex.  For each movement, every
  sector entered is interdicted independently.  This means the same
  fort, ship, land unit or plane can interdict multiple times.
  Interdiction order depends on the order the code examines
  ships. which the player can control.  This is all pretty much
  undocumented.

* Complicates the code and its maintenance.  Multiplies the number of
  test cases needed to cover navigate.

I feel we're better off without this feature.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
This commit is contained in:
Markus Armbruster 2014-12-28 22:27:37 +01:00
parent 69c99a0f29
commit a024dbb8a3
9 changed files with 44 additions and 60 deletions

View file

@ -171,12 +171,12 @@ extern double shp_torp_hitchance(struct shpstr *, int);
/* src/lib/subs/shpsub.c */ /* src/lib/subs/shpsub.c */
extern void shp_sel(struct nstr_item *, struct emp_qelem *); extern void shp_sel(struct nstr_item *, struct emp_qelem *);
extern struct ulist *shp_insque(struct shpstr *, struct emp_qelem *); extern struct ulist *shp_insque(struct shpstr *, struct emp_qelem *);
extern void shp_nav(struct emp_qelem *, double *, double *, int *, natid); extern void shp_nav(struct emp_qelem *, double *, double *, natid);
extern int shp_sweep(struct emp_qelem *, int, int, natid); extern int shp_sweep(struct emp_qelem *, int, int, natid);
extern enum shp_stuck shp_check_nav(struct shpstr *, struct sctstr *); extern enum shp_stuck shp_check_nav(struct shpstr *, struct sctstr *);
extern int sect_has_dock(struct sctstr *); extern int sect_has_dock(struct sctstr *);
extern int shp_hardtarget(struct shpstr *); extern int shp_hardtarget(struct shpstr *);
extern int shp_nav_one_sector(struct emp_qelem *, int, natid, int); extern int shp_nav_one_sector(struct emp_qelem *, int, natid);
extern int shp_missile_defense(coord, coord, natid, int); extern int shp_missile_defense(coord, coord, natid, int);
extern void shp_missdef(struct shpstr *, natid); extern void shp_missdef(struct shpstr *, natid);
extern double shp_mobcost(struct shpstr *); extern double shp_mobcost(struct shpstr *);

View file

@ -3,7 +3,8 @@
.LV Basic .LV Basic
.SY "navigate <SHIP/FLEET> <ROUTE|DESTINATION>" .SY "navigate <SHIP/FLEET> <ROUTE|DESTINATION>"
The navigate command is the \*Qmove\*U command applied to the sea. The navigate command is the \*Qmove\*U command applied to the sea.
You can control one ship or an entire fleet with it. You can control one ship or an entire fleet with it, but they must all
start in the same sector.
.s1 .s1
A ship must have at least one crew A ship must have at least one crew
(which may be civilian or military, (which may be civilian or military,
@ -114,10 +115,6 @@ For example,
patrol boat #18 stopped at -6,-2 patrol boat #18 stopped at -6,-2
.FI .FI
.s1 .s1
Note that if you are navigating multiple ships, you may only specify a
destination sector on the command line if all the ships start in the
same sector.
.s1
The formula for the movement cost for 1 sector is: The formula for the movement cost for 1 sector is:
.NF .NF

View file

@ -50,17 +50,16 @@ navi(void)
struct nstr_item ni_ship; struct nstr_item ni_ship;
struct emp_qelem ship_list; struct emp_qelem ship_list;
double minmob, maxmob; double minmob, maxmob;
int together; int together = 1;
if (!snxtitem(&ni_ship, EF_SHIP, player->argp[1], NULL)) if (!snxtitem(&ni_ship, EF_SHIP, player->argp[1], NULL))
return RET_SYN; return RET_SYN;
shp_sel(&ni_ship, &ship_list); shp_sel(&ni_ship, &ship_list);
shp_nav(&ship_list, &minmob, &maxmob, &together, player->cnum); shp_nav(&ship_list, &minmob, &maxmob, player->cnum);
if (QEMPTY(&ship_list)) { if (QEMPTY(&ship_list)) {
pr("No ships\n"); pr("No ships\n");
return RET_FAIL; return RET_FAIL;
} }
return do_unit_move(&ship_list, &together, &minmob, &maxmob); return do_unit_move(&ship_list, &together, &minmob, &maxmob);
} }
@ -99,7 +98,7 @@ do_unit_move(struct emp_qelem *ulist, int *together,
if (cp == NULL || *cp == '\0' || stopping) { if (cp == NULL || *cp == '\0' || stopping) {
stopping = 0; stopping = 0;
if (type == EF_SHIP) if (type == EF_SHIP)
shp_nav(ulist, minmob, maxmob, together, player->cnum); shp_nav(ulist, minmob, maxmob, player->cnum);
else else
lnd_mar(ulist, minmob, maxmob, player->cnum); lnd_mar(ulist, minmob, maxmob, player->cnum);
if (QEMPTY(ulist)) { if (QEMPTY(ulist)) {
@ -126,7 +125,7 @@ do_unit_move(struct emp_qelem *ulist, int *together,
* at the prompt, we call shp_nav() or lnd_mar() again. * at the prompt, we call shp_nav() or lnd_mar() again.
*/ */
if (type == EF_SHIP) if (type == EF_SHIP)
shp_nav(ulist, minmob, maxmob, together, player->cnum); shp_nav(ulist, minmob, maxmob, player->cnum);
else else
lnd_mar(ulist, minmob, maxmob, player->cnum); lnd_mar(ulist, minmob, maxmob, player->cnum);
if (QEMPTY(ulist)) { if (QEMPTY(ulist)) {
@ -152,8 +151,7 @@ do_unit_move(struct emp_qelem *ulist, int *together,
dir = chkdir(*cp, DIR_STOP, DIR_LAST); dir = chkdir(*cp, DIR_STOP, DIR_LAST);
if (dir >= 0) { if (dir >= 0) {
if (type == EF_SHIP) if (type == EF_SHIP)
stopping |= shp_nav_one_sector(ulist, dir, stopping |= shp_nav_one_sector(ulist, dir, player->cnum);
player->cnum, *together);
else { else {
if (!moved && !lnd_abandon_askyn(ulist)) if (!moved && !lnd_abandon_askyn(ulist))
return RET_FAIL; return RET_FAIL;

View file

@ -106,20 +106,16 @@ shp_insque(struct shpstr *sp, struct emp_qelem *list)
/* This function assumes that the list was created by shp_sel */ /* This function assumes that the list was created by shp_sel */
void void
shp_nav(struct emp_qelem *list, double *minmobp, double *maxmobp, shp_nav(struct emp_qelem *list, double *minmobp, double *maxmobp,
int *togetherp, natid actor) natid actor)
{ {
struct emp_qelem *qp; struct emp_qelem *qp;
struct emp_qelem *next; struct emp_qelem *next;
struct ulist *mlp; struct ulist *mlp;
struct shpstr *sp; struct shpstr *sp, *flg = NULL;
struct sctstr sect; struct sctstr sect;
coord allx;
coord ally;
int first = 1;
*minmobp = 9876.0; *minmobp = 9876.0;
*maxmobp = -9876.0; *maxmobp = -9876.0;
*togetherp = 1;
for (qp = list->q_back; qp != list; qp = next) { for (qp = list->q_back; qp != list; qp = next) {
next = qp->q_back; next = qp->q_back;
mlp = (struct ulist *)qp; mlp = (struct ulist *)qp;
@ -155,13 +151,12 @@ shp_nav(struct emp_qelem *list, double *minmobp, double *maxmobp,
shp_stays(actor, "is landlocked", mlp); shp_stays(actor, "is landlocked", mlp);
continue; continue;
} }
if (first) { if (!flg)
allx = sp->shp_x; flg = sp;
ally = sp->shp_y; else if (sp->shp_x != flg->shp_x || sp->shp_y != flg->shp_y) {
first = 0; shp_stays(actor, "is not with the flagship", mlp);
continue;
} }
if (sp->shp_x != allx || sp->shp_y != ally)
*togetherp = 0;
if (sp->shp_mobil + 1 < (int)mlp->mobil) { if (sp->shp_mobil + 1 < (int)mlp->mobil) {
mlp->mobil = sp->shp_mobil; mlp->mobil = sp->shp_mobil;
} }
@ -749,14 +744,12 @@ shp_hit_mine(struct shpstr *sp)
} }
int int
shp_nav_one_sector(struct emp_qelem *list, int dir, natid actor, shp_nav_one_sector(struct emp_qelem *list, int dir, natid actor)
int together)
{ {
struct sctstr sect; struct sctstr sect;
struct emp_qelem *qp; struct emp_qelem *qp;
struct emp_qelem *next; struct emp_qelem *next;
struct ulist *mlp; struct ulist *mlp;
struct emp_qelem done;
coord dx; coord dx;
coord dy; coord dy;
coord newx; coord newx;
@ -767,6 +760,9 @@ shp_nav_one_sector(struct emp_qelem *list, int dir, natid actor,
double mobcost; double mobcost;
char dp[80]; char dp[80];
if (CANT_HAPPEN(QEMPTY(list)))
return 1;
if (dir <= DIR_STOP || dir >= DIR_VIEW) { if (dir <= DIR_STOP || dir >= DIR_VIEW) {
shp_nav_put(list, actor); shp_nav_put(list, actor);
return 1; return 1;
@ -774,13 +770,15 @@ shp_nav_one_sector(struct emp_qelem *list, int dir, natid actor,
dx = diroff[dir][0]; dx = diroff[dir][0];
dy = diroff[dir][1]; dy = diroff[dir][1];
mlp = (struct ulist *)list->q_back;
newx = xnorm(mlp->unit.ship.shp_x + dx);
newy = ynorm(mlp->unit.ship.shp_y + dy);
getsect(newx, newy, &sect);
move = 0; move = 0;
for (qp = list->q_back; qp != list; qp = next) { for (qp = list->q_back; qp != list; qp = next) {
next = qp->q_back; next = qp->q_back;
mlp = (struct ulist *)qp; mlp = (struct ulist *)qp;
newx = xnorm(mlp->unit.ship.shp_x + dx);
newy = ynorm(mlp->unit.ship.shp_y + dy);
getsect(newx, newy, &sect);
stuck = shp_check_nav(&mlp->unit.ship, &sect); stuck = shp_check_nav(&mlp->unit.ship, &sect);
if (stuck == SHP_STUCK_NOT && if (stuck == SHP_STUCK_NOT &&
(!sect.sct_own (!sect.sct_own
@ -791,9 +789,6 @@ shp_nav_one_sector(struct emp_qelem *list, int dir, natid actor,
for (qp = list->q_back; qp != list; qp = next) { for (qp = list->q_back; qp != list; qp = next) {
next = qp->q_back; next = qp->q_back;
mlp = (struct ulist *)qp; mlp = (struct ulist *)qp;
newx = xnorm(mlp->unit.ship.shp_x + dx);
newy = ynorm(mlp->unit.ship.shp_y + dy);
getsect(newx, newy, &sect);
stuck = shp_check_nav(&mlp->unit.ship, &sect); stuck = shp_check_nav(&mlp->unit.ship, &sect);
if (stuck != SHP_STUCK_NOT || if (stuck != SHP_STUCK_NOT ||
(sect.sct_own (sect.sct_own
@ -804,7 +799,7 @@ shp_nav_one_sector(struct emp_qelem *list, int dir, natid actor,
xyas(newx, newy, actor)); xyas(newx, newy, actor));
else else
sprintf(dp, "can't go to %s", xyas(newx, newy, actor)); sprintf(dp, "can't go to %s", xyas(newx, newy, actor));
if (together && !move) { if (!move) {
mpr(actor, "%s\n", dp); mpr(actor, "%s\n", dp);
return 1; return 1;
} else { } else {
@ -842,28 +837,7 @@ shp_nav_one_sector(struct emp_qelem *list, int dir, natid actor,
stopping |= shp_check_mines(list); stopping |= shp_check_mines(list);
if (QEMPTY(list)) if (QEMPTY(list))
return stopping; return stopping;
/* interdict ships sector by sector */
emp_initque(&done);
while (!QEMPTY(list)) {
mlp = (struct ulist *)list->q_back;
newx = mlp->unit.ship.shp_x;
newy = mlp->unit.ship.shp_y;
stopping |= shp_interdict(list, newx, newy, actor); stopping |= shp_interdict(list, newx, newy, actor);
/* move survivors in this sector to done */
for (qp = list->q_back; qp != list; qp = next) {
next = qp->q_back;
mlp = (struct ulist *)qp;
if (mlp->unit.ship.shp_x == newx &&
mlp->unit.ship.shp_y == newy) {
emp_remque(qp);
emp_insque(qp, &done);
}
}
}
/* assign surviving ships back to list */
emp_insque(list, &done);
emp_remque(&done);
return stopping; return stopping;
} }

View file

@ -16,7 +16,6 @@ WORLD_Y 16
MARKET 1 MARKET 1
EOF EOF
customize big-city customize big-city
# TODO cover scattered navigate
# TODO cover RAILWAYS 0 # TODO cover RAILWAYS 0
begin_test "$srcdir"/tests/navi-march/setup-POGO begin_test "$srcdir"/tests/navi-march/setup-POGO

View file

@ -19,6 +19,9 @@ navi 24/26 yh
navi 25 h navi 25 h
| landlocked in 1,-1 | landlocked in 1,-1
navi 27 h navi 27 h
| not with flagship
nav 28/10 yh
__cmd added 1 1 0
|| get stuck on the way || get stuck on the way
| sink, by hitting mine in 11,-5 | sink, by hitting mine in 11,-5
| #31 hits a mine, #30 doesn't | #31 hits a mine, #30 doesn't

View file

@ -142,6 +142,7 @@ uid owner xloc yloc type effic mobil off tech opx opy mission radius fleet civil
25 1 4 2 9 100 127 0 40 4 2 none 0 "" 0 2 0 0 0 0 0 0 0 0 0 0 0 0 healthy 0 0 "" 1 1 1 () "" 25 1 4 2 9 100 127 0 40 4 2 none 0 "" 0 2 0 0 0 0 0 0 0 0 0 0 0 0 healthy 0 0 "" 1 1 1 () ""
26 1 2 2 2 100 127 0 20 0 0 none 0 "" 0 5 0 0 0 0 0 0 0 0 0 0 0 0 healthy 0 0 "" 1 1 1 () "" 26 1 2 2 2 100 127 0 20 0 0 none 0 "" 0 5 0 0 0 0 0 0 0 0 0 0 0 0 healthy 0 0 "" 1 1 1 () ""
27 1 1 -1 9 100 127 0 40 1 -1 none 0 "" 0 2 0 0 0 0 0 0 0 0 0 0 0 0 healthy 0 0 "" 1 1 1 () "" 27 1 1 -1 9 100 127 0 40 1 -1 none 0 "" 0 2 0 0 0 0 0 0 0 0 0 0 0 0 healthy 0 0 "" 1 1 1 () ""
28 1 3 -1 9 100 117 0 40 4 0 none 0 "" 0 2 0 0 0 0 0 0 0 0 0 0 0 0 healthy 0 0 "" 1 1 1 () ""
30 1 10 -6 9 100 108 0 40 9 -5 none 0 "" 0 2 0 0 0 0 0 0 0 0 0 0 0 0 healthy 0 0 "" 1 1 1 () "" 30 1 10 -6 9 100 108 0 40 9 -5 none 0 "" 0 2 0 0 0 0 0 0 0 0 0 0 0 0 healthy 0 0 "" 1 1 1 () ""
31 0 11 -5 9 0 53 0 40 9 -5 none 0 "" 0 2 0 0 0 0 0 0 0 0 0 0 0 0 healthy 0 0 "" 1 1 1 () "" 31 0 11 -5 9 0 53 0 40 9 -5 none 0 "" 0 2 0 0 0 0 0 0 0 0 0 0 0 0 healthy 0 0 "" 1 1 1 () ""
32 1 10 -6 9 75 105 0 40 9 -5 none 0 "" 0 1 0 0 0 0 0 0 0 0 0 0 0 0 healthy 0 0 "" 1 1 1 () "" 32 1 10 -6 9 75 105 0 40 9 -5 none 0 "" 0 1 0 0 0 0 0 0 0 0 0 0 0 0 healthy 0 0 "" 1 1 1 () ""

View file

@ -114,6 +114,15 @@
Play#1 output Play#1 1 No ships Play#1 output Play#1 1 No ships
Play#1 output Play#1 1 command failed Play#1 output Play#1 1 command failed
Play#1 output Play#1 6 0 630 Play#1 output Play#1 6 0 630
Play#1 input nav 28/10 yh
Play#1 command navigate
Play#1 output Play#1 1 pt patrol boat (#10) is not with the flagship & stays in -1,-1
Play#1 output Play#1 1 Flagship is pt patrol boat (#28)
Play#1 output Play#1 1 pt patrol boat (#28) stopped at 3,-1
Play#1 output Play#1 6 0 629
Play#1 input __cmd added 1 1 0
Play#1 command __cmd
Play#1 output Play#1 6 0 630
Play#1 input navi 31/30 jX Play#1 input navi 31/30 jX
Play#1 command navigate Play#1 command navigate
Play#1 output Play#1 1 Flagship is pt patrol boat (#31) Play#1 output Play#1 1 Flagship is pt patrol boat (#31)
@ -1393,6 +1402,7 @@
Play#0 output Play#0 1 1 25 pt patrol boat 4,2 100% 0 2 0 0 0 0 0 0 127 40 Play#0 output Play#0 1 1 25 pt patrol boat 4,2 100% 0 2 0 0 0 0 0 0 127 40
Play#0 output Play#0 1 1 26 cs cargo ship 2,2 100% 0 5 0 0 0 0 0 0 127 20 Play#0 output Play#0 1 1 26 cs cargo ship 2,2 100% 0 5 0 0 0 0 0 0 127 20
Play#0 output Play#0 1 1 27 pt patrol boat 1,-1 100% 0 2 0 0 0 0 0 0 127 40 Play#0 output Play#0 1 1 27 pt patrol boat 1,-1 100% 0 2 0 0 0 0 0 0 127 40
Play#0 output Play#0 1 1 28 pt patrol boat 3,-1 100% 0 2 0 0 0 0 0 0 117 40
Play#0 output Play#0 1 1 30 pt patrol boat 10,-6 100% 0 2 0 0 0 0 0 0 108 40 Play#0 output Play#0 1 1 30 pt patrol boat 10,-6 100% 0 2 0 0 0 0 0 0 108 40
Play#0 output Play#0 1 1 32 pt patrol boat 10,-6 75% 0 1 0 0 0 0 0 0 105 40 Play#0 output Play#0 1 1 32 pt patrol boat 10,-6 75% 0 1 0 0 0 0 0 0 105 40
Play#0 output Play#0 1 1 33 pt patrol boat 10,-6 80% 0 1 0 0 0 0 0 0 106 40 Play#0 output Play#0 1 1 33 pt patrol boat 10,-6 80% 0 1 0 0 0 0 0 0 106 40
@ -1445,7 +1455,7 @@
Play#0 output Play#0 1 1 137 pt patrol boat 11,-5 100% 0 2 0 0 0 0 0 0 117 40 Play#0 output Play#0 1 1 137 pt patrol boat 11,-5 100% 0 2 0 0 0 0 0 0 117 40
Play#0 output Play#0 1 1 138 pt patrol boat 11,-5 80% 0 1 0 0 0 0 0 0 93 40 Play#0 output Play#0 1 1 138 pt patrol boat 11,-5 80% 0 1 0 0 0 0 0 0 93 40
Play#0 output Play#0 1 1 139 pt patrol boat 11,-5 74% 0 1 0 0 0 0 0 0 86 40 Play#0 output Play#0 1 1 139 pt patrol boat 11,-5 74% 0 1 0 0 0 0 0 0 86 40
Play#0 output Play#0 1 70 ships Play#0 output Play#0 1 71 ships
Play#0 output Play#0 6 0 640 Play#0 output Play#0 6 0 640
Play#0 input carg * ?shell#0 Play#0 input carg * ?shell#0
Play#0 command cargo Play#0 command cargo

View file

@ -88,6 +88,8 @@ edit s 0 U 24 L 2,2 U 25 L 4,2
edit s 1 U 26 L 2,2 edit s 1 U 26 L 2,2
| landlocked in 1,-1 | landlocked in 1,-1
edit s 0 U 27 L 1,-1 edit s 0 U 27 L 1,-1
| at sea, away from #10
edit s 0 U 28 L 4,0
| next to minefield 11,-5 | next to minefield 11,-5
edit s 0 U 30 L 9,-5 U 31 E 20 edit s 0 U 30 L 9,-5 U 31 E 20
edit s 30 U 32 m 1 U 33 U 34 U 35 U 36 U 37 U 38 U 39 edit s 30 U 32 m 1 U 33 U 34 U 35 U 36 U 37 U 38 U 39