]> git.pond.sub.org Git - empserver/blob - src/lib/subs/mission.c
Check ef_type before dereferencing struct empobj
[empserver] / src / lib / subs / mission.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2008, Dave Pare, Jeff Bailey, Thomas Ruschak,
4  *                           Ken Stevens, Steve McClure
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  *  ---
21  *
22  *  See files README, COPYING and CREDITS in the root of the source
23  *  tree for related information and legal notices.  It is expected
24  *  that future projects/authors will amend these files as needed.
25  *
26  *  ---
27  *
28  *  mission.c: Mission subroutines for planes/ships/units
29  * 
30  *  Known contributors to this file:
31  *     Ken Stevens, 1995
32  *     Steve McClure, 1996-2000
33  */
34
35 #include <config.h>
36
37 #include <stdlib.h>
38 #include "damage.h"
39 #include "empobj.h"
40 #include "file.h"
41 #include "item.h"
42 #include "misc.h"
43 #include "mission.h"
44 #include "nsc.h"
45 #include "optlist.h"
46 #include "path.h"
47 #include "player.h"
48 #include "prototypes.h"
49 #include "queue.h"
50 #include "xy.h"
51
52 struct genlist {
53     struct emp_qelem queue;     /* list of units */
54     void *cp;                   /* pointer to desc of thing */
55     struct empobj *thing;       /* thing's struct */
56 };
57
58 struct airport {
59     struct emp_qelem queue;
60     coord x, y;
61     natid own;
62 };
63
64 static void add_airport(struct emp_qelem *, coord, coord);
65 static int air_damage(struct emp_qelem *, coord, coord, int, natid,
66                       char *, int);
67 static void build_mission_list(struct genlist *, coord, coord, int, natid);
68 static void build_mission_list_type(struct genlist *, coord, coord, int,
69                                     int, natid);
70 static void divide(struct emp_qelem *, struct emp_qelem *, coord, coord);
71 static int dosupport(struct genlist *, coord, coord, natid, natid);
72 static int find_airport(struct emp_qelem *, coord, coord);
73 static int mission_pln_arm(struct emp_qelem *, coord, coord, int,
74                            int, struct ichrstr *, int, int, int *);
75 static void mission_pln_sel(struct emp_qelem *, int, int, int);
76 static int perform_mission(coord, coord, natid, struct emp_qelem *, int,
77                            char *, int);
78
79 /*
80  * Interdict commodities & transported planes
81  */
82 int
83 ground_interdict(coord x, coord y, natid victim, char *s)
84 {
85     int cn;
86     int dam = 0, newdam, rel;
87     struct genlist mi[MAXNOC];
88     int z;
89
90     memset(mi, 0, sizeof(mi));
91     for (z = 1; z < MAXNOC; z++)
92         emp_initque((struct emp_qelem *)&mi[z]);
93
94     build_mission_list(mi, x, y, MI_INTERDICT, victim);
95
96     for (cn = 1; cn < MAXNOC; cn++) {
97         rel = getrel(getnatp(cn), victim);
98         if (rel > HOSTILE)
99             continue;
100
101         if (QEMPTY(&mi[cn].queue))
102             continue;
103
104         newdam = perform_mission(x, y, victim, &mi[cn].queue,
105                                  MI_INTERDICT, s, SECT_HARDTARGET);
106         dam += newdam;
107         if (newdam)
108             mpr(victim, "%s interdiction mission does %d damage!\n",
109                 cname(cn), newdam);
110     }
111     if (dam) {
112         collateral_damage(x, y, dam, 0);
113     }
114     return dam;
115 }
116
117 int
118 collateral_damage(coord x, coord y, int dam, struct emp_qelem *list)
119 {
120     int coll;
121     struct sctstr sect;
122
123     if (!dam)
124         return 0;
125
126     getsect(x, y, &sect);
127     if (sect.sct_own) {
128         coll = ldround((double)dam * collateral_dam, 1);
129         if (coll == 0)
130             return 0;
131         mpr(sect.sct_own, "%s takes %d%% collateral damage\n",
132             xyas(x, y, sect.sct_own), coll);
133         sectdamage(&sect, coll, list);
134         putsect(&sect);
135         return coll;
136     }
137     return 0;
138 }
139
140 static int
141 only_subs(struct emp_qelem *list)
142 {
143     struct emp_qelem *qp;
144     struct genlist *glp;
145     struct mchrstr *mcp;
146
147     for (qp = list->q_forw; qp != list; qp = qp->q_forw) {
148         glp = (struct genlist *)qp;
149
150         if (glp->thing->ef_type != EF_SHIP)
151             return 0;
152         mcp = glp->cp;
153         if (!(mcp->m_flags & M_SUB))
154             return 0;
155         /* It's a sub! */
156     }
157     /* They were all subs! */
158     return 1;
159 }
160
161
162 /*
163  *  Interdict ships & land units
164  */
165 int
166 unit_interdict(coord x, coord y, natid victim, char *s, int hardtarget,
167                int mission)
168 {
169     int cn;
170     int dam = 0, newdam;
171     struct genlist mi[MAXNOC];
172     int z;
173     int osubs;
174
175     memset(mi, 0, sizeof(mi));
176     for (z = 1; z < MAXNOC; z++)
177         emp_initque((struct emp_qelem *)&mi[z]);
178
179     build_mission_list(mi, x, y, mission, victim);
180
181     for (cn = 1; cn < MAXNOC; cn++) {
182         if (cn == victim)
183             continue;
184         if (mission == MI_SINTERDICT) {
185             if (getrel(getnatp(cn), victim) >= FRIENDLY)
186                 continue;
187         } else if (getrel(getnatp(cn), victim) > HOSTILE)
188             continue;
189
190         if (QEMPTY(&mi[cn].queue))
191             continue;
192
193         osubs = only_subs(&mi[cn].queue);
194         newdam = perform_mission(x, y, victim, &mi[cn].queue,
195                                  mission, s, hardtarget);
196         dam += newdam;
197         if (newdam) {
198             /* If only subs responded, then we don't know who's
199                subs they are */
200             mpr(victim, "%s interdiction mission does %d damage!\n",
201                 osubs ? "Enemy" : cname(cn), newdam);
202         }
203     }
204     if (dam) {
205         collateral_damage(x, y, dam, 0);
206     }
207     return dam;
208 }
209
210 /*
211  *  Perform a mission against victim, on behalf of actee
212  */
213 int
214 off_support(coord x, coord y, natid victim, natid actee)
215 {
216     int dam = 0;
217     struct genlist mi[MAXNOC];
218     int z;
219
220     memset(mi, 0, sizeof(mi));
221     for (z = 1; z < MAXNOC; z++)
222         emp_initque((struct emp_qelem *)&mi[z]);
223
224     build_mission_list(mi, x, y, MI_SUPPORT, victim);
225     build_mission_list(mi, x, y, MI_OSUPPORT, victim);
226
227     dam = dosupport(mi, x, y, victim, actee);
228     return dam;
229 }
230
231 /*
232  *  Perform a mission against victim, on behalf of actee
233  */
234 int
235 def_support(coord x, coord y, natid victim, natid actee)
236 {
237     int dam = 0;
238     struct genlist mi[MAXNOC];
239     int z;
240
241     memset(mi, 0, sizeof(mi));
242     for (z = 1; z < MAXNOC; z++)
243         emp_initque((struct emp_qelem *)&mi[z]);
244
245     build_mission_list(mi, x, y, MI_SUPPORT, victim);
246     build_mission_list(mi, x, y, MI_DSUPPORT, victim);
247
248     dam = dosupport(mi, x, y, victim, actee);
249     return dam;
250 }
251
252 static int
253 dosupport(struct genlist *mi, coord x, coord y, natid victim, natid actee)
254 {
255     int cn;
256     int rel;
257     int dam = 0;
258
259     for (cn = 1; cn < MAXNOC; cn++) {
260         rel = getrel(getnatp(cn), actee);
261         if ((cn != actee) && (rel != ALLIED))
262             continue;
263         rel = getrel(getnatp(cn), victim);
264         if ((cn != actee) && (rel != AT_WAR))
265             continue;
266
267         if (QEMPTY(&mi[cn].queue))
268             continue;
269
270         dam += perform_mission(x, y, victim, &mi[cn].queue, MI_SUPPORT,
271                                "", SECT_HARDTARGET);
272     }
273     return dam;
274 }
275
276 static void
277 build_mission_list(struct genlist *mi, coord x, coord y, int mission,
278                    natid victim)
279 {
280     build_mission_list_type(mi, x, y, mission, EF_LAND, victim);
281     build_mission_list_type(mi, x, y, mission, EF_SHIP, victim);
282     build_mission_list_type(mi, x, y, mission, EF_PLANE, victim);
283 }
284
285 static void
286 build_mission_list_type(struct genlist *mi, coord x, coord y, int mission,
287                         int type, natid victim)
288 {
289     struct nstr_item ni;
290     struct genlist *glp;
291     struct empobj *gp;
292     union empobj_storage item;
293     int dist;
294     int radius;
295     int relat;
296     struct sctstr sect;
297
298     snxtitem_all(&ni, type);
299     while (nxtitem(&ni, &item)) {
300         gp = (struct empobj *)&item;
301
302         if (gp->own == 0)
303             continue;
304
305         if (gp->mobil < 1)
306             continue;
307
308         if ((gp->mission != mission) && (mission != MI_SINTERDICT))
309             continue;
310
311         if ((gp->mission != mission) && (mission == MI_SINTERDICT) &&
312             (gp->mission != MI_INTERDICT))
313             continue;
314
315         relat = getrel(getnatp(gp->own), victim);
316         if (mission == MI_SINTERDICT) {
317             if (relat >= FRIENDLY)
318                 continue;
319             else if (type != EF_PLANE && relat > HOSTILE)
320                 continue;
321         } else if (relat > HOSTILE)
322             continue;
323
324         dist = mapdist(x, y, gp->opx, gp->opy);
325
326         radius = gp->radius;
327         if (mission != MI_RESERVE)      /* XXX */
328             oprange(gp, &radius);
329
330         if (dist > radius)
331             continue;
332
333         /* Ok, it is within the operations range. */
334         /* Now check from where the object actually is */
335         dist = mapdist(x, y, gp->x, gp->y);
336         radius = 999;
337         oprange(gp, &radius);
338         if (dist > radius)
339             continue;
340         /* Ok, the object can get to where the x,y is */
341
342         if (opt_SLOW_WAR) {
343             if (mission != MI_AIR_DEFENSE) {
344                 getsect(x, y, &sect);
345                 if (getrel(getnatp(gp->own), sect.sct_own) > AT_WAR) {
346
347                     /*
348                      * If the player->owner of the unit isn't at war
349                      * with the victim, and doesn't own the
350                      * sect being acted upon, and isn't the
351                      * old player->owner of that sect, bounce them.
352                      */
353                     if (sect.sct_type != SCT_WATER &&
354                         sect.sct_own != gp->own &&
355                         sect.sct_oldown != gp->own)
356                         continue;
357                 }
358             }
359         }
360
361         glp = malloc(sizeof(struct genlist));
362         memset(glp, 0, sizeof(struct genlist));
363         glp->cp = get_empobj_chr(gp);
364         glp->thing = malloc(sizeof(item));
365         memcpy(glp->thing, &item, sizeof(item));
366         emp_insque(&glp->queue, &mi[gp->own].queue);
367     }
368 }
369
370 static void
371 find_escorts(coord x, coord y, natid cn, struct emp_qelem *escorts)
372 {
373     struct nstr_item ni;
374     struct plist *plp;
375     struct plnstr plane;
376     int dist;
377
378     snxtitem_all(&ni, EF_PLANE);
379     while (nxtitem(&ni, &plane)) {
380         if (plane.pln_own != cn)
381             continue;
382
383         if (plane.pln_mission != MI_ESCORT)
384             continue;
385
386         dist = mapdist(x, y, plane.pln_x, plane.pln_y);
387         if (dist > plane.pln_range / 2)
388             continue;
389
390         plp = malloc(sizeof(struct plist));
391         memset(plp, 0, sizeof(struct plist));
392         plp->pcp = &plchr[(int)plane.pln_type];
393         plp->plane = plane;
394         emp_insque(&plp->queue, escorts);
395     }
396 }
397
398 static int
399 perform_mission(coord x, coord y, natid victim, struct emp_qelem *list,
400                 int mission, char *s, int hardtarget)
401 {
402     struct emp_qelem *qp, missiles, bombers, escorts, airp, b, e;
403     struct emp_qelem *newqp;
404     struct genlist *glp;
405     struct plist *plp;
406     struct empobj *gp;
407     struct lndstr *lp;
408     struct shpstr *sp;
409     struct sctstr sect;
410     struct mchrstr *mcp;
411     struct plchrstr *pcp;
412     int dam = 0, dam2, mission_flags, tech;
413     natid plane_owner = 0;
414     int gun, shell, md, range, air_dam = 0;
415     double prb, hitchance, vrange;
416
417     getsect(x, y, &sect);
418
419     emp_initque(&missiles);
420     emp_initque(&bombers);
421     emp_initque(&escorts);
422     emp_initque(&airp);
423
424     for (qp = list->q_forw; qp != list; qp = qp->q_forw) {
425         glp = (struct genlist *)qp;
426         gp = glp->thing;
427
428         md = mapdist(x, y, gp->x, gp->y);
429
430         if (glp->thing->ef_type == EF_LAND) {
431             lp = (struct lndstr *)glp->thing;
432
433             if (lp->lnd_effic < LAND_MINFIREEFF)
434                 continue;
435
436             if (mission == MI_SINTERDICT)
437                 continue;
438
439             if ((mission == MI_INTERDICT) &&
440                 (md > land_max_interdiction_range))
441                 continue;
442
443             if ((lp->lnd_ship != -1) || (lp->lnd_land != -1))
444                 continue;
445
446             if (lp->lnd_item[I_MILIT] < 1)
447                 continue;
448
449             range = roundrange(effrange(lp->lnd_frg, lp->lnd_tech));
450             if (md > range)
451                 continue;
452
453             shell = lp->lnd_item[I_SHELL];
454             gun = lp->lnd_item[I_GUN];
455             if (shell == 0 || gun == 0)
456                 continue;
457
458             if (has_supply(lp)) {
459                 use_supply(lp);
460                 putland(lp->lnd_uid, lp);
461                 dam2 = ldround(landunitgun(lp->lnd_effic, lp->lnd_dam, gun,
462                                            lp->lnd_ammo, shell), 1);
463                 if (sect.sct_type == SCT_WATER) {
464                     if (chance(lp->lnd_acc / 100.0))
465                         dam2 = ldround(dam2 / 2.0, 1);
466                 }
467                 dam += dam2;
468                 if (sect.sct_type == SCT_WATER)
469                     nreport(lp->lnd_own, N_SHP_SHELL, victim, 1);
470                 else
471                     nreport(lp->lnd_own, N_SCT_SHELL, victim, 1);
472                 wu(0, lp->lnd_own,
473                    "%s fires at %s %s at %s\n",
474                    prland(lp), cname(victim), s, xyas(x, y, lp->lnd_own));
475
476                 mpr(victim, "%s %s fires at you at %s\n",
477                     cname(lp->lnd_own), prland(lp), xyas(x, y, victim));
478             }
479         } else if (glp->thing->ef_type == EF_SHIP) {
480             sp = (struct shpstr *)glp->thing;
481             mcp = glp->cp;
482
483             if (sp->shp_effic < 60)
484                 continue;
485             if (sp->shp_frnge == 0)
486                 continue;
487             if (((mission == MI_INTERDICT) ||
488                  (mission == MI_SINTERDICT)) &&
489                 (md > ship_max_interdiction_range))
490                 continue;
491             if (sp->shp_item[I_MILIT] < 1)
492                 continue;
493 /*
494   if ((mcp->m_flags & M_SUB) &&
495   (sect.sct_type != SCT_WATER))
496   continue;
497 */
498             if (mission == MI_SINTERDICT) {
499                 if (!(mcp->m_flags & M_SONAR))
500                     continue;
501                 if (!(mcp->m_flags & M_DCH) && !(mcp->m_flags & M_SUBT))
502                     continue;
503                 vrange = techfact(sp->shp_tech, mcp->m_vrnge);
504                 vrange *= sp->shp_effic / 200.0;
505                 if (md > vrange)
506                     continue;
507                 /* can't look all the time */
508                 if (chance(0.5))
509                     continue;
510             }
511             if (mcp->m_flags & M_SUB) {
512 /* If we aren't shooting at "subs" or "ships" don't fire at all from
513    a sub. */
514                 if (*s != 's')
515                     continue;
516                 if (sp->shp_mobil < 0)
517                     continue;
518                 gun = sp->shp_item[I_GUN];
519                 if (gun < 1)
520                     continue;
521                 shell = sp->shp_item[I_SHELL];
522                 if (shell < SHP_TORP_SHELLS)
523                     shell += supply_commod(sp->shp_own,
524                                            sp->shp_x, sp->shp_y, I_SHELL,
525                                            SHP_TORP_SHELLS - shell);
526                 if (shell < SHP_TORP_SHELLS)
527                     continue;
528
529                 range = roundrange(torprange(sp));
530                 if (md > range)
531                     continue;
532
533                 if (!line_of_sight(NULL, x, y, gp->x, gp->y))
534                     continue;
535                 sp->shp_item[I_SHELL] = shell - SHP_TORP_SHELLS;
536                 sp->shp_mobil -= shp_mobcost(sp) / 2.0;
537                 putship(sp->shp_uid, sp);
538                 hitchance = DTORP_HITCHANCE(md, sp->shp_visib);
539
540                 wu(0, sp->shp_own,
541                    "%s locking on %s %s in %s\n",
542                    prship(sp), cname(victim), s, xyas(x, y, sp->shp_own));
543                 wu(0, sp->shp_own,
544                    "\tEffective torpedo range is %d.0\n", range);
545                 wu(0, sp->shp_own,
546                    "\tWhooosh... Hitchance = %d%%\n",
547                    (int)(hitchance * 100));
548
549                 if (hitchance < 1.0 && !chance(hitchance)) {
550                     wu(0, sp->shp_own, "\tMissed\n");
551                     mpr(victim,
552                         "Incoming torpedo sighted @ %s missed (whew)!\n",
553                         xyas(x, y, victim));
554                     continue;
555                 }
556                 wu(0, sp->shp_own, "\tBOOM!...\n");
557                 dam2 = TORP_DAMAGE();
558
559                 dam += dam2;
560                 nreport(victim, N_TORP_SHIP, 0, 1);
561                 wu(0, sp->shp_own,
562                    "\tTorpedo hit %s %s for %d damage\n",
563                    cname(victim), s, dam2);
564
565                 mpr(victim,
566                     "Incoming torpedo sighted @ %s hits and does %d damage!\n",
567                     xyas(x, y, victim), dam2);
568             } else {
569                 range = roundrange(effrange(sp->shp_frnge, sp->shp_tech));
570                 if (md > range)
571                     continue;
572                 gun = sp->shp_item[I_GUN];
573                 gun = MIN(gun, sp->shp_glim);
574                 shell = sp->shp_item[I_SHELL];
575                 if (shell < gun)
576                     shell += supply_commod(sp->shp_own,
577                                            sp->shp_x, sp->shp_y, I_SHELL,
578                                            gun - shell);
579                 gun = MIN(gun, shell);
580                 gun = MIN(gun, sp->shp_item[I_MILIT] / 2.0);
581                 if (gun == 0)
582                     continue;
583                 gun = MAX(gun, 1);
584                 dam2 = seagun(sp->shp_effic, gun);
585                 if (range == 0.0)
586                     prb = 1.0;
587                 else
588                     prb = (double)md / range;
589                 prb *= prb;
590                 if (chance(prb))
591                     dam2 /= 2;
592                 dam += dam2;
593                 if (sect.sct_type == SCT_WATER)
594                     nreport(sp->shp_own, N_SHP_SHELL, victim, 1);
595                 else
596                     nreport(sp->shp_own, N_SCT_SHELL, victim, 1);
597                 wu(0, sp->shp_own,
598                    "%s fires at %s %s at %s\n",
599                    prship(sp), cname(victim), s, xyas(x, y, sp->shp_own));
600
601                 mpr(victim, "%s %s fires at you at %s\n",
602                     cname(sp->shp_own), prship(sp), xyas(x, y, victim));
603
604                 sp->shp_item[I_SHELL] = shell - gun;
605                 putship(sp->shp_uid, sp);
606             }
607         } else if (glp->thing->ef_type == EF_PLANE) {
608             pcp = glp->cp;
609             if (pcp->pl_flags & P_M)
610                 /* units have their own missile interdiction */
611                 if (hardtarget != SECT_HARDTARGET || pcp->pl_flags & P_MAR)
612                     continue;
613
614             /* save planes for later */
615             plp = malloc(sizeof(struct plist));
616
617             memset(plp, 0, sizeof(struct plist));
618             plp->pcp = pcp;
619             memcpy(&plp->plane, glp->thing, sizeof(struct plnstr));
620             if (plp->pcp->pl_flags & P_M)
621                 emp_insque(&plp->queue, &missiles);
622             else
623                 emp_insque(&plp->queue, &bombers);
624             plane_owner = plp->plane.pln_own;
625         } else {
626             CANT_REACH();
627             break;
628         }
629     }
630     if (!QEMPTY(&missiles)) {
631         /* I arbitrarily chose 100 mindam -KHS */
632         dam +=
633             msl_launch_mindam(&missiles, x, y, hardtarget, EF_SECTOR, 100,
634                               "sector", victim, mission);
635         qp = missiles.q_forw;
636         while (qp != (&missiles)) {
637             newqp = qp->q_forw;
638             emp_remque(qp);
639             free(qp);
640             qp = newqp;
641         }
642     }
643
644     if (QEMPTY(&bombers)) {
645         qp = list->q_forw;
646         while (qp != list) {
647             glp = (struct genlist *)qp;
648             qp = qp->q_forw;
649
650             free(glp->thing);
651             free(glp);
652         }
653         return dam;
654     }
655     /*
656      * If there are planes performing an
657      * interdict or support mission, find
658      * some escorts for them, if possible.
659      * Up to 2 per bomber, if possible.
660      */
661     find_escorts(x, y, plane_owner, &escorts);
662
663     if (mission == MI_SINTERDICT)
664         mission_pln_sel(&bombers, P_T | P_A, 0, hardtarget);
665     else
666         mission_pln_sel(&bombers, P_T, P_A, SECT_HARDTARGET);
667
668     mission_pln_sel(&escorts, P_ESC | P_F, 0, SECT_HARDTARGET);
669
670     for (qp = bombers.q_forw; qp != (&bombers); qp = qp->q_forw) {
671         plp = (struct plist *)qp;
672         if (!find_airport(&airp, plp->plane.pln_x, plp->plane.pln_y))
673             add_airport(&airp, plp->plane.pln_x, plp->plane.pln_y);
674     }
675
676     for (qp = airp.q_forw; qp != (&airp); qp = qp->q_forw) {
677         struct airport *air;
678         char buf[512];
679         char *pp;
680
681         air = (struct airport *)qp;
682         md = mapdist(x, y, air->x, air->y);
683
684         emp_initque(&b);
685         emp_initque(&e);
686
687         /* Split off the bombers at this base into b */
688         divide(&bombers, &b, air->x, air->y);
689
690         /* Split off the escorts at this base into e */
691         divide(&escorts, &e, air->x, air->y);
692
693         tech = 0;
694         mission_flags = 0;
695         mission_flags |= P_X;   /* stealth (shhh) */
696         mission_flags |= P_H;   /* gets turned off if not all choppers */
697
698         mission_flags = mission_pln_arm(&b, air->x, air->y, 2 * md, 'p', 0,
699                                         0, mission_flags, &tech);
700
701         if (QEMPTY(&b))
702             continue;
703
704         mission_flags = mission_pln_arm(&e, air->x, air->y, 2 * md, 'p', 0,
705                                         P_F | P_ESC, mission_flags, &tech);
706
707         pp = BestAirPath(buf, air->x, air->y, x, y);
708         if (CANT_HAPPEN(!pp))
709             continue;
710         wu(0, plane_owner, "Flying %s mission from %s\n",
711            mission_name(mission), xyas(air->x, air->y, plane_owner));
712         if (air->own && (air->own != plane_owner)) {
713             wu(0, air->own, "%s is flying %s mission from %s\n",
714                cname(plane_owner), mission_name(mission),
715                xyas(air->x, air->y, air->own));
716         }
717
718         ac_encounter(&b, &e, air->x, air->y, pp, mission_flags, 0, 0, 0);
719
720         if (!QEMPTY(&b))
721             air_dam +=
722                 air_damage(&b, x, y, mission, victim, s, hardtarget);
723
724         pln_put(&b);
725         pln_put(&e);
726     }
727
728     if (air_dam > 0) {
729         dam += air_dam;
730         if (sect.sct_type == SCT_WATER)
731             nreport(plane_owner, N_SHP_BOMB, victim, 1);
732         else
733             nreport(plane_owner, N_SCT_BOMB, victim, 1);
734     }
735
736     /* free up all this memory */
737     qp = list->q_forw;
738     while (qp != list) {
739         glp = (struct genlist *)qp;
740         qp = qp->q_forw;
741
742         free(glp->thing);
743         free(glp);
744     }
745
746     qp = escorts.q_forw;
747     while (qp != (&escorts)) {
748         newqp = qp->q_forw;
749         emp_remque(qp);
750         free(qp);
751         qp = newqp;
752     }
753
754     qp = bombers.q_forw;
755     while (qp != (&bombers)) {
756         newqp = qp->q_forw;
757         emp_remque(qp);
758         free(qp);
759         qp = newqp;
760     }
761
762     return dam;
763 }
764
765 int
766 cando(int mission, int type)
767 {
768     switch (mission) {
769     case MI_ESCORT:
770         if (type == EF_PLANE)
771             return 1;
772         return 0;
773     case MI_AIR_DEFENSE:
774         if (type == EF_PLANE)
775             return 1;
776         return 0;
777     case MI_SINTERDICT:
778         if ((type == EF_PLANE) || (type == EF_SHIP))
779             return 1;
780         return 0;
781     case MI_INTERDICT:
782         return 1;
783     case MI_SUPPORT:
784     case MI_OSUPPORT:
785     case MI_DSUPPORT:
786         if (type == EF_PLANE)
787             return 1;
788         return 0;
789     case MI_RESERVE:
790         if (type == EF_LAND)
791             return 1;
792         return 0;
793     }
794
795     return 0;
796 }
797
798 char *
799 mission_name(short mission)
800 {
801     switch (mission) {
802     case MI_INTERDICT:
803         return "an interdiction";
804     case MI_SUPPORT:
805         return "a support";
806     case MI_OSUPPORT:
807         return "a offensive support";
808     case MI_DSUPPORT:
809         return "a defensive support";
810     case MI_RESERVE:
811         return "a reserve";
812     case MI_ESCORT:
813         return "an escort";
814     case MI_SINTERDICT:
815         return "a sub interdiction";
816     case MI_AIR_DEFENSE:
817         return "an air defense";
818     }
819     return "a mysterious";
820 }
821
822 void
823 show_mission(int type, struct nstr_item *np)
824 {
825     int first = 1, radius;
826     union empobj_storage item;
827     struct empobj *gp;
828
829     while (nxtitem(np, &item)) {
830         gp = (struct empobj *)&item;
831         if (!player->owner || gp->own == 0)
832             continue;
833
834         if (first) {
835             pr("Thing                         x,y   op-sect rad mission\n");
836             first = 0;
837         }
838         pr("%-25s", obj_nameof(gp));
839         prxy(" %3d,%-3d", gp->x, gp->y, player->cnum);
840         if (gp->mission == MI_INTERDICT || gp->mission == MI_SUPPORT ||
841             gp->mission == MI_OSUPPORT ||
842             gp->mission == MI_DSUPPORT || gp->mission == MI_AIR_DEFENSE) {
843             radius = 999;
844             oprange(gp, &radius);
845             prxy(" %3d,%-3d", gp->opx, gp->opy, player->cnum);
846             if (radius < gp->radius)
847                 pr("  %4d", radius);
848             else
849                 pr("  %4d", gp->radius);
850         } else if (gp->mission == MI_RESERVE) {
851             struct sctstr sect;
852             int plus = 2;
853
854             getsect(gp->x, gp->y, &sect);
855             if ((sect.sct_type == SCT_HEADQ) && (sect.sct_effic >= 60))
856                 plus++;
857
858             if (item.land.lnd_rad_max == 0)
859                 plus = 0;
860             else
861                 plus += item.land.lnd_rad_max;
862             prxy(" %3d,%-3d", gp->x, gp->y, player->cnum);
863             pr("  %4d", plus);
864         } else if (gp->mission == MI_ESCORT) {
865             pr("        ");
866             pr("  %4d", item.plane.pln_range / 2);
867         } else
868             pr("              ");
869         if (gp->mission)
870             pr(" is on %s mission\n", mission_name(gp->mission));
871         else
872             pr(" has no mission.\n");
873     }
874 }
875
876 int
877 oprange(struct empobj *gp, int *radius)
878 {
879     int range;
880
881     switch (gp->ef_type) {
882     case EF_SHIP:
883         range = ldround(effrange(((struct shpstr *)gp)->shp_frnge,
884                                  ((struct shpstr *)gp)->shp_tech), 1);
885         break;
886     case EF_LAND:
887         range = ldround(effrange(((struct lndstr *)gp)->lnd_frg,
888                                  ((struct lndstr *)gp)->lnd_tech), 1);
889         break;
890     case EF_PLANE:
891         /* missiles go one way, so we can use all the range */
892         if (plchr[(int)gp->type].pl_flags & P_M)
893             range = ((struct plnstr *)gp)->pln_range;
894         else
895             range = ((struct plnstr *)gp)->pln_range / 2;
896         break;
897     default:
898         CANT_HAPPEN("bad TYPE");
899         range = -1;
900     }
901
902     if (*radius > range)
903         *radius = range;
904
905     return range;
906 }
907
908 /*
909  *  Remove all planes who cannot go on
910  *  the mission from the plane list.
911  */
912 static void
913 mission_pln_sel(struct emp_qelem *list, int wantflags, int nowantflags,
914                 int hardtarget)
915 {
916     struct emp_qelem *qp, *next;
917     struct plnstr *pp;
918     struct plchrstr *pcp;
919     struct plist *plp;
920
921     for (qp = list->q_forw; qp != list; qp = next) {
922         next = qp->q_forw;
923         plp = (struct plist *)qp;
924         pp = &plp->plane;
925         pcp = plp->pcp;
926
927         if (pp->pln_effic < 40) {
928             emp_remque(qp);
929             free(qp);
930             continue;
931         }
932
933         if (pp->pln_mobil < 1) {
934             emp_remque(qp);
935             free(qp);
936             continue;
937         }
938
939         if (opt_MARKET) {
940             if (ontradingblock(EF_PLANE, pp)) {
941                 emp_remque(qp);
942                 free(qp);
943                 continue;
944             }
945         }
946
947         if (!pln_capable(pp, wantflags, nowantflags)) {
948             emp_remque(qp);
949             free(qp);
950             continue;
951         }
952
953         if (!pln_airbase_ok(pp, 0, 0)) {
954             emp_remque(qp);
955             free(qp);
956             continue;
957         }
958             
959         if (pcp->pl_flags & P_A) {
960             if (roll(100) > pln_identchance(pp, hardtarget, EF_SHIP)) {
961                 emp_remque(qp);
962                 free(qp);
963                 continue;
964             }
965         }
966
967         putplane(pp->pln_uid, pp);
968     }
969 }
970
971 /*
972  * Arm only the planes at x,y
973  */
974 static int
975 mission_pln_arm(struct emp_qelem *list, coord x, coord y, int dist,
976                 int mission, struct ichrstr *ip, int flags,
977                 int mission_flags, int *tech)
978 {
979     struct emp_qelem *qp;
980     struct emp_qelem *next;
981     struct plist *plp;
982
983     if (*tech == 0)
984         *tech = 9999;
985     for (qp = list->q_forw; qp != list; qp = next) {
986         next = qp->q_forw;
987         plp = (struct plist *)qp;
988
989         if (plp->plane.pln_x != x)
990             continue;
991         if (plp->plane.pln_y != y)
992             continue;
993
994         if (mission_pln_equip(plp, ip, flags, mission) < 0) {
995             emp_remque(qp);
996             free(qp);
997             continue;
998         }
999         if (flags & (P_S | P_I)) {
1000             if (plp->pcp->pl_flags & P_S)
1001                 mission_flags |= P_S;
1002             if (plp->pcp->pl_flags & P_I)
1003                 mission_flags |= P_I;
1004         }
1005         if (*tech > plp->plane.pln_tech)
1006             *tech = plp->plane.pln_tech;
1007         if (!(plp->pcp->pl_flags & P_H))
1008             /* no stealth on this mission */
1009             mission_flags &= ~P_H;
1010         if (!(plp->pcp->pl_flags & P_X))
1011             /* no stealth on this mission */
1012             mission_flags &= ~P_X;
1013         if (!(plp->pcp->pl_flags & P_A)) {
1014             /* no asw on this mission */
1015             mission_flags &= ~P_A;
1016         }
1017         if (!(plp->pcp->pl_flags & P_MINE)) {
1018             /* no asw on this mission */
1019             mission_flags &= ~P_MINE;
1020         }
1021
1022         /*
1023          *      Mob costs for missions are 1/2 normal
1024          *       Not anymore. :)
1025          */
1026 /*      plp->plane.pln_mobil -= pln_mobcost(dist,&plp->plane,flags)/2;*/
1027         plp->plane.pln_mobil -= pln_mobcost(dist, &plp->plane, flags);
1028
1029     }
1030     return mission_flags;
1031 }
1032
1033 int
1034 mission_pln_equip(struct plist *plp, struct ichrstr *ip, int flags,
1035                   char mission)
1036 {
1037     struct plchrstr *pcp;
1038     struct plnstr *pp;
1039     int needed;
1040     struct lndstr land;
1041     struct shpstr ship;
1042     struct sctstr sect;
1043     i_type itype;
1044     int rval;
1045     short *item;
1046
1047     pp = &plp->plane;
1048     pcp = plp->pcp;
1049     if (pp->pln_ship >= 0) {
1050         getship(pp->pln_ship, &ship);
1051         item = ship.shp_item;
1052     } else if (pp->pln_land >= 0) {
1053         getland(pp->pln_land, &land);
1054         item = land.lnd_item;
1055     } else {
1056         getsect(pp->pln_x, pp->pln_y, &sect);
1057         item = sect.sct_item;
1058     }
1059     if (pcp->pl_fuel > item[I_PETROL]) {
1060         return -1;
1061     }
1062     item[I_PETROL] -= pcp->pl_fuel;
1063     rval = 0;
1064     if (!(flags & P_F)) {
1065         itype = I_NONE;
1066         needed = 0;
1067         switch (mission) {
1068         case 's':
1069         case 'p':
1070             if (pp->pln_nuketype == -1) {
1071                 itype = I_SHELL;
1072                 needed = pp->pln_load;
1073             }
1074             break;
1075         case 't':
1076             if ((pcp->pl_flags & P_C) == 0 || ip == 0)
1077                 break;
1078             itype = ip->i_uid;
1079             needed = (pp->pln_load * 2) / ip->i_lbs;
1080             break;
1081         case 'd':
1082             if ((pcp->pl_flags & P_C) == 0 || ip == 0)
1083                 break;
1084             itype = ip->i_uid;
1085             needed = (pp->pln_load * 2) / ip->i_lbs;
1086             break;
1087         case 'a':
1088             if ((pcp->pl_flags & (P_V | P_C)) == 0)
1089                 break;
1090             itype = I_MILIT;
1091             needed = pp->pln_load / ip->i_lbs;
1092             break;
1093         case 'n':
1094             if (pp->pln_nuketype == -1)
1095                 rval = -1;
1096             break;
1097         case 'i':               /* missile interception */
1098             if (pp->pln_load) {
1099                 itype = I_SHELL;
1100                 needed = pp->pln_load;
1101             }
1102             break;
1103         default:
1104             break;
1105         }
1106         if (rval < 0 || (itype != I_NONE && needed <= 0)) {
1107             return -1;
1108         }
1109         if (itype != I_NONE) {
1110             if (itype == I_SHELL && item[itype] < needed)
1111                 item[itype] += supply_commod(plp->plane.pln_own,
1112                                              plp->plane.pln_x,
1113                                              plp->plane.pln_y,
1114                                              I_SHELL, needed);
1115             if (item[itype] < needed)
1116                 return -1;
1117             item[itype] -= needed;
1118         }
1119         if (itype == I_SHELL && (mission == 's' || mission == 'p'))
1120             plp->bombs = needed;
1121         else
1122             plp->misc = needed;
1123     }
1124     if (pp->pln_ship >= 0)
1125         putship(ship.shp_uid, &ship);
1126     else if (pp->pln_land >= 0)
1127         putland(land.lnd_uid, &land);
1128     else
1129         putsect(&sect);
1130     return rval;
1131 }
1132
1133 /*
1134  *  Return 1 if this x,y pair is in the list
1135  */
1136 static int
1137 find_airport(struct emp_qelem *airp, coord x, coord y)
1138 {
1139     struct emp_qelem *qp;
1140     struct airport *a;
1141
1142     for (qp = airp->q_forw; qp != airp; qp = qp->q_forw) {
1143         a = (struct airport *)qp;
1144         if ((a->x == x) && (a->y == y))
1145             return 1;
1146     }
1147
1148     return 0;
1149 }
1150
1151 /* #*# This needs to be changed to include acc's -KHS */
1152 static void
1153 add_airport(struct emp_qelem *airp, coord x, coord y)
1154 {
1155     struct airport *a;
1156     struct sctstr sect;
1157
1158     a = malloc(sizeof(struct airport));
1159
1160     a->x = x;
1161     a->y = y;
1162     getsect(x, y, &sect);
1163     a->own = sect.sct_own;
1164
1165     emp_insque((struct emp_qelem *)a, airp);
1166 }
1167
1168 /*
1169  *  Take all the planes in list 1 that
1170  *  are at x,y, and put them into list 2.
1171  */
1172 static void
1173 divide(struct emp_qelem *l1, struct emp_qelem *l2, coord x, coord y)
1174 {
1175     struct emp_qelem *qp, *next;
1176     struct plist *plp;
1177
1178     for (qp = l1->q_forw; qp != l1; qp = next) {
1179         next = qp->q_forw;
1180         plp = (struct plist *)qp;
1181
1182         if (plp->plane.pln_x != x)
1183             continue;
1184         if (plp->plane.pln_y != y)
1185             continue;
1186
1187         emp_remque(qp);
1188         emp_insque(qp, l2);
1189     }
1190 }
1191
1192 static int
1193 air_damage(struct emp_qelem *bombers, coord x, coord y, int mission,
1194            natid victim, char *s, int hardtarget)
1195 {
1196     struct emp_qelem *qp;
1197     struct plist *plp;
1198     struct plnstr *pp;
1199     int newdam, dam = 0;
1200     int hitchance;
1201     int nukedam;
1202
1203     for (qp = bombers->q_forw; qp != bombers; qp = qp->q_forw) {
1204         plp = (struct plist *)qp;
1205         pp = &plp->plane;
1206
1207         if ((mission == MI_SINTERDICT) && !(plp->pcp->pl_flags & P_A))
1208             continue;
1209
1210         if (!plp->bombs)
1211             continue;
1212
1213         newdam = 0;
1214         if (plp->pcp->pl_flags & P_A) {
1215             if (roll(100) > pln_identchance(pp, hardtarget, EF_SHIP)) {
1216                 wu(0, pp->pln_own,
1217                    "\t%s detects sub movement in %s\n",
1218                    prplane(pp), xyas(x, y, pp->pln_own));
1219                 continue;
1220             }
1221             if (getrel(getnatp(pp->pln_own), victim) > HOSTILE) {
1222                 wu(0, pp->pln_own,
1223                    "\t%s tracks %s %s at %s\n",
1224                    prplane(pp), cname(victim), s, xyas(x, y, pp->pln_own));
1225                 continue;
1226             }
1227             wu(0, pp->pln_own,
1228                "\t%s depth-charging %s %s in %s\n",
1229                prplane(pp), cname(victim), s, xyas(x, y, pp->pln_own));
1230         } else {
1231             wu(0, pp->pln_own,
1232                "\t%s pinbombing %s %s in %s\n",
1233                prplane(pp), cname(victim), s, xyas(x, y, pp->pln_own));
1234         }
1235         hitchance = pln_hitchance(pp, hardtarget, EF_SHIP);
1236         if (plp->plane.pln_nuketype != -1)
1237             hitchance = 100;
1238         else if (hardtarget != SECT_HARDTARGET)
1239             wu(0, pp->pln_own, "\t\t%d%% hitchance...", hitchance);
1240         /* Always calculate damage */
1241         if (roll(100) <= hitchance) {
1242             newdam = pln_damage(&plp->plane, x, y, 'p', &nukedam, 1);
1243             if (nukedam) {
1244                 if (mission == MI_INTERDICT) {
1245                     wu(0, pp->pln_own,
1246                        "\t\tnuclear warhead on plane %s does %d damage to %s %s\n",
1247                        prplane(pp), nukedam, cname(victim), s);
1248                     dam += nukedam;
1249                 }
1250             } else {
1251                 wu(0, pp->pln_own,
1252                    "\t\thit %s %s for %d damage\n",
1253                    cname(victim), s, newdam);
1254                 dam += newdam;
1255             }
1256         } else {
1257             newdam = pln_damage(&plp->plane, x, y, 'p', &nukedam, 0);
1258             wu(0, pp->pln_own, "missed\n");
1259             if (mission == MI_SINTERDICT) {
1260                 mpr(victim,
1261                     "RUMBLE... your sub in %s hears a depth-charge explode nearby\n",
1262                     xyas(x, y, victim));
1263             } else if (*s == 's') {
1264                 mpr(victim, "SPLASH!  Bombs miss your %s in %s\n",
1265                     s, xyas(x, y, victim));
1266             } else {
1267                 mpr(victim, "SPLAT!  Bombs miss your %s in %s\n",
1268                     s, xyas(x, y, victim));
1269             }
1270             /* Now, even though we missed, the bombs
1271                land somewhere. */
1272             collateral_damage(x, y, newdam, bombers);
1273         }
1274
1275         /* use up missiles */
1276         if (plp->pcp->pl_flags & P_M)
1277             pp->pln_effic = 0;
1278     }
1279
1280     return dam;
1281 }
1282
1283 /*
1284  * Check to see if anyone hostile to the victim
1285  * is running an air defense mission on this
1286  * sector. If so, do air combat
1287  */
1288 int
1289 air_defense(coord x, coord y, natid victim, struct emp_qelem *bomb_list,
1290             struct emp_qelem *esc_list)
1291 {
1292     int dam = 0, cn;
1293     int mission_flags, tech, combat = 0, rel, dist, z;
1294     struct emp_qelem *qp, interceptors, airp, i, empty, *next;
1295     struct plist *plp;
1296     struct genlist *glp;
1297     struct empobj *gp;
1298     struct genlist mi[MAXNOC];
1299     char buf[512];
1300     char *path;
1301     int count;
1302     int tcount;
1303
1304     count = 0;
1305     for (qp = bomb_list->q_forw; qp != bomb_list; qp = qp->q_forw)
1306         count++;
1307     for (qp = esc_list->q_forw; qp != esc_list; qp = qp->q_forw)
1308         count++;
1309
1310     memset(mi, 0, sizeof(mi));
1311     for (z = 1; z < MAXNOC; z++)
1312         emp_initque((struct emp_qelem *)&mi[z]);
1313
1314     build_mission_list_type(mi, x, y, MI_AIR_DEFENSE, EF_PLANE, victim);
1315
1316     for (cn = 1; cn < MAXNOC; cn++) {
1317         /* Check our relations */
1318         rel = getrel(getnatp(cn), victim);
1319
1320         if (rel > HOSTILE)
1321             continue;
1322
1323         if (QEMPTY(&mi[cn].queue))
1324             continue;
1325
1326         /* Ok, make a list of all the interceptors.  Note that this *copies* the
1327          * list from the mission creation.  This list must be deleted later. */
1328         emp_initque(&interceptors);
1329         for (qp = mi[cn].queue.q_forw; qp != (&mi[cn].queue); qp = next) {
1330             next = qp->q_forw;
1331             glp = (struct genlist *)qp;
1332             gp = glp->thing;
1333             if (CANT_HAPPEN(gp->ef_type != EF_PLANE))
1334                 break;
1335
1336             dist = mapdist(x, y, gp->x, gp->y);
1337
1338             plp = malloc(sizeof(struct plist));
1339             memset(plp, 0, sizeof(struct plist));
1340             plp->pcp = glp->cp;
1341             memcpy(&plp->plane, glp->thing, sizeof(struct plnstr));
1342
1343             /* missiles go one way, so we can use all the range */
1344             if (!(plp->pcp->pl_flags & P_M))
1345                 dist *= 2;
1346             /* If it's out of range, free it and continue on */
1347             if (dist > plp->plane.pln_range) {
1348                 free(plp);
1349                 continue;
1350             }
1351             emp_insque(&plp->queue, &interceptors);
1352         }
1353
1354         /* Remove those who cannot go */
1355         mission_pln_sel(&interceptors, P_F, 0, SECT_HARDTARGET);
1356
1357         if (QEMPTY(&interceptors))
1358             continue;
1359
1360         /* Now, delete all the extras, but delete the first ones, not the last ones, so
1361          * that the higher numbered planes go into battle (they should be the better ones
1362          * at fighting, if all went well.) */
1363         tcount = 0;
1364         for (qp = interceptors.q_forw; qp != (&interceptors);
1365              qp = qp->q_forw)
1366             tcount++;
1367         tcount -= count * 2;
1368         /* Just in case there are more incoming than we have */
1369         if (tcount < 0)
1370             tcount = 0;
1371         for (qp = interceptors.q_forw; qp != (&interceptors); qp = next) {
1372             next = qp->q_forw;
1373             if (tcount) {
1374                 tcount--;
1375                 /* Free it up and continue */
1376                 emp_remque(qp);
1377                 glp = (struct genlist *)qp;
1378                 free(glp);
1379             }
1380         }
1381
1382         /* Now, make a list of all the airports these planes are coming from */
1383         emp_initque(&airp);
1384         for (qp = interceptors.q_forw; qp != (&interceptors);
1385              qp = qp->q_forw) {
1386             plp = (struct plist *)qp;
1387             if (!find_airport(&airp, plp->plane.pln_x, plp->plane.pln_y))
1388                 add_airport(&airp, plp->plane.pln_x, plp->plane.pln_y);
1389         }
1390
1391         /* Now, fly them out one airport at a time */
1392         for (qp = airp.q_forw; qp != (&airp); qp = qp->q_forw) {
1393             struct airport *air;
1394
1395             air = (struct airport *)qp;
1396             dist = mapdist(x, y, air->x, air->y);
1397
1398             emp_initque(&i);
1399
1400             /* Split off the interceptors at this base into i */
1401             divide(&interceptors, &i, air->x, air->y);
1402
1403             tech = 0;
1404             mission_flags = 0;
1405             mission_flags |= P_X;       /* stealth (shhh) */
1406             /* gets turned off if not all choppers */
1407             mission_flags |= P_H;
1408             sam_intercept(bomb_list, &i, cn, victim, x, y, 0);
1409             sam_intercept(esc_list, &i, cn, victim, x, y, 1);
1410
1411             /* Did we run out of interceptors? */
1412             if (QEMPTY(&i))
1413                 continue;
1414             /* Did we run out of bombers? */
1415             if (QEMPTY(bomb_list)) {
1416                 /* Yes, so we have to put the rest of the interceptors back, and
1417                    then continue, or we leak memory */
1418                 pln_put(&i);
1419                 continue;
1420             }
1421             mission_flags =
1422                 mission_pln_arm(&i, air->x, air->y, 2 * dist, 'r', 0, P_F,
1423                                 mission_flags, &tech);
1424
1425             /* Did we run out of interceptors? */
1426             if (QEMPTY(&i))
1427                 continue;
1428             /* Did we run out of bombers? */
1429             if (QEMPTY(bomb_list)) {
1430                 /* Yes, so we have to put the rest of the interceptors back, and
1431                    then continue, or we leak memory */
1432                 pln_put(&i);
1433                 continue;
1434             }
1435
1436             path = BestAirPath(buf, air->x, air->y, x, y);
1437             if (CANT_HAPPEN(!path))
1438                 continue;
1439             wu(0, cn, "Flying %s mission from %s\n",
1440                mission_name(MI_AIR_DEFENSE), xyas(air->x, air->y, cn));
1441             if (air->own && (air->own != cn)) {
1442                 wu(0, air->own, "%s is flying %s mission from %s\n",
1443                    cname(cn), mission_name(MI_AIR_DEFENSE),
1444                    xyas(air->x, air->y, air->own));
1445             }
1446
1447             /* Now, fly the planes to the sector */
1448             emp_initque(&empty);
1449             ac_encounter(&i, &empty, air->x, air->y,
1450                          path, mission_flags, 1, bomb_list, esc_list);
1451
1452             /* If none made it, continue */
1453             if (QEMPTY(&i))
1454                 continue;
1455
1456             /* Some made it, so now they get to try to fight. */
1457             /* Intercept the escorts first */
1458             combat = 0;
1459             if (!QEMPTY(esc_list)) {
1460                 mpr(victim, "%s air defense planes intercept!\n",
1461                     cname(cn));
1462                 ac_combat_headers(victim, cn);
1463                 ac_airtoair(esc_list, &i);
1464                 combat = 1;
1465             }
1466             /* Now intercept the bombers */
1467             if (!QEMPTY(bomb_list)) {
1468                 if (!combat) {
1469                     mpr(victim, "%s air defense planes intercept!\n",
1470                         cname(cn));
1471                     ac_combat_headers(victim, cn);
1472                 }
1473                 ac_airtoair(bomb_list, &i);
1474                 PR(cn, "\n");
1475                 PR(victim, "\n");
1476             }
1477
1478             pln_put(&i);
1479         }
1480     }
1481
1482     /* We have to free all of these, if they are still there, otherwise they get
1483        lost and we leak memory all over the place. */
1484     for (cn = 1; cn < MAXNOC; cn++) {
1485         /* free up all this memory if it's still there */
1486         for (qp = mi[cn].queue.q_forw; qp != (&mi[cn].queue); qp = next) {
1487             next = qp->q_forw;
1488             glp = (struct genlist *)qp;
1489             free(glp->thing);
1490             free(glp);
1491         }
1492     }
1493
1494     return dam;
1495 }