]> git.pond.sub.org Git - empserver/blob - src/lib/subs/plnsub.c
(pln_arm): Callers don't use parameter tech; remove it. Callers
[empserver] / src / lib / subs / plnsub.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  *  plnsub.c: Plane subroutine stuff
29  * 
30  *  Known contributors to this file:
31  *     Dave Pare, 1986
32  *     Ken Stevens, 1995
33  *     Steve McClure, 1998-2000
34  */
35
36 #include <math.h>
37 #include "misc.h"
38 #include "player.h"
39 #include "var.h"
40 #include "sect.h"
41 #include "ship.h"
42 #include "land.h"
43 #include "item.h"
44 #include "plane.h"
45 #include "nuke.h"
46 #include "xy.h"
47 #include "nsc.h"
48 #include "news.h"
49 #include "file.h"
50 #include "nat.h"
51 #include "path.h"
52 #include "prototypes.h"
53 #include "optlist.h"
54
55 static int pln_equip(struct plist *, struct ichrstr *, int, s_char);
56
57 int
58 pln_onewaymission(struct sctstr *target, int *shipno, int *flagp)
59 {
60     int nships;
61     int cno;
62     int flags;
63     struct shpstr ship;
64     char buf[1024];
65     char *p;
66
67     flags = *flagp;
68
69     /* offer carriers */
70     nships = carriersatxy(target->sct_x, target->sct_y,
71                           M_FLY | M_CHOPPER, 0, player->cnum);
72     if (nships) {
73         for (;;) {
74             if (!(p = getstarg(0, "Carrier #? ", buf)) || !*p)
75                 break;
76             cno = atoi(p);
77             if (cno < 0
78                 || !getship(cno, &ship)
79                 || (!player->owner
80                     && (getrel(getnatp(ship.shp_own), player->cnum)
81                         != ALLIED))) {
82                 pr("Not yours\n");
83                 continue;
84             }
85             if (ship.shp_x != target->sct_x || ship.shp_y != target->sct_y) {
86                 pr("Ship #%d not in %s\n", cno,
87                    xyas(target->sct_x, target->sct_y, player->cnum));
88                 continue;
89             }
90             if ((!(mchr[(int)ship.shp_type].m_flags & M_FLY)
91                  && !(mchr[(int)ship.shp_type].m_flags & M_XLIGHT)
92                  && !(mchr[(int)ship.shp_type].m_flags & M_CHOPPER))
93                 || ship.shp_effic < SHP_AIROPS_EFF) {
94                 pr("Can't land on %s.\n", prship(&ship));
95                 continue;
96             }
97
98             /* clear to land on ship#CNO */
99             pr("landing on carrier %d\n", cno);
100             if (mchr[(int)ship.shp_type].m_flags & M_FLY)
101                 flags |= P_L;
102             if (mchr[(int)ship.shp_type].m_flags & M_CHOPPER)
103                 flags |= P_K;
104             if (mchr[(int)ship.shp_type].m_flags & M_XLIGHT)
105                 flags |= P_E;
106             *shipno = cno;
107             *flagp = flags;
108             return 0;
109         }
110     }
111
112     /* try to land at sector */
113     if (target->sct_own != player->cnum
114         && getrel(getnatp(target->sct_own), player->cnum) != ALLIED) {
115         pr("Nowhere to land at sector %s!\n",
116            xyas(target->sct_x, target->sct_y, player->cnum));
117         return -1;
118     }
119     if (target->sct_type == SCT_MOUNT) {
120         pr("Nowhere to land at sector %s!\n",
121            xyas(target->sct_x, target->sct_y, player->cnum));
122         return -1;
123     }
124     if (target->sct_type != SCT_AIRPT || target->sct_effic < 60)
125         flags |= P_V;
126
127     /* clear to land at sector */
128     *shipno = -1;
129     *flagp = flags;
130     return 0;
131 }
132
133 int
134 pln_oneway_to_carrier_ok(struct emp_qelem *bomb_list,
135                          struct emp_qelem *esc_list, int cno)
136 {
137     struct emp_qelem *list, *qp;
138     struct plist *plp;
139     struct plchrstr *pcp;
140     struct shpstr ship;
141     struct mchrstr *mcp;
142     int nchoppers, nxlight, nplane;
143
144     if (cno < 0 || !getship(cno, &ship))
145         return 0;
146
147     count_planes(&ship);
148     nchoppers = ship.shp_nchoppers;
149     nxlight = ship.shp_nxlight;
150     nplane = ship.shp_nplane;
151     mcp = &mchr[(int)ship.shp_type];
152
153     /* for both lists */
154     for (list = bomb_list;
155          list;
156          list = list == bomb_list ? esc_list : NULL) {
157         for (qp = list->q_forw; qp != list; qp = qp->q_forw) {
158             /* FIXME duplicates put_plane_on_ship() logic; refactor */
159             plp = (struct plist *)qp;
160             pcp = &plchr[(int)plp->plane.pln_type];
161             if (plp->plane.pln_ship == ship.shp_uid)
162                 continue;
163             /* try chopper space */
164             if ((pcp->pl_flags & P_K) && (mcp->m_flags & M_CHOPPER)
165                 && nchoppers < mcp->m_nchoppers)
166                 ++nchoppers;
167             /* try xlight space */
168             else if ((pcp->pl_flags & P_E) && (mcp->m_flags & M_XLIGHT)
169                      && nxlight < mcp->m_nxlight)
170                 ++nxlight;
171             /* try plane space */
172             else if ((((pcp->pl_flags & P_L) && (mcp->m_flags & M_FLY))
173                       || ((pcp->pl_flags & P_M) && (pcp->pl_flags & P_L)
174                           && (mcp->m_flags & M_MSL)))
175                      && nplane < mcp->m_nplanes)
176                 ++nplane;
177             else
178                 return 0;               /* won't be able to land */
179         }
180     }
181     return 1;
182 }
183
184 void
185 pln_newlanding(struct emp_qelem *list, coord tx, coord ty, int cno)
186 {
187     struct emp_qelem *qp;
188     struct plist *plp;
189     struct shpstr ship;
190     struct sctstr sect;
191
192     if (cno >= 0)
193         getship(cno, &ship);
194     for (qp = list->q_forw; qp != list; qp = qp->q_forw) {
195         plp = (struct plist *)qp;
196         if (cno >= 0) {
197             count_planes(&ship);
198             if (!can_be_on_ship(plp->plane.pln_uid, ship.shp_uid))
199                 pr("\t%s cannot land on ship #%d! %s aborts!\n",
200                    prplane(&plp->plane), cno, prplane(&plp->plane));
201             else if (!put_plane_on_ship(&plp->plane, &ship))
202                 pr("\tNo room on ship #%d! %s aborts!\n", cno,
203                    prplane(&plp->plane));
204             else {
205                 if (plp->plane.pln_own != ship.shp_own) {
206 /*                                      plp->plane.pln_own = ship.shp_own;*/
207                     wu(0, ship.shp_own,
208                        "%s %s lands on your %s\n",
209                        cname(player->cnum),
210                        prplane(&plp->plane), prship(&ship));
211                 }
212             }
213         } else {
214             plp->plane.pln_x = tx;
215             plp->plane.pln_y = ty;
216             getsect(tx, ty, &sect);
217             if (plp->plane.pln_own != sect.sct_own) {
218 /*                              plp->plane.pln_own = sect.sct_own;*/
219                 wu(0, sect.sct_own,
220                    "%s %s lands at your sector %s\n",
221                    cname(player->cnum),
222                    prplane(&plp->plane), xyas(tx, ty, sect.sct_own));
223             }
224             plp->plane.pln_ship = cno;
225         }
226     }
227     if (cno >= 0)
228         putship(ship.shp_uid, &ship);
229 }
230
231 void
232 pln_dropoff(struct emp_qelem *list, struct ichrstr *ip, coord tx, coord ty,
233             void *ptr, int type)
234 {
235     struct emp_qelem *qp;
236     struct plist *plp;
237     int amt;
238     struct sctstr *sectp;
239     struct shpstr *sp;
240     int there;
241     int max;
242     struct mchrstr *mp;
243
244     if (ip == 0)
245         return;
246     amt = 0;
247     for (qp = list->q_forw; qp != list; qp = qp->q_forw) {
248         plp = (struct plist *)qp;
249         amt += plp->misc;
250     }
251     if (type == EF_SECTOR) {
252         sectp = ptr;
253         if (!sectp->sct_own) {
254             if (sectp->sct_type == SCT_WATER)
255                 pr("Your %s sink like a rock!\n", ip->i_name);
256             else
257                 pr("Your %s vanish without a trace.\n", ip->i_name);
258             return;
259         }
260         if (sectp->sct_own != player->cnum
261             && getrel(getnatp(sectp->sct_own), player->cnum) != ALLIED) {
262             pr("You don't own %s!  Cargo jettisoned...\n",
263                xyas(tx, ty, player->cnum));
264             return;
265         }
266         if (ip->i_vtype == I_CIVIL && sectp->sct_own != sectp->sct_oldown) {
267             pr("%s is occupied.  Your civilians suffer from identity crisis and die.\n",
268                xyas(tx, ty, player->cnum));
269             return;
270         }
271         there = sectp->sct_item[ip->i_vtype];
272         max = ITEM_MAX;
273     } else {
274         sp = ptr;
275         there = sp->shp_item[ip->i_vtype];
276         mp = &mchr[(int)sp->shp_type];
277         max = mp->m_item[ip->i_vtype];
278     }
279     there += amt;
280     if (there > max) {
281         pr("%d excess %s discarded\n", max - there, ip->i_name);
282         amt = max - there;
283         there = max;
284     }
285     pr("%d %s landed safely", amt, ip->i_name);
286     if (type == EF_SECTOR) {
287         sectp = ptr;
288         sectp->sct_item[ip->i_vtype] = there;
289         if (sectp->sct_own != player->cnum)
290             wu(0, sectp->sct_own, "%s planes drop %d %s in %s\n",
291                cname(player->cnum), amt, ip->i_name,
292                xyas(sectp->sct_x, sectp->sct_y, sectp->sct_own));
293         pr(" at %s\n", xyas(tx, ty, player->cnum));
294         putsect((struct sctstr *)ptr);
295     } else {
296         struct shpstr *sp = (struct shpstr *)ptr;
297         sp->shp_item[ip->i_vtype] = there;
298         if (sp->shp_own != player->cnum)
299             wu(0, sp->shp_own, "%s planes land %d %s on carrier %d\n",
300                cname(player->cnum), amt, ip->i_name, sp->shp_uid);
301         pr(" on carrier #%d\n", sp->shp_uid);
302         putship(sp->shp_uid, sp);
303     }
304 }
305
306 void
307 pln_mine(struct emp_qelem *list, struct sctstr *sectp)
308 {
309     struct emp_qelem *qp;
310     struct plist *plp;
311     int amt;
312
313     amt = 0;
314     for (qp = list->q_forw; qp != list; qp = qp->q_forw) {
315         plp = (struct plist *)qp;
316         amt += plp->misc;
317
318     }
319     if (amt > 0) {
320         sectp->sct_mines = min(sectp->sct_mines + amt, MINES_MAX);
321         pr("%d mines laid in %s.\n", amt,
322            xyas(sectp->sct_x, sectp->sct_y, player->cnum));
323         if (map_set(player->cnum, sectp->sct_x, sectp->sct_y, 'X', 0))
324             writemap(player->cnum);
325         putsect(sectp);
326     }
327 }
328
329 void
330 pln_sel(struct nstr_item *ni, struct emp_qelem *list, struct sctstr *ap,
331         int ap_to_target, int rangemult, int wantflags, int nowantflags)
332 {
333     struct plnstr plane;
334     struct shpstr ship;
335     struct lndstr land;
336     struct sctstr sect;
337     int range;
338     struct plchrstr *pcp;
339     struct plist *plp;
340     register int y;
341     register int bad, bad1;
342     unsigned int x;
343
344     emp_initque(list);
345     while (nxtitem(ni, (s_char *)&plane)) {
346         if (!player->owner)
347             continue;
348         if (plane.pln_mobil <= (s_char)0)
349             continue;
350         if (opt_MARKET) {
351             if (ontradingblock(EF_PLANE, (int *)&plane)) {
352                 pr("plane #%d inelligible - it's for sale.\n",
353                    plane.pln_uid);
354                 continue;
355             }
356         }
357
358         range = mapdist(plane.pln_x, plane.pln_y, ap->sct_x, ap->sct_y);
359         if (range > 4) {
360             pr("%s too far from assembly point\n", prplane(&plane));
361             continue;
362         }
363         if (plane.pln_effic < 40) {
364             pr("%s not efficient enough (must be 40%%)\n",
365                prplane(&plane));
366             continue;
367         }
368         range += ap_to_target;
369         pcp = &plchr[(int)plane.pln_type];
370         bad = 0;
371         bad1 = 0;
372         if (wantflags) {
373             for (x = 0; x < sizeof(wantflags) * 8; x++) {
374                 y = (1 << x);
375                 if ((wantflags & y) == y)
376                     if ((pcp->pl_flags & y) != y) {
377                         switch (y) {
378                         case P_F:
379                         case P_ESC:
380                             bad1 = 2;
381                             break;
382                         case P_E:
383                         case P_L:
384                         case P_K:
385                             bad1 = 1;
386                             break;
387                         default:
388                             bad = 1;
389                         }
390                     }
391             }
392             if (bad)
393                 continue;
394             if (bad1 == 2) {
395                 if ((pcp->pl_flags & P_ESC) || (pcp->pl_flags & P_F))
396                     bad1 = 0;
397             }
398             if (bad1 == 1) {
399                 if ((wantflags & P_L) && (pcp->pl_flags & P_L))
400                     bad1 = 0;
401                 if ((wantflags & P_K) && (pcp->pl_flags & P_K))
402                     bad1 = 0;
403                 if ((wantflags & P_E) && (pcp->pl_flags & P_E))
404                     bad1 = 0;
405             }
406             if (bad1)
407                 continue;
408         }
409         bad = 0;
410         bad1 = 0;
411         if (nowantflags) {
412             for (x = 0; x < sizeof(nowantflags) * 8; x++) {
413                 y = (1 << x);
414                 if ((nowantflags & y) == y)
415                     if ((pcp->pl_flags & y) == y)
416                         bad = 1;
417             }
418             if (bad)
419                 continue;
420         }
421         range *= rangemult;
422         if (plane.pln_range < range) {
423             pr("%s out of range (%d:%d)\n", prplane(&plane),
424                plane.pln_range, range);
425             continue;
426         }
427         if (plane.pln_ship >= 0) {
428             if (!getship(plane.pln_ship, &ship) ||
429                 plane.pln_own != player->cnum) {
430               shipsunk:
431                 plane.pln_effic = 0;
432                 pr("(note) ship not valid for %s\n", prplane(&plane));
433                 putplane(plane.pln_uid, &plane);
434                 continue;
435             }
436             if (!can_be_on_ship(plane.pln_uid, ship.shp_uid))
437                 goto shipsunk;
438             if (ship.shp_effic < SHIP_MINEFF)
439                 goto shipsunk;
440             if (ship.shp_effic < SHP_AIROPS_EFF)
441                 continue;
442             /* Can't fly off non-owned ships or non-allied ship */
443             if ((ship.shp_own != player->cnum) &&
444                 (getrel(getnatp(ship.shp_own), player->cnum) != ALLIED)) {
445                 pr("(note) An ally does not own the ship %s is on\n",
446                    prplane(&plane));
447                 continue;
448             }
449         }
450         if (plane.pln_land >= 0) {
451             if (!getland(plane.pln_land, &land) ||
452                 (plane.pln_own != player->cnum)) {
453               landdead:
454                 plane.pln_effic = 0;
455                 pr("(note) land unit not valid for %s\n", prplane(&plane));
456                 putplane(plane.pln_uid, &plane);
457                 continue;
458             }
459             if (!(plchr[(int)plane.pln_type].pl_flags & P_E))
460                 goto landdead;
461             if (land.lnd_effic < LAND_MINEFF)
462                 goto landdead;
463             if (land.lnd_effic < LND_AIROPS_EFF)
464                 continue;
465             /* Can't fly off units in ships or other units */
466             if ((land.lnd_ship >= 0) || (land.lnd_land >= 0))
467                 continue;
468             /* Can't fly off non-owned units or non-allied unit */
469             if ((land.lnd_own != player->cnum) &&
470                 (getrel(getnatp(land.lnd_own), player->cnum) != ALLIED)) {
471                 pr("(note) An ally does not own the unit %s is on\n",
472                    prplane(&plane));
473                 continue;
474             }
475         }
476         /* Now, check the sector status if not on a plane or unit */
477         if ((plane.pln_ship < 0) && (plane.pln_land < 0)) {
478             if (!getsect(plane.pln_x, plane.pln_y, &sect))
479                 continue;
480             /* First, check allied status */
481             /* Can't fly from non-owned sectors or non-allied sectors */
482             if ((sect.sct_own != player->cnum) &&
483                 (getrel(getnatp(sect.sct_own), player->cnum) != ALLIED)) {
484                 pr("(note) An ally does not own the sector %s is in\n",
485                    prplane(&plane));
486                 continue;
487             }
488             /* non-vtol plane */
489             if ((pcp->pl_flags & P_V) == 0) {
490                 if (sect.sct_type != SCT_AIRPT) {
491                     pr("%s not at airport\n", prplane(&plane));
492                     continue;
493                 }
494                 if (sect.sct_effic < 40) {
495                     pr("%s is not 40%% efficient, %s can't take off from there.\n", xyas(sect.sct_x, sect.sct_y, plane.pln_own), prplane(&plane));
496                     continue;
497                 }
498                 if (rangemult == 2 && sect.sct_effic < 60) {
499                     pr("%s is not 60%% efficient, %s can't land there.\n",
500                        xyas(sect.sct_x, sect.sct_y, plane.pln_own),
501                        prplane(&plane));
502                     continue;
503                 }
504             }
505         }
506         pr("%s standing by\n", prplane(&plane));
507         plane.pln_mission = 0;
508         putplane(plane.pln_uid, &plane);
509         plp = (struct plist *)malloc(sizeof(struct plist));
510         plp->state = P_OK;
511         plp->misc = 0;
512         plp->bombs = 0;
513         plp->pcp = pcp;
514         plp->plane = plane;
515         emp_insque(&plp->queue, list);
516     }
517 }
518
519 int
520 pln_arm(struct emp_qelem *list, int dist, int mission, struct ichrstr *ip,
521         int flags, int mission_flags)
522 {
523     struct emp_qelem *qp;
524     struct emp_qelem *next;
525     struct plist *plp;
526
527     for (qp = list->q_forw; qp != list; qp = next) {
528         next = qp->q_forw;
529         plp = (struct plist *)qp;
530         if (pln_equip(plp, ip, flags, mission) < 0) {
531             emp_remque(qp);
532             free((s_char *)qp);
533             continue;
534         }
535         if (flags & (P_S | P_I)) {
536             if (plp->pcp->pl_flags & P_S)
537                 mission_flags |= P_S;
538             if (plp->pcp->pl_flags & P_I)
539                 mission_flags |= P_I;
540         }
541         if (!(plp->pcp->pl_flags & P_H))
542             /* no stealth on this mission */
543             mission_flags &= ~P_H;
544         if (!(plp->pcp->pl_flags & P_X))
545             /* no stealth on this mission */
546             mission_flags &= ~P_X;
547         if (!(plp->pcp->pl_flags & P_A)) {
548             /* no asw on this mission */
549             mission_flags &= ~P_A;
550         }
551         if (!(plp->pcp->pl_flags & P_MINE)) {
552             /* no asw on this mission */
553             mission_flags &= ~P_MINE;
554         }
555         plp->plane.pln_mobil -= pln_mobcost(dist, &plp->plane, flags);
556         pr("%s equipped\n", prplane(&plp->plane));
557     }
558     return mission_flags;
559 }
560
561 static int
562 pln_equip(struct plist *plp, struct ichrstr *ip, int flags, s_char mission)
563 {
564     register struct plchrstr *pcp;
565     struct plnstr *pp;
566     int needed;
567     struct lndstr land;
568     struct shpstr ship;
569     struct sctstr sect;
570     int itype;
571     int rval;
572     short *item;
573     int own;
574
575     pp = &plp->plane;
576     pcp = plp->pcp;
577     if (pp->pln_ship >= 0) {
578         getship(pp->pln_ship, &ship);
579         item = ship.shp_item;
580         own = ship.shp_own;
581     } else if (pp->pln_land >= 0) {
582         getland(pp->pln_land, &land);
583         item = land.lnd_item;
584         own = land.lnd_own;
585     } else {
586         getsect(pp->pln_x, pp->pln_y, &sect);
587         item = sect.sct_item;
588         own = sect.sct_oldown;
589     }
590     if (ip) {
591         if (ip->i_vtype == I_CIVIL) {
592             if (pp->pln_own != own) {
593                 pr("You don't control those civilians!\n");
594                 return -1;
595             }
596         }
597     }
598     if (pcp->pl_fuel > item[I_PETROL]) {
599         pr("%s not enough petrol there!\n", prplane(pp));
600         return -1;
601     }
602     item[I_PETROL] -= pcp->pl_fuel;
603     rval = 0;
604     if ((flags & P_F) == 0) {
605         itype = 0;
606         needed = 0;
607         switch (mission) {
608         case 's':
609         case 'p':
610             if (pp->pln_nuketype == -1) {
611                 itype = I_SHELL;
612                 needed = pp->pln_load;
613             }
614             break;
615         case 't':
616             if ((pcp->pl_flags & P_C) == 0 || ip == 0)
617                 break;
618             itype = ip->i_vtype;
619             needed = (pp->pln_load * 2) / ip->i_lbs;
620             break;
621         case 'd':
622             itype = ip->i_vtype;
623             needed = (pp->pln_load * 2) / ip->i_lbs;
624             /* Is this mine dropping excursion? */
625             if (itype == I_SHELL && (pcp->pl_flags & P_MINE))
626                 break;
627             /* Is this a cargo drop? */
628             if ((pcp->pl_flags & P_C) == 0 || ip == 0) {
629                 itype = 0;
630                 needed = 0;
631                 break;
632             }
633             break;
634         case 'a':
635             if ((pcp->pl_flags & (P_V | P_C)) == 0)
636                 break;
637             itype = I_MILIT;
638             needed = pp->pln_load / ip->i_lbs;
639             break;
640         case 'n':
641             if (pp->pln_nuketype == (s_char)-1)
642                 rval = -1;
643             break;
644         default:
645             break;
646         }
647         if (rval < 0 || (itype && needed <= 0)) {
648             pr("%s can't contribute to mission\n", prplane(pp));
649             return -1;
650         }
651 #if 0
652         /* Supply is broken somewhere, so don't use it for now */
653         if (item[itype] < needed && itype == I_SHELL)
654             item[itype] += supply_commod(plp->plane.pln_own,
655                                          plp->plane.pln_x, plp->plane.pln_y,
656                                          I_SHELL, needed);
657 #endif
658         if (item[itype] < needed) {
659             pr("Not enough %s for %s\n", ichr[itype].i_name, prplane(pp));
660             return -1;
661         } else {
662             item[itype] -= needed;
663         }
664         if (itype == I_SHELL && (mission == 's' || mission == 'p'))
665             plp->bombs = needed;
666         else
667             plp->misc = needed;
668     }
669     if (pp->pln_ship >= 0) {
670         if (pp->pln_own != ship.shp_own) {
671             wu(0, ship.shp_own,
672                "%s %s prepares for takeoff from ship %s\n",
673                cname(pp->pln_own), prplane(pp), prship(&ship));
674         }
675         putship(ship.shp_uid, &ship);
676     } else if (pp->pln_land >= 0) {
677         if (pp->pln_own != land.lnd_own) {
678             wu(0, land.lnd_own,
679                "%s %s prepares for takeoff from unit %s\n",
680                cname(pp->pln_own), prplane(pp), prland(&land));
681         }
682         putland(land.lnd_uid, &land);
683     } else {
684         if (pp->pln_own != sect.sct_own) {
685             wu(0, sect.sct_own, "%s %s prepares for takeoff from %s\n",
686                cname(pp->pln_own), prplane(pp), xyas(sect.sct_x,
687                                                      sect.sct_y,
688                                                      sect.sct_own));
689         }
690         putsect(&sect);
691     }
692     return rval;
693 }
694
695 void
696 pln_put(struct emp_qelem *list)
697 {
698     register struct emp_qelem *qp;
699     register struct emp_qelem *newqp;
700     struct plist *plp;
701     struct plnstr *pp;
702     struct shpstr ship;
703     struct sctstr sect;
704
705     /* Here is where planes return home from bombing runs.
706        We need to make sure they still have somewhere to return
707        home to! */
708     qp = list->q_forw;
709     while (qp != list) {
710         plp = (struct plist *)qp;
711         pp = &plp->plane;
712         /* Ok, check out where it wants to land */
713         if (pp->pln_ship >= 0) {
714             /* It is landing on a carrier */
715             getship(pp->pln_ship, &ship);
716             /* We should do more, like make sure it's really
717                a carrier, etc. but for now just make sure it's
718                not sunk. */
719             if (ship.shp_effic < SHIP_MINEFF) {
720                 mpr(pp->pln_own,
721                     "Ship #%d has been sunk, plane #%d has nowhere to land, and\nsplashes into the sea.\n",
722                     pp->pln_ship, pp->pln_uid);
723                 pp->pln_effic = 0;
724             }
725         } else {
726             /* Presume we are landing back in a sector. */
727             getsect(pp->pln_x, pp->pln_y, &sect);
728             if (sect.sct_type == SCT_WATER || sect.sct_type == SCT_WASTE) {
729                 mpr(pp->pln_own,
730                     "Nowhere to land at %s, plane #%d crashes and burns...\n",
731                     xyas(pp->pln_x, pp->pln_y, pp->pln_own), pp->pln_uid);
732                 pp->pln_effic = 0;
733             }
734         }
735         putplane(pp->pln_uid, pp);
736         newqp = qp->q_forw;
737         emp_remque(qp);
738         free((s_char *)qp);
739         qp = newqp;
740     }
741 }
742
743 void
744 pln_removedupes(struct emp_qelem *bomb_list, struct emp_qelem *esc_list)
745 {
746     struct emp_qelem *bomb;
747     struct emp_qelem *esc;
748     struct plist *bombp;
749     struct plist *escp;
750
751     if (QEMPTY(bomb_list) || QEMPTY(esc_list))
752         return;
753     bomb = bomb_list->q_forw;
754     while (bomb != bomb_list) {
755         if (QEMPTY(esc_list)) {
756             bomb = bomb_list;
757             continue;
758         }
759         esc = esc_list->q_forw;
760         bombp = (struct plist *)bomb;
761         while (esc != esc_list) {
762             escp = (struct plist *)esc;
763             if (escp->plane.pln_uid == bombp->plane.pln_uid) {
764                 emp_remque(esc);
765                 free((s_char *)esc);
766                 esc = esc_list;
767             } else
768                 esc = esc->q_forw;
769         }
770         bomb = bomb->q_forw;
771     }
772 }
773
774 int
775 put_plane_on_ship(struct plnstr *plane, struct shpstr *ship)
776 {
777     struct plchrstr *pcp;
778     struct mchrstr *mcp;
779
780     pcp = &plchr[(int)plane->pln_type];
781     mcp = &mchr[(int)ship->shp_type];
782
783     if (((int)plane->pln_ship) == ((int)ship->shp_uid))
784         return 1;               /* Already on ship */
785
786     /* Try to put on ship as a chopper plane */
787     if ((pcp->pl_flags & P_K) &&
788         (mcp->m_flags & M_CHOPPER) &&
789         (ship->shp_nchoppers < mcp->m_nchoppers)) {
790
791         ship->shp_nchoppers++;
792         plane->pln_x = ship->shp_x;
793         plane->pln_y = ship->shp_y;
794         plane->pln_ship = ship->shp_uid;
795         putship(ship->shp_uid, ship);
796         putplane(plane->pln_uid, plane);
797         return 1;
798     }
799
800     /* Try to put on ship as an xlight plane */
801     if ((pcp->pl_flags & P_E) &&
802         (mcp->m_flags & M_XLIGHT) &&
803         (ship->shp_nxlight < mcp->m_nxlight)) {
804
805         ship->shp_nxlight++;
806         plane->pln_x = ship->shp_x;
807         plane->pln_y = ship->shp_y;
808         plane->pln_ship = ship->shp_uid;
809         putship(ship->shp_uid, ship);
810         putplane(plane->pln_uid, plane);
811         return 1;
812     }
813
814     /* Try to put on ship as a normal plane */
815     if ((((pcp->pl_flags & P_L) && (mcp->m_flags & M_FLY)) ||
816          ((pcp->pl_flags & P_M) && (pcp->pl_flags & P_L) &&
817           (mcp->m_flags & M_MSL))) &&
818         (ship->shp_nplane < mcp->m_nplanes)) {
819
820         ship->shp_nplane++;
821         plane->pln_x = ship->shp_x;
822         plane->pln_y = ship->shp_y;
823         plane->pln_ship = ship->shp_uid;
824         putship(ship->shp_uid, ship);
825         putplane(plane->pln_uid, plane);
826         return 1;
827     }
828
829     /* We have failed */
830     return 0;
831 }
832
833 int
834 take_plane_off_ship(struct plnstr *plane, struct shpstr *ship)
835 {
836     struct plchrstr *pcp;
837     struct mchrstr *mcp;
838
839     pcp = &plchr[(int)plane->pln_type];
840     mcp = &mchr[(int)ship->shp_type];
841
842     /* Try to take off ship as a chopper plane */
843     if ((pcp->pl_flags & P_K) &&
844         (mcp->m_flags & M_CHOPPER) && (ship->shp_nchoppers)) {
845
846         ship->shp_nchoppers--;
847         plane->pln_ship = -1;
848         putship(ship->shp_uid, ship);
849         putplane(plane->pln_uid, plane);
850         return 1;
851     }
852
853     /* Try to take off ship as an xlight plane */
854     if ((pcp->pl_flags & P_E) &&
855         (mcp->m_flags & M_XLIGHT) && (ship->shp_nxlight)) {
856
857         ship->shp_nxlight--;
858         plane->pln_ship = -1;
859         putship(ship->shp_uid, ship);
860         putplane(plane->pln_uid, plane);
861         return 1;
862     }
863
864     /* Try to take off ship as a normal plane */
865     if ((((pcp->pl_flags & P_L) && (mcp->m_flags & M_FLY)) ||
866          ((pcp->pl_flags & P_M) && (pcp->pl_flags & P_L) &&
867           (mcp->m_flags & M_MSL))) && (ship->shp_nplane)) {
868
869         ship->shp_nplane--;
870         plane->pln_ship = -1;
871         putship(ship->shp_uid, ship);
872         putplane(plane->pln_uid, plane);
873         return 1;
874     }
875
876     /* We have failed */
877     return 0;
878 }
879
880 int
881 take_plane_off_land(struct plnstr *plane, struct lndstr *land)
882 {
883     struct plchrstr *pcp;
884     struct lchrstr *lcp;
885
886     pcp = &plchr[(int)plane->pln_type];
887     lcp = &lchr[(int)land->lnd_type];
888
889     /* Try to take off ship as an xlight plane */
890     if ((pcp->pl_flags & P_E) &&
891         (lcp->l_flags & L_XLIGHT) && (land->lnd_nxlight)) {
892
893         land->lnd_nxlight--;
894         plane->pln_land = -1;
895         putland(land->lnd_uid, land);
896         putplane(plane->pln_uid, plane);
897         return 1;
898     }
899
900     /* We have failed */
901     return 0;
902 }
903
904 int
905 can_be_on_ship(int p, int s)
906 {
907     struct plnstr plane;
908     struct shpstr ship;
909     struct plchrstr *pcp;
910     struct mchrstr *mcp;
911
912     getplane(p, &plane);
913     getship(s, &ship);
914
915     pcp = &plchr[(int)plane.pln_type];
916     mcp = &mchr[(int)ship.shp_type];
917
918     if (pcp->pl_flags & P_L)
919         if (mcp->m_flags & M_FLY)
920             return 1;
921
922     if (pcp->pl_flags & P_K)
923         if (mcp->m_flags & M_CHOPPER)
924             return 1;
925
926     if (pcp->pl_flags & P_M)
927         if (mcp->m_flags & M_MSL)
928             return 1;
929
930     if (pcp->pl_flags & P_E)
931         if (mcp->m_flags & M_XLIGHT)
932             return 1;
933
934     return 0;
935 }
936
937 void
938 plane_sweep(struct emp_qelem *plane_list, coord x, coord y)
939 {
940     struct plnstr *pp;
941     struct plchrstr *pcp;
942     struct emp_qelem *qp;
943     struct emp_qelem *next;
944     struct plist *ip;
945     struct sctstr sect;
946     int mines_there;
947     int found = 0;
948
949     getsect(x, y, &sect);
950     mines_there = sect.sct_mines;
951
952     if (mines_there == 0)
953         return;
954
955     if ((sect.sct_type != SCT_WATER) && (sect.sct_type != SCT_HARBR))
956         return;
957
958     for (qp = plane_list->q_forw; ((qp != plane_list) && (mines_there));
959          qp = next) {
960         next = qp->q_forw;
961         ip = (struct plist *)qp;
962         pp = &ip->plane;
963         pcp = ip->pcp;
964         if (!(pcp->pl_flags & P_SWEEP)) /* if it isn't an sweep plane */
965             continue;
966
967         if (chance(((double)(100 - pp->pln_acc)) / 100.0)) {
968             pr("Sweep! in %s\n",
969                xyas(sect.sct_x, sect.sct_y, pp->pln_own));
970             mines_there--;
971             found = 1;
972         }
973     }
974
975     if (found && map_set(player->cnum, sect.sct_x, sect.sct_y, 'X', 0))
976         writemap(player->cnum);
977     sect.sct_mines = mines_there;
978     putsect(&sect);
979 }
980
981 void
982 count_planes(struct shpstr *sp)
983 {
984     struct nstr_item ni;
985     struct plnstr plane;
986     struct plchrstr *pcp;
987     struct mchrstr *mcp;
988     int nplane = 0;
989     int nchoppers = 0;
990     int nxlight = 0;
991
992     if (sp->shp_effic < SHIP_MINEFF)
993         return;
994
995     mcp = &mchr[(int)sp->shp_type];
996     snxtitem_xy(&ni, EF_PLANE, sp->shp_x, sp->shp_y);
997     while (nxtitem(&ni, (s_char *)&plane)) {
998         if (plane.pln_own == 0)
999             continue;
1000         if (plane.pln_ship == sp->shp_uid) {
1001             pcp = &plchr[(int)plane.pln_type];
1002             if ((pcp->pl_flags & P_K) && (nchoppers < mcp->m_nchoppers))
1003                 nchoppers++;
1004             else if ((pcp->pl_flags & P_E) && (nxlight < mcp->m_nxlight))
1005                 nxlight++;
1006             else if ((pcp->pl_flags & P_L) || (pcp->pl_flags & P_M))
1007                 nplane++;
1008         }
1009     }
1010
1011     if (nplane != sp->shp_nplane ||
1012         nxlight != sp->shp_nxlight || nchoppers != sp->shp_nchoppers) {
1013         sp->shp_nplane = nplane;
1014         sp->shp_nxlight = nxlight;
1015         sp->shp_nchoppers = nchoppers;
1016         putship(sp->shp_uid, sp);
1017     }
1018 }
1019
1020 void
1021 count_land_planes(struct lndstr *lp)
1022 {
1023     struct nstr_item ni;
1024     struct plnstr plane;
1025     int nplane = 0;
1026
1027     if (lp->lnd_effic < LAND_MINEFF)
1028         return;
1029
1030     snxtitem_all(&ni, EF_PLANE);
1031     while (nxtitem(&ni, (s_char *)&plane)) {
1032         if (plane.pln_own == 0)
1033             continue;
1034         if (plane.pln_land == lp->lnd_uid)
1035             nplane++;
1036     }
1037
1038     if (lp->lnd_nxlight != nplane) {
1039         lp->lnd_nxlight = nplane;
1040         putland(lp->lnd_uid, lp);
1041     }
1042 }
1043
1044 int
1045 count_sect_planes(struct sctstr *sp)
1046 {
1047     int count = 0;
1048     struct nstr_item ni;
1049     struct plnstr plane;
1050
1051     snxtitem_all(&ni, EF_PLANE);
1052     while (nxtitem(&ni, (s_char *)&plane)) {
1053         if (!plane.pln_own)
1054             continue;
1055         if (plane.pln_flags & PLN_LAUNCHED)
1056             continue;
1057         if (plane.pln_x == sp->sct_x && plane.pln_y == sp->sct_y)
1058             ++count;
1059     }
1060
1061     return count;
1062 }
1063
1064 int
1065 put_plane_on_land(struct plnstr *plane, struct lndstr *land)
1066 {
1067     struct plchrstr *pcp;
1068     struct lchrstr *lcp;
1069
1070     pcp = &plchr[(int)plane->pln_type];
1071     lcp = &lchr[(int)land->lnd_type];
1072
1073     if (((int)plane->pln_land) == ((int)land->lnd_uid))
1074         return 1;               /* Already on unit */
1075
1076     /* Try to put on unit as an xlight plane */
1077     if ((pcp->pl_flags & P_E) &&
1078         (lcp->l_flags & L_XLIGHT) &&
1079         (land->lnd_nxlight < lcp->l_nxlight)) {
1080
1081         land->lnd_nxlight++;
1082         plane->pln_x = land->lnd_x;
1083         plane->pln_y = land->lnd_y;
1084         plane->pln_land = land->lnd_uid;
1085         putland(land->lnd_uid, land);
1086         putplane(plane->pln_uid, plane);
1087         return 1;
1088     }
1089
1090     /* We have failed */
1091     return 0;
1092 }
1093
1094 int
1095 pln_hitchance(struct plnstr *pp, int hardtarget, int type)
1096 {
1097     struct plchrstr *pcp = plchr + pp->pln_type;
1098     float tfact = (float)(pp->pln_tech - pcp->pl_tech) /
1099         (pp->pln_tech - pcp->pl_tech / 2);
1100     int acc = pp->pln_acc;
1101     int hitchance;
1102
1103     if (type == EF_SHIP) {
1104         if (pcp->pl_flags & P_A)
1105             acc -= 20;
1106         if (!(pcp->pl_flags & P_T))
1107             acc += 35;
1108     }
1109     hitchance = (int)(pp->pln_effic * (1.0 - 0.1 * tfact) *
1110                       (1.0 - (float)acc / 100.0)) - hardtarget;
1111
1112     /* smooth out the bottom of the graph with asymtote at 5 -KHS */
1113     if (hitchance < 20)
1114         hitchance = 5 + ldround(300.0 / (40.0 - hitchance), 1);
1115     if (hitchance > 100)
1116         hitchance = 100;
1117     return hitchance;
1118 }
1119
1120 /* return 0 if there was a nuclear detonation */
1121
1122 int
1123 pln_damage(struct plnstr *pp, coord x, coord y, s_char type, int *nukedamp,
1124            int noisy)
1125 {
1126     struct plchrstr *pcp = plchr + pp->pln_type;
1127     int i;
1128     int hitroll;
1129     int dam = 0;
1130     int aim;
1131     int effective = 1;
1132     int pinbomber = 0;
1133
1134     if (pp->pln_nuketype != (s_char)-1) {
1135         mpr(pp->pln_own, "Releasing RV's for %s detonation...\n",
1136             pp->pln_flags & PLN_AIRBURST ? "airburst" : "groundburst");
1137         *nukedamp = detonate(pp, x, y);
1138         return 0;
1139     } else
1140         *nukedamp = 0;
1141
1142     if (!pp->pln_load)          /* e.g. ab, blowing up on launch pad */
1143         return 0;
1144
1145     i = roll(pp->pln_load) + 1;
1146     if (i > pp->pln_load)
1147         i = pp->pln_load;
1148
1149     if (pcp->pl_flags & P_M) {
1150         if (pcp->pl_flags & P_MAR)
1151             pinbomber = 1;
1152     } else if (pcp->pl_flags & P_T)
1153         pinbomber = 1;
1154
1155     aim = 100 - pp->pln_acc;
1156     if (type == 's') {
1157         if (pinbomber) {
1158             aim = pp->pln_acc;
1159             effective = 0;
1160         }
1161         aim += 30;
1162     } else {
1163         if (!pinbomber) {
1164             effective = 0;
1165         }
1166     }
1167     while (i--) {
1168         dam += roll(6);
1169         hitroll = roll(100);
1170         if (hitroll >= 90) {
1171             dam += 8;
1172             if (noisy)
1173                 mpr(pp->pln_own, "BLAM");
1174         } else if (hitroll < aim) {
1175             dam += 5;
1176             if (noisy)
1177                 mpr(pp->pln_own, "Blam");
1178         } else {
1179             dam += 1;
1180             if (noisy)
1181                 mpr(pp->pln_own, "blam");
1182         }
1183         if (i && noisy)
1184             mpr(pp->pln_own, "-");
1185     }
1186     if (noisy)
1187         mpr(pp->pln_own, "\n");
1188     if (effective)
1189         dam *= 2;
1190     return dam;
1191 }
1192
1193 int
1194 pln_identchance(struct plnstr *pp, int hardtarget, int type)
1195 {
1196     double misschance =
1197         (100.0 - pln_hitchance(pp, hardtarget, type)) / 100.0;
1198     return (int)(100 - 100 * misschance * misschance);
1199 }
1200
1201 int
1202 pln_mobcost(int dist, struct plnstr *pp, int flags)
1203 {
1204     int cost;
1205
1206     if ((flags & P_F) || (flags & P_ESC))
1207         cost = 10 * 100 / pp->pln_effic;
1208     else
1209         cost = 20 * 100 / pp->pln_effic;
1210
1211     cost = ldround((double)cost * dist / pp->pln_range_max, 1);
1212
1213     return min(32 + pp->pln_mobil, cost + 5);
1214 }
1215
1216 /*
1217  * Set PP's tech to TLEV along with everything else that depends on it.
1218  */
1219 void
1220 pln_set_tech(struct plnstr *pp, int tlev)
1221 {
1222     struct plchrstr *pcp = plchr + pp->pln_type;
1223     int tech_diff = tlev - pcp->pl_tech;
1224     int limited_range = pp->pln_range < pp->pln_range_max;
1225
1226     if (CANT_HAPPEN(tech_diff < 0)) {
1227       tlev -= tech_diff;
1228       tech_diff = 0;
1229     }
1230
1231     pp->pln_tech = tlev;
1232     pp->pln_att = PLN_ATTDEF(pcp->pl_att, tech_diff);
1233     pp->pln_def = PLN_ATTDEF(pcp->pl_def, tech_diff);
1234     pp->pln_acc = PLN_ACC(pcp->pl_acc, tech_diff);
1235     pp->pln_range_max = PLN_RAN(pcp->pl_range, tech_diff);
1236     pp->pln_load = PLN_LOAD(pcp->pl_load, tech_diff);
1237
1238     if (!limited_range || pp->pln_range > pp->pln_range_max)
1239         pp->pln_range = pp->pln_range_max;
1240 }