]> git.pond.sub.org Git - empserver/blob - src/lib/common/cargo.c
Fix trailing whitespace
[empserver] / src / lib / common / cargo.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2008, Dave Pare, Jeff Bailey, Thomas Ruschak,
4  *                           Ken Stevens, Steve McClure
5  *
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.
10  *
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.
15  *
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
19  *
20  *  ---
21  *
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.
25  *
26  *  ---
27  *
28  *  cargo.c: Cargo lists
29  *
30  *  Known contributors to this file:
31  *     Markus Armbruster, 2008
32  */
33
34 #include <config.h>
35
36 #include <stdlib.h>
37 #include <stdio.h>
38 #include <string.h>
39 #include "file.h"
40 #include "unit.h"
41
42 struct clink {
43     short next;
44     short head[EF_NUKE - EF_PLANE + 1];
45 };
46
47 /*
48  * Cargo lists
49  *
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.
53  *
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
59  * zero.
60  *
61  * clink[TYPE][UID].next is the uid of the next unit of the same type
62  * in the same carrier, -1 if none.
63  *
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,
67  * and so forth.
68  *
69  * Each type of carrier can only carry certain types of cargo, but
70  * cargo lists know nothing about that.
71  */
72 static struct clink *clink[EF_NUKE + 1];
73 static short nclink[EF_NUKE + 1];
74
75 /*
76  * Return pointer to CL's cargo list head for file type TYPE.
77  */
78 static short *
79 clink_headp(struct clink *cl, int type)
80 {
81     static short dummy;
82
83     if (CANT_HAPPEN(type < EF_PLANE || type > EF_NUKE)) {
84         dummy = -1;
85         return &dummy;
86     }
87     return &cl->head[type - EF_PLANE];
88 }
89
90 /*
91  * Initialize cargo list link CL to empty.
92  */
93 static void
94 clink_init(struct clink *cl)
95 {
96     unsigned i;
97
98     cl->next = -1;
99     for (i = 0; i < sizeof(cl->head) / sizeof(*cl->head); i++)
100         cl->head[i] = -1;
101 }
102
103 /*
104  * Check whether *UIDP is a valid uid for file type TYPE.
105  */
106 static void
107 clink_check1(short *uidp, int type)
108 {
109     if (CANT_HAPPEN(*uidp >= nclink[type]))
110         *uidp = -1;
111 }
112
113 /*
114  * Check validity of cargo lists for file type TYPE.
115  */
116 static void
117 clink_check(int type)
118 {
119     int carr_type, i;
120
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),
126                              type);
127         }
128     }
129     /* check the nexts */
130     for (i = 0; i < nclink[type]; i++)
131         clink_check1(&clink[type][i].next, type);
132 }
133
134 /*
135  * Add to CL's cargo list for type TYPE the uid UID.
136  * UID must not be on any cargo list already.
137  */
138 static void
139 clink_add(struct clink *cl, int type, int uid)
140 {
141     short *head = clink_headp(cl, type);
142
143     if (CANT_HAPPEN(type < 0 || type > EF_NUKE
144                     || uid < 0 || uid >= nclink[type]))
145         return;
146     if (CANT_HAPPEN(*head >= nclink[type]))
147         *head = -1;
148     CANT_HAPPEN(clink[type][uid].next >= 0);
149     clink[type][uid].next = *head;
150     *head = uid;
151 }
152
153 /*
154  * Remove from CL's cargo list for type TYPE the uid UID.
155  * UID must be on that cargo list.
156  */
157 static void
158 clink_rem(struct clink *cl, int type, int uid)
159 {
160     short *head = clink_headp(cl, type);
161     struct clink *linkv;
162     int n;
163     short *p;
164
165     if (CANT_HAPPEN(type < 0 || type > EF_NUKE))
166         return;
167     linkv = clink[type];
168     n = nclink[type];
169
170     for (p = head; *p != uid; p = &linkv[*p].next) {
171         if (CANT_HAPPEN(*p < 0 || *p >= n))
172             return;
173     }
174
175     *p = linkv[uid].next;
176     linkv[uid].next = -1;
177 }
178
179 /*
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.
183  */
184 void
185 unit_carrier_change(struct empobj *cargo, int type, int old, int new)
186 {
187     if (CANT_HAPPEN(type < 0 || type > EF_NUKE))
188         return;
189     if (old >= 0)
190         clink_rem(&clink[type][old], cargo->ef_type, cargo->uid);
191     if (new >= 0)
192         clink_add(&clink[type][new], cargo->ef_type, cargo->uid);
193 }
194
195 /*
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.
199  */
200 void
201 pln_carrier_change(struct plnstr *pp, int type, int old, int new)
202 {
203     unit_carrier_change((struct empobj *)pp, type, old, new);
204 }
205
206 /*
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.
210  */
211 void
212 lnd_carrier_change(struct lndstr *lp, int type, int old, int new)
213 {
214     unit_carrier_change((struct empobj *)lp, type, old, new);
215 }
216
217 /*
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.
221  */
222 void
223 nuk_carrier_change(struct nukstr *np, int type, int old, int new)
224 {
225     unit_carrier_change((struct empobj *)np, type, old, new);
226 }
227
228 /*
229  * Initialize cargo lists from game state.
230  */
231 void
232 unit_cargo_init(void)
233 {
234     int i;
235     struct plnstr *pp;
236     struct lndstr *lp;
237     struct nukstr *np;
238
239     memset(nclink, 0, sizeof(nclink));
240     for (i = EF_SHIP; i <= EF_NUKE; i++)
241         unit_onresize(i);
242
243     for (i = 0; (pp = getplanep(i)); i++) {
244         if (!pp->pln_own)
245             continue;
246         if (CANT_HAPPEN(pp->pln_ship >= 0 && pp->pln_land >= 0))
247             pp->pln_land = -1;
248         pln_carrier_change(pp, EF_SHIP, -1, pp->pln_ship);
249         pln_carrier_change(pp, EF_LAND, -1, pp->pln_land);
250     }
251     for (i = 0; (lp = getlandp(i)); i++) {
252         if (!lp->lnd_own)
253             continue;
254         if (CANT_HAPPEN(lp->lnd_ship >= 0 && lp->lnd_land >= 0))
255             lp->lnd_land = -1;
256         lnd_carrier_change(lp, EF_SHIP, -1, lp->lnd_ship);
257         lnd_carrier_change(lp, EF_LAND, -1, lp->lnd_land);
258     }
259     for (i = 0; (np = getnukep(i)); i++) {
260         if (!np->nuk_own)
261             continue;
262         nuk_carrier_change(np, EF_PLANE, -1, np->nuk_plane);
263     }
264 }
265
266 /*
267  * Resize clink[TYPE] to match ef_nelem(TYPE).
268  * Return 0 on success, -1 on error.
269  * This is the struct empfile onresize callback for units.
270  */
271 int
272 unit_onresize(int type)
273 {
274     int n, i;
275     struct clink *cl;
276
277     if (CANT_HAPPEN(type < EF_SHIP || type > EF_NUKE))
278         return -1;
279
280     n = ef_nelem(type);
281     cl = realloc(clink[type], n * sizeof(*clink[type]));
282     if (!cl && n)
283         exit_nomem();
284     for (i = nclink[type]; i < n; i++)
285         clink_init(&cl[i]);
286     clink[type] = cl;
287     nclink[type] = n;
288     if (ef_flags(type) & EFF_MEM)
289         clink_check(type);
290     return 0;
291 }
292
293 /*
294  * Find first unit on a carrier's cargo list for file type CARGO_TYPE.
295  * Search carrier UID of type TYPE.
296  * Return first unit's uid, or -1 if the carrier isn't carrying such
297  * units.
298  */
299 int
300 unit_cargo_first(int type, int uid, int cargo_type)
301 {
302     short *headp;
303
304     if (CANT_HAPPEN(type < EF_SHIP || type > EF_NUKE))
305         return -1;
306     if (CANT_HAPPEN(uid < 0 || uid >= nclink[type]))
307         return -1;
308     headp = clink_headp(&clink[type][uid], cargo_type);
309     if (CANT_HAPPEN(!headp))
310         return -1;
311     return *headp;
312 }
313
314 /*
315  * Find the next unit on a cargo list for file type CARGO_TYPE.
316  * Get the unit after CARGO_UID.
317  * Return its uid, or -1 if there are no more on this list.
318  */
319 int
320 unit_cargo_next(int cargo_type, int cargo_uid)
321 {
322     if (CANT_HAPPEN(cargo_type < EF_SHIP || cargo_type > EF_NUKE))
323         return -1;
324     if (CANT_HAPPEN(cargo_uid < 0 || cargo_uid >= nclink[cargo_type]))
325         return -1;
326     return clink[cargo_type][cargo_uid].next;
327 }
328
329 /*
330  * If SP carries planes, return the uid of the first one, else -1.
331  */
332 int
333 pln_first_on_ship(struct shpstr *sp)
334 {
335     return unit_cargo_first(EF_SHIP, sp->shp_uid, EF_PLANE);
336 }
337
338 /*
339  * If LP carries planes, return the uid of the first one, else -1.
340  */
341 int
342 pln_first_on_land(struct lndstr *lp)
343 {
344     return unit_cargo_first(EF_LAND, lp->lnd_uid, EF_PLANE);
345 }
346
347 /*
348  * Find the next plane on the same carrier as plane#UID.
349  * Return its uid, or -1 if there are no more.
350  */
351 int
352 pln_next_on_unit(int uid)
353 {
354     return unit_cargo_next(EF_PLANE, uid);
355 }
356
357 /*
358  * If SP carries land units, return the uid of the first one, else -1.
359  */
360 int
361 lnd_first_on_ship(struct shpstr *sp)
362 {
363     return unit_cargo_first(EF_SHIP, sp->shp_uid, EF_LAND);
364 }
365
366 /*
367  * If SP carries land units, return the uid of the first one, else -1.
368  */
369 int
370 lnd_first_on_land(struct lndstr *lp)
371 {
372     return unit_cargo_first(EF_LAND, lp->lnd_uid, EF_LAND);
373 }
374
375 /*
376  * Find the next land unit on the same carrier as land#UID.
377  * Return its uid, or -1 if there are no more.
378  */
379 int
380 lnd_next_on_unit(int uid)
381 {
382     return unit_cargo_next(EF_LAND, uid);
383 }
384
385 /*
386  * If PP carries a nuke, return its uid, else -1.
387  */
388 int
389 nuk_on_plane(struct plnstr *pp)
390 {
391     return unit_cargo_first(EF_PLANE, pp->pln_uid, EF_NUKE);
392 }
393
394 /*
395  * Return length of a carrier's cargo list for file type CARGO_TYPE.
396  */
397 int
398 unit_cargo_count(int type, int uid, int cargo_type)
399 {
400     int n, cargo;
401
402     n = 0;
403     for (cargo = unit_cargo_first(type, uid, cargo_type);
404          cargo >= 0;
405          cargo = unit_cargo_next(cargo_type, cargo))
406         n++;
407
408     return n;
409 }
410
411 /*
412  * Return number of land units loaded on SP.
413  */
414 int
415 shp_nland(struct shpstr *sp)
416 {
417     return unit_cargo_count(EF_SHIP, sp->shp_uid, EF_LAND);
418 }
419
420 /*
421  * Return number of land units loaded on LP.
422  */
423 int
424 lnd_nland(struct lndstr *lp)
425 {
426     return unit_cargo_count(EF_LAND, lp->lnd_uid, EF_LAND);
427 }
428
429 int
430 unit_nplane(int type, int uid, int *nchopper, int *nxlight, int *nmsl)
431 {
432     int n, nch, nxl, nms, cargo;
433     struct plnstr *pp;
434     struct plchrstr *pcp;
435
436     n = nxl = nch = nms = 0;
437     for (cargo = unit_cargo_first(type, uid, EF_PLANE);
438          (pp = getplanep(cargo));
439          cargo = pln_next_on_unit(cargo)) {
440         pcp = &plchr[pp->pln_type];
441         if (pcp->pl_flags & P_K)
442             nch++;
443         else if (pcp->pl_flags & P_E)
444             nxl++;
445         else if (pcp->pl_flags & P_M)
446             nms++;
447         n++;
448     }
449
450     if (nchopper)
451         *nchopper = nch;
452     if (nxlight)
453         *nxlight = nxl;
454     if (nmsl)
455         *nmsl = nms;
456     return n;
457 }
458
459 int
460 shp_nplane(struct shpstr *sp, int *nchopper, int *nxlight, int *nmsl)
461 {
462     return unit_nplane(EF_SHIP, sp->shp_uid, nchopper, nxlight, nmsl);
463 }
464
465 int
466 lnd_nxlight(struct lndstr *lp)
467 {
468     int n;
469
470     unit_nplane(EF_LAND, lp->lnd_uid, NULL, &n, NULL);
471     return n;
472 }