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