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