2 * Empire - A multi-player, client/server Internet based war game.
3 * Copyright (C) 1986-2015, Dave Pare, Jeff Bailey, Thomas Ruschak,
4 * Ken Stevens, Steve McClure, Markus Armbruster
6 * Empire is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 * See files README, COPYING and CREDITS in the root of the source
22 * tree for related information and legal notices. It is expected
23 * that future projects/authors will amend these files as needed.
27 * retreat.c: Retreat subroutines
29 * Known contributors to this file:
31 * Ron Koenderink, 2005-2006
32 * Markus Armbruster, 2006-2015
41 #include "prototypes.h"
45 static void retreat_ship_sel(struct shpstr *, struct emp_qelem *, int);
46 static int retreat_ships_step(struct emp_qelem *, char, natid);
47 static void retreat_land_sel(struct lndstr *, struct emp_qelem *, int);
48 static int retreat_lands_step(struct emp_qelem *, char, natid);
51 retreat_steps(char *rpath)
55 for (i = 0; i < MAX_RETREAT && rpath[i]; i++) {
63 consume_step(char *rpath, int *rflags)
65 memmove(rpath, rpath + 1, RET_LEN - 1);
71 retreat_ship(struct shpstr *sp, natid own, char code)
74 struct emp_qelem list;
78 if (CANT_HAPPEN(!own || (sp->shp_own && sp->shp_own != own)))
80 if (own == player->cnum || !sp->shp_rpath[0])
83 n = retreat_steps(sp->shp_rpath);
88 * We're going to put a copy of *sp into list. The movement loop
89 * will use that copy, which may render *sp stale. To avoid
90 * leaving the caller with a stale *sp, we'll re-get it at the
91 * end. To make that work, we need to put it now. Resets
92 * sp->shp_own when the ship sinks.
94 putship(sp->shp_uid, sp);
98 retreat_ship_sel(sp, &list, n);
100 if (sp->shp_rflags & RET_GROUP) {
101 snxtitem_xy(&ni, EF_SHIP, sp->shp_x, sp->shp_y);
102 while (nxtitem(&ni, &ship)) {
103 if (ship.shp_own != own
104 || !(ship.shp_rflags & RET_GROUP)
105 || ship.shp_fleet != sp->shp_fleet
106 || ship.shp_uid == sp->shp_uid)
108 if (strncmp(ship.shp_rpath, sp->shp_rpath, MAX_RETREAT + 1))
110 retreat_ship_sel(&ship, &list, n);
114 /* Loop similar to the one in unit_move(). Keep it that way! */
115 for (i = 0; i < n && !QEMPTY(&list); i++) {
117 * Invariant: shp_may_nav() true for all ships
118 * Implies all are in the same sector
120 if (!retreat_ships_step(&list, sp->shp_rpath[i], own))
122 shp_nav_stay_behind(&list, own);
123 unit_rad_map_set(&list);
127 shp_nav_put(&list, own);
128 getship(sp->shp_uid, sp);
132 retreat_ship_sel(struct shpstr *sp, struct emp_qelem *list, int n)
134 struct shpstr *flg = QEMPTY(list) ? NULL
135 : &((struct ulist *)(list->q_back))->unit.ship;
137 if (!shp_may_nav(sp, flg, ", and can't retreat!"))
139 if (sp->shp_mobil <= 0) {
140 mpr(sp->shp_own, "%s has no mobility, and can't retreat!\n",
146 mpr(sp->shp_own, "%s retreats with her\n", prship(sp));
148 mpr(sp->shp_own, "%s retreats along path %.*s\n",
149 prship(sp), n, sp->shp_rpath);
150 shp_insque(sp, list);
154 retreat_ships_step(struct emp_qelem *list, char step, natid actor)
156 int dir = chkdir(step, DIR_STOP, DIR_LAST);
157 struct emp_qelem *qp;
161 if (dir != DIR_STOP && shp_nav_dir(list, dir, actor))
162 return 0; /* can't go there */
164 for (qp = list->q_back; qp != list; qp = qp->q_back) {
165 mlp = (struct ulist *)qp;
166 sp = &mlp->unit.ship;
167 consume_step(sp->shp_rpath, &sp->shp_rflags);
170 putship(sp->shp_uid, sp);
173 return dir != DIR_STOP && !shp_nav_gauntlet(list, 0, actor);
177 retreat_land(struct lndstr *lp, natid own, char code)
180 struct emp_qelem list;
184 if (CANT_HAPPEN(!own || (lp->lnd_own && lp->lnd_own != own)))
186 if (own == player->cnum || !lp->lnd_rpath[0])
189 n = retreat_steps(lp->lnd_rpath);
193 /* See explanation in retreat_ship() */
194 putland(lp->lnd_uid, lp);
198 retreat_land_sel(lp, &list, n);
200 if (lp->lnd_rflags & RET_GROUP) {
201 snxtitem_xy(&ni, EF_LAND, lp->lnd_x, lp->lnd_y);
202 while (nxtitem(&ni, &land)) {
203 if (land.lnd_own != own
204 || !(land.lnd_rflags & RET_GROUP)
205 || land.lnd_army != lp->lnd_army
206 || land.lnd_uid == lp->lnd_uid)
208 if (strncmp(land.lnd_rpath, lp->lnd_rpath, MAX_RETREAT + 1))
210 retreat_land_sel(&land, &list, n);
214 /* Loop similar to the one in unit_move(). Keep it that way! */
215 for (i = 0; i < n && !QEMPTY(&list); i++) {
217 * Invariant: lnd_may_nav() true for all land units
218 * Implies all are in the same sector
220 if (!retreat_lands_step(&list, lp->lnd_rpath[i], own))
222 lnd_mar_stay_behind(&list, own);
223 unit_rad_map_set(&list);
227 lnd_mar_put(&list, own);
228 getland(lp->lnd_uid, lp);
232 retreat_land_sel(struct lndstr *lp, struct emp_qelem *list, int n)
234 struct lndstr *ldr = QEMPTY(list)
235 ? NULL : &((struct ulist *)(list->q_back))->unit.land;
237 if (!lnd_may_mar(lp, ldr, ", and can't retreat!"))
239 if (lp->lnd_mobil <= 0) {
240 mpr(lp->lnd_own, "%s has no mobility, and can't retreat!\n",
246 mpr(lp->lnd_own, "%s retreats with them\n", prland(lp));
248 mpr(lp->lnd_own, "%s retreats along path %.*s\n",
249 prland(lp), n, lp->lnd_rpath);
250 lnd_insque(lp, list);
254 retreat_lands_step(struct emp_qelem *list, char step, natid actor)
256 int dir = chkdir(step, DIR_STOP, DIR_LAST);
257 struct emp_qelem *qp;
261 if (dir != DIR_STOP && lnd_mar_dir(list, dir, actor))
262 return 0; /* can't go there */
264 for (qp = list->q_back; qp != list; qp = qp->q_back) {
265 llp = (struct ulist *)qp;
266 lp = &llp->unit.land;
267 consume_step(lp->lnd_rpath, &lp->lnd_rflags);
268 if (dir != DIR_STOP) {
272 putland(lp->lnd_uid, lp);
275 return dir != DIR_STOP && !lnd_mar_gauntlet(list, 0, actor);