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