2 * Empire - A multi-player, client/server Internet based war game.
3 * Copyright (C) 1986-2018, 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 * cargo.c: Cargo lists
29 * Known contributors to this file:
30 * Markus Armbruster, 2009
42 int head[EF_NUKE - EF_PLANE + 1];
48 * Persistent game state encodes "who carries what" by storing the
49 * carrier UID in the cargo. Cargo lists augment that: they store
50 * lists of cargo for each carrier.
52 * clink[TYPE] points to an array of cargo list links. The array has
53 * nclink[TYPE] elements. nclink[TYPE] tracks ef_nelem(TYPE).
54 * clink[TYPE][UID] is the cargo list link for unit UID of type TYPE.
55 * TYPE must be a unit file type: EF_SHIP, EF_PLANE, EF_LAND or
56 * EF_NUKE. Other slots of clink[] and nclink[] are unused and remain
59 * clink[TYPE][UID].next is the UID of the next unit of the same type
60 * in the same carrier, -1 if none.
62 * clink[TYPE][UID].head[CARGO-EF_PLANE] is the UID of the first unit
63 * of type CARGO carried by this unit, -1 if none. The next unit, if
64 * any, is clink[CARGO][clink[TYPE][UID].head[CARGO-EF_PLANE]].next,
67 * Each type of carrier can only carry certain types of cargo, but
68 * cargo lists know nothing about that.
70 static struct clink *clink[EF_NUKE + 1];
71 static int nclink[EF_NUKE + 1];
74 * Return pointer to @cl's cargo list head for file type @type.
77 clink_headp(struct clink *cl, int type)
81 if (CANT_HAPPEN(type < EF_PLANE || type > EF_NUKE)) {
85 return &cl->head[type - EF_PLANE];
89 * Initialize cargo list link @cl to empty.
92 clink_init(struct clink *cl)
97 for (i = 0; i < sizeof(cl->head) / sizeof(*cl->head); i++)
102 * Check whether *@uidp is a valid UID for file type @type.
105 clink_check1(int *uidp, int type)
107 if (CANT_HAPPEN(*uidp >= nclink[type]))
112 * Check validity of cargo lists for file type @type.
115 clink_check(int type)
119 /* check the heads for all carriers */
120 if (type != EF_SHIP) {
121 for (carr_type = EF_PLANE; carr_type <= EF_NUKE; carr_type++) {
122 for (i = 0; i < nclink[carr_type]; i++)
123 clink_check1(clink_headp(&clink[carr_type][i], type),
127 /* check the nexts */
128 for (i = 0; i < nclink[type]; i++)
129 clink_check1(&clink[type][i].next, type);
133 * Add to @cl's cargo list for type @type the UID @uid.
134 * @uid must not be on any cargo list already.
137 clink_add(struct clink *cl, int type, int uid)
139 int *head = clink_headp(cl, type);
141 if (CANT_HAPPEN(type < 0 || type > EF_NUKE
142 || uid < 0 || uid >= nclink[type]))
144 if (CANT_HAPPEN(*head >= nclink[type]))
146 CANT_HAPPEN(clink[type][uid].next >= 0);
147 clink[type][uid].next = *head;
152 * Remove from @cl's cargo list for type @type the UID @uid.
153 * @uid must be on that cargo list.
156 clink_rem(struct clink *cl, int type, int uid)
158 int *head = clink_headp(cl, type);
163 if (CANT_HAPPEN(type < 0 || type > EF_NUKE))
168 for (p = head; *p != uid; p = &linkv[*p].next) {
169 if (CANT_HAPPEN(*p < 0 || *p >= n))
173 *p = linkv[uid].next;
174 linkv[uid].next = -1;
178 * Update cargo lists for a change of @cargo's carrier.
179 * Carrier is of type @type, and changes from UID @old to @new.
180 * Negative UIDs mean no carrier.
183 unit_carrier_change(struct empobj *cargo, int type, int old, int new)
185 if (CANT_HAPPEN(type < 0 || type > EF_NUKE))
187 if (old >= 0 && !CANT_HAPPEN(old >= nclink[type]))
188 clink_rem(&clink[type][old], cargo->ef_type, cargo->uid);
189 if (new >= 0 && !CANT_HAPPEN(new >= nclink[type]))
190 clink_add(&clink[type][new], cargo->ef_type, cargo->uid);
194 * Update cargo lists for a change of @pp's carrier.
195 * Carrier is of type @type, and changes from UID @old to @new.
196 * Negative UIDs mean no carrier.
199 pln_carrier_change(struct plnstr *pp, int type, int old, int new)
201 unit_carrier_change((struct empobj *)pp, type, old, new);
205 * Update cargo lists for a change of @lp's carrier.
206 * Carrier is of type @type, and changes from UID @old to @new.
207 * Negative UIDs mean no carrier.
210 lnd_carrier_change(struct lndstr *lp, int type, int old, int new)
212 unit_carrier_change((struct empobj *)lp, type, old, new);
216 * Update cargo lists for a change of @np's carrier.
217 * Carrier is of type @type, and changes from UID @old to @new.
218 * Negative UIDs mean no carrier.
221 nuk_carrier_change(struct nukstr *np, int type, int old, int new)
223 unit_carrier_change((struct empobj *)np, type, old, new);
227 * Initialize cargo lists from game state.
230 unit_cargo_init(void)
237 memset(nclink, 0, sizeof(nclink));
238 for (i = EF_SHIP; i <= EF_NUKE; i++)
241 for (i = 0; (pp = getplanep(i)); i++) {
243 if (CANT_HAPPEN(pp->pln_ship >= 0 || pp->pln_land >= 0))
244 pp->pln_ship = pp->pln_land = -1;
247 if (CANT_HAPPEN(pp->pln_ship >= 0 && pp->pln_land >= 0))
249 pln_carrier_change(pp, EF_SHIP, -1, pp->pln_ship);
250 pln_carrier_change(pp, EF_LAND, -1, pp->pln_land);
252 for (i = 0; (lp = getlandp(i)); i++) {
254 if (CANT_HAPPEN(lp->lnd_ship >= 0 || lp->lnd_land >= 0))
255 lp->lnd_ship = lp->lnd_land = -1;
258 if (CANT_HAPPEN(lp->lnd_ship >= 0 && lp->lnd_land >= 0))
260 lnd_carrier_change(lp, EF_SHIP, -1, lp->lnd_ship);
261 lnd_carrier_change(lp, EF_LAND, -1, lp->lnd_land);
263 for (i = 0; (np = getnukep(i)); i++) {
265 if (CANT_HAPPEN(np->nuk_plane >= 0))
269 nuk_carrier_change(np, EF_PLANE, -1, np->nuk_plane);
274 * Resize clink[@type] to match ef_nelem(@type).
275 * Return 0 on success, -1 on error.
276 * This is the struct empfile onresize callback for units.
279 unit_onresize(int type)
284 if (CANT_HAPPEN(type < EF_SHIP || type > EF_NUKE))
288 cl = realloc(clink[type], n * sizeof(*clink[type]));
291 for (i = nclink[type]; i < n; i++)
295 if (ef_flags(type) & EFF_MEM)
300 * Find first unit on a carrier's cargo list for file type @cargo_type.
301 * Search carrier @uid of type @type.
302 * Return first unit's UID, or -1 if the carrier isn't carrying such
306 unit_cargo_first(int type, int uid, int cargo_type)
310 if (CANT_HAPPEN(type < EF_SHIP || type > EF_NUKE))
312 if (CANT_HAPPEN(uid < 0 || uid >= nclink[type]))
314 headp = clink_headp(&clink[type][uid], cargo_type);
315 if (CANT_HAPPEN(!headp))
321 * Find the next unit on a cargo list for file type @cargo_type.
322 * Get the unit after @cargo_uid.
323 * Return its UID, or -1 if there are no more on this list.
326 unit_cargo_next(int cargo_type, int cargo_uid)
328 if (CANT_HAPPEN(cargo_type < EF_SHIP || cargo_type > EF_NUKE))
330 if (CANT_HAPPEN(cargo_uid < 0 || cargo_uid >= nclink[cargo_type]))
332 return clink[cargo_type][cargo_uid].next;
336 * If @sp carries planes, return the UID of the first one, else -1.
339 pln_first_on_ship(struct shpstr *sp)
341 return unit_cargo_first(EF_SHIP, sp->shp_uid, EF_PLANE);
345 * If @lp carries planes, return the UID of the first one, else -1.
348 pln_first_on_land(struct lndstr *lp)
350 return unit_cargo_first(EF_LAND, lp->lnd_uid, EF_PLANE);
354 * Find the next plane on the same carrier as plane#@uid.
355 * Return its UID, or -1 if there are no more.
358 pln_next_on_unit(int uid)
360 return unit_cargo_next(EF_PLANE, uid);
364 * If @sp carries land units, return the UID of the first one, else -1.
367 lnd_first_on_ship(struct shpstr *sp)
369 return unit_cargo_first(EF_SHIP, sp->shp_uid, EF_LAND);
373 * If @lp carries land units, return the UID of the first one, else -1.
376 lnd_first_on_land(struct lndstr *lp)
378 return unit_cargo_first(EF_LAND, lp->lnd_uid, EF_LAND);
382 * Find the next land unit on the same carrier as land#@uid.
383 * Return its UID, or -1 if there are no more.
386 lnd_next_on_unit(int uid)
388 return unit_cargo_next(EF_LAND, uid);
392 * If @pp carries a nuke, return its UID, else -1.
395 nuk_on_plane(struct plnstr *pp)
397 return unit_cargo_first(EF_PLANE, pp->pln_uid, EF_NUKE);
401 * Return length of a carrier's cargo list for file type @cargo_type.
402 * Use carrier @uid of type @type.
405 unit_cargo_count(int type, int uid, int cargo_type)
410 for (cargo = unit_cargo_first(type, uid, cargo_type);
412 cargo = unit_cargo_next(cargo_type, cargo))
419 * Return number of land units loaded on @sp.
422 shp_nland(struct shpstr *sp)
424 return unit_cargo_count(EF_SHIP, sp->shp_uid, EF_LAND);
428 * Return number of land units loaded on @lp.
431 lnd_nland(struct lndstr *lp)
433 return unit_cargo_count(EF_LAND, lp->lnd_uid, EF_LAND);
437 unit_nplane(int type, int uid, int *nchopper, int *nxlight, int *nmsl)
439 int n, nch, nxl, nms, cargo;
441 struct plchrstr *pcp;
443 n = nxl = nch = nms = 0;
444 for (cargo = unit_cargo_first(type, uid, EF_PLANE);
445 (pp = getplanep(cargo));
446 cargo = pln_next_on_unit(cargo)) {
447 pcp = &plchr[pp->pln_type];
448 if (pcp->pl_flags & P_K)
450 else if (pcp->pl_flags & P_E)
452 else if (pcp->pl_flags & P_M)
467 shp_nplane(struct shpstr *sp, int *nchopper, int *nxlight, int *nmsl)
469 return unit_nplane(EF_SHIP, sp->shp_uid, nchopper, nxlight, nmsl);
473 lnd_nxlight(struct lndstr *lp)
477 unit_nplane(EF_LAND, lp->lnd_uid, NULL, &n, NULL);