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 setcont(plane_owner, sect.sct_own, FOUND_FLY);
143 if (mission_flags & PM_R) {
144 if (sect.sct_type == SCT_WATER) {
145 PR(plane_owner, "flying over %s at %s\n",
146 dchr[sect.sct_type].d_name, xyas(x, y, plane_owner));
147 if (mission_flags & PM_S)
148 plane_sweep(bomb_list, x, y);
149 if (mission_flags & P_A) {
150 plane_sona(bomb_list, x, y, &head);
152 changed += map_set(plane_owner,
153 sect.sct_x, sect.sct_y,
154 dchr[sect.sct_type].d_mnem, 0);
155 } else if (mission_flags & P_S) {
156 satdisp(§, (mission_flags & P_I) ? 10 : 50, 1);
158 /* This is borrowed from lookout */
159 if (sect.sct_own == plane_owner)
160 PR(plane_owner, "Your ");
163 "%s (#%d) ", cname(sect.sct_own), sect.sct_own);
164 PR(plane_owner, dchr[sect.sct_type].d_name);
165 changed += map_set(plane_owner,
166 sect.sct_x, sect.sct_y,
167 dchr[sect.sct_type].d_mnem, 0);
168 PR(plane_owner, " %d%% efficient ",
169 (sect.sct_own == plane_owner) ?
170 sect.sct_effic : roundintby((int)sect.sct_effic, 25));
171 civ = sect.sct_item[I_CIVIL];
172 mil = sect.sct_item[I_MILIT];
174 PR(plane_owner, "with %s%d civ ",
175 (sect.sct_own == plane_owner) ?
177 (sect.sct_own == plane_owner) ?
178 civ : roundintby(civ, 25));
180 PR(plane_owner, "with %s%d mil ",
181 (sect.sct_own == plane_owner) ?
183 (sect.sct_own == plane_owner) ?
184 mil : roundintby(mil, 25));
185 PR(plane_owner, "@ %s\n", xyas(x, y, plane_owner));
188 PR(plane_owner, "flying over %s at %s\n",
189 dchr[sect.sct_type].d_name, xyas(x, y, plane_owner));
190 changed += map_set(plane_owner, sect.sct_x,
191 sect.sct_y, dchr[sect.sct_type].d_mnem, 0);
193 if ((rel = getrel(over, plane_owner)) == ALLIED)
196 evaded = do_evade(bomb_list, esc_list);
198 if (sect.sct_own != 0 && sect.sct_own != plane_owner && (!evaded)) {
199 /* We only show planes overhead if they didn't
201 overfly[sect.sct_own]++;
202 PR(sect.sct_own, "%s planes spotted over %s\n",
203 cname(plane_owner), xyas(x, y, sect.sct_own));
208 if (unfriendly[sect.sct_own])
209 ac_doflak(bomb_list, §);
210 /* If bombers left, fire flak from units and ships */
211 if (!QEMPTY(bomb_list))
212 ac_landflak(bomb_list, x, y);
213 if (!QEMPTY(bomb_list))
214 ac_shipflak(bomb_list, x, y);
216 /* mission planes aborted due to flak -- don't send escorts */
217 if (QEMPTY(bomb_list))
219 if ((!no_air_defense) && (!evaded))
220 air_defense(x, y, plane_owner, bomb_list, esc_list);
222 if (sect.sct_own == 0 || sect.sct_own == plane_owner)
229 for (qp = bomb_list->q_forw; qp != bomb_list; qp = qp->q_forw) {
230 struct plist *ip = (struct plist *)qp;
231 if (!(plchr[(int)ip->plane.pln_type].pl_flags & P_M))
238 if (unfriendly[sect.sct_own] && !gotilist[sect.sct_own]) {
239 getilist(&ilist[sect.sct_own], sect.sct_own,
240 bomb_list, esc_list, obomb, oesc);
241 gotilist[sect.sct_own]++;
245 ac_intercept(bomb_list, esc_list, &ilist[sect.sct_own],
247 intown = sect.sct_own;
250 /* Let's report all of the overflights even if aborted */
251 for (cn = 1; cn < MAXNOC; cn++) {
252 if (plane_owner == cn)
255 nreport(plane_owner, N_OVFLY_SECT, cn, overfly[cn]);
257 /* If the map changed, update it */
259 if (!update_pending && plane_owner == player->cnum)
260 writemap(player->cnum);
261 /* Now, if the bomber and escort lists are empty, we are done */
262 if (QEMPTY(bomb_list) && QEMPTY(esc_list)) {
263 if (mission_flags & P_A)
264 free_shiplist(&head);
268 /* Something made it through */
269 /* Go figure out if there are ships in this sector, and who's they are */
270 memset(nats, 0, sizeof(nats));
271 snxtitem_xy(&ni, EF_SHIP, x, y);
272 while (nxtitem(&ni, &ship)) {
273 if (mchr[(int)ship.shp_type].m_flags & M_SUB)
275 nats[ship.shp_own]++;
277 /* Go figure out if there are units in this sector, and who's they are */
278 memset(lnats, 0, sizeof(lnats));
279 snxtitem_xy(&ni, EF_LAND, x, y);
280 while (nxtitem(&ni, &land)) {
281 if (land.lnd_ship >= 0 || land.lnd_land >= 0)
283 lnats[land.lnd_own]++;
286 /* Now, let's make life a little rougher. */
287 for (cn = 1; cn < MAXNOC && !QEMPTY(bomb_list); cn++) {
288 if (plane_owner == cn)
291 /* Are there ships owned by this country? */
295 PR(cn, "%s planes spotted over ships in %s\n",
296 cname(plane_owner), xyas(x, y, cn));
297 if (unfriendly[cn]) {
298 /* They are unfriendly too */
300 getilist(&ilist[cn], cn, bomb_list, esc_list, obomb,
304 PR(plane_owner, "Flying over %s ships in %s\n", cname(cn),
305 xyas(x, y, plane_owner));
306 /* This makes going for ships in harbors tough */
308 /* We already fired flak up above. Now we intercept again if we haven't already */
309 /* Flag that we intercepted */
311 /* And now intercept again */
312 ac_intercept(bomb_list, esc_list, &ilist[cn], cn, x,
317 /* Are there units owned by this country? */
318 if (lnats[cn] != 0) {
321 PR(cn, "%s planes spotted over land units in %s\n",
322 cname(plane_owner), xyas(x, y, cn));
323 if (unfriendly[cn]) {
324 /* They are unfriendly too */
326 getilist(&ilist[cn], cn, bomb_list, esc_list, obomb,
330 PR(plane_owner, "Flying over %s land units in %s\n",
331 cname(cn), xyas(x, y, plane_owner));
334 /* We haven't intercepted yet, so intercept */
335 ac_intercept(bomb_list, esc_list, &ilist[cn], cn,
342 if (mission_flags & P_A)
343 free_shiplist(&head);
347 count_non_missiles(struct emp_qelem *list)
349 struct emp_qelem *qp;
353 /* don't intercept missiles */
354 for (qp = list->q_forw; qp != list; qp = qp->q_forw) {
355 plp = (struct plist *)qp;
356 if (!(plp->pcp->pl_flags & P_M))
363 sam_intercept(struct emp_qelem *att_list, struct emp_qelem *def_list,
364 natid def_own, natid plane_owner, coord x, coord y,
367 struct emp_qelem *aqp;
368 struct emp_qelem *anext;
369 struct emp_qelem *dqp;
370 struct emp_qelem *dnext;
375 for (aqp = att_list->q_forw,
376 dqp = def_list->q_forw;
377 aqp != att_list && dqp != def_list; aqp = anext) {
379 aplp = (struct plist *)aqp;
380 if (aplp->pcp->pl_flags & P_M)
382 if (aplp->pcp->pl_cost < 1000)
384 for (; dqp != def_list; dqp = dnext) {
386 dplp = (struct plist *)dqp;
387 if (!(dplp->pcp->pl_flags & P_M))
390 if (dplp->plane.pln_range <
391 mapdist(x, y, dplp->plane.pln_x, dplp->plane.pln_y)) {
396 if (mission_pln_equip(dplp, 0, P_F, 0) < 0) {
403 PR(plane_owner, "%s launches SAMs!\n", cname(def_own));
404 PR(def_own, "Launching SAMs at %s planes!\n",
406 ac_combat_headers(plane_owner, def_own);
414 PR(plane_owner, "\n");
417 if (delete_missiles) {
418 for (; dqp != def_list; dqp = dnext) {
420 dplp = (struct plist *)dqp;
421 if (!(dplp->pcp->pl_flags & P_M))
431 ac_intercept(struct emp_qelem *bomb_list, struct emp_qelem *esc_list,
432 struct emp_qelem *def_list, natid def_own, coord x, coord y)
437 struct emp_qelem *next;
438 struct emp_qelem *qp;
439 struct emp_qelem int_list;
444 plp = (struct plist *)bomb_list->q_forw;
445 plane_owner = plp->plane.pln_own;
449 sam_intercept(bomb_list, def_list, def_own, plane_owner, x, y, 0);
450 sam_intercept(esc_list, def_list, def_own, plane_owner, x, y, 1);
451 if (!(att_count = count_non_missiles(bomb_list) +
452 count_non_missiles(esc_list)))
455 emp_initque(&int_list);
456 for (qp = def_list->q_forw; qp != def_list; qp = next) {
458 plp = (struct plist *)qp;
460 /* SAMs interdict separately */
461 if (plp->pcp->pl_flags & P_M)
463 dist = mapdist(x, y, pp->pln_x, pp->pln_y) * 2;
464 if (pp->pln_range < dist)
466 if (mission_pln_equip(plp, 0, P_F, 0) < 0) {
471 /* got one; delete from def_list, add to int_list */
473 emp_insque(qp, &int_list);
474 pp->pln_mobil -= pln_mobcost(dist, pp, P_F);
475 putplane(pp->pln_uid, pp);
477 if (icount > att_count)
482 PR(plane_owner, "%d %s fighter%s rising to intercept!\n", icount,
483 cname(def_own), icount == 1 ? " is" : "s are");
484 PR(def_own, "%d fighter%s intercepting %s planes!\n", icount,
485 icount == 1 ? " is" : "s are", cname(plane_owner));
486 ac_combat_headers(plane_owner, def_own);
487 ac_airtoair(esc_list, &int_list);
488 ac_airtoair(bomb_list, &int_list);
489 PR(plane_owner, "\n");
494 ac_combat_headers(natid plane_owner, natid def_own)
497 " %-10.10s %-10.10s strength int odds damage results\n",
498 cname(plane_owner), cname(def_own));
500 " %-10.10s %-10.10s strength int odds damage results\n",
501 cname(def_own), cname(plane_owner));
508 ac_airtoair(struct emp_qelem *att_list, struct emp_qelem *int_list)
510 struct plist *attacker;
511 struct plist *interceptor;
512 struct emp_qelem *att;
513 struct emp_qelem *in;
517 struct emp_qelem *att_next;
518 struct emp_qelem *in_next;
520 att = att_list->q_forw;
521 in = int_list->q_forw;
524 if (QEMPTY(att_list) || QEMPTY(int_list)) {
528 while (more_att || more_int) {
529 in_next = in->q_forw;
530 att_next = att->q_forw;
531 attacker = (struct plist *)att;
533 /* skip missiles. If only missiles left, we're done */
534 if (plchr[(int)attacker->plane.pln_type].pl_flags & P_M) {
536 if (att == att_list) {
538 if (QEMPTY(att_list))
543 if (all_missiles(att_list))
547 interceptor = (struct plist *)in;
548 nplanes = attacker->plane.pln_effic;
549 if (nplanes > interceptor->plane.pln_effic)
550 nplanes = interceptor->plane.pln_effic;
551 ac_dog(attacker, interceptor);
554 if (att == att_list) {
556 if (QEMPTY(att_list))
561 if (in == int_list) {
563 if (QEMPTY(int_list))
572 all_missiles(struct emp_qelem *att_list)
574 struct emp_qelem *qp;
577 qp = att_list->q_forw;
578 while (qp != att_list) {
579 p = (struct plist *)qp;
580 if (!(plchr[(int)p->plane.pln_type].pl_flags & P_M))
589 ac_dog(struct plist *ap, struct plist *dp)
594 natid att_own, def_own;
599 att_own = ap->plane.pln_own;
600 def_own = dp->plane.pln_own;
602 PR(att_own, " %3.3s #%-4d %3.3s #%-4d",
604 ap->plane.pln_uid, dp->pcp->pl_name, dp->plane.pln_uid);
606 PR(def_own, " %3.3s #%-4d %3.3s #%-4d",
608 dp->plane.pln_uid, ap->pcp->pl_name, ap->plane.pln_uid);
609 if (ap->plane.pln_att == 0) {
610 att = ap->plane.pln_def * ap->plane.pln_effic / 100;
611 att = MAX(att, ap->pcp->pl_def / 2);
613 att = ap->plane.pln_att * ap->plane.pln_effic / 100;
614 att = MAX(att, ap->pcp->pl_att / 2);
617 def = dp->plane.pln_def * dp->plane.pln_effic / 100;
618 def = MAX(def, dp->pcp->pl_def / 2);
620 if ((ap->pcp->pl_flags & P_F) && ap->bombs != 0)
622 if ((dp->pcp->pl_flags & P_F) && dp->bombs != 0)
624 att += ((float)ap->pcp->pl_stealth / 25.0);
625 def += ((float)dp->pcp->pl_stealth / 25.0);
634 odds = ((double)att / ((double)def + (double)att));
637 intensity = roll(20) + roll(20) + roll(20) + roll(20) + 1;
639 PR(att_own, " %3d/%-3d %3d %3.2f ", att, def, intensity, odds);
640 PR(def_own, " %3d/%-3d %3d %3.2f ", def, att, intensity, odds);
644 while ((intensity--) > 0) {
648 if ((dp->plane.pln_effic - ddam) < PLANE_MINEFF)
652 if ((ap->plane.pln_effic - adam) < PLANE_MINEFF)
657 if (dp->pcp->pl_flags & P_M)
660 PR(att_own, "%3d/%-3d", adam, ddam);
661 PR(def_own, "%3d/%-3d", ddam, adam);
662 ac_planedamage(ap, dp->plane.pln_own, adam, def_own, 1, 0, mesg);
663 strncpy(temp, mesg, 14);
664 ac_planedamage(dp, ap->plane.pln_own, ddam, att_own, 1, 0, mesg);
665 PR(att_own, "%-13.13s %-13.13s\n", temp, mesg);
666 PR(def_own, "%-13.13s %-13.13s\n", mesg, temp);
670 * zap plane associated with plp.
671 * Damaging country is "from", damage is "dam".
672 * def_own is the country on the other side of the conflict from the plane
673 * owner. The only time def_own != from is when the interceptor is getting
676 * NOTE: This routine removes the appropriate plane element from the
677 * queue if it gets destroyed. That means that the caller must assume
678 * that the current queue pointer is invalid on return from the ac_planedamage
679 * call. (this has caused bugs in the past)
682 ac_planedamage(struct plist *plp, natid from, int dam, natid other,
683 int checkabort, int show, s_char *mesg)
691 /* s_char *sprintf(); already in misc.h [JFW] */
696 plane_owner = pp->pln_own;
698 sprintf(dmess, " no damage");
703 memset(dmess, 0, sizeof(dmess));
707 if (eff < PLANE_MINEFF) {
708 sprintf(dmess, " shot down");
710 } else if (eff < 80 && chance((100 - eff) / 100.0) && checkabort) {
711 sprintf(dmess, " aborted @%2d%%", eff);
713 } else if (show == 0) {
714 sprintf(dmess, " cleared");
717 if ((plp->pcp->pl_flags & P_M) == 0) {
719 PR(plane_owner, " %s %s takes %d%s.\n",
720 cname(pp->pln_own), prplane(pp), dam, dmess);
722 PR(other, " %s %s takes %d%s.\n",
723 cname(pp->pln_own), prplane(pp), dam, dmess);
726 if (show && checkabort == 1) {
727 PR(plane_owner, "\n");
733 pp->pln_mobil -= min(32 + pp->pln_mobil, dam / 2);
735 if (from != 0 && (plp->pcp->pl_flags & P_M) == 0)
736 nreport(from, N_DOWN_PLANE, pp->pln_own, 1);
737 if (pp->pln_ship >= 0) {
738 getship(pp->pln_ship, &ship);
739 take_plane_off_ship(pp, &ship);
741 if (pp->pln_land >= 0) {
742 getland(pp->pln_land, &land);
743 take_plane_off_land(pp, &land);
745 makelost(EF_PLANE, pp->pln_own, pp->pln_uid, pp->pln_x, pp->pln_y);
747 putplane(pp->pln_uid, pp);
748 emp_remque(&plp->queue);
750 } else if (disp == 2) {
751 putplane(pp->pln_uid, pp);
752 emp_remque(&plp->queue);
755 putplane(pp->pln_uid, pp);
760 ac_doflak(struct emp_qelem *list, struct sctstr *from)
767 plp = (struct plist *)list->q_forw;
768 plane_owner = plp->plane.pln_own;
770 gun = from->sct_item[I_GUN];
771 shell = from->sct_item[I_SHELL];
774 if (gun > shell * 2) {
775 shell += supply_commod(from->sct_own, from->sct_x, from->sct_y,
776 I_SHELL, (gun + 1) / 2 - shell);
777 from->sct_item[I_SHELL] = shell;
783 gun = 2.0 * tfact(from->sct_own, gun);
785 PR(plane_owner, "firing %d flak guns in %s...\n",
786 gun, xyas(from->sct_x, from->sct_y, plane_owner));
787 if (from->sct_own != 0)
788 PR(from->sct_own, "firing %d flak guns in %s...\n",
789 gun, xyas(from->sct_x, from->sct_y, from->sct_own));
790 ac_fireflak(list, from->sct_own, 0, gun);
795 ac_shipflak(struct emp_qelem *list, coord x, coord y)
810 plp = (struct plist *)list->q_forw;
811 plane_owner = plp->plane.pln_own;
813 memset(nats, 0, sizeof(nats));
815 snxtitem_xy(&ni, EF_SHIP, x, y);
816 while (!QEMPTY(list) && nxtitem(&ni, &ship)) {
817 if (ship.shp_own == 0 || ship.shp_own == plane_owner)
821 mcp = &mchr[(int)ship.shp_type];
822 if (mcp->m_flags & M_SUB)
824 rel = getrel(getnatp(ship.shp_own), plane_owner);
828 gun = min(ship.shp_item[I_GUN], ship.shp_glim);
830 shell = ship.shp_item[I_SHELL];
832 shell = supply_commod(ship.shp_own, ship.shp_x,
833 ship.shp_y, I_SHELL, 1);
834 ship.shp_item[I_SHELL] = shell;
835 putship(ship.shp_uid, &ship);
838 if (gun == 0 || shell == 0)
840 firing = (int)(techfact(ship.shp_tech, (double)gun) * 2.0);
843 if (!nats[ship.shp_own]) {
844 /* First time here, print the message */
845 PR(ship.shp_own, "%s planes spotted over ships in %s\n",
846 cname(plane_owner), xyas(x, y, ship.shp_own));
847 PR(plane_owner, "Flying over %s ships in %s\n",
848 cname(ship.shp_own), xyas(x, y, plane_owner));
849 nats[ship.shp_own] = 1;
851 PR(ship.shp_own, "firing %d flak guns from %s...\n",
852 firing, prship(&ship));
858 guns = 2.0 * tfact(from, (double)guns);
859 PR(plane_owner, "Flak! Ships firing %d flak guns...\n", guns);
860 ac_fireflak(list, from, 0, guns);
865 ac_landflak(struct emp_qelem *list, coord x, coord y)
878 plp = (struct plist *)list->q_forw;
879 plane_owner = plp->plane.pln_own;
881 memset(nats, 0, sizeof(nats));
883 snxtitem_xy(&ni, EF_LAND, x, y);
884 while (!QEMPTY(list) && nxtitem(&ni, &land)) {
885 if (land.lnd_own == 0 || land.lnd_own == plane_owner)
889 lcp = &lchr[(int)land.lnd_type];
891 if ((lcp->l_flags & L_FLAK) == 0)
894 if (land.lnd_aaf == 0)
897 rel = getrel(getnatp(land.lnd_own), plane_owner);
901 (int)(techfact(land.lnd_tech, (double)land.lnd_aaf) * 3.0);
904 if (!nats[land.lnd_own]) {
905 /* First time here, print the message */
906 PR(land.lnd_own, "%s planes spotted over land units in %s\n",
907 cname(plane_owner), xyas(x, y, land.lnd_own));
908 PR(plane_owner, "Flying over %s land units in %s\n",
909 cname(land.lnd_own), xyas(x, y, plane_owner));
910 nats[land.lnd_own] = 1;
912 PR(land.lnd_own, "firing flak guns from unit %s (aa rating %d)\n",
913 prland(&land), land.lnd_aaf);
915 from = land.lnd_own; /* We always use the last owner as the from */
920 guns = 2.0 * tfact(from, (double)guns);
921 PR(plane_owner, "Flak! Land units firing %d flak guns...\n",
923 ac_fireflak(list, from, 0, guns);
928 * Called from shipflak, landflak, and doflak.
931 ac_fireflak(struct emp_qelem *list, natid from, natid other, int guns)
937 struct emp_qelem *qp;
938 struct emp_qelem *next;
941 plp = (struct plist *)list->q_forw;
943 for (qp = list->q_forw; qp != list; qp = next) {
945 * fighters don't get shot at by flak
946 * non-tactical bombers are harder to hit with flak.
947 * ('Cause they're not dive-bombing?)
950 plp = (struct plist *)qp;
952 diff = guns - pp->pln_def;
953 if ((plp->pcp->pl_flags & P_T) == 0)
955 if (plp->pcp->pl_flags & P_X)
957 if (plp->pcp->pl_flags & P_H)
959 n = ac_flak_dam(diff);
960 ac_planedamage(plp, from, n, other, 2, 1, msg);
965 * Calculate flak damage
968 ac_flak_dam(int flak)
972 /* <-7 -7 -6 -5 -4 */
973 static float flaktable[18] = { 0.132f, 0.20f, 0.20f, 0.25f, 0.30f,
974 /* -3 -2 -1 0 +1 +2 +3 +4 */
975 0.35f, 0.40f, 0.45f, 0.50f, 0.50f, 0.55f, 0.60f, 0.65f,
976 /* +5 +6 +7 +8 >+8 */
977 0.70f,0.75f, 0.80f, 0.85f, 1.1305f };
978 enum { FLAK_MAX = sizeof(flaktable)/sizeof(flaktable[0]) };
981 mult = flaktable[FLAK_MAX];
986 mult = flaktable[flak];
989 dam = (int)((roll(8) + 2) * mult);
996 * See if this plane is flying in this list
999 ac_isflying(struct plnstr *plane, struct emp_qelem *list)
1001 struct emp_qelem *qp;
1002 struct emp_qelem *next;
1008 for (qp = list->q_forw; qp != list; qp = next) {
1010 plp = (struct plist *)qp;
1012 if (plane->pln_uid == pp->pln_uid)
1020 * Get a list of planes available for interception duties.
1023 getilist(struct emp_qelem *list, natid own, struct emp_qelem *a,
1024 struct emp_qelem *b, struct emp_qelem *c, struct emp_qelem *d)
1026 struct plchrstr *pcp;
1027 struct plnstr plane;
1031 struct nstr_item ni;
1036 snxtitem_all(&ni, EF_PLANE);
1037 while (nxtitem(&ni, &plane)) {
1038 if (plane.pln_own != own)
1040 pcp = &plchr[(int)plane.pln_type];
1041 if ((pcp->pl_flags & P_F) == 0)
1043 if (plane.pln_mission != 0)
1045 if (plane.pln_mobil <= 0)
1047 if (plane.pln_effic < 40)
1049 if (plane.pln_ship >= 0) {
1050 if (!can_fly(plane.pln_uid))
1052 getship(plane.pln_ship, &ship);
1053 petrol = ship.shp_item[I_PETROL];
1054 } else if (plane.pln_land >= 0) {
1055 if (!can_fly(plane.pln_uid))
1057 getland(plane.pln_land, &land);
1058 petrol = land.lnd_item[I_PETROL];
1060 getsect(plane.pln_x, plane.pln_y, §);
1061 petrol = sect.sct_item[I_PETROL];
1062 if ((sect.sct_effic < 60 || sect.sct_type != SCT_AIRPT)
1063 && (pcp->pl_flags & P_V) == 0)
1066 if ((float)petrol < (float)pcp->pl_fuel / 2.0)
1068 /* Finally, is it in the list of planes already in
1070 if (ac_isflying(&plane, a))
1072 if (ac_isflying(&plane, b))
1074 if (ac_isflying(&plane, c))
1076 if (ac_isflying(&plane, d))
1079 ip = malloc(sizeof(*ip));
1082 ip->pcp = &plchr[(int)plane.pln_type];
1084 emp_insque(&ip->queue, list);
1092 { /* Can this plane fly from the ship or land unit it is on? */
1093 struct plnstr plane;
1096 struct plchrstr *pcp;
1097 struct mchrstr *scp;
1098 struct lchrstr *lcp;
1100 getplane(p, &plane);
1101 pcp = &plchr[(int)plane.pln_type];
1103 if (plane.pln_ship >= 0) {
1104 if (!(pcp->pl_flags & P_L) && !(pcp->pl_flags & P_M)
1105 && !(pcp->pl_flags & P_K)
1106 && !(pcp->pl_flags & P_E)
1110 getship(plane.pln_ship, &ship);
1111 scp = &mchr[(int)ship.shp_type];
1113 if ((pcp->pl_flags & P_L) && (scp->m_flags & M_FLY)) {
1117 if ((pcp->pl_flags & P_M) && (scp->m_flags & M_MSL)) {
1121 if ((pcp->pl_flags & P_K) && (scp->m_flags & M_CHOPPER)) {
1125 if ((pcp->pl_flags & P_E) && (scp->m_flags & M_XLIGHT)) {
1130 if (plane.pln_land >= 0) {
1131 if (!(pcp->pl_flags & P_E))
1134 getland(plane.pln_land, &land);
1135 lcp = &lchr[(int)land.lnd_type];
1137 if ((pcp->pl_flags & P_E) && (lcp->l_flags & L_XLIGHT)) {
1146 do_evade(struct emp_qelem *bomb_list, struct emp_qelem *esc_list)
1148 struct emp_qelem *qp;
1153 for (qp = bomb_list->q_forw; qp != bomb_list; qp = qp->q_forw) {
1154 plp = (struct plist *)qp;
1155 if (evade > ((float)plp->pcp->pl_stealth / 100.0))
1156 evade = (plp->pcp->pl_stealth / 100.0);
1158 for (qp = esc_list->q_forw; qp != esc_list; qp = qp->q_forw) {
1159 plp = (struct plist *)qp;
1160 if (evade > plp->pcp->pl_stealth / 100.0)
1161 evade = (plp->pcp->pl_stealth / 100.0);