]> git.pond.sub.org Git - empserver/blob - src/lib/commands/load.c
<string.h> is ISO C, no need to #if it.
[empserver] / src / lib / commands / load.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2000, 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 the "LEGAL", "LICENSE", "CREDITS" and "README" files for all the
23  *  related information and legal notices. It is expected that any future
24  *  projects/authors will amend these files as needed.
25  *
26  *  ---
27  *
28  *  load.c: load/unload goods from a sector onto a ship or land unit
29  * 
30  *  Known contributors to this file:
31  *     David Sharnoff, 1987
32  *     Ken Stevens, 1995 (rewritten)
33  *     Steve McClure, 1998-2000
34  */
35
36 #include <string.h>
37 #include "misc.h"
38 #include "player.h"
39 #include "xy.h"
40 #include "file.h"
41 #include "var.h"
42 #include "sect.h"
43 #include "ship.h"
44 #include "plane.h"
45 #include "land.h"
46 #include "item.h"
47 #include "nsc.h"
48 #include "nat.h"
49 #include "optlist.h"
50 #include "commands.h"
51
52 /*
53  * The values 1 and -1 are important below, don't change them.
54  */
55 #define LOAD    1
56 #define UNLOAD  -1
57
58 void gift(int givee, int giver, s_char *ptr, int type, s_char *mesg);
59 static int load_plane_ship(struct sctstr *sectp, struct shpstr *sp,
60                            int noisy, int load_unload, int *nshipsp);
61 static int load_land_ship(struct sctstr *sectp, struct shpstr *sp,
62                           int noisy, int load_unload, int *nshipsp);
63 static int load_comm_ship(struct sctstr *sectp, struct shpstr *sp,
64                           struct ichrstr *ich, int load_unload,
65                           int *nshipsp);
66 static int load_plane_land(struct sctstr *sectp, struct lndstr *lp,
67                            int noisy, int load_unload, int *nunitsp);
68 static int load_land_land(struct sctstr *sectp, struct lndstr *lp,
69                           int noisy, int load_unload, int *nunitsp);
70 static int load_comm_land(struct sctstr *sectp, struct lndstr *lp,
71                           struct ichrstr *ich, int load_unload,
72                           int *nunitsp);
73
74 int
75 load(void)
76 {
77     int noisy;
78     int load_unload;
79     int type;
80     struct nstr_item nbst;
81     struct ichrstr *ich;
82     int nships;
83     struct sctstr sect;
84     struct shpstr ship;
85     int retval;
86     s_char *p;
87     s_char buf[1024];
88
89     if (!(p = getstarg(player->argp[1],
90                        "What commodity (or 'plane' or 'land')? ", buf))
91         || !*p)
92         return RET_SYN;
93
94     if (!strncmp(p, "plane", 5))
95         type = EF_PLANE;
96     else if (!strncmp(p, "land", 4))
97         type = EF_LAND;
98     else if (NULL != (ich = whatitem(p, (s_char *)0)))
99         type = EF_SECTOR;
100     else {
101         pr("Bad commodity.\n");
102         return RET_SYN;
103     }
104
105     if (!(p = getstarg(player->argp[2], "Ship(s): ", buf)) || !*p)
106         return RET_SYN;
107
108     noisy = isdigit(*p);
109
110     if (!snxtitem(&nbst, EF_SHIP, p))
111         return RET_SYN;
112
113     nbst.flags &= ~(EFF_OWNER);
114
115     load_unload = **player->argp == 'l' ? LOAD : UNLOAD;
116
117     nships = 0;
118     while (nxtitem(&nbst, (s_char *)&ship)) {
119         if (!ship.shp_own)
120             continue;
121         if (!player->owner && (load_unload == UNLOAD)) {
122             continue;
123         }
124         if (opt_MARKET) {
125             if (ontradingblock(EF_SHIP, (int *)&ship)) {
126                 pr("You cannot load/unload an item on the trading block!\n");
127                 continue;
128             }
129         }
130
131         if (ship.shp_own != player->cnum) {
132             if (!noisy)
133                 continue;
134             if (getrel(getnatp(player->cnum), ship.shp_own) < FRIENDLY)
135                 continue;
136         }
137         if (!getsect(ship.shp_x, ship.shp_y, &sect))    /* XXX */
138             continue;
139         if ((sect.sct_own != player->cnum) &&
140             (ship.shp_own != player->cnum))
141             continue;
142         if (!player->owner &&
143             sect.sct_type != SCT_HARBR &&
144             (!opt_BIG_CITY || sect.sct_type != SCT_CAPIT))
145             continue;
146         if (!sect.sct_own)
147             continue;
148         if ((sect.sct_own != player->cnum) && (load_unload == LOAD)) {
149             if (noisy)
150                 pr("You don't own %s \n",
151                    xyas(ship.shp_x, ship.shp_y, player->cnum));
152             continue;
153         }
154         if (sect.sct_type != SCT_HARBR &&
155             (!opt_BIG_CITY || sect.sct_type != SCT_CAPIT)) {
156             if (noisy)
157                 pr("Sector %s is not a harbor%s.\n",
158                    xyas(ship.shp_x, ship.shp_y, player->cnum),
159                    opt_BIG_CITY ? " or a city" : "");
160             continue;
161         }
162         if (sect.sct_own != player->cnum && load_unload == UNLOAD
163             && getrel(getnatp(sect.sct_own), player->cnum) < FRIENDLY) {
164             if (noisy)
165                 pr("You can't unload into an unfriendly %s\n",
166                    dchr[sect.sct_type].d_name);
167             continue;
168         }
169         if (sect.sct_effic < 2) {
170             if (noisy)
171                 pr("The %s at %s is not 2%% efficient yet.\n",
172                    dchr[sect.sct_type].d_name,
173                    xyas(ship.shp_x, ship.shp_y, player->cnum));
174             continue;
175         }
176         switch (type) {
177         case EF_PLANE:
178             if (0 !=
179                 (retval =
180                  load_plane_ship(&sect, &ship, noisy, load_unload,
181                                  &nships)))
182                 return retval;
183             break;
184         case EF_LAND:
185             if (0 !=
186                 (retval =
187                  load_land_ship(&sect, &ship, noisy, load_unload,
188                                 &nships)))
189                 return retval;
190             break;
191         case EF_SECTOR:
192             if (0 !=
193                 (retval =
194                  load_comm_ship(&sect, &ship, ich, load_unload, &nships)))
195                 return retval;
196         }
197         /* load/unload plague */
198         if (getvar(V_PSTAGE, (s_char *)&sect, EF_SECTOR) == PLG_INFECT &&
199             getvar(V_PSTAGE, (s_char *)&ship, EF_SHIP) == PLG_HEALTHY)
200             putvar(V_PSTAGE, PLG_EXPOSED, (s_char *)&ship, EF_SHIP);
201         if (getvar(V_PSTAGE, (s_char *)&ship, EF_SHIP) == PLG_INFECT &&
202             getvar(V_PSTAGE, (s_char *)&sect, EF_SECTOR) == PLG_HEALTHY)
203             putvar(V_PSTAGE, PLG_EXPOSED, (s_char *)&sect, EF_SECTOR);
204         putsect(&sect);
205         putship(ship.shp_uid, &ship);
206     }
207     if (!nships)
208         pr("No ships affected\n");
209     else
210         pr("%d ship%s %sloaded\n", nships, splur(nships),
211            load_unload == UNLOAD ? "un" : "");
212     return RET_OK;
213 }
214
215 int
216 lload(void)
217 {
218     int noisy;
219     int load_unload;
220     int type;
221     struct nstr_item nbst;
222     struct ichrstr *ich;
223     int nunits;
224     struct sctstr sect;
225     struct lndstr land;
226     int retval;
227     s_char *p;
228     s_char buf[1024];
229
230     if (!(p = getstarg(player->argp[1],
231                        "What commodity (or 'plane' or 'land')? ", buf))
232         || !*p)
233         return RET_SYN;
234     if (!strncmp(p, "plane", 5))
235         type = EF_PLANE;
236     else if (!strncmp(p, "land", 4))
237         type = EF_LAND;
238     else if (NULL != (ich = whatitem(p, (s_char *)0)))
239         type = EF_SECTOR;
240     else {
241         pr("Bad commodity.\n");
242         return RET_SYN;
243     }
244
245     if (!(p = getstarg(player->argp[2], "Unit(s): ", buf)) || !*p)
246         return RET_SYN;
247
248     noisy = isdigit(*p);
249
250     if (!snxtitem(&nbst, EF_LAND, p))
251         return RET_SYN;
252
253     load_unload = *(*player->argp + 1) == 'l' ? LOAD : UNLOAD;
254
255     nbst.flags &= ~(EFF_OWNER);
256
257     nunits = 0;
258     while (nxtitem(&nbst, (s_char *)&land)) {
259         if (land.lnd_own == 0)
260             continue;
261
262         if (player->cnum != land.lnd_own &&
263             getrel(getnatp(player->cnum), land.lnd_own) != ALLIED)
264             continue;
265
266         if (!getsect(land.lnd_x, land.lnd_y, &sect))    /* XXX */
267             continue;
268
269         if (sect.sct_own != player->cnum && land.lnd_own != player->cnum)
270             continue;
271         if (opt_MARKET) {
272             if (ontradingblock(EF_LAND, (int *)&land)) {
273                 pr("You cannot load/unload an item on the trading block!\n");
274                 continue;
275             }
276         }
277
278         if (sect.sct_own != player->cnum &&
279             getrel(getnatp(sect.sct_own), land.lnd_own) != ALLIED) {
280             pr("Sector %s is not yours.\n",
281                xyas(land.lnd_x, land.lnd_y, player->cnum));
282             continue;
283         }
284         switch (type) {
285         case EF_LAND:
286             if (0 !=
287                 (retval =
288                  load_land_land(&sect, &land, noisy, load_unload,
289                                 &nunits)))
290                 return retval;
291             break;
292         case EF_PLANE:
293             if (0 !=
294                 (retval =
295                  load_plane_land(&sect, &land, noisy, load_unload,
296                                  &nunits)))
297                 return retval;
298             break;
299         case EF_SECTOR:
300             if (0 !=
301                 (retval =
302                  load_comm_land(&sect, &land, ich, load_unload, &nunits)))
303                 return retval;
304         }
305         /* load/unload plague */
306         if (getvar(V_PSTAGE, (s_char *)&sect, EF_SECTOR) == PLG_INFECT &&
307             getvar(V_PSTAGE, (s_char *)&land, EF_LAND) == PLG_HEALTHY)
308             putvar(V_PSTAGE, PLG_EXPOSED, (s_char *)&land, EF_LAND);
309         if (getvar(V_PSTAGE, (s_char *)&land, EF_LAND) == PLG_INFECT &&
310             getvar(V_PSTAGE, (s_char *)&sect, EF_SECTOR) == PLG_HEALTHY)
311             putvar(V_PSTAGE, PLG_EXPOSED, (s_char *)&sect, EF_SECTOR);
312
313         putsect(&sect);
314         putland(land.lnd_uid, &land);
315     }
316     if (nunits == 0)
317         pr("No units affected\n");
318     else
319         pr("%d unit%s %sloaded\n", nunits, splur(nunits),
320            load_unload == UNLOAD ? "un" : "");
321     return RET_OK;
322 }
323
324 void
325 gift(int givee, int giver, s_char *ptr, int type, s_char *mesg)
326 {
327     s_char *p, line[256];
328
329     if (giver == givee)
330         return;
331
332
333     switch (type) {
334     case EF_SHIP:
335         p = prship((struct shpstr *)ptr);
336         break;
337     case EF_PLANE:
338         p = prplane((struct plnstr *)ptr);
339         break;
340     case EF_LAND:
341         p = prland((struct lndstr *)ptr);
342         break;
343     }
344
345     sprintf(line, "%s %s %s\n", cname(giver), p, mesg);
346     wu(0, givee, line);
347 }
348
349 static int
350 still_ok_ship(struct sctstr *sectp, struct shpstr *shipp)
351 {
352     if (!check_sect_ok(sectp))
353         return 0;
354     if (!check_ship_ok(shipp))
355         return 0;
356     return 1;
357 }
358
359 static int
360 still_ok_land(struct sctstr *sectp, struct lndstr *landp)
361 {
362     if (!check_sect_ok(sectp))
363         return 0;
364     if (!check_land_ok(landp))
365         return 0;
366     return 1;
367 }
368
369 static int
370 load_plane_ship(struct sctstr *sectp, struct shpstr *sp, int noisy,
371                 int load_unload, int *nshipsp)
372 {
373     struct nstr_item ni;
374     struct plnstr pln;
375     int loaded = 0;
376     s_char buf[1024];
377     s_char *p;
378     s_char prompt[512];
379     struct mchrstr *mcp = mchr + sp->shp_type;
380
381     if (!(mcp->m_flags & (M_CHOPPER | M_XLIGHT | M_FLY | M_MSL))) {
382         if (noisy)
383             pr("%s cannot carry planes\n", prship(sp));
384         return 0;
385     }
386     count_planes(sp);
387     if (load_unload == LOAD &&
388         sp->shp_nchoppers >= mcp->m_nchoppers &&
389         sp->shp_nxlight >= mcp->m_nxlight &&
390         sp->shp_nplane >= mcp->m_nplanes) {
391         if (noisy)
392             pr("%s doesn't have room for any more planes\n", prship(sp));
393         return 0;
394     }
395     sprintf(prompt, "Plane(s) to %s %s? ",
396             load_unload == LOAD ? "load onto" : "unload from", prship(sp));
397     if (!snxtitem
398         (&ni, EF_PLANE, p = getstarg(player->argp[3], prompt, buf)))
399         return RET_SYN;
400
401     if (!still_ok_ship(sectp, sp))
402         return RET_SYN;
403
404     if (p && *p)
405         noisy &= isdigit(*p);
406
407     while (nxtitem(&ni, (s_char *)&pln)) {
408         if (pln.pln_own != player->cnum)
409             continue;
410         if (!(plchr[(int)pln.pln_type].pl_flags & P_L)
411             && !(plchr[(int)pln.pln_type].pl_flags & P_E)
412             && !(plchr[(int)pln.pln_type].pl_flags & P_K)
413             && !(plchr[(int)pln.pln_type].pl_flags & P_M)
414             ) {
415             if (noisy)
416                 pr("You can only load light planes, helos, xtra-light, or missiles onto ships.\n");
417             continue;
418         }
419         if (load_unload == LOAD && pln.pln_ship > -1) {
420             if (noisy)
421                 pr("%s is already on ship #%d!\n",
422                    prplane(&pln), pln.pln_ship);
423             continue;
424         }
425         if (load_unload == LOAD && pln.pln_land > -1) {
426             if (noisy)
427                 pr("%s is already on land unit #%d!\n",
428                    prplane(&pln), pln.pln_land);
429             continue;
430         }
431
432         /* Plane sanity done */
433         /* Find the right ship */
434         if (load_unload == UNLOAD) {
435             if (pln.pln_ship != sp->shp_uid)
436                 continue;
437         } else if (sp->shp_x != pln.pln_x || sp->shp_y != pln.pln_y)
438             continue;
439
440         /* ship to (plane or missle) sanity */
441         if (!can_be_on_ship(pln.pln_uid, sp->shp_uid)) {
442             if (plchr[(int)pln.pln_type].pl_flags & P_L) {
443                 strcpy(buf, "planes");
444             } else if (plchr[(int)pln.pln_type].pl_flags & P_K) {
445                 strcpy(buf, "choppers");
446             } else if (plchr[(int)pln.pln_type].pl_flags & P_M) {
447                 strcpy(buf, "missiles");
448             } else if (plchr[(int)pln.pln_type].pl_flags & P_E) {
449                 strcpy(buf, "extra light planes");
450             }                   /* else impossible */
451             if (noisy)
452                 pr("%s cannot carry %s.\n", prship(sp), buf);
453             continue;
454         }
455         /* Fit plane on ship */
456         if (load_unload == LOAD) {
457             if (!put_plane_on_ship(&pln, sp)) {
458                 if (noisy)
459                     pr("Can't put plane %d on this ship!\n", pln.pln_uid);
460                 continue;
461             }
462             sprintf(buf, "loaded on your %s at %s",
463                     prship(sp), xyas(sp->shp_x, sp->shp_y, sp->shp_own));
464             gift(sp->shp_own, player->cnum, (s_char *)&pln, EF_PLANE, buf);
465             makelost(EF_PLANE, pln.pln_own, pln.pln_uid, pln.pln_x,
466                      pln.pln_y);
467             pln.pln_own = sp->shp_own;
468             makenotlost(EF_PLANE, pln.pln_own, pln.pln_uid, pln.pln_x,
469                         pln.pln_y);
470             pln.pln_mission = 0;
471             putplane(pln.pln_uid, &pln);
472         } else {
473             if (!take_plane_off_ship(&pln, sp)) {
474                 pr("Unable to take plane off ship!\n");
475                 logerror("load: plane %d could not be taken off ship %d\n",
476                          pln.pln_uid, sp->shp_uid);
477                 continue;
478             }
479             sprintf(buf, "unloaded in your %s at %s",
480                     dchr[sectp->sct_type].d_name,
481                     xyas(sectp->sct_x, sectp->sct_y, sectp->sct_own));
482             gift(sectp->sct_own, player->cnum, (s_char *)&pln,
483                  EF_PLANE, buf);
484             makelost(EF_PLANE, pln.pln_own, pln.pln_uid, pln.pln_x,
485                      pln.pln_y);
486             pln.pln_own = sectp->sct_own;
487             makenotlost(EF_PLANE, pln.pln_own, pln.pln_uid, pln.pln_x,
488                         pln.pln_y);
489             putplane(pln.pln_uid, &pln);
490         }
491         pr("%s %s %s at %s.\n",
492            prplane(&pln),
493            (load_unload == UNLOAD) ?
494            "unloaded from" : "loaded onto",
495            prship(sp), xyas(sp->shp_x, sp->shp_y, player->cnum));
496         loaded = 1;
497     }
498     *nshipsp += loaded;
499     return 0;
500 }
501
502 static int
503 load_land_ship(struct sctstr *sectp, struct shpstr *sp, int noisy,
504                int load_unload, int *nshipsp)
505 {
506     struct nstr_item pni, ni;
507     struct lndstr land;
508     struct plnstr plane;
509     int loaded = 0;
510     s_char *p;
511     s_char prompt[512];
512     s_char buf[1024];
513     int load_spy = 0;
514
515     count_units(sp);
516     if (load_unload == LOAD) {
517         if (opt_LANDSPIES) {
518             if ((mchr[(int)sp->shp_type].m_flags & M_SUB) &&
519                 (mchr[(int)sp->shp_type].m_nland == 0)) {
520                 if (sp->shp_nland >= 2) {
521                     pr("Non-land unit carrying subs can only carry up to two spy units.\n");
522                     return 0;
523                 }
524                 /* Eh, let 'em load a spy only */
525                 load_spy = 1;
526             }
527         }
528         if ((!load_spy) &&
529             (sp->shp_nland >= mchr[(int)sp->shp_type].m_nland)) {
530             if (noisy) {
531                 if (mchr[(int)sp->shp_type].m_nland)
532                     pr("%s doesn't have room for any more land units!\n",
533                        prship(sp));
534                 else
535                     pr("%s cannot carry land units!\n", prship(sp));
536             }
537             return 0;
538         }
539     }
540     sprintf(prompt, "Land unit(s) to %s %s? ",
541             load_unload == LOAD ? "load onto" : "unload from", prship(sp));
542     if (!snxtitem
543         (&ni, EF_LAND, p = getstarg(player->argp[3], prompt, buf)))
544         return RET_SYN;
545
546     if (!still_ok_ship(sectp, sp))
547         return RET_SYN;
548
549     if (p && *p)
550         noisy &= isdigit(*p);
551
552     while (nxtitem(&ni, (s_char *)&land)) {
553         if (land.lnd_own != player->cnum)
554             continue;
555
556         if (load_unload == LOAD) {
557             if (land.lnd_ship > -1) {
558                 if (noisy)
559                     pr("%s is already on ship #%d!\n",
560                        prland(&land), land.lnd_ship);
561                 continue;
562             }
563             if (land.lnd_land > -1) {
564                 if (noisy)
565                     pr("%s is already on land #%d!\n",
566                        prland(&land), land.lnd_land);
567                 continue;
568             }
569             lnd_count_units(&land);
570             if (land.lnd_nland > 0) {
571                 if (noisy)
572                     pr("%s cannot be loaded since it is carrying units\n",
573                        prland(&land));
574                 continue;
575             }
576             if (lchr[(int)land.lnd_type].l_flags & L_HEAVY) {
577                 if (noisy)
578                     pr("%s is too heavy to load.\n", prland(&land));
579                 continue;
580             }
581             if (load_spy && !(lchr[(int)land.lnd_type].l_flags & L_SPY)) {
582                 if (noisy)
583                     pr("Subs can only carry spy units.\n");
584                 continue;
585             }
586         }
587
588         /* Unit sanity done */
589         /* Find the right ship */
590         if (load_unload == UNLOAD) {
591             if (land.lnd_ship != sp->shp_uid)
592                 continue;
593             if (land.lnd_land > -1)
594                 continue;
595         } else if (sp->shp_x != land.lnd_x || sp->shp_y != land.lnd_y)
596             continue;
597
598         if ((!(lchr[(int)land.lnd_type].l_flags & L_LIGHT)) &&
599             (!((mchr[(int)sp->shp_type].m_flags & M_SUPPLY) &&
600                (!(mchr[(int)sp->shp_type].m_flags & M_SUB))))) {
601             if (noisy) {
602                 pr("You can only load light units onto ships,\n");
603                 pr("unless the ship is a non-sub supply ship\n");
604                 pr("%s not loaded\n", prland(&land));
605             }
606             continue;
607         }
608         /* Fit unit on ship */
609         if (load_unload == LOAD) {
610             count_units(sp);
611             /* We have to check again, since it may have changed */
612             if (opt_LANDSPIES) {
613                 if ((mchr[(int)sp->shp_type].m_flags & M_SUB) &&
614                     (mchr[(int)sp->shp_type].m_nland == 0)) {
615                     if (sp->shp_nland >= 2) {
616                         pr("Non-land unit carrying subs can only carry up to two spy units.\n");
617                         return 0;
618                     }
619                     /* Eh, let 'em load a spy only */
620                     load_spy = 1;
621                 }
622             }
623             if ((!load_spy) &&
624                 (sp->shp_nland >= mchr[(int)sp->shp_type].m_nland)) {
625                 if (noisy) {
626                     if (mchr[(int)sp->shp_type].m_nland)
627                         pr("%s doesn't have room for any more land units!\n", prship(sp));
628                     else
629                         pr("%s cannot carry land units!\n", prship(sp));
630                 }
631                 return 0;
632             }
633 #if 0
634             if (sp->shp_nland >= mchr[(int)sp->shp_type].m_nland) {
635                 if (noisy)
636                     if (mchr[(int)sp->shp_type].m_nland)
637                         pr("%s doesn't have room for any more land units!\n", prship(sp));
638                     else
639                         pr("%s cannot carry land units!\n", prship(sp));
640                 break;
641             }
642 #endif
643             sprintf(buf, "loaded on your %s at %s",
644                     prship(sp), xyas(sp->shp_x, sp->shp_y, sp->shp_own));
645             gift(sp->shp_own, player->cnum, (s_char *)&land, EF_LAND, buf);
646             makelost(EF_LAND, land.lnd_own, land.lnd_uid, land.lnd_x,
647                      land.lnd_y);
648             land.lnd_own = sp->shp_own;
649             makenotlost(EF_LAND, land.lnd_own, land.lnd_uid, land.lnd_x,
650                         land.lnd_y);
651             land.lnd_ship = sp->shp_uid;
652             land.lnd_harden = 0;
653             land.lnd_mission = 0;
654             resupply_all(&land);
655             sp->shp_nland++;
656             putland(land.lnd_uid, &land);
657             if (!has_supply(&land))
658                 pr("WARNING: %s is out of supply!\n", prland(&land));
659             putship(sp->shp_uid, sp);
660             snxtitem_xy(&pni, EF_PLANE, land.lnd_x, land.lnd_y);
661             while (nxtitem(&pni, (s_char *)&plane)) {
662                 if (plane.pln_flags & PLN_LAUNCHED)
663                     continue;
664                 if (plane.pln_land != land.lnd_uid)
665                     continue;
666                 sprintf(buf, "loaded on %s", prship(sp));
667                 gift(sp->shp_own, player->cnum, (s_char *)&plane,
668                      EF_PLANE, buf);
669                 makelost(EF_PLANE, plane.pln_own, plane.pln_uid,
670                          plane.pln_x, plane.pln_y);
671                 plane.pln_own = sp->shp_own;
672                 makenotlost(EF_PLANE, plane.pln_own, plane.pln_uid,
673                             plane.pln_x, plane.pln_y);
674                 plane.pln_mission = 0;
675                 putplane(plane.pln_uid, &plane);
676             }
677         } else {
678             sprintf(buf, "unloaded in your %s at %s",
679                     dchr[sectp->sct_type].d_name,
680                     xyas(sectp->sct_x, sectp->sct_y, sectp->sct_own));
681
682             /* Spies are unloaded quietly, others aren't */
683             if (!(lchr[(int)land.lnd_type].l_flags & L_SPY)) {
684                 gift(sectp->sct_own, player->cnum, (s_char *)&land,
685                      EF_LAND, buf);
686                 makelost(EF_LAND, land.lnd_own, land.lnd_uid,
687                          land.lnd_x, land.lnd_y);
688                 land.lnd_own = sectp->sct_own;
689                 makenotlost(EF_LAND, land.lnd_own, land.lnd_uid,
690                             land.lnd_x, land.lnd_y);
691             }
692
693             land.lnd_ship = (-1);
694             sp->shp_nland--;
695             putland(land.lnd_uid, &land);
696             putship(sp->shp_uid, sp);
697
698             /* Spies are unloaded quietly, others aren't, and
699                in the off chance they can carry a plane (missile?)
700                they are quietly unloaded too. */
701             if (!(lchr[(int)land.lnd_type].l_flags & L_SPY)) {
702                 snxtitem_xy(&pni, EF_PLANE, land.lnd_x, land.lnd_y);
703                 while (nxtitem(&pni, (s_char *)&plane)) {
704                     if (plane.pln_flags & PLN_LAUNCHED)
705                         continue;
706                     if (plane.pln_land != land.lnd_uid)
707                         continue;
708                     sprintf(buf, "unloaded at %s",
709                             xyas(plane.pln_x, plane.pln_y,
710                                  sectp->sct_own));
711                     gift(sectp->sct_own, player->cnum, (s_char *)&plane,
712                          EF_PLANE, buf);
713                     makelost(EF_PLANE, plane.pln_own, plane.pln_uid,
714                              plane.pln_x, plane.pln_y);
715                     plane.pln_own = sectp->sct_own;
716                     makenotlost(EF_PLANE, plane.pln_own, plane.pln_uid,
717                                 plane.pln_x, plane.pln_y);
718                     plane.pln_mission = 0;
719                     putplane(plane.pln_uid, &plane);
720                 }
721             }
722         }
723         pr("%s %s %s at %s.\n",
724            prland(&land),
725            (load_unload == UNLOAD) ?
726            "unloaded from" : "loaded onto",
727            prship(sp), xyas(sp->shp_x, sp->shp_y, player->cnum));
728         loaded = 1;
729     }
730     *nshipsp += loaded;
731     return 0;
732 }
733
734 static int
735 load_comm_ship(struct sctstr *sectp, struct shpstr *sp,
736                struct ichrstr *ich, int load_unload, int *nshipsp)
737 {
738     register int item = ich->i_vtype;
739     register int max_amt;
740     register int move_amt;
741     register int ship_amt;
742     register int sect_amt;
743     int amount;
744     int upto = 0, abs_max;
745     s_char prompt[512];
746     s_char *p;
747     s_char buf[1024];
748
749     sprintf(prompt, "Number of %s to %s %s at %s? ",
750             ich->i_name,
751             (load_unload == UNLOAD) ?
752             "unload from" : "load onto",
753             prship(sp), xyas(sp->shp_x, sp->shp_y, player->cnum));
754     if (!(p = getstarg(player->argp[3], prompt, buf)) || !*p)
755         return RET_SYN;
756
757     if (!still_ok_ship(sectp, sp))
758         return RET_SYN;
759
760     amount = atoi(p);
761     if (amount < 0) {
762         /* We want to load up to this amount */
763         upto = -(amount);
764         load_unload = LOAD;
765     } else if (!amount)
766         return 0;
767     ship_amt = getvar(item, (s_char *)sp, EF_SHIP);
768     sect_amt = getvar(item, (s_char *)sectp, EF_SECTOR);
769     if (sectp->sct_oldown != player->cnum && item == V_CIVIL) {
770         pr("%s civilians refuse to %s at %s!\n",
771            load_unload == UNLOAD ? "Your" : "Foreign",
772            load_unload == UNLOAD ?
773            "disembark" : "board",
774            xyas(sectp->sct_x, sectp->sct_y, player->cnum));
775         return 0;
776     }
777     if (load_unload == UNLOAD) {
778         abs_max = max_amt = min(9999 - sect_amt, ship_amt);
779     } else {
780         struct mchrstr *vbase;
781         vbase = &mchr[(int)sp->shp_type];
782         abs_max = max_amt = vl_find(item, vbase->m_vtype,
783                                     vbase->m_vamt, (int)vbase->m_nv);
784         max_amt = min(sect_amt, max_amt - ship_amt);
785     }
786     if (max_amt <= 0 && !upto)
787         return 0;
788     if (upto) {
789         move_amt = upto - ship_amt;
790         if (move_amt > sect_amt)
791             move_amt = sect_amt;
792         if (ship_amt + move_amt > abs_max)
793             move_amt = abs_max - ship_amt;
794     } else
795         move_amt = load_unload * min(amount, max_amt);
796     if (!move_amt)
797         return 0;
798
799     if (!want_to_abandon(sectp, item, move_amt, 0))
800         return RET_FAIL;
801     if (!still_ok_ship(sectp, sp))
802         return RET_SYN;
803     putvar(item, sect_amt - move_amt, (s_char *)sectp, EF_SECTOR);
804     putvar(item, ship_amt + move_amt, (s_char *)sp, EF_SHIP);
805     if (load_unload == LOAD) {
806         pr("%d %s loaded onto %s at %s\n",
807            move_amt,
808            ich->i_name,
809            prship(sp), xyas(sp->shp_x, sp->shp_y, player->cnum));
810         if (sp->shp_own != player->cnum) {
811             sprintf(buf, "%s loaded %d %s onto %s at %s\n",
812                     cname(player->cnum),
813                     move_amt,
814                     ich->i_name,
815                     prship(sp), xyas(sp->shp_x, sp->shp_y, sp->shp_own));
816             wu(0, sp->shp_own, buf);
817         }
818     } else {
819         pr("%d %s unloaded from %s at %s\n",
820            -move_amt,
821            ich->i_name,
822            prship(sp), xyas(sp->shp_x, sp->shp_y, player->cnum));
823         if (sectp->sct_own != player->cnum) {
824             sprintf(buf, "%s unloaded %d %s from %s at %s\n",
825                     cname(player->cnum),
826                     -move_amt,
827                     ich->i_name,
828                     prship(sp),
829                     xyas(sp->shp_x, sp->shp_y, sectp->sct_own));
830             wu(0, sectp->sct_own, buf);
831         }
832     }
833     ++(*nshipsp);
834     return 0;
835 }
836
837 static int
838 load_plane_land(struct sctstr *sectp, struct lndstr *lp, int noisy,
839                 int load_unload, int *nunitsp)
840 {
841     struct nstr_item ni;
842     struct plnstr pln;
843     int loaded = 0;
844     s_char *p;
845     s_char prompt[512];
846     s_char buf[1024];
847
848     if (!(lchr[(int)lp->lnd_type].l_flags & L_XLIGHT)) {
849         if (noisy)
850             pr("%s cannot carry extra-light planes.\n", prland(lp));
851         return 0;
852     }
853     count_land_planes(lp);
854     if (load_unload == LOAD && lp->lnd_nxlight >= lp->lnd_maxlight) {
855         if (noisy)
856             pr("%s doesn't have room for any more extra-light planes\n",
857                prland(lp));
858         return 0;
859     }
860     sprintf(prompt, "Plane(s) to %s %s? ",
861             load_unload == LOAD ? "load onto" : "unload from", prland(lp));
862     if (!snxtitem
863         (&ni, EF_PLANE, p = getstarg(player->argp[3], prompt, buf)))
864         return RET_SYN;
865
866     if (!still_ok_land(sectp, lp))
867         return RET_SYN;
868
869     if (p && *p)
870         noisy &= isdigit(*p);
871
872     if (sectp->sct_own != player->cnum && load_unload == LOAD) {
873         pr("Sector %s is not yours.\n",
874            xyas(lp->lnd_x, lp->lnd_y, player->cnum));
875         return 0;
876     }
877
878     while (nxtitem(&ni, (s_char *)&pln)) {
879         if (pln.pln_own != player->cnum)
880             continue;
881
882         if (!(plchr[(int)pln.pln_type].pl_flags & P_E)) {
883             if (noisy)
884                 pr("You can only load xlight planes onto units.\n");
885             continue;
886         }
887
888         if (load_unload == LOAD && pln.pln_ship > -1) {
889             if (noisy)
890                 pr("%s is already on ship #%d!\n",
891                    prplane(&pln), pln.pln_ship);
892             continue;
893         }
894         if (load_unload == LOAD && pln.pln_land > -1) {
895             if (noisy)
896                 pr("%s is already on unit #%d!\n",
897                    prplane(&pln), pln.pln_land);
898             continue;
899         }
900         /* Plane sanity done */
901         /* Find the right unit */
902         if (load_unload == UNLOAD) {
903             if (pln.pln_land != lp->lnd_uid)
904                 continue;
905         } else if (lp->lnd_x != pln.pln_x || lp->lnd_y != pln.pln_y)
906             continue;
907
908         /* Fit plane on unit */
909         if (load_unload == LOAD) {
910             if (!put_plane_on_land(&pln, lp)) {
911                 if (noisy)
912                     pr("Can't put plane %d on this unit!\n", pln.pln_uid);
913                 continue;
914             }
915             sprintf(buf, "loaded on %s at %s",
916                     prland(lp), xyas(lp->lnd_x, lp->lnd_y, lp->lnd_own));
917             gift(lp->lnd_own, player->cnum, (s_char *)&pln, EF_PLANE, buf);
918             makelost(EF_PLANE, pln.pln_own, pln.pln_uid, pln.pln_x,
919                      pln.pln_y);
920             pln.pln_own = lp->lnd_own;
921             makenotlost(EF_PLANE, pln.pln_own, pln.pln_uid, pln.pln_x,
922                         pln.pln_y);
923             putplane(pln.pln_uid, &pln);
924         } else {
925             if (!take_plane_off_land(&pln, lp)) {
926                 pr("Unable to take plane off unit!\n");
927                 logerror("load: plane %d could not be taken off unit %d\n",
928                          pln.pln_uid, lp->lnd_uid);
929                 continue;
930             }
931             sprintf(buf, "unloaded at your sector at %s",
932                     xyas(sectp->sct_x, sectp->sct_y, sectp->sct_own));
933             gift(sectp->sct_own, player->cnum, (s_char *)&pln,
934                  EF_PLANE, buf);
935             makelost(EF_PLANE, pln.pln_own, pln.pln_uid, pln.pln_x,
936                      pln.pln_y);
937             pln.pln_own = sectp->sct_own;
938             makenotlost(EF_PLANE, pln.pln_own, pln.pln_uid, pln.pln_x,
939                         pln.pln_y);
940             putplane(pln.pln_uid, &pln);
941         }
942         pr("%s %s %s at %s.\n",
943            prplane(&pln),
944            (load_unload == UNLOAD) ?
945            "unloaded from" : "loaded onto",
946            prland(lp), xyas(lp->lnd_x, lp->lnd_y, player->cnum));
947         loaded = 1;
948     }
949     *nunitsp += loaded;
950     return 0;
951 }
952
953 static int
954 load_comm_land(struct sctstr *sectp, struct lndstr *lp,
955                struct ichrstr *ich, int load_unload, int *nunitsp)
956 {
957     register int item = ich->i_vtype;
958     register int max_amt;
959     register int move_amt;
960     register int land_amt;
961     register int sect_amt;
962     int amount;
963     int upto = 0, abs_max;
964     s_char prompt[512];
965     s_char *p;
966     s_char buf[1024];
967
968     sprintf(prompt, "Number of %s to %s %s at %s? ",
969             ich->i_name,
970             (load_unload == UNLOAD) ?
971             "unload from" : "load onto",
972             prland(lp), xyas(lp->lnd_x, lp->lnd_y, player->cnum));
973     if (!(p = getstarg(player->argp[3], prompt, buf)) || !*p)
974         return RET_SYN;
975
976     if (!still_ok_land(sectp, lp))
977         return RET_SYN;
978
979     amount = atoi(p);
980     if (amount < 0) {
981         /* We want to load up to this amount */
982         upto = -(amount);
983         load_unload = LOAD;
984     } else if (!amount)
985         return 0;
986
987     if (sectp->sct_own != player->cnum && load_unload == LOAD) {
988         pr("Sector %s is not yours.\n",
989            xyas(lp->lnd_x, lp->lnd_y, player->cnum));
990         return 0;
991     }
992
993     land_amt = getvar(item, (s_char *)lp, EF_LAND);
994     sect_amt = getvar(item, (s_char *)sectp, EF_SECTOR);
995     if (sectp->sct_oldown != player->cnum && item == V_CIVIL) {
996         pr("%s civilians refuse to %s at %s!\n",
997            load_unload == UNLOAD ? "Your" : "Foreign",
998            load_unload == UNLOAD ?
999            "disembark" : "board",
1000            xyas(sectp->sct_x, sectp->sct_y, player->cnum));
1001         return 0;
1002     }
1003     if (load_unload == UNLOAD) {
1004         abs_max = max_amt = min(9999 - sect_amt, land_amt);
1005     } else {
1006         struct lchrstr *vbase;
1007         vbase = &lchr[(int)lp->lnd_type];
1008         abs_max = max_amt = vl_find(item, vbase->l_vtype,
1009                                     vbase->l_vamt, (int)vbase->l_nv);
1010         max_amt = min(sect_amt, max_amt - land_amt);
1011     }
1012     if ((max_amt <= 0) && (upto == 0))
1013         return 0;
1014     if (upto) {
1015         move_amt = upto - land_amt;
1016         if (land_amt + move_amt > abs_max)
1017             move_amt = abs_max - land_amt;
1018         if (move_amt > sect_amt)
1019             move_amt = sect_amt;
1020     } else
1021         move_amt = load_unload * min(amount, max_amt);
1022     if (move_amt == 0)
1023         return 0;
1024     putvar(item, sect_amt - move_amt, (s_char *)sectp, EF_SECTOR);
1025     putvar(item, land_amt + move_amt, (s_char *)lp, EF_LAND);
1026
1027     /* Did we put mils onto this unit? If so, reset the fortification */
1028     if (item == V_MILIT && move_amt > 0)
1029         lp->lnd_harden = 0;
1030     if (load_unload == LOAD) {
1031         pr("%d %s loaded onto %s at %s\n",
1032            move_amt,
1033            ich->i_name,
1034            prland(lp), xyas(lp->lnd_x, lp->lnd_y, player->cnum));
1035         if (lp->lnd_own != player->cnum) {
1036             sprintf(buf, "%s loaded %d %s onto %s at %s\n",
1037                     cname(player->cnum),
1038                     move_amt,
1039                     ich->i_name,
1040                     prland(lp), xyas(lp->lnd_x, lp->lnd_y, lp->lnd_own));
1041             wu(0, lp->lnd_own, buf);
1042         }
1043     } else {
1044         pr("%d %s unloaded from %s at %s\n",
1045            -move_amt,
1046            ich->i_name,
1047            prland(lp), xyas(lp->lnd_x, lp->lnd_y, player->cnum));
1048         if (sectp->sct_own != player->cnum) {
1049             sprintf(buf, "%s unloaded %d %s from %s at %s\n",
1050                     cname(player->cnum),
1051                     -move_amt,
1052                     ich->i_name,
1053                     prland(lp),
1054                     xyas(lp->lnd_x, lp->lnd_y, sectp->sct_own));
1055             wu(0, sectp->sct_own, buf);
1056         }
1057     }
1058
1059     ++(*nunitsp);
1060     return 0;
1061 }
1062
1063 static int
1064 load_land_land(struct sctstr *sectp, struct lndstr *lp, int noisy,
1065                int load_unload, int *nunitsp)
1066 {
1067     struct nstr_item pni, ni;
1068     struct lndstr land;
1069     struct plnstr plane;
1070     int loaded = 0;
1071     s_char *p;
1072     s_char prompt[512];
1073     s_char buf[1024];
1074
1075     lnd_count_units(lp);
1076
1077     if (load_unload == LOAD && lp->lnd_nland >= lp->lnd_maxland) {
1078         if (noisy) {
1079             if (lp->lnd_nland)
1080                 pr("%s doesn't have room for any more land units!\n",
1081                    prland(lp));
1082             else
1083                 pr("%s cannot carry land units!\n", prland(lp));
1084         }
1085         return 0;
1086     }
1087     sprintf(prompt, "Land unit(s) to %s %s? ",
1088             load_unload == LOAD ? "load onto" : "unload from", prland(lp));
1089     if (!snxtitem
1090         (&ni, EF_LAND, p = getstarg(player->argp[3], prompt, buf)))
1091         return RET_SYN;
1092
1093     if (!still_ok_land(sectp, lp))
1094         return RET_SYN;
1095
1096     if (p && *p)
1097         noisy &= isdigit(*p);
1098
1099     while (nxtitem(&ni, (s_char *)&land)) {
1100
1101         if (land.lnd_own != player->cnum)
1102             continue;
1103
1104         if (load_unload == LOAD) {
1105             if (land.lnd_ship > -1) {
1106                 if (noisy)
1107                     pr("%s is already on ship #%d!\n",
1108                        prland(&land), land.lnd_ship);
1109                 continue;
1110             }
1111             if (land.lnd_land > -1) {
1112                 if (noisy)
1113                     pr("%s is already on land #%d!\n",
1114                        prland(&land), land.lnd_land);
1115                 continue;
1116             }
1117             lnd_count_units(&land);
1118             if (land.lnd_nland > 0) {
1119                 if (noisy)
1120                     pr("%s cannot be loaded since it is carrying units\n",
1121                        prland(&land));
1122                 continue;
1123             }
1124             if (land.lnd_uid == lp->lnd_uid) {
1125                 if (noisy)
1126                     pr("%s can't be loaded onto itself!\n", prland(&land));
1127                 continue;
1128             }
1129             if (lchr[(int)land.lnd_type].l_flags & L_HEAVY) {
1130                 if (noisy)
1131                     pr("%s is too heavy to load.\n", prland(&land));
1132                 continue;
1133             }
1134         }
1135
1136         /* Unit sanity done */
1137         /* Find the right ship */
1138         if (load_unload == UNLOAD) {
1139             if (land.lnd_land != lp->lnd_uid)
1140                 continue;
1141             if (land.lnd_ship > -1)
1142                 continue;
1143         } else if (lp->lnd_x != land.lnd_x || lp->lnd_y != land.lnd_y)
1144             continue;
1145
1146         /* Fit unit on ship */
1147         if (load_unload == LOAD) {
1148             lnd_count_units(lp);
1149             if (lp->lnd_nland >= lp->lnd_maxland) {
1150                 if (noisy) {
1151                     if (lp->lnd_nland)
1152                         pr("%s doesn't have room for any more land units!\n", prland(lp));
1153                     else
1154                         pr("%s cannot carry land units!\n", prland(lp));
1155                 }
1156                 break;
1157             }
1158             sprintf(buf, "loaded on your %s at %s",
1159                     prland(lp), xyas(lp->lnd_x, lp->lnd_y, lp->lnd_own));
1160             gift(lp->lnd_own, player->cnum, (s_char *)&land, EF_LAND, buf);
1161             makelost(EF_LAND, land.lnd_own, land.lnd_uid, land.lnd_x,
1162                      land.lnd_y);
1163             land.lnd_own = lp->lnd_own;
1164             makenotlost(EF_LAND, land.lnd_own, land.lnd_uid, land.lnd_x,
1165                         land.lnd_y);
1166             land.lnd_land = lp->lnd_uid;
1167             land.lnd_harden = 0;
1168             land.lnd_mission = 0;
1169             resupply_all(&land);
1170             lp->lnd_nland++;
1171             putland(land.lnd_uid, &land);
1172             if (!has_supply(&land))
1173                 pr("WARNING: %s is out of supply!\n", prland(&land));
1174             putland(lp->lnd_uid, lp);
1175             snxtitem_xy(&pni, EF_PLANE, land.lnd_x, land.lnd_y);
1176             while (nxtitem(&pni, (s_char *)&plane)) {
1177                 if (plane.pln_flags & PLN_LAUNCHED)
1178                     continue;
1179                 if (plane.pln_land != land.lnd_uid)
1180                     continue;
1181                 sprintf(buf, "loaded on %s", prland(lp));
1182                 gift(lp->lnd_own, player->cnum, (s_char *)&plane,
1183                      EF_PLANE, buf);
1184                 makelost(EF_PLANE, plane.pln_own, plane.pln_uid,
1185                          plane.pln_x, plane.pln_y);
1186                 plane.pln_own = lp->lnd_own;
1187                 makenotlost(EF_PLANE, plane.pln_own, plane.pln_uid,
1188                             plane.pln_x, plane.pln_y);
1189                 plane.pln_mission = 0;
1190                 putplane(plane.pln_uid, &plane);
1191             }
1192         } else {
1193             sprintf(buf, "unloaded in your %s at %s",
1194                     dchr[sectp->sct_type].d_name,
1195                     xyas(sectp->sct_x, sectp->sct_y, sectp->sct_own));
1196             gift(sectp->sct_own, player->cnum, (s_char *)&land,
1197                  EF_LAND, buf);
1198             makelost(EF_LAND, land.lnd_own, land.lnd_uid, land.lnd_x,
1199                      land.lnd_y);
1200             land.lnd_own = sectp->sct_own;
1201             makenotlost(EF_LAND, land.lnd_own, land.lnd_uid, land.lnd_x,
1202                         land.lnd_y);
1203             land.lnd_land = (-1);
1204             lp->lnd_nland--;
1205             putland(land.lnd_uid, &land);
1206             putland(lp->lnd_uid, lp);
1207             snxtitem_xy(&pni, EF_PLANE, land.lnd_x, land.lnd_y);
1208             while (nxtitem(&pni, (s_char *)&plane)) {
1209                 if (plane.pln_flags & PLN_LAUNCHED)
1210                     continue;
1211                 if (plane.pln_land != land.lnd_uid)
1212                     continue;
1213                 sprintf(buf, "unloaded at %s",
1214                         xyas(plane.pln_x, plane.pln_y, sectp->sct_own));
1215                 gift(sectp->sct_own, player->cnum, (s_char *)&plane,
1216                      EF_PLANE, buf);
1217                 makelost(EF_PLANE, plane.pln_own, plane.pln_uid,
1218                          plane.pln_x, plane.pln_y);
1219                 plane.pln_own = sectp->sct_own;
1220                 makenotlost(EF_PLANE, plane.pln_own, plane.pln_uid,
1221                             plane.pln_x, plane.pln_y);
1222                 plane.pln_mission = 0;
1223                 putplane(plane.pln_uid, &plane);
1224             }
1225         }
1226         pr("%s %s %s at %s.\n",
1227            prland(&land),
1228            (load_unload == UNLOAD) ?
1229            "unloaded from" : "loaded onto",
1230            prland(lp), xyas(lp->lnd_x, lp->lnd_y, player->cnum));
1231         loaded = 1;
1232     }
1233     *nunitsp += loaded;
1234     return 0;
1235 }