]> git.pond.sub.org Git - empserver/blob - src/lib/commands/load.c
load unload lload lunload: Fix for areas starting with a digit
[empserver] / src / lib / commands / load.c
1 /*
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
5  *
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.
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, see <http://www.gnu.org/licenses/>.
18  *
19  *  ---
20  *
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.
24  *
25  *  ---
26  *
27  *  load.c: load/unload goods from a sector onto a ship or land unit
28  *
29  *  Known contributors to this file:
30  *     David Sharnoff, 1987
31  *     Ken Stevens, 1995 (rewritten)
32  *     Steve McClure, 1998-2000
33  *     Markus Armbruster, 2004-2017
34  */
35
36 #include <config.h>
37
38 #include <ctype.h>
39 #include "commands.h"
40 #include "item.h"
41 #include "land.h"
42 #include "optlist.h"
43 #include "plague.h"
44 #include "plane.h"
45 #include "ship.h"
46 #include "unit.h"
47
48 static int load_plane_ship(struct sctstr *sectp, struct shpstr *sp,
49                            int noisy, int loading, int *nshipsp);
50 static int load_land_ship(struct sctstr *sectp, struct shpstr *sp,
51                           int noisy, int loading, int *nshipsp);
52 static int load_comm_ship(struct sctstr *sectp, struct shpstr *sp,
53                           struct ichrstr *ich, int loading,
54                           int *nshipsp);
55 static int load_plane_land(struct sctstr *sectp, struct lndstr *lp,
56                            int noisy, int loading, int *nunitsp);
57 static int load_land_land(struct sctstr *sectp, struct lndstr *lp,
58                           int noisy, int loading, int *nunitsp);
59 static int load_comm_land(struct sctstr *sectp, struct lndstr *lp,
60                           struct ichrstr *ich, int loading,
61                           int *nunitsp);
62
63 int
64 load(void)
65 {
66     int loading = **player->argp == 'l';
67     int noisy;
68     int type;
69     struct nstr_item nbst;
70     struct ichrstr *ich;
71     int nships;
72     struct sctstr sect;
73     struct shpstr ship;
74     int retval;
75     char *p;
76     char buf[1024];
77
78     p = getstarg(player->argp[1],
79                  "What commodity (or 'plane' or 'land')? ", buf);
80     if (!p || !*p)
81         return RET_SYN;
82
83     if (!strncmp(p, "plane", 5))
84         type = EF_PLANE;
85     else if (!strncmp(p, "land", 4))
86         type = EF_LAND;
87     else if (NULL != (ich = item_by_name(p)))
88         type = EF_SECTOR;
89     else {
90         pr("Can't %sload '%s'\n", loading ? "" : "un", p);
91         return RET_SYN;
92     }
93
94     p = getstarg(player->argp[2], "Ship(s): ", buf);
95     if (!p || !*p)
96         return RET_SYN;
97
98     if (!snxtitem(&nbst, EF_SHIP, p, NULL))
99         return RET_SYN;
100
101     noisy = nbst.sel == NS_LIST;
102
103     nships = 0;
104     while (nxtitem(&nbst, &ship)) {
105         if (!ship.shp_own)
106             continue;
107         if (!player->owner) {
108             if (!loading || !noisy)
109                 continue;
110             if (relations_with(ship.shp_own, player->cnum) < FRIENDLY)
111                 continue;
112         }
113
114         if (!getsect(ship.shp_x, ship.shp_y, &sect))    /* XXX */
115             continue;
116         if (!sect.sct_own)
117             continue;
118         if (!player->owner) {
119             if (ship.shp_own != player->cnum)
120                 continue;
121             if (!sect_has_dock(&sect))
122                 continue;
123             if (loading) {
124                 if (noisy)
125                     pr("You don't own %s\n",
126                        xyas(sect.sct_x, sect.sct_y, player->cnum));
127                 continue;
128             }
129         }
130         if (!sect_has_dock(&sect)) {
131             if (noisy)
132                 pr("Sector %s is not a harbor or canal.\n",
133                    xyas(sect.sct_x, sect.sct_y, player->cnum));
134             continue;
135         }
136         if (!loading
137             && !player->owner
138             && relations_with(sect.sct_own, player->cnum) < FRIENDLY) {
139             if (noisy)
140                 pr("You can't unload into an unfriendly %s\n",
141                    dchr[sect.sct_type].d_name);
142             continue;
143         }
144         if (sect.sct_effic < 2) {
145             if (noisy)
146                 pr("The %s at %s is not 2%% efficient yet.\n",
147                    dchr[sect.sct_type].d_name,
148                    xyas(sect.sct_x, sect.sct_y, player->cnum));
149             continue;
150         }
151
152         if (opt_MARKET) {
153             if (ontradingblock(EF_SHIP, &ship)) {
154                 pr("You cannot load/unload an item on the trading block!\n");
155                 continue;
156             }
157         }
158
159         switch (type) {
160         case EF_PLANE:
161             retval = load_plane_ship(&sect, &ship, noisy, loading, &nships);
162             if (retval != 0)
163                 return retval;
164             break;
165         case EF_LAND:
166             retval = load_land_ship(&sect, &ship, noisy, loading, &nships);
167             if (retval != 0)
168                 return retval;
169             break;
170         case EF_SECTOR:
171             retval = load_comm_ship(&sect, &ship, ich, loading, &nships);
172             if (retval != 0)
173                 return retval;
174         }
175         /* load/unload plague */
176         if (sect.sct_pstage == PLG_INFECT
177             && ship.shp_pstage == PLG_HEALTHY)
178             ship.shp_pstage = PLG_EXPOSED;
179         if (ship.shp_pstage == PLG_INFECT
180             && sect.sct_pstage == PLG_HEALTHY)
181             sect.sct_pstage = PLG_EXPOSED;
182         putsect(&sect);
183         putship(ship.shp_uid, &ship);
184     }
185     if (!nships)
186         pr("No ships affected\n");
187     else
188         pr("%d ship%s %sloaded\n", nships, splur(nships),
189            loading ? "" : "un");
190     return RET_OK;
191 }
192
193 int
194 lload(void)
195 {
196     int loading = player->argp[0][1] == 'l';
197     int noisy;
198     int type;
199     struct nstr_item nbst;
200     struct ichrstr *ich;
201     int nunits;
202     struct sctstr sect;
203     struct lndstr land;
204     int retval;
205     char *p;
206     char buf[1024];
207
208     p = getstarg(player->argp[1],
209                  "What commodity (or 'plane' or 'land')? ", buf);
210     if (!p || !*p)
211         return RET_SYN;
212     if (!strncmp(p, "plane", 5))
213         type = EF_PLANE;
214     else if (!strncmp(p, "land", 4))
215         type = EF_LAND;
216     else if (NULL != (ich = item_by_name(p)))
217         type = EF_SECTOR;
218     else {
219         pr("Can't %sload '%s'\n", loading ? "" : "un", p);
220         return RET_SYN;
221     }
222
223     p = getstarg(player->argp[2], "Unit(s): ", buf);
224     if (!p || !*p)
225         return RET_SYN;
226
227     if (!snxtitem(&nbst, EF_LAND, p, NULL))
228         return RET_SYN;
229
230     noisy = nbst.sel == NS_LIST;
231
232     nunits = 0;
233     while (nxtitem(&nbst, &land)) {
234         if (land.lnd_own == 0)
235             continue;
236         if (!player->owner) {
237             if (!loading || !noisy)
238                 continue;
239             if (relations_with(land.lnd_own, player->cnum) != ALLIED)
240                 continue;
241         }
242
243         if (!getsect(land.lnd_x, land.lnd_y, &sect))    /* XXX */
244             continue;
245         if (!player->owner) {
246             if (land.lnd_own != player->cnum)
247                 continue;
248             if (loading) {
249                 if (noisy)
250                     pr("Sector %s is not yours.\n",
251                        xyas(sect.sct_x, sect.sct_y, player->cnum));
252                 continue;
253             }
254             if (relations_with(sect.sct_own, player->cnum) != ALLIED) {
255                 pr("Sector %s is not yours.\n",
256                    xyas(sect.sct_x, sect.sct_y, player->cnum));
257                 continue;
258             }
259         }
260
261         if (opt_MARKET) {
262             if (ontradingblock(EF_LAND, &land)) {
263                 pr("You cannot load/unload an item on the trading block!\n");
264                 continue;
265             }
266         }
267
268         switch (type) {
269         case EF_LAND:
270             retval = load_land_land(&sect, &land, noisy, loading, &nunits);
271             if (retval != 0)
272                 return retval;
273             break;
274         case EF_PLANE:
275             retval = load_plane_land(&sect, &land, noisy, loading, &nunits);
276             if (retval != 0)
277                 return retval;
278             break;
279         case EF_SECTOR:
280             retval = load_comm_land(&sect, &land, ich, loading, &nunits);
281             if (retval != 0)
282                 return retval;
283         }
284         /* load/unload plague */
285         if (sect.sct_pstage == PLG_INFECT
286             && land.lnd_pstage == PLG_HEALTHY)
287             land.lnd_pstage = PLG_EXPOSED;
288         if (land.lnd_pstage == PLG_INFECT
289             && sect.sct_pstage == PLG_HEALTHY)
290             sect.sct_pstage = PLG_EXPOSED;
291
292         putsect(&sect);
293         putland(land.lnd_uid, &land);
294     }
295     if (nunits == 0)
296         pr("No units affected\n");
297     else
298         pr("%d unit%s %sloaded\n", nunits, splur(nunits),
299            loading ? "" : "un");
300     return RET_OK;
301 }
302
303 static int
304 move_amount(int sect_amt, int unit_amt, int unit_max,
305            int loading, int amount)
306 {
307     int move_amt;
308
309     if (amount < 0)
310         move_amt = -amount - unit_amt;
311     else
312         move_amt = loading ? amount : -amount;
313     move_amt = LIMIT_TO(move_amt, -unit_amt, unit_max - unit_amt);
314     move_amt = LIMIT_TO(move_amt, sect_amt - ITEM_MAX, sect_amt);
315     return move_amt;
316 }
317
318 int
319 load_comm_ok(struct sctstr *sectp, natid unit_own,
320              i_type item, int move_amt)
321 {
322     if (!move_amt)
323         return 0;
324     if (move_amt < 0 && !player->god && unit_own != player->cnum)
325         return 0;
326     if (move_amt > 0 && !player->god && sectp->sct_own != player->cnum)
327         return 0;
328     if (sectp->sct_oldown != unit_own && item == I_CIVIL) {
329         pr("%s civilians refuse to %s at %s!\n",
330            (move_amt < 0 ? unit_own : sectp->sct_oldown) == player->cnum
331            ? "Your" : "Foreign",
332            move_amt < 0 ? "disembark" : "board",
333            xyas(sectp->sct_x, sectp->sct_y, player->cnum));
334         return 0;
335     }
336     return 1;
337 }
338
339 void
340 gift(natid givee, natid giver, void *ptr, char *mesg)
341 {
342     if (giver != givee)
343         wu(0, givee, "%s %s %s\n", cname(giver), unit_nameof(ptr), mesg);
344     unit_give_away(ptr, givee, 0);
345 }
346
347 static int
348 still_ok_ship(struct sctstr *sectp, struct shpstr *shipp)
349 {
350     if (!check_sect_ok(sectp))
351         return 0;
352     if (!check_ship_ok(shipp))
353         return 0;
354     return 1;
355 }
356
357 static int
358 still_ok_land(struct sctstr *sectp, struct lndstr *landp)
359 {
360     if (!check_sect_ok(sectp))
361         return 0;
362     if (!check_land_ok(landp))
363         return 0;
364     return 1;
365 }
366
367 static int
368 load_plane_ship(struct sctstr *sectp, struct shpstr *sp, int noisy,
369                 int loading, int *nshipsp)
370 {
371     struct nstr_item ni;
372     struct plnstr pln;
373     int loaded = 0;
374     char buf[1024];
375     char *p;
376     char prompt[512];
377     struct mchrstr *mcp = mchr + sp->shp_type;
378
379     if (mcp->m_nplanes + mcp->m_nchoppers + mcp->m_nxlight == 0) {
380         if (noisy)
381             pr("%s cannot carry planes\n", prship(sp));
382         return 0;
383     }
384     if (loading &&
385         shp_nplane(sp, NULL, NULL, NULL)
386                 >= mcp->m_nchoppers + mcp->m_nxlight + mcp->m_nplanes) {
387         if (noisy)
388             pr("%s doesn't have room for any more planes\n", prship(sp));
389         return 0;
390     }
391     sprintf(prompt, "Plane(s) to %s %s? ",
392             loading ? "load onto" : "unload from", prship(sp));
393     p = getstarg(player->argp[3], prompt, buf);
394     if (!p)
395         return RET_SYN;
396     if (!snxtitem(&ni, EF_PLANE, p, NULL))
397         return RET_SYN;
398
399     if (!still_ok_ship(sectp, sp))
400         return RET_SYN;
401
402     if (noisy)
403         noisy = ni.sel == NS_LIST;
404
405     while (nxtitem(&ni, &pln)) {
406         if (!player->owner)
407             continue;
408         if (!(plchr[(int)pln.pln_type].pl_flags & P_L)
409             && !(plchr[(int)pln.pln_type].pl_flags & P_E)
410             && !(plchr[(int)pln.pln_type].pl_flags & P_K)
411             && !(plchr[(int)pln.pln_type].pl_flags & P_M)
412             ) {
413             if (noisy)
414                 pr("You can only load light planes, helos, xtra-light, or missiles onto ships.\n");
415             continue;
416         }
417         if (loading && pln.pln_ship > -1) {
418             if (noisy)
419                 pr("%s is already on ship #%d!\n",
420                    prplane(&pln), pln.pln_ship);
421             continue;
422         }
423         if (loading && pln.pln_land > -1) {
424             if (noisy)
425                 pr("%s is already on land unit #%d!\n",
426                    prplane(&pln), pln.pln_land);
427             continue;
428         }
429         if (pln.pln_harden != 0) {
430             if (noisy)
431                 pr("%s has been hardened and can't be loaded\n",
432                    prplane(&pln));
433             continue;
434         }
435
436         if (!loading) {
437             if (pln.pln_ship != sp->shp_uid)
438                 continue;
439         } else if (sp->shp_x != pln.pln_x || sp->shp_y != pln.pln_y)
440             continue;
441
442         if (!could_be_on_ship(&pln, sp)) {
443             if (noisy) {
444                 if (plchr[(int)pln.pln_type].pl_flags & P_K)
445                     p = "choppers";
446                 else if (plchr[(int)pln.pln_type].pl_flags & P_E)
447                     p = "extra light planes";
448                 else if (plchr[(int)pln.pln_type].pl_flags & P_M)
449                     p = "missiles";
450                 else
451                     p = "planes";
452                 pr("%s cannot carry %s.\n", prship(sp), p);
453             }
454             continue;
455         }
456         /* Fit plane on ship */
457         if (loading) {
458             if (!put_plane_on_ship(&pln, sp)) {
459                 if (noisy)
460                     pr("Can't put plane %d on this ship!\n", pln.pln_uid);
461                 continue;
462             }
463             sprintf(buf, "loaded on your %s at %s",
464                     prship(sp), xyas(sp->shp_x, sp->shp_y, sp->shp_own));
465             gift(sp->shp_own, player->cnum, &pln, buf);
466             putplane(pln.pln_uid, &pln);
467         } else {
468             pln.pln_ship = -1;
469             sprintf(buf, "unloaded in your %s at %s",
470                     dchr[sectp->sct_type].d_name,
471                     xyas(sectp->sct_x, sectp->sct_y, sectp->sct_own));
472             gift(sectp->sct_own, player->cnum, &pln, buf);
473             putplane(pln.pln_uid, &pln);
474         }
475         pr("%s %s %s at %s.\n",
476            prplane(&pln),
477            loading ? "loaded onto" : "unloaded from",
478            prship(sp), xyas(sp->shp_x, sp->shp_y, player->cnum));
479         loaded = 1;
480     }
481     *nshipsp += loaded;
482     return 0;
483 }
484
485 static int
486 load_land_ship(struct sctstr *sectp, struct shpstr *sp, int noisy,
487                int loading, int *nshipsp)
488 {
489     struct nstr_item ni;
490     struct lndstr land;
491     int loaded = 0;
492     char *p;
493     char prompt[512];
494     char buf[1024];
495     int load_spy = 0;
496
497     if (loading) {
498         if ((mchr[(int)sp->shp_type].m_flags & M_SUB) &&
499             (mchr[(int)sp->shp_type].m_nland == 0)) {
500             if (shp_nland(sp) >= 2) {
501                 pr("Non-land unit carrying subs can only carry up to two spy units.\n");
502                 return 0;
503             }
504             /* Eh, let 'em load a spy only */
505             load_spy = 1;
506         }
507         if (!load_spy && shp_nland(sp) >= mchr[sp->shp_type].m_nland) {
508             if (noisy) {
509                 if (mchr[(int)sp->shp_type].m_nland)
510                     pr("%s doesn't have room for any more land units!\n",
511                        prship(sp));
512                 else
513                     pr("%s cannot carry land units!\n", prship(sp));
514             }
515             return 0;
516         }
517     }
518     sprintf(prompt, "Land unit(s) to %s %s? ",
519             loading ? "load onto" : "unload from", prship(sp));
520     p = getstarg(player->argp[3], prompt, buf);
521     if (!p)
522         return RET_SYN;
523     if (!snxtitem(&ni, EF_LAND, p, NULL))
524         return RET_SYN;
525
526     if (!still_ok_ship(sectp, sp))
527         return RET_SYN;
528
529     if (noisy)
530         noisy = ni.sel == NS_LIST;
531
532     while (nxtitem(&ni, &land)) {
533         if (!player->owner)
534             continue;
535
536         if (loading) {
537             if (land.lnd_ship > -1) {
538                 if (noisy)
539                     pr("%s is already on ship #%d!\n",
540                        prland(&land), land.lnd_ship);
541                 continue;
542             }
543             if (land.lnd_land > -1) {
544                 if (noisy)
545                     pr("%s is already on land #%d!\n",
546                        prland(&land), land.lnd_land);
547                 continue;
548             }
549             if (lnd_first_on_land(&land) >= 0) {
550                 if (noisy)
551                     pr("%s cannot be loaded since it is carrying units\n",
552                        prland(&land));
553                 continue;
554             }
555             if (lchr[(int)land.lnd_type].l_flags & L_HEAVY) {
556                 if (noisy)
557                     pr("%s is too heavy to load.\n", prland(&land));
558                 continue;
559             }
560             if (load_spy && !(lchr[(int)land.lnd_type].l_flags & L_SPY)) {
561                 if (noisy)
562                     pr("Subs can only carry spy units.\n");
563                 continue;
564             }
565         }
566
567         /* Unit sanity done */
568         /* Find the right ship */
569         if (!loading) {
570             if (land.lnd_ship != sp->shp_uid)
571                 continue;
572             if (land.lnd_land > -1)
573                 continue;
574         } else if (sp->shp_x != land.lnd_x || sp->shp_y != land.lnd_y)
575             continue;
576
577         if ((!(lchr[(int)land.lnd_type].l_flags & L_LIGHT)) &&
578             (!((mchr[(int)sp->shp_type].m_flags & M_SUPPLY) &&
579                (!(mchr[(int)sp->shp_type].m_flags & M_SUB))))) {
580             if (noisy) {
581                 pr("You can only load light units onto ships,\n");
582                 pr("unless the ship is a non-sub supply ship\n");
583                 pr("%s not loaded\n", prland(&land));
584             }
585             continue;
586         }
587         /* Fit unit on ship */
588         if (loading) {
589             /* We have to check again, since it may have changed */
590             if ((mchr[(int)sp->shp_type].m_flags & M_SUB) &&
591                 (mchr[(int)sp->shp_type].m_nland == 0)) {
592                 if (shp_nland(sp) >= 2) {
593                     pr("Non-land unit carrying subs can only carry up to two spy units.\n");
594                     return 0;
595                 }
596                 /* Eh, let 'em load a spy only */
597                 load_spy = 1;
598             }
599             if (!load_spy && shp_nland(sp) >= mchr[sp->shp_type].m_nland) {
600                 if (noisy) {
601                     if (mchr[(int)sp->shp_type].m_nland)
602                         pr("%s doesn't have room for any more land units!\n",
603                            prship(sp));
604                     else
605                         pr("%s cannot carry land units!\n", prship(sp));
606                 }
607                 return 0;
608             }
609             sprintf(buf, "loaded on your %s at %s",
610                     prship(sp), xyas(sp->shp_x, sp->shp_y, sp->shp_own));
611             gift(sp->shp_own, player->cnum, &land, buf);
612             land.lnd_ship = sp->shp_uid;
613             land.lnd_harden = 0;
614             putland(land.lnd_uid, &land);
615 #if 0
616            /*
617             * FIXME if this supplies from the sector, the putsect in
618             * load() / lload() duplicates those supplies, causing a
619             * seqno mismatch
620             */
621             if (!lnd_supply_all(&land))
622                 pr("WARNING: %s is out of supply!\n", prland(&land));
623 #else
624             if (!lnd_in_supply(&land))
625                 pr("WARNING: %s is out of supply!\n", prland(&land));
626 #endif
627         } else {
628             sprintf(buf, "unloaded in your %s at %s",
629                     dchr[sectp->sct_type].d_name,
630                     xyas(sectp->sct_x, sectp->sct_y, sectp->sct_own));
631
632             /* Spies are unloaded quietly, others aren't */
633             if (!(lchr[(int)land.lnd_type].l_flags & L_SPY))
634                 gift(sectp->sct_own, player->cnum, &land, buf);
635             land.lnd_ship = -1;
636             putland(land.lnd_uid, &land);
637         }
638         pr("%s %s %s at %s.\n",
639            prland(&land),
640            loading ? "loaded onto" : "unloaded from",
641            prship(sp), xyas(sp->shp_x, sp->shp_y, player->cnum));
642         loaded = 1;
643     }
644     *nshipsp += loaded;
645     return 0;
646 }
647
648 static int
649 load_comm_ship(struct sctstr *sectp, struct shpstr *sp,
650                struct ichrstr *ich, int loading, int *nshipsp)
651 {
652     i_type item = ich->i_uid;
653     struct mchrstr *mcp = &mchr[(int)sp->shp_type];
654     int ship_amt, sect_amt, move_amt;
655     char prompt[512];
656     char *p;
657     char buf[1024];
658
659     sprintf(prompt, "Number of %s to %s %s at %s? ",
660             ich->i_name,
661             loading ? "load onto" : "unload from",
662             prship(sp), xyas(sp->shp_x, sp->shp_y, player->cnum));
663     p = getstarg(player->argp[3], prompt, buf);
664     if (!p || !*p)
665         return RET_SYN;
666
667     if (!still_ok_ship(sectp, sp))
668         return RET_SYN;
669
670     ship_amt = sp->shp_item[item];
671     sect_amt = sectp->sct_item[item];
672     move_amt = move_amount(sect_amt, ship_amt, mcp->m_item[item],
673                            loading, atoi(p));
674     if (!load_comm_ok(sectp, sp->shp_own, item, move_amt))
675         return RET_OK;
676     if (!abandon_askyn(sectp, item, move_amt, NULL))
677         return RET_FAIL;
678     if (!still_ok_ship(sectp, sp))
679         return RET_SYN;
680     sectp->sct_item[item] = sect_amt - move_amt;
681     sp->shp_item[item] = ship_amt + move_amt;
682
683     if (move_amt >= 0) {
684         pr("%d %s loaded onto %s at %s\n",
685            move_amt, ich->i_name,
686            prship(sp), xyas(sp->shp_x, sp->shp_y, player->cnum));
687         if (sp->shp_own != player->cnum) {
688             wu(0, sp->shp_own, "%s loaded %d %s onto %s at %s\n",
689                cname(player->cnum), move_amt, ich->i_name,
690                prship(sp), xyas(sp->shp_x, sp->shp_y, sp->shp_own));
691         }
692     } else {
693         pr("%d %s unloaded from %s at %s\n",
694            -move_amt, ich->i_name,
695            prship(sp), xyas(sp->shp_x, sp->shp_y, player->cnum));
696         if (sectp->sct_own != player->cnum) {
697             wu(0, sectp->sct_own, "%s unloaded %d %s from %s at %s\n",
698                cname(player->cnum), -move_amt, ich->i_name,
699                prship(sp), xyas(sp->shp_x, sp->shp_y, sectp->sct_own));
700         }
701     }
702     ++*nshipsp;
703     return 0;
704 }
705
706 static int
707 load_plane_land(struct sctstr *sectp, struct lndstr *lp, int noisy,
708                 int loading, int *nunitsp)
709 {
710     struct nstr_item ni;
711     struct plnstr pln;
712     int loaded = 0;
713     char *p;
714     char prompt[512];
715     char buf[1024];
716     struct lchrstr *lcp = lchr + lp->lnd_type;
717
718     if (!lcp->l_nxlight) {
719         if (noisy)
720             pr("%s cannot carry extra-light planes.\n", prland(lp));
721         return 0;
722     }
723     if (loading && lnd_nxlight(lp) >= lcp->l_nxlight) {
724         if (noisy)
725             pr("%s doesn't have room for any more extra-light planes\n",
726                prland(lp));
727         return 0;
728     }
729     sprintf(prompt, "Plane(s) to %s %s? ",
730             loading ? "load onto" : "unload from", prland(lp));
731     p = getstarg(player->argp[3], prompt, buf);
732     if (!p)
733         return RET_SYN;
734     if (!snxtitem(&ni, EF_PLANE, p, NULL))
735         return RET_SYN;
736
737     if (!still_ok_land(sectp, lp))
738         return RET_SYN;
739
740     if (noisy)
741         noisy = ni.sel == NS_LIST;
742
743     while (nxtitem(&ni, &pln)) {
744         if (!player->owner)
745             continue;
746
747         if (!(plchr[(int)pln.pln_type].pl_flags & P_E)) {
748             if (noisy)
749                 pr("You can only load xlight planes onto units.\n");
750             continue;
751         }
752
753         if (loading && pln.pln_ship > -1) {
754             if (noisy)
755                 pr("%s is already on ship #%d!\n",
756                    prplane(&pln), pln.pln_ship);
757             continue;
758         }
759         if (loading && pln.pln_land > -1) {
760             if (noisy)
761                 pr("%s is already on unit #%d!\n",
762                    prplane(&pln), pln.pln_land);
763             continue;
764         }
765         if (pln.pln_harden != 0) {
766             if (noisy)
767                 pr("%s has been hardened and can't be loaded\n",
768                    prplane(&pln));
769             continue;
770         }
771
772         /* Plane sanity done */
773         /* Find the right unit */
774         if (!loading) {
775             if (pln.pln_land != lp->lnd_uid)
776                 continue;
777         } else if (lp->lnd_x != pln.pln_x || lp->lnd_y != pln.pln_y)
778             continue;
779
780         /* Fit plane on unit */
781         if (loading) {
782             if (!put_plane_on_land(&pln, lp)) {
783                 if (noisy)
784                     pr("Can't put plane %d on this unit!\n", pln.pln_uid);
785                 continue;
786             }
787             sprintf(buf, "loaded on %s at %s",
788                     prland(lp), xyas(lp->lnd_x, lp->lnd_y, lp->lnd_own));
789             gift(lp->lnd_own, player->cnum, &pln, buf);
790             putplane(pln.pln_uid, &pln);
791         } else {
792             pln.pln_land = -1;
793             sprintf(buf, "unloaded at your sector at %s",
794                     xyas(sectp->sct_x, sectp->sct_y, sectp->sct_own));
795             gift(sectp->sct_own, player->cnum, &pln, buf);
796             putplane(pln.pln_uid, &pln);
797         }
798         pr("%s %s %s at %s.\n",
799            prplane(&pln),
800            loading ? "loaded onto" : "unloaded from",
801            prland(lp), xyas(lp->lnd_x, lp->lnd_y, player->cnum));
802         loaded = 1;
803     }
804     *nunitsp += loaded;
805     return 0;
806 }
807
808 static int
809 load_comm_land(struct sctstr *sectp, struct lndstr *lp,
810                struct ichrstr *ich, int loading, int *nunitsp)
811 {
812     i_type item = ich->i_uid;
813     struct lchrstr *lcp = &lchr[(int)lp->lnd_type];
814     int land_amt, sect_amt, move_amt;
815     char prompt[512];
816     char *p;
817     char buf[1024];
818
819     sprintf(prompt, "Number of %s to %s %s at %s? ",
820             ich->i_name,
821             loading ? "load onto" : "unload from",
822             prland(lp), xyas(lp->lnd_x, lp->lnd_y, player->cnum));
823     p = getstarg(player->argp[3], prompt, buf);
824     if (!p || !*p)
825         return RET_SYN;
826
827     if (!still_ok_land(sectp, lp))
828         return RET_SYN;
829
830     land_amt = lp->lnd_item[item];
831     sect_amt = sectp->sct_item[item];
832     move_amt = move_amount(sect_amt, land_amt, lcp->l_item[item],
833                            loading, atoi(p));
834     if (!load_comm_ok(sectp, lp->lnd_own, item, move_amt))
835         return RET_OK;
836     sectp->sct_item[item] = sect_amt - move_amt;
837     lp->lnd_item[item] = land_amt + move_amt;
838
839     /* Did we put mils onto this unit? If so, reset the fortification */
840     if (item == I_MILIT && move_amt > 0)
841         lp->lnd_harden = 0;
842
843     if (move_amt >= 0) {
844         pr("%d %s loaded onto %s at %s\n",
845            move_amt, ich->i_name,
846            prland(lp), xyas(lp->lnd_x, lp->lnd_y, player->cnum));
847         if (lp->lnd_own != player->cnum) {
848             wu(0, lp->lnd_own, "%s loaded %d %s onto %s at %s\n",
849                cname(player->cnum), move_amt, ich->i_name,
850                prland(lp), xyas(lp->lnd_x, lp->lnd_y, lp->lnd_own));
851         }
852     } else {
853         pr("%d %s unloaded from %s at %s\n",
854            -move_amt, ich->i_name,
855            prland(lp), xyas(lp->lnd_x, lp->lnd_y, player->cnum));
856         if (sectp->sct_own != player->cnum) {
857             wu(0, sectp->sct_own, "%s unloaded %d %s from %s at %s\n",
858                cname(player->cnum), -move_amt, ich->i_name,
859                prland(lp), xyas(lp->lnd_x, lp->lnd_y, sectp->sct_own));
860         }
861     }
862     ++*nunitsp;
863     return 0;
864 }
865
866 static int
867 load_land_land(struct sctstr *sectp, struct lndstr *lp, int noisy,
868                int loading, int *nunitsp)
869 {
870     struct nstr_item ni;
871     struct lndstr land;
872     int loaded = 0;
873     char *p;
874     char prompt[512];
875     char buf[1024];
876
877     if (loading && lnd_nland(lp) >= lchr[lp->lnd_type].l_nland) {
878         if (noisy) {
879             if (lchr[lp->lnd_type].l_nland)
880                 pr("%s doesn't have room for any more land units!\n",
881                    prland(lp));
882             else
883                 pr("%s cannot carry land units!\n", prland(lp));
884         }
885         return 0;
886     }
887     sprintf(prompt, "Land unit(s) to %s %s? ",
888             loading ? "load onto" : "unload from", prland(lp));
889     p = getstarg(player->argp[3], prompt, buf);
890     if (!p)
891         return RET_SYN;
892     if (!snxtitem(&ni, EF_LAND, p, NULL))
893         return RET_SYN;
894
895     if (!still_ok_land(sectp, lp))
896         return RET_SYN;
897
898     if (noisy)
899         noisy = ni.sel == NS_LIST;
900
901     while (nxtitem(&ni, &land)) {
902         if (!player->owner)
903             continue;
904
905         if (loading) {
906             if (land.lnd_ship > -1) {
907                 if (noisy)
908                     pr("%s is already on ship #%d!\n",
909                        prland(&land), land.lnd_ship);
910                 continue;
911             }
912             if (land.lnd_land > -1) {
913                 if (noisy)
914                     pr("%s is already on land #%d!\n",
915                        prland(&land), land.lnd_land);
916                 continue;
917             }
918             if (lnd_first_on_land(&land) >= 0) {
919                 if (noisy)
920                     pr("%s cannot be loaded since it is carrying units\n",
921                        prland(&land));
922                 continue;
923             }
924             if (land.lnd_uid == lp->lnd_uid) {
925                 if (noisy)
926                     pr("%s can't be loaded onto itself!\n", prland(&land));
927                 continue;
928             }
929             if (lchr[(int)land.lnd_type].l_flags & (L_HEAVY | L_TRAIN)) {
930                 if (noisy)
931                     pr("%s is too heavy to load.\n", prland(&land));
932                 continue;
933             }
934         }
935
936         /* Unit sanity done */
937         /* Find the right ship */
938         if (!loading) {
939             if (land.lnd_land != lp->lnd_uid)
940                 continue;
941             if (land.lnd_ship > -1)
942                 continue;
943         } else if (lp->lnd_x != land.lnd_x || lp->lnd_y != land.lnd_y)
944             continue;
945
946         /* Fit unit on ship */
947         if (loading) {
948             if (lnd_nland(lp) >= lchr[lp->lnd_type].l_nland) {
949                 if (noisy) {
950                     if (lchr[lp->lnd_type].l_nland)
951                         pr("%s doesn't have room for any more land units!\n",
952                            prland(lp));
953                     else
954                         pr("%s cannot carry land units!\n", prland(lp));
955                 }
956                 break;
957             }
958             sprintf(buf, "loaded on your %s at %s",
959                     prland(lp), xyas(lp->lnd_x, lp->lnd_y, lp->lnd_own));
960             gift(lp->lnd_own, player->cnum, &land, buf);
961             land.lnd_land = lp->lnd_uid;
962             land.lnd_harden = 0;
963             putland(land.lnd_uid, &land);
964 #if 0
965            /* FIXME same issue as in load_land_ship() */
966             if (!lnd_supply_all(&land))
967                 pr("WARNING: %s is out of supply!\n", prland(&land));
968 #else
969             if (!lnd_in_supply(&land))
970                 pr("WARNING: %s is out of supply!\n", prland(&land));
971 #endif
972         } else {
973             sprintf(buf, "unloaded in your %s at %s",
974                     dchr[sectp->sct_type].d_name,
975                     xyas(sectp->sct_x, sectp->sct_y, sectp->sct_own));
976             gift(sectp->sct_own, player->cnum, &land, buf);
977             land.lnd_land = -1;
978             putland(land.lnd_uid, &land);
979         }
980         pr("%s %s %s at %s.\n",
981            prland(&land),
982            loading ? "loaded onto" : "unloaded from",
983            prland(lp), xyas(lp->lnd_x, lp->lnd_y, player->cnum));
984         loaded = 1;
985     }
986     *nunitsp += loaded;
987     return 0;
988 }