2 * Empire - A multi-player, client/server Internet based war game.
3 * Copyright (C) 1986-2005, Dave Pare, Jeff Bailey, Thomas Ruschak,
4 * Ken Stevens, Steve McClure
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.
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.
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
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.
28 * aircombat.c: Deal with air to air combat
30 * Known contributors to this file:
32 * Thomas Ruschak, 1992
50 #include "prototypes.h"
56 #define MAX(x,y) ((x) < (y) ? (y) : (x))
59 static void getilist(struct emp_qelem *list, natid own,
60 struct emp_qelem *a, struct emp_qelem *b,
61 struct emp_qelem *c, struct emp_qelem *d);
62 static void ac_dog(struct plist *ap, struct plist *dp);
65 ac_encounter(struct emp_qelem *bomb_list, struct emp_qelem *esc_list,
66 coord x, coord y, s_char *path, int mission_flags,
67 int no_air_defense, struct emp_qelem *obomb,
68 struct emp_qelem *oesc)
70 int val, non_missiles;
76 int unfriendly[MAXNOC];
78 struct emp_qelem ilist[MAXNOC], *qp;
88 struct natstr *over, *mynatp;
91 struct shiplist *head = NULL;
93 int intown = 0; /* Last owner to intercept */
94 /* We want to only intercept once per sector per owner. So, if we overfly
95 a sector, and then overfly some land units or ships, we don't want to
96 potentially intercept 3 times. */
98 plp = (struct plist *)bomb_list->q_forw;
99 plane_owner = plp->plane.pln_own;
101 strncpy(mypath, path, sizeof(mypath));
104 memset(overfly, 0, sizeof(overfly));
105 memset(gotilist, 0, sizeof(gotilist));
106 memset(unfriendly, 0, sizeof(unfriendly));
107 for (cn = 1; cn < MAXNOC; cn++) {
108 if ((mynatp = getnatp(cn)) == 0)
110 rel = getrel(mynatp, plane_owner);
113 if (plane_owner == cn)
117 if (mission_flags & PM_R) {
118 if (mission_flags & P_S) {
119 PR(plane_owner, "\nSPY Plane report\n");
122 } else if (mission_flags & P_A) {
123 PR(plane_owner, "\nAnti-Sub Patrol report\n");
125 PR(plane_owner, "\nReconnaissance report\n");
130 pln_removedupes(bomb_list, esc_list);
131 while ((dir = mypath[myp++]) && !QEMPTY(bomb_list)) {
132 if ((val = diridx(dir)) == DIR_STOP)
134 /* XXX using xnorm is probably bad */
135 x = xnorm(x + diroff[val][0]);
136 y = ynorm(y + diroff[val][1]);
137 getsect(x, y, §);
138 over = getnatp(sect.sct_own);
140 if (mission_flags & PM_R) {
142 setcont(plane_owner, sect.sct_own, FOUND_FLY);
143 if (sect.sct_type == SCT_WATER) {
144 PR(plane_owner, "flying over %s at %s\n",
145 dchr[sect.sct_type].d_name, xyas(x, y, plane_owner));
146 if (mission_flags & PM_S)
147 plane_sweep(bomb_list, x, y);
148 if (mission_flags & P_A) {
149 plane_sona(bomb_list, x, y, &head);
151 changed += map_set(plane_owner,
152 sect.sct_x, sect.sct_y,
153 dchr[sect.sct_type].d_mnem, 0);
154 } else if (mission_flags & P_S) {
155 satdisp(§, (mission_flags & P_I) ? 10 : 50, 1);
157 /* This is borrowed from lookout */
158 if (sect.sct_own == plane_owner)
159 PR(plane_owner, "Your ");
162 "%s (#%d) ", cname(sect.sct_own), sect.sct_own);
163 PR(plane_owner, dchr[sect.sct_type].d_name);
164 changed += map_set(plane_owner,
165 sect.sct_x, sect.sct_y,
166 dchr[sect.sct_type].d_mnem, 0);
167 PR(plane_owner, " %d%% efficient ",
168 (sect.sct_own == plane_owner) ?
169 sect.sct_effic : roundintby((int)sect.sct_effic, 25));
170 civ = sect.sct_item[I_CIVIL];
171 mil = sect.sct_item[I_MILIT];
173 PR(plane_owner, "with %s%d civ ",
174 (sect.sct_own == plane_owner) ?
176 (sect.sct_own == plane_owner) ?
177 civ : roundintby(civ, 25));
179 PR(plane_owner, "with %s%d mil ",
180 (sect.sct_own == plane_owner) ?
182 (sect.sct_own == plane_owner) ?
183 mil : roundintby(mil, 25));
184 PR(plane_owner, "@ %s\n", xyas(x, y, plane_owner));
187 PR(plane_owner, "flying over %s at %s\n",
188 dchr[sect.sct_type].d_name, xyas(x, y, plane_owner));
189 changed += map_set(plane_owner, sect.sct_x,
190 sect.sct_y, dchr[sect.sct_type].d_mnem, 0);
192 if ((rel = getrel(over, plane_owner)) == ALLIED)
195 evaded = do_evade(bomb_list, esc_list);
197 if (sect.sct_own != 0 && sect.sct_own != plane_owner && !evaded) {
198 /* We only show planes overhead if they didn't
200 overfly[sect.sct_own]++;
201 PR(sect.sct_own, "%s planes spotted over %s\n",
202 cname(plane_owner), xyas(x, y, sect.sct_own));
204 setcont(cn, plane_owner, FOUND_FLY);
209 if (unfriendly[sect.sct_own])
210 ac_doflak(bomb_list, §);
211 /* If bombers left, fire flak from units and ships */
212 if (!QEMPTY(bomb_list))
213 ac_landflak(bomb_list, x, y);
214 if (!QEMPTY(bomb_list))
215 ac_shipflak(bomb_list, x, y);
217 /* mission planes aborted due to flak -- don't send escorts */
218 if (QEMPTY(bomb_list))
220 if (!no_air_defense && !evaded)
221 air_defense(x, y, plane_owner, bomb_list, esc_list);
223 if (sect.sct_own == 0 || sect.sct_own == plane_owner)
230 for (qp = bomb_list->q_forw; qp != bomb_list; qp = qp->q_forw) {
231 struct plist *ip = (struct plist *)qp;
232 if (!(plchr[(int)ip->plane.pln_type].pl_flags & P_M))
239 if (unfriendly[sect.sct_own] && !gotilist[sect.sct_own]) {
240 getilist(&ilist[sect.sct_own], sect.sct_own,
241 bomb_list, esc_list, obomb, oesc);
242 gotilist[sect.sct_own]++;
246 ac_intercept(bomb_list, esc_list, &ilist[sect.sct_own],
248 intown = sect.sct_own;
251 /* Let's report all of the overflights even if aborted */
252 for (cn = 1; cn < MAXNOC; cn++) {
253 if (plane_owner == cn)
256 nreport(plane_owner, N_OVFLY_SECT, cn, overfly[cn]);
258 /* If the map changed, update it */
260 if (!update_pending && plane_owner == player->cnum)
261 writemap(player->cnum);
262 /* Now, if the bomber and escort lists are empty, we are done */
263 if (QEMPTY(bomb_list) && QEMPTY(esc_list)) {
264 if (mission_flags & P_A)
265 free_shiplist(&head);
269 /* Something made it through */
270 /* Go figure out if there are ships in this sector, and who's they are */
271 memset(nats, 0, sizeof(nats));
272 snxtitem_xy(&ni, EF_SHIP, x, y);
273 while (nxtitem(&ni, &ship)) {
274 if (mchr[(int)ship.shp_type].m_flags & M_SUB)
276 nats[ship.shp_own]++;
278 /* Go figure out if there are units in this sector, and who's they are */
279 memset(lnats, 0, sizeof(lnats));
280 snxtitem_xy(&ni, EF_LAND, x, y);
281 while (nxtitem(&ni, &land)) {
282 if (land.lnd_ship >= 0 || land.lnd_land >= 0)
284 lnats[land.lnd_own]++;
287 /* Now, let's make life a little rougher. */
288 for (cn = 1; cn < MAXNOC && !QEMPTY(bomb_list); cn++) {
289 if (plane_owner == cn)
292 /* Are there ships owned by this country? */
296 PR(cn, "%s planes spotted over ships in %s\n",
297 cname(plane_owner), xyas(x, y, cn));
299 setcont(cn, plane_owner, FOUND_FLY);
301 if (unfriendly[cn]) {
302 /* They are unfriendly too */
304 getilist(&ilist[cn], cn, bomb_list, esc_list, obomb,
308 PR(plane_owner, "Flying over %s ships in %s\n", cname(cn),
309 xyas(x, y, plane_owner));
310 /* This makes going for ships in harbors tough */
312 /* We already fired flak up above. Now we intercept again if we haven't already */
313 /* Flag that we intercepted */
315 /* And now intercept again */
316 ac_intercept(bomb_list, esc_list, &ilist[cn], cn, x,
321 /* Are there units owned by this country? */
322 if (lnats[cn] != 0) {
325 PR(cn, "%s planes spotted over land units in %s\n",
326 cname(plane_owner), xyas(x, y, cn));
328 setcont(cn, plane_owner, FOUND_FLY);
330 if (unfriendly[cn]) {
331 /* They are unfriendly too */
333 getilist(&ilist[cn], cn, bomb_list, esc_list, obomb,
337 PR(plane_owner, "Flying over %s land units in %s\n",
338 cname(cn), xyas(x, y, plane_owner));
341 /* We haven't intercepted yet, so intercept */
342 ac_intercept(bomb_list, esc_list, &ilist[cn], cn,
349 if (mission_flags & P_A)
350 free_shiplist(&head);
354 count_non_missiles(struct emp_qelem *list)
356 struct emp_qelem *qp;
360 /* don't intercept missiles */
361 for (qp = list->q_forw; qp != list; qp = qp->q_forw) {
362 plp = (struct plist *)qp;
363 if (!(plp->pcp->pl_flags & P_M))
370 sam_intercept(struct emp_qelem *att_list, struct emp_qelem *def_list,
371 natid def_own, natid plane_owner, coord x, coord y,
374 struct emp_qelem *aqp;
375 struct emp_qelem *anext;
376 struct emp_qelem *dqp;
377 struct emp_qelem *dnext;
382 for (aqp = att_list->q_forw,
383 dqp = def_list->q_forw;
384 aqp != att_list && dqp != def_list; aqp = anext) {
386 aplp = (struct plist *)aqp;
387 if (aplp->pcp->pl_flags & P_M)
389 if (aplp->pcp->pl_cost < 1000)
391 for (; dqp != def_list; dqp = dnext) {
393 dplp = (struct plist *)dqp;
394 if (!(dplp->pcp->pl_flags & P_M))
397 if (dplp->plane.pln_range <
398 mapdist(x, y, dplp->plane.pln_x, dplp->plane.pln_y)) {
403 if (mission_pln_equip(dplp, 0, P_F, 0) < 0) {
410 PR(plane_owner, "%s launches SAMs!\n", cname(def_own));
411 PR(def_own, "Launching SAMs at %s planes!\n",
413 ac_combat_headers(plane_owner, def_own);
421 PR(plane_owner, "\n");
424 if (delete_missiles) {
425 for (; dqp != def_list; dqp = dnext) {
427 dplp = (struct plist *)dqp;
428 if (!(dplp->pcp->pl_flags & P_M))
438 ac_intercept(struct emp_qelem *bomb_list, struct emp_qelem *esc_list,
439 struct emp_qelem *def_list, natid def_own, coord x, coord y)
444 struct emp_qelem *next;
445 struct emp_qelem *qp;
446 struct emp_qelem int_list;
451 plp = (struct plist *)bomb_list->q_forw;
452 plane_owner = plp->plane.pln_own;
456 sam_intercept(bomb_list, def_list, def_own, plane_owner, x, y, 0);
457 sam_intercept(esc_list, def_list, def_own, plane_owner, x, y, 1);
458 if (!(att_count = count_non_missiles(bomb_list) +
459 count_non_missiles(esc_list)))
462 emp_initque(&int_list);
463 for (qp = def_list->q_forw; qp != def_list; qp = next) {
465 plp = (struct plist *)qp;
467 /* SAMs interdict separately */
468 if (plp->pcp->pl_flags & P_M)
470 dist = mapdist(x, y, pp->pln_x, pp->pln_y) * 2;
471 if (pp->pln_range < dist)
473 if (mission_pln_equip(plp, 0, P_F, 0) < 0) {
478 /* got one; delete from def_list, add to int_list */
480 emp_insque(qp, &int_list);
481 pp->pln_mobil -= pln_mobcost(dist, pp, P_F);
482 putplane(pp->pln_uid, pp);
484 if (icount > att_count)
489 PR(plane_owner, "%d %s fighter%s rising to intercept!\n", icount,
490 cname(def_own), icount == 1 ? " is" : "s are");
491 PR(def_own, "%d fighter%s intercepting %s planes!\n", icount,
492 icount == 1 ? " is" : "s are", cname(plane_owner));
493 ac_combat_headers(plane_owner, def_own);
494 ac_airtoair(esc_list, &int_list);
495 ac_airtoair(bomb_list, &int_list);
496 PR(plane_owner, "\n");
501 ac_combat_headers(natid plane_owner, natid def_own)
504 " %-10.10s %-10.10s strength int odds damage results\n",
505 cname(plane_owner), cname(def_own));
507 " %-10.10s %-10.10s strength int odds damage results\n",
508 cname(def_own), cname(plane_owner));
515 ac_airtoair(struct emp_qelem *att_list, struct emp_qelem *int_list)
517 struct plist *attacker;
518 struct plist *interceptor;
519 struct emp_qelem *att;
520 struct emp_qelem *in;
524 struct emp_qelem *att_next;
525 struct emp_qelem *in_next;
527 att = att_list->q_forw;
528 in = int_list->q_forw;
531 if (QEMPTY(att_list) || QEMPTY(int_list)) {
535 while (more_att || more_int) {
536 in_next = in->q_forw;
537 att_next = att->q_forw;
538 attacker = (struct plist *)att;
540 /* skip missiles. If only missiles left, we're done */
541 if (plchr[(int)attacker->plane.pln_type].pl_flags & P_M) {
543 if (att == att_list) {
545 if (QEMPTY(att_list))
550 if (all_missiles(att_list))
554 interceptor = (struct plist *)in;
555 nplanes = attacker->plane.pln_effic;
556 if (nplanes > interceptor->plane.pln_effic)
557 nplanes = interceptor->plane.pln_effic;
558 ac_dog(attacker, interceptor);
561 if (att == att_list) {
563 if (QEMPTY(att_list))
568 if (in == int_list) {
570 if (QEMPTY(int_list))
579 all_missiles(struct emp_qelem *att_list)
581 struct emp_qelem *qp;
584 qp = att_list->q_forw;
585 while (qp != att_list) {
586 p = (struct plist *)qp;
587 if (!(plchr[(int)p->plane.pln_type].pl_flags & P_M))
596 ac_dog(struct plist *ap, struct plist *dp)
601 natid att_own, def_own;
606 att_own = ap->plane.pln_own;
607 def_own = dp->plane.pln_own;
609 PR(att_own, " %3.3s #%-4d %3.3s #%-4d",
611 ap->plane.pln_uid, dp->pcp->pl_name, dp->plane.pln_uid);
613 PR(def_own, " %3.3s #%-4d %3.3s #%-4d",
615 dp->plane.pln_uid, ap->pcp->pl_name, ap->plane.pln_uid);
616 if (ap->plane.pln_att == 0) {
617 att = ap->plane.pln_def * ap->plane.pln_effic / 100;
618 att = MAX(att, ap->pcp->pl_def / 2);
620 att = ap->plane.pln_att * ap->plane.pln_effic / 100;
621 att = MAX(att, ap->pcp->pl_att / 2);
624 def = dp->plane.pln_def * dp->plane.pln_effic / 100;
625 def = MAX(def, dp->pcp->pl_def / 2);
627 if ((ap->pcp->pl_flags & P_F) && ap->bombs != 0)
629 if ((dp->pcp->pl_flags & P_F) && dp->bombs != 0)
631 att += ((float)ap->pcp->pl_stealth / 25.0);
632 def += ((float)dp->pcp->pl_stealth / 25.0);
641 odds = ((double)att / ((double)def + (double)att));
644 intensity = roll(20) + roll(20) + roll(20) + roll(20) + 1;
646 PR(att_own, " %3d/%-3d %3d %3.2f ", att, def, intensity, odds);
647 PR(def_own, " %3d/%-3d %3d %3.2f ", def, att, intensity, odds);
651 while ((intensity--) > 0) {
655 if ((dp->plane.pln_effic - ddam) < PLANE_MINEFF)
659 if ((ap->plane.pln_effic - adam) < PLANE_MINEFF)
664 if (dp->pcp->pl_flags & P_M)
667 PR(att_own, "%3d/%-3d", adam, ddam);
668 PR(def_own, "%3d/%-3d", ddam, adam);
669 ac_planedamage(ap, dp->plane.pln_own, adam, def_own, 1, 0, mesg);
670 strncpy(temp, mesg, 14);
671 ac_planedamage(dp, ap->plane.pln_own, ddam, att_own, 1, 0, mesg);
672 PR(att_own, "%-13.13s %-13.13s\n", temp, mesg);
673 PR(def_own, "%-13.13s %-13.13s\n", mesg, temp);
676 setcont(att_own, def_own, FOUND_FLY);
677 setcont(def_own, att_own, FOUND_FLY);
682 * zap plane associated with plp.
683 * Damaging country is "from", damage is "dam".
684 * def_own is the country on the other side of the conflict from the plane
685 * owner. The only time def_own != from is when the interceptor is getting
688 * NOTE: This routine removes the appropriate plane element from the
689 * queue if it gets destroyed. That means that the caller must assume
690 * that the current queue pointer is invalid on return from the ac_planedamage
691 * call. (this has caused bugs in the past)
694 ac_planedamage(struct plist *plp, natid from, int dam, natid other,
695 int checkabort, int show, s_char *mesg)
703 /* s_char *sprintf(); already in misc.h [JFW] */
708 plane_owner = pp->pln_own;
710 sprintf(dmess, " no damage");
715 memset(dmess, 0, sizeof(dmess));
719 if (eff < PLANE_MINEFF) {
720 sprintf(dmess, " shot down");
722 } else if (eff < 80 && chance((100 - eff) / 100.0) && checkabort) {
723 sprintf(dmess, " aborted @%2d%%", eff);
725 } else if (show == 0) {
726 sprintf(dmess, " cleared");
729 if ((plp->pcp->pl_flags & P_M) == 0) {
731 PR(plane_owner, " %s %s takes %d%s.\n",
732 cname(pp->pln_own), prplane(pp), dam, dmess);
734 PR(other, " %s %s takes %d%s.\n",
735 cname(pp->pln_own), prplane(pp), dam, dmess);
738 if (show && checkabort == 1) {
739 PR(plane_owner, "\n");
745 pp->pln_mobil -= min(32 + pp->pln_mobil, dam / 2);
747 if (from != 0 && (plp->pcp->pl_flags & P_M) == 0)
748 nreport(from, N_DOWN_PLANE, pp->pln_own, 1);
749 if (pp->pln_ship >= 0) {
750 getship(pp->pln_ship, &ship);
751 take_plane_off_ship(pp, &ship);
753 if (pp->pln_land >= 0) {
754 getland(pp->pln_land, &land);
755 take_plane_off_land(pp, &land);
757 makelost(EF_PLANE, pp->pln_own, pp->pln_uid, pp->pln_x, pp->pln_y);
759 putplane(pp->pln_uid, pp);
760 emp_remque(&plp->queue);
762 } else if (disp == 2) {
763 putplane(pp->pln_uid, pp);
764 emp_remque(&plp->queue);
767 putplane(pp->pln_uid, pp);
772 ac_doflak(struct emp_qelem *list, struct sctstr *from)
779 plp = (struct plist *)list->q_forw;
780 plane_owner = plp->plane.pln_own;
782 gun = from->sct_item[I_GUN];
783 shell = from->sct_item[I_SHELL];
786 if (gun > shell * 2) {
787 shell += supply_commod(from->sct_own, from->sct_x, from->sct_y,
788 I_SHELL, (gun + 1) / 2 - shell);
789 from->sct_item[I_SHELL] = shell;
795 gun = 2.0 * tfact(from->sct_own, gun);
797 PR(plane_owner, "firing %d flak guns in %s...\n",
798 gun, xyas(from->sct_x, from->sct_y, plane_owner));
799 if (from->sct_own != 0)
800 PR(from->sct_own, "firing %d flak guns in %s...\n",
801 gun, xyas(from->sct_x, from->sct_y, from->sct_own));
802 ac_fireflak(list, from->sct_own, 0, gun);
807 ac_shipflak(struct emp_qelem *list, coord x, coord y)
822 plp = (struct plist *)list->q_forw;
823 plane_owner = plp->plane.pln_own;
825 memset(nats, 0, sizeof(nats));
827 snxtitem_xy(&ni, EF_SHIP, x, y);
828 while (!QEMPTY(list) && nxtitem(&ni, &ship)) {
829 if (ship.shp_own == 0 || ship.shp_own == plane_owner)
833 mcp = &mchr[(int)ship.shp_type];
834 if (mcp->m_flags & M_SUB)
836 rel = getrel(getnatp(ship.shp_own), plane_owner);
840 gun = min(ship.shp_item[I_GUN], ship.shp_glim);
842 shell = ship.shp_item[I_SHELL];
844 shell = supply_commod(ship.shp_own, ship.shp_x,
845 ship.shp_y, I_SHELL, 1);
846 ship.shp_item[I_SHELL] = shell;
847 putship(ship.shp_uid, &ship);
850 if (gun == 0 || shell == 0)
852 firing = (int)(techfact(ship.shp_tech, (double)gun) * 2.0);
855 if (!nats[ship.shp_own]) {
856 /* First time here, print the message */
857 PR(ship.shp_own, "%s planes spotted over ships in %s\n",
858 cname(plane_owner), xyas(x, y, ship.shp_own));
859 PR(plane_owner, "Flying over %s ships in %s\n",
860 cname(ship.shp_own), xyas(x, y, plane_owner));
861 nats[ship.shp_own] = 1;
863 PR(ship.shp_own, "firing %d flak guns from %s...\n",
864 firing, prship(&ship));
870 guns = 2.0 * tfact(from, (double)guns);
871 PR(plane_owner, "Flak! Ships firing %d flak guns...\n", guns);
872 ac_fireflak(list, from, 0, guns);
877 ac_landflak(struct emp_qelem *list, coord x, coord y)
890 plp = (struct plist *)list->q_forw;
891 plane_owner = plp->plane.pln_own;
893 memset(nats, 0, sizeof(nats));
895 snxtitem_xy(&ni, EF_LAND, x, y);
896 while (!QEMPTY(list) && nxtitem(&ni, &land)) {
897 if (land.lnd_own == 0 || land.lnd_own == plane_owner)
901 lcp = &lchr[(int)land.lnd_type];
903 if ((lcp->l_flags & L_FLAK) == 0)
906 if (land.lnd_aaf == 0)
909 if (land.lnd_ship >= 0 || land.lnd_land >= 0)
912 rel = getrel(getnatp(land.lnd_own), plane_owner);
916 (int)(techfact(land.lnd_tech, (double)land.lnd_aaf) * 3.0);
919 if (!nats[land.lnd_own]) {
920 /* First time here, print the message */
921 PR(land.lnd_own, "%s planes spotted over land units in %s\n",
922 cname(plane_owner), xyas(x, y, land.lnd_own));
923 PR(plane_owner, "Flying over %s land units in %s\n",
924 cname(land.lnd_own), xyas(x, y, plane_owner));
925 nats[land.lnd_own] = 1;
927 PR(land.lnd_own, "firing flak guns from unit %s (aa rating %d)\n",
928 prland(&land), land.lnd_aaf);
930 from = land.lnd_own; /* We always use the last owner as the from */
935 guns = 2.0 * tfact(from, (double)guns);
936 PR(plane_owner, "Flak! Land units firing %d flak guns...\n",
938 ac_fireflak(list, from, 0, guns);
943 * Called from shipflak, landflak, and doflak.
946 ac_fireflak(struct emp_qelem *list, natid from, natid other, int guns)
952 struct emp_qelem *qp;
953 struct emp_qelem *next;
956 plp = (struct plist *)list->q_forw;
958 for (qp = list->q_forw; qp != list; qp = next) {
960 * fighters don't get shot at by flak
961 * non-tactical bombers are harder to hit with flak.
962 * ('Cause they're not dive-bombing?)
965 plp = (struct plist *)qp;
967 diff = guns - pp->pln_def;
968 if ((plp->pcp->pl_flags & P_T) == 0)
970 if (plp->pcp->pl_flags & P_X)
972 if (plp->pcp->pl_flags & P_H)
974 n = ac_flak_dam(diff);
975 ac_planedamage(plp, from, n, other, 2, 1, msg);
980 * Calculate flak damage
983 ac_flak_dam(int flak)
987 /* <-7 -7 -6 -5 -4 */
988 static float flaktable[18] = { 0.132f, 0.20f, 0.20f, 0.25f, 0.30f,
989 /* -3 -2 -1 0 +1 +2 +3 +4 */
990 0.35f, 0.40f, 0.45f, 0.50f, 0.50f, 0.55f, 0.60f, 0.65f,
991 /* +5 +6 +7 +8 >+8 */
992 0.70f,0.75f, 0.80f, 0.85f, 1.1305f };
993 enum { FLAK_MAX = sizeof(flaktable)/sizeof(flaktable[0]) };
996 mult = flaktable[FLAK_MAX];
1001 mult = flaktable[flak];
1004 dam = (int)((roll(8) + 2) * mult);
1011 * See if this plane is flying in this list
1014 ac_isflying(struct plnstr *plane, struct emp_qelem *list)
1016 struct emp_qelem *qp;
1017 struct emp_qelem *next;
1023 for (qp = list->q_forw; qp != list; qp = next) {
1025 plp = (struct plist *)qp;
1027 if (plane->pln_uid == pp->pln_uid)
1035 * Get a list of planes available for interception duties.
1038 getilist(struct emp_qelem *list, natid own, struct emp_qelem *a,
1039 struct emp_qelem *b, struct emp_qelem *c, struct emp_qelem *d)
1041 struct plchrstr *pcp;
1042 struct plnstr plane;
1046 struct nstr_item ni;
1051 snxtitem_all(&ni, EF_PLANE);
1052 while (nxtitem(&ni, &plane)) {
1053 if (plane.pln_own != own)
1055 pcp = &plchr[(int)plane.pln_type];
1056 if ((pcp->pl_flags & P_F) == 0)
1058 if (plane.pln_mission != 0)
1060 if (plane.pln_mobil <= 0)
1062 if (plane.pln_effic < 40)
1064 if (plane.pln_ship >= 0) {
1065 if (!can_fly(plane.pln_uid))
1067 getship(plane.pln_ship, &ship);
1068 petrol = ship.shp_item[I_PETROL];
1069 } else if (plane.pln_land >= 0) {
1070 if (!can_fly(plane.pln_uid))
1072 getland(plane.pln_land, &land);
1073 petrol = land.lnd_item[I_PETROL];
1075 getsect(plane.pln_x, plane.pln_y, §);
1076 petrol = sect.sct_item[I_PETROL];
1077 if ((sect.sct_effic < 60 || sect.sct_type != SCT_AIRPT)
1078 && (pcp->pl_flags & P_V) == 0)
1081 if ((float)petrol < (float)pcp->pl_fuel / 2.0)
1083 /* Finally, is it in the list of planes already in
1085 if (ac_isflying(&plane, a))
1087 if (ac_isflying(&plane, b))
1089 if (ac_isflying(&plane, c))
1091 if (ac_isflying(&plane, d))
1094 ip = malloc(sizeof(*ip));
1097 ip->pcp = &plchr[(int)plane.pln_type];
1099 emp_insque(&ip->queue, list);
1107 { /* Can this plane fly from the ship or land unit it is on? */
1108 struct plnstr plane;
1111 struct plchrstr *pcp;
1112 struct mchrstr *scp;
1113 struct lchrstr *lcp;
1115 getplane(p, &plane);
1116 pcp = &plchr[(int)plane.pln_type];
1118 if (plane.pln_ship >= 0) {
1119 if (!(pcp->pl_flags & P_L) && !(pcp->pl_flags & P_M)
1120 && !(pcp->pl_flags & P_K)
1121 && !(pcp->pl_flags & P_E)
1125 getship(plane.pln_ship, &ship);
1126 scp = &mchr[(int)ship.shp_type];
1128 if ((pcp->pl_flags & P_L) && (scp->m_flags & M_FLY)) {
1132 if ((pcp->pl_flags & P_M) && (scp->m_flags & M_MSL)) {
1136 if ((pcp->pl_flags & P_K) && (scp->m_flags & M_CHOPPER)) {
1140 if ((pcp->pl_flags & P_E) && (scp->m_flags & M_XLIGHT)) {
1145 if (plane.pln_land >= 0) {
1146 if (!(pcp->pl_flags & P_E))
1149 getland(plane.pln_land, &land);
1150 lcp = &lchr[(int)land.lnd_type];
1152 if ((pcp->pl_flags & P_E) && (lcp->l_flags & L_XLIGHT)) {
1161 do_evade(struct emp_qelem *bomb_list, struct emp_qelem *esc_list)
1163 struct emp_qelem *qp;
1168 for (qp = bomb_list->q_forw; qp != bomb_list; qp = qp->q_forw) {
1169 plp = (struct plist *)qp;
1170 if (evade > ((float)plp->pcp->pl_stealth / 100.0))
1171 evade = (plp->pcp->pl_stealth / 100.0);
1173 for (qp = esc_list->q_forw; qp != esc_list; qp = qp->q_forw) {
1174 plp = (struct plist *)qp;
1175 if (evade > plp->pcp->pl_stealth / 100.0)
1176 evade = (plp->pcp->pl_stealth / 100.0);