2 * Empire - A multi-player, client/server Internet based war game.
3 * Copyright (C) 1986-2009, Dave Pare, Jeff Bailey, Thomas Ruschak,
4 * Ken Stevens, Steve McClure
6 * This program 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 2 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, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 * See files README, COPYING and CREDITS in the root of the source
23 * tree for related information and legal notices. It is expected
24 * that future projects/authors will amend these files as needed.
28 * cargo.c: Cargo lists
30 * Known contributors to this file:
31 * Markus Armbruster, 2009
44 short head[EF_NUKE - EF_PLANE + 1];
50 * Persistent game state encodes "who carries what" by storing the
51 * carrier uid in the cargo. Cargo lists augment that: they store
52 * lists of cargo for each carrier.
54 * clink[TYPE] points to an array of cargo list links. The array has
55 * nclink[TYPE] elements. nclink[TYPE] tracks ef_nelem(TYPE).
56 * clink[TYPE][UID] is the cargo list link for unit UID of type TYPE.
57 * TYPE must be a unit file type: EF_SHIP, EF_PLANE, EF_LAND or
58 * EF_NUKE. Other slots of clink[] and nclink[] are unused and remain
61 * clink[TYPE][UID].next is the uid of the next unit of the same type
62 * in the same carrier, -1 if none.
64 * clink[TYPE][UID].head[CARGO-EF_PLANE] is the uid of the first unit
65 * of type CARGO carried by this unit, -1 if none. The next unit, if
66 * any, is clink[CARGO][clink[TYPE][UID].head[CARGO-EF_PLANE]].next,
69 * Each type of carrier can only carry certain types of cargo, but
70 * cargo lists know nothing about that.
72 static struct clink *clink[EF_NUKE + 1];
73 static short nclink[EF_NUKE + 1];
76 * Return pointer to CL's cargo list head for file type TYPE.
79 clink_headp(struct clink *cl, int type)
83 if (CANT_HAPPEN(type < EF_PLANE || type > EF_NUKE)) {
87 return &cl->head[type - EF_PLANE];
91 * Initialize cargo list link CL to empty.
94 clink_init(struct clink *cl)
99 for (i = 0; i < sizeof(cl->head) / sizeof(*cl->head); i++)
104 * Check whether *UIDP is a valid uid for file type TYPE.
107 clink_check1(short *uidp, int type)
109 if (CANT_HAPPEN(*uidp >= nclink[type]))
114 * Check validity of cargo lists for file type TYPE.
117 clink_check(int type)
121 /* check the heads for all carriers */
122 if (type != EF_SHIP) {
123 for (carr_type = EF_PLANE; carr_type <= EF_NUKE; carr_type++) {
124 for (i = 0; i < nclink[carr_type]; i++)
125 clink_check1(clink_headp(&clink[carr_type][i], type),
129 /* check the nexts */
130 for (i = 0; i < nclink[type]; i++)
131 clink_check1(&clink[type][i].next, type);
135 * Add to CL's cargo list for type TYPE the uid UID.
136 * UID must not be on any cargo list already.
139 clink_add(struct clink *cl, int type, int uid)
141 short *head = clink_headp(cl, type);
143 if (CANT_HAPPEN(type < 0 || type > EF_NUKE
144 || uid < 0 || uid >= nclink[type]))
146 if (CANT_HAPPEN(*head >= nclink[type]))
148 CANT_HAPPEN(clink[type][uid].next >= 0);
149 clink[type][uid].next = *head;
154 * Remove from CL's cargo list for type TYPE the uid UID.
155 * UID must be on that cargo list.
158 clink_rem(struct clink *cl, int type, int uid)
160 short *head = clink_headp(cl, type);
165 if (CANT_HAPPEN(type < 0 || type > EF_NUKE))
170 for (p = head; *p != uid; p = &linkv[*p].next) {
171 if (CANT_HAPPEN(*p < 0 || *p >= n))
175 *p = linkv[uid].next;
176 linkv[uid].next = -1;
180 * Update cargo lists for a change of CARGO's carrier.
181 * Carrier is of type TYPE, and changes from uid OLD to NEW.
182 * Negative uids mean no carrier.
185 unit_carrier_change(struct empobj *cargo, int type, int old, int new)
187 if (CANT_HAPPEN(type < 0 || type > EF_NUKE))
189 if (old >= 0 && !CANT_HAPPEN(old >= nclink[type]))
190 clink_rem(&clink[type][old], cargo->ef_type, cargo->uid);
191 if (new >= 0 && !CANT_HAPPEN(new >= nclink[type]))
192 clink_add(&clink[type][new], cargo->ef_type, cargo->uid);
196 * Update cargo lists for a change of PP's carrier.
197 * Carrier is of type TYPE, and changes from uid OLD to NEW.
198 * Negative uids mean no carrier.
201 pln_carrier_change(struct plnstr *pp, int type, int old, int new)
203 unit_carrier_change((struct empobj *)pp, type, old, new);
207 * Update cargo lists for a change of LP's carrier.
208 * Carrier is of type TYPE, and changes from uid OLD to NEW.
209 * Negative uids mean no carrier.
212 lnd_carrier_change(struct lndstr *lp, int type, int old, int new)
214 unit_carrier_change((struct empobj *)lp, type, old, new);
218 * Update cargo lists for a change of NP's carrier.
219 * Carrier is of type TYPE, and changes from uid OLD to NEW.
220 * Negative uids mean no carrier.
223 nuk_carrier_change(struct nukstr *np, int type, int old, int new)
225 unit_carrier_change((struct empobj *)np, type, old, new);
229 * Initialize cargo lists from game state.
232 unit_cargo_init(void)
239 memset(nclink, 0, sizeof(nclink));
240 for (i = EF_SHIP; i <= EF_NUKE; i++)
243 for (i = 0; (pp = getplanep(i)); i++) {
245 if (CANT_HAPPEN(pp->pln_ship >= 0 || pp->pln_land >= 0))
246 pp->pln_ship = pp->pln_land = -1;
249 if (CANT_HAPPEN(pp->pln_ship >= 0 && pp->pln_land >= 0))
251 pln_carrier_change(pp, EF_SHIP, -1, pp->pln_ship);
252 pln_carrier_change(pp, EF_LAND, -1, pp->pln_land);
254 for (i = 0; (lp = getlandp(i)); i++) {
256 if (CANT_HAPPEN(lp->lnd_ship >= 0 || lp->lnd_land >= 0))
257 lp->lnd_ship = lp->lnd_land = -1;
260 if (CANT_HAPPEN(lp->lnd_ship >= 0 && lp->lnd_land >= 0))
262 lnd_carrier_change(lp, EF_SHIP, -1, lp->lnd_ship);
263 lnd_carrier_change(lp, EF_LAND, -1, lp->lnd_land);
265 for (i = 0; (np = getnukep(i)); i++) {
267 if (CANT_HAPPEN(np->nuk_plane >= 0))
271 nuk_carrier_change(np, EF_PLANE, -1, np->nuk_plane);
276 * Resize clink[TYPE] to match ef_nelem(TYPE).
277 * Return 0 on success, -1 on error.
278 * This is the struct empfile onresize callback for units.
281 unit_onresize(int type)
286 if (CANT_HAPPEN(type < EF_SHIP || type > EF_NUKE))
290 cl = realloc(clink[type], n * sizeof(*clink[type]));
293 for (i = nclink[type]; i < n; i++)
297 if (ef_flags(type) & EFF_MEM)
303 * Find first unit on a carrier's cargo list for file type CARGO_TYPE.
304 * Search carrier UID of type TYPE.
305 * Return first unit's uid, or -1 if the carrier isn't carrying such
309 unit_cargo_first(int type, int uid, int cargo_type)
313 if (CANT_HAPPEN(type < EF_SHIP || type > EF_NUKE))
315 if (CANT_HAPPEN(uid < 0 || uid >= nclink[type]))
317 headp = clink_headp(&clink[type][uid], cargo_type);
318 if (CANT_HAPPEN(!headp))
324 * Find the next unit on a cargo list for file type CARGO_TYPE.
325 * Get the unit after CARGO_UID.
326 * Return its uid, or -1 if there are no more on this list.
329 unit_cargo_next(int cargo_type, int cargo_uid)
331 if (CANT_HAPPEN(cargo_type < EF_SHIP || cargo_type > EF_NUKE))
333 if (CANT_HAPPEN(cargo_uid < 0 || cargo_uid >= nclink[cargo_type]))
335 return clink[cargo_type][cargo_uid].next;
339 * If SP carries planes, return the uid of the first one, else -1.
342 pln_first_on_ship(struct shpstr *sp)
344 return unit_cargo_first(EF_SHIP, sp->shp_uid, EF_PLANE);
348 * If LP carries planes, return the uid of the first one, else -1.
351 pln_first_on_land(struct lndstr *lp)
353 return unit_cargo_first(EF_LAND, lp->lnd_uid, EF_PLANE);
357 * Find the next plane on the same carrier as plane#UID.
358 * Return its uid, or -1 if there are no more.
361 pln_next_on_unit(int uid)
363 return unit_cargo_next(EF_PLANE, uid);
367 * If SP carries land units, return the uid of the first one, else -1.
370 lnd_first_on_ship(struct shpstr *sp)
372 return unit_cargo_first(EF_SHIP, sp->shp_uid, EF_LAND);
376 * If SP carries land units, return the uid of the first one, else -1.
379 lnd_first_on_land(struct lndstr *lp)
381 return unit_cargo_first(EF_LAND, lp->lnd_uid, EF_LAND);
385 * Find the next land unit on the same carrier as land#UID.
386 * Return its uid, or -1 if there are no more.
389 lnd_next_on_unit(int uid)
391 return unit_cargo_next(EF_LAND, uid);
395 * If PP carries a nuke, return its uid, else -1.
398 nuk_on_plane(struct plnstr *pp)
400 return unit_cargo_first(EF_PLANE, pp->pln_uid, EF_NUKE);
404 * Return length of a carrier's cargo list for file type CARGO_TYPE.
407 unit_cargo_count(int type, int uid, int cargo_type)
412 for (cargo = unit_cargo_first(type, uid, cargo_type);
414 cargo = unit_cargo_next(cargo_type, cargo))
421 * Return number of land units loaded on SP.
424 shp_nland(struct shpstr *sp)
426 return unit_cargo_count(EF_SHIP, sp->shp_uid, EF_LAND);
430 * Return number of land units loaded on LP.
433 lnd_nland(struct lndstr *lp)
435 return unit_cargo_count(EF_LAND, lp->lnd_uid, EF_LAND);
439 unit_nplane(int type, int uid, int *nchopper, int *nxlight, int *nmsl)
441 int n, nch, nxl, nms, cargo;
443 struct plchrstr *pcp;
445 n = nxl = nch = nms = 0;
446 for (cargo = unit_cargo_first(type, uid, EF_PLANE);
447 (pp = getplanep(cargo));
448 cargo = pln_next_on_unit(cargo)) {
449 pcp = &plchr[pp->pln_type];
450 if (pcp->pl_flags & P_K)
452 else if (pcp->pl_flags & P_E)
454 else if (pcp->pl_flags & P_M)
469 shp_nplane(struct shpstr *sp, int *nchopper, int *nxlight, int *nmsl)
471 return unit_nplane(EF_SHIP, sp->shp_uid, nchopper, nxlight, nmsl);
475 lnd_nxlight(struct lndstr *lp)
479 unit_nplane(EF_LAND, lp->lnd_uid, NULL, &n, NULL);