2 * Empire - A multi-player, client/server Internet based war game.
3 * Copyright (C) 1986-2000, Dave Pare, Jeff Bailey, Thomas Ruschak,
4 * Ken Stevens, Steve McClure
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
52 #include "prototypes.h"
55 extern int update_pending;
58 #define MIN(x,y) ((x) < (y) ? (x) : (y))
61 #define MAX(x,y) ((x) < (y) ? (y) : (x))
64 static void getilist(struct emp_qelem *list, natid own,
65 struct emp_qelem *a, struct emp_qelem *b,
66 struct emp_qelem *c, struct emp_qelem *d);
67 static void ac_dog(register struct plist *ap, register struct plist *dp);
72 /* -7 -6 -5 -4 -3 -2 -1 0 */
73 float flaktable[16] = { 0.20, 0.20, 0.25, 0.30, 0.35, 0.40, 0.45, 0.50,
74 0.50, 0.55, 0.60, 0.65, 0.70, 0.75, 0.80, 0.85, };
77 ac_encounter(struct emp_qelem *bomb_list, struct emp_qelem *esc_list, coord x, coord y, s_char *path, int mission_flags, int no_air_defense, struct emp_qelem *obomb, struct emp_qelem *oesc)
79 int val, non_missiles;
85 int unfriendly[MAXNOC];
87 struct emp_qelem ilist[MAXNOC], *qp;
97 struct natstr *over, *mynatp;
100 struct shiplook head;
101 struct shiplook *s,*s2;
103 int intx, inty; /* Last sector planes intercepted over */
104 int intown = 0; /* Last owner to intercept */
105 /* We want to only intercept once per sector per owner. So, if we overfly
106 a sector, and then overfly some land units or ships, we don't want to
107 potentially intercept 3 times. */
109 bzero((s_char *)&head,sizeof(struct shiplook));
112 plp = (struct plist *) bomb_list->q_forw;
113 plane_owner = plp->plane.pln_own;
115 bzero((s_char *)mypath, 1024);
116 bcopy(path,mypath,strlen(path));
119 bzero((s_char *)overfly, sizeof(overfly));
120 bzero((s_char *)gotilist, sizeof(gotilist));
121 bzero((s_char *)unfriendly, sizeof(unfriendly));
122 for (cn=1; cn<MAXNOC; cn++) {
123 if ((mynatp=getnatp(cn)) == 0)
125 rel = getrel(mynatp, plane_owner);
128 if (plane_owner == cn)
132 if (mission_flags & PM_R) {
133 if (mission_flags & P_S) {
134 PR(plane_owner,"\nSPY Plane report\n");
137 } else if (mission_flags & P_A){
138 PR(plane_owner,"\nAnti-Sub Patrol report\n");
140 PR(plane_owner,"\nReconnaissance report\n");
145 pln_removedupes(bomb_list, esc_list);
146 while ((dir = mypath[myp++]) && !QEMPTY(bomb_list)) {
147 if ((val = chkdir(dir, DIR_STOP, DIR_LAST)) == 0)
149 /* XXX using xnorm is probably bad */
150 x = xnorm(x + diroff[val][0]);
151 y = ynorm(y + diroff[val][1]);
152 getsect(x, y, §);
153 over = getnatp(sect.sct_own);
155 setcont(plane_owner,sect.sct_own, FOUND_FLY);
158 if (mission_flags & PM_R) {
159 if (sect.sct_type == SCT_WATER){
160 PR(plane_owner,"flying over %s at %s\n",
161 dchr[sect.sct_type].d_name,
162 xyas(x, y, plane_owner));
163 if (mission_flags & PM_S)
164 plane_sweep(bomb_list,x,y);
165 if (mission_flags & P_A){
166 plane_sona(bomb_list,x,y,&head);
168 changed += map_set(plane_owner,
169 sect.sct_x, sect.sct_y,
170 dchr[sect.sct_type].d_mnem,
172 } else if (mission_flags & P_S) {
173 satdisp(§, (mission_flags&P_I)?10:50, 1);
175 /* This is borrowed from lookout */
176 if (sect.sct_own == plane_owner)
177 PR(plane_owner,"Your ");
183 PR(plane_owner,dchr[sect.sct_type].d_name);
184 changed += map_set(plane_owner,
185 sect.sct_x, sect.sct_y,
186 dchr[sect.sct_type].d_mnem,
188 PR(plane_owner," %d%% efficient ",
189 (sect.sct_own == plane_owner) ?
191 roundintby((int)sect.sct_effic,25));
192 civ = getvar(V_CIVIL, (s_char *)§, EF_SECTOR);
193 mil = getvar(V_MILIT, (s_char *)§, EF_SECTOR);
195 PR(plane_owner,"with %s%d civ ",
196 (sect.sct_own == plane_owner) ?
198 (sect.sct_own == plane_owner) ?
199 civ : roundintby(civ, 25));
201 PR(plane_owner,"with %s%d mil ",
202 (sect.sct_own == plane_owner) ?
204 (sect.sct_own == plane_owner) ?
205 mil : roundintby(mil, 25));
206 PR(plane_owner,"@ %s\n", xyas(x, y, plane_owner));
209 PR(plane_owner,"flying over %s at %s\n",
210 dchr[sect.sct_type].d_name,
211 xyas(x, y, plane_owner));
212 changed += map_set(plane_owner, sect.sct_x,
214 dchr[sect.sct_type].d_mnem, 0);
216 if ((rel = getrel(over, plane_owner)) == ALLIED)
219 evaded = do_evade(bomb_list,esc_list);
221 if (sect.sct_own != 0 && sect.sct_own != plane_owner &&
223 /* We only show planes overhead if they didn't
225 overfly[sect.sct_own]++;
226 PR(sect.sct_own, "%s planes spotted over %s\n",
227 cname(plane_owner), xyas(x, y, sect.sct_own));
232 if (unfriendly[sect.sct_own])
233 ac_doflak(bomb_list, §);
234 /* If bombers left, fire flak from units and ships */
235 if (!QEMPTY(bomb_list))
236 ac_landflak(bomb_list, x, y);
237 if (!QEMPTY(bomb_list))
238 ac_shipflak(bomb_list, x, y);
240 /* mission planes aborted due to flak -- don't send escorts */
241 if (QEMPTY(bomb_list))
243 if ((!no_air_defense) && (!evaded))
244 air_defense(x,y,plane_owner,bomb_list, esc_list);
246 if (sect.sct_own == 0 || sect.sct_own == plane_owner)
253 for (qp = bomb_list->q_forw; qp != bomb_list; qp = qp->q_forw){
254 struct plist *ip = (struct plist *) qp;
255 if (!(plchr[(int)ip->plane.pln_type].pl_flags & P_M))
262 if (unfriendly[sect.sct_own] && !gotilist[sect.sct_own]) {
263 getilist(&ilist[sect.sct_own], sect.sct_own,
264 bomb_list, esc_list, obomb, oesc);
265 gotilist[sect.sct_own]++;
269 ac_intercept(bomb_list, esc_list, &ilist[sect.sct_own],
273 intown = sect.sct_own;
276 /* Let's report all of the overflights even if aborted */
277 for (cn = 1; cn < MAXNOC; cn++) {
278 if (plane_owner == cn)
281 nreport(plane_owner, N_OVFLY_SECT, cn, overfly[cn]);
283 /* If the map changed, update it */
285 if (!update_pending && plane_owner == player->cnum)
286 writemap(player->cnum);
287 /* Now, if the bomber and escort lists are empty, we are done */
288 if (QEMPTY(bomb_list) && QEMPTY(esc_list)) {
289 if (mission_flags & P_A){
291 while (s != (struct shiplook *)0){
300 /* Something made it through */
301 /* Go figure out if there are ships in this sector, and who's they are */
302 bzero((s_char *)nats, sizeof(nats));
303 snxtitem_xy(&ni, EF_SHIP, x, y);
304 while (nxtitem(&ni, (s_char *)&ship)) {
305 if (mchr[(int)ship.shp_type].m_flags & M_SUB)
307 nats[ship.shp_own]++;
309 /* Go figure out if there are units in this sector, and who's they are */
310 bzero((s_char *)lnats, sizeof(lnats));
311 snxtitem_xy(&ni, EF_LAND, x, y);
312 while (nxtitem(&ni, (s_char *)&land)) {
313 lnats[land.lnd_own]++;
316 /* Now, let's make life a little rougher. */
317 for (cn = 1; cn < MAXNOC && !QEMPTY(bomb_list); cn++) {
318 if (plane_owner == cn)
321 /* Are there ships owned by this country? */
325 PR(cn, "%s planes spotted over ships in %s\n",
326 cname(plane_owner), xyas(x, y, cn));
327 if (unfriendly[cn]) {
328 /* They are unfriendly too */
330 getilist(&ilist[cn], cn, bomb_list, esc_list, obomb, oesc);
333 PR(plane_owner, "Flying over %s ships in %s\n", cname(cn), xyas(x, y, plane_owner));
334 /* This makes going for ships in harbors tough */
336 /* We already fired flak up above. Now we intercept again if we haven't already */
337 /* Flag that we intercepted */
339 /* And now intercept again */
340 ac_intercept(bomb_list, esc_list, &ilist[cn], cn, x, y);
344 /* Are there units owned by this country? */
345 if (lnats[cn] != 0) {
348 PR(cn, "%s planes spotted over land units in %s\n",
349 cname(plane_owner), xyas(x, y, cn));
350 if (unfriendly[cn]) {
351 /* They are unfriendly too */
353 getilist(&ilist[cn], cn, bomb_list, esc_list, obomb, oesc);
356 PR(plane_owner,"Flying over %s land units in %s\n", cname(cn), xyas(x, y, plane_owner));
359 /* We haven't intercepted yet, so intercept */
360 ac_intercept(bomb_list, esc_list, &ilist[cn], cn, x, y);
367 if ((mission_flags & P_A) && (head.uid != -1)) {
369 while (s != (struct shiplook *)0){
378 count_non_missiles(struct emp_qelem *list)
380 struct emp_qelem *qp;
384 /* don't intercept missiles */
385 for (qp = list->q_forw; qp != list; qp = qp->q_forw){
386 plp = (struct plist *)qp;
387 if (!(plp->pcp->pl_flags & P_M))
394 sam_intercept(struct emp_qelem *att_list, struct emp_qelem *def_list, natid def_own, natid plane_owner, coord x, coord y, int delete_missiles)
396 struct emp_qelem *aqp;
397 struct emp_qelem *anext;
398 struct emp_qelem *dqp;
399 struct emp_qelem *dnext;
404 for (aqp = att_list->q_forw,
405 dqp = def_list->q_forw;
410 aplp = (struct plist *)aqp;
411 if (aplp->pcp->pl_flags & P_M)
413 if (aplp->pcp->pl_cost < 1000)
415 for (;dqp != def_list; dqp = dnext) {
417 dplp = (struct plist *)dqp;
418 if (!(dplp->pcp->pl_flags & P_M))
421 if (dplp->plane.pln_range < mapdist(x, y, dplp->plane.pln_x, dplp->plane.pln_y)) {
426 if (mission_pln_equip(dplp, 0, P_F, 0) < 0) {
433 PR(plane_owner,"%s launches SAMs!\n", cname(def_own));
434 PR(def_own, "Launching SAMs at %s planes!\n", cname(plane_owner));
435 ac_combat_headers(plane_owner, def_own);
443 PR(plane_owner, "\n");
446 if (delete_missiles) {
447 for (;dqp != def_list; dqp = dnext) {
449 dplp = (struct plist *)dqp;
450 if (!(dplp->pcp->pl_flags & P_M))
460 ac_intercept(struct emp_qelem *bomb_list, struct emp_qelem *esc_list, struct emp_qelem *def_list, natid def_own, coord x, coord y)
462 register struct plnstr *pp;
465 struct emp_qelem *next;
466 struct emp_qelem *qp;
467 struct emp_qelem int_list;
472 plp = (struct plist *)bomb_list->q_forw;
473 plane_owner = plp->plane.pln_own;
477 sam_intercept(bomb_list, def_list, def_own, plane_owner, x, y, 0);
478 sam_intercept(esc_list, def_list, def_own, plane_owner, x, y, 1);
479 if (!(att_count = count_non_missiles(bomb_list) +
480 count_non_missiles(esc_list)))
483 emp_initque(&int_list);
484 for (qp = def_list->q_forw; qp != def_list; qp = next) {
486 plp = (struct plist *) qp;
488 /* SAMs interdict separately */
489 if (plp->pcp->pl_flags & P_M)
491 dist = mapdist(x, y, pp->pln_x, pp->pln_y) * 2;
492 if (pp->pln_range < dist)
494 if (mission_pln_equip(plp, 0, P_F, 0) < 0) {
499 /* got one; delete from def_list, add to int_list */
501 emp_insque(qp, &int_list);
502 pp->pln_mobil -= pln_mobcost(dist,pp,P_F);
503 putplane(pp->pln_uid, pp);
505 if (icount > att_count)
510 PR(plane_owner,"%d %s fighter%s rising to intercept!\n", icount,
511 cname(def_own), icount == 1 ? " is" : "s are");
512 PR(def_own,"%d fighter%s intercepting %s planes!\n", icount,
513 icount == 1 ? " is" : "s are", cname(plane_owner));
514 ac_combat_headers(plane_owner, def_own);
515 ac_airtoair(esc_list, &int_list, def_own);
516 ac_airtoair(bomb_list, &int_list, def_own);
517 PR(plane_owner, "\n");
522 ac_combat_headers(natid plane_owner, natid def_own)
524 PR(plane_owner," %-10.10s %-10.10s strength int odds damage results\n", cname(plane_owner), cname(def_own));
525 PR(def_own," %-10.10s %-10.10s strength int odds damage results\n", cname(def_own), cname(plane_owner));
532 ac_airtoair(struct emp_qelem *att_list, struct emp_qelem *int_list, natid def_own)
534 register struct plist *attacker;
535 register struct plist *interceptor;
536 struct emp_qelem *att;
537 struct emp_qelem *in;
541 struct emp_qelem *att_next;
542 struct emp_qelem *in_next;
545 att = att_list->q_forw;
546 in = int_list->q_forw;
549 if (QEMPTY(att_list) || QEMPTY(int_list)) {
553 while (more_att || more_int) {
554 in_next = in->q_forw;
555 att_next = att->q_forw;
556 attacker = (struct plist *) att;
558 /* skip missiles. If only missiles left, we're done */
559 if (plchr[(int)attacker->plane.pln_type].pl_flags & P_M){
561 if (att == att_list) {
563 if (QEMPTY(att_list))
568 if (all_missiles(att_list))
572 interceptor = (struct plist *) in;
573 att_own = attacker->plane.pln_own;
574 def_own = interceptor->plane.pln_own;
575 nplanes = attacker->plane.pln_effic;
576 if (nplanes > interceptor->plane.pln_effic)
577 nplanes = interceptor->plane.pln_effic;
578 ac_dog(attacker, interceptor);
581 if (att == att_list) {
583 if (QEMPTY(att_list))
588 if (in == int_list) {
590 if (QEMPTY(int_list))
599 all_missiles(struct emp_qelem *att_list)
601 struct emp_qelem *qp;
604 qp = att_list->q_forw;
605 while (qp != att_list){
606 p = (struct plist *)qp;
607 if (!(plchr[(int)p->plane.pln_type].pl_flags & P_M))
616 ac_dog(register struct plist *ap, register struct plist *dp)
621 natid att_own, def_own;
626 att_own = ap->plane.pln_own;
627 def_own = dp->plane.pln_own;
629 PR(att_own," %3.3s #%-4d %3.3s #%-4d",
635 PR(def_own," %3.3s #%-4d %3.3s #%-4d",
640 if (ap->plane.pln_att == 0){
641 att = ap->plane.pln_def * ap->plane.pln_effic / 100;
642 att = MAX(att,ap->pcp->pl_def/2);
644 att = ap->plane.pln_att * ap->plane.pln_effic / 100;
645 att = MAX(att,ap->pcp->pl_att/2);
648 def = dp->plane.pln_def * dp->plane.pln_effic / 100;
649 def = MAX(def,dp->pcp->pl_def/2);
651 if ((ap->pcp->pl_flags & P_F) && ap->bombs != 0)
653 if ((dp->pcp->pl_flags & P_F) && dp->bombs != 0)
655 att += ((float)ap->pcp->pl_stealth/25.0);
656 def += ((float)dp->pcp->pl_stealth/25.0);
665 odds = ((double)att/((double)def+(double)att));
668 intensity = roll(20)+roll(20)+roll(20)+roll(20)+1;
670 PR(att_own," %3d/%-3d %3d %3.2f ",att,def,intensity,odds);
671 PR(def_own," %3d/%-3d %3d %3.2f ",def,att,intensity,odds);
674 while ((intensity--)>0){
678 if ((dp->plane.pln_effic-ddam) < PLANE_MINEFF)
682 if ((ap->plane.pln_effic-adam) < PLANE_MINEFF)
687 if (dp->pcp->pl_flags & P_M)
690 PR(att_own,"%3d/%-3d", adam, ddam);
691 PR(def_own,"%3d/%-3d", ddam, adam);
692 ac_planedamage(ap, dp->plane.pln_own,
693 adam, def_own, 1, 0, mesg);
694 strncpy(temp,mesg,14);
695 ac_planedamage(dp, ap->plane.pln_own,
696 ddam, att_own, 1, 0, mesg);
697 PR(att_own, "%-13.13s %-13.13s\n", temp, mesg);
698 PR(def_own, "%-13.13s %-13.13s\n", mesg, temp);
702 * zap plane associated with plp.
703 * Damaging country is "from", damage is "dam".
704 * def_own is the country on the other side of the conflict from the plane
705 * owner. The only time def_own != from is when the interceptor is getting
708 * NOTE: This routine removes the appropriate plane element from the
709 * queue if it gets destroyed. That means that the caller must assume
710 * that the current queue pointer is invalid on return from the ac_planedamage
711 * call. (this has caused bugs in the past)
714 ac_planedamage(struct plist *plp, natid from, int dam, natid other, int checkabort, int show, s_char *mesg)
716 register struct plnstr *pp;
722 /* s_char *sprintf(); already in misc.h [JFW] */
727 plane_owner = pp->pln_own;
729 sprintf(dmess," no damage");
738 if (eff < PLANE_MINEFF) {
739 sprintf(dmess," shot down");
741 } else if (eff < 80 && chance((100-eff)/100.0) && checkabort){
742 sprintf(dmess," aborted @%2d%%", eff);
744 } else if (show == 0) {
745 sprintf(dmess," cleared");
748 if ((plp->pcp->pl_flags & P_M) == 0) {
750 PR(plane_owner, " %s %s takes %d%s.\n",
752 prplane(pp), dam, dmess);
754 PR(other, " %s %s takes %d%s.\n",
756 prplane(pp), dam, dmess);
759 if (show && checkabort == 1) {
760 PR(plane_owner,"\n");
766 pp->pln_mobil -= min(32 + pp->pln_mobil, dam/2);
768 if (from != 0 && (plp->pcp->pl_flags & P_M) == 0)
769 nreport(from, N_DOWN_PLANE, pp->pln_own, 1);
770 if (pp->pln_ship >= 0) {
771 getship(pp->pln_ship,&ship);
772 take_plane_off_ship(pp,&ship);
774 if (pp->pln_land >= 0) {
775 getland(pp->pln_land,&land);
776 take_plane_off_land(pp,&land);
778 makelost(EF_PLANE, pp->pln_own, pp->pln_uid, pp->pln_x, pp->pln_y);
780 putplane(pp->pln_uid, pp);
781 emp_remque(&plp->queue);
783 } else if (disp == 2) {
784 putplane(pp->pln_uid, pp);
785 emp_remque(&plp->queue);
788 putplane(pp->pln_uid, pp);
793 ac_doflak(struct emp_qelem *list, struct sctstr *from)
800 plp = (struct plist *)list->q_forw;
801 plane_owner = plp->plane.pln_own;
803 gun = getvar(V_GUN, (s_char *)from, EF_SECTOR);
804 shell = getvar(V_SHELL, (s_char *)from, EF_SECTOR);
807 add = supply_commod(from->sct_own,from->sct_x,from->sct_y,
808 I_SHELL,ldround(((double)gun/2.0),1)-shell);
810 if (gun == 0 || shell == 0)
817 putvar(V_SHELL, shell, (s_char *)from, EF_SECTOR);
819 gun = 2.0 * tfact(from->sct_own, (double) gun);
821 PR(plane_owner,"firing %d flak guns in %s...\n",
822 gun, xyas(from->sct_x, from->sct_y, plane_owner));
823 if(from->sct_own != 0)
824 PR(from->sct_own, "firing %d flak guns in %s...\n",
825 gun, xyas(from->sct_x, from->sct_y, from->sct_own));
826 ac_fireflak(list, from->sct_own, 0, gun);
831 ac_shipflak(struct emp_qelem *list, coord x, coord y)
846 plp = (struct plist *)list->q_forw;
847 plane_owner = plp->plane.pln_own;
849 bzero((s_char *)nats, sizeof(nats));
851 snxtitem_xy(&ni, EF_SHIP, x, y);
852 while (!QEMPTY(list) && nxtitem(&ni, (s_char *)&ship)) {
853 if (ship.shp_own == 0 || ship.shp_own == plane_owner)
857 mcp = &mchr[(int)ship.shp_type];
858 if (mcp->m_flags & M_SUB)
860 rel = getrel(getnatp(ship.shp_own), plane_owner);
864 gun = min(getvar(V_GUN, (s_char *)&ship, EF_SHIP), ship.shp_glim);
866 shell = getvar(V_SHELL, (s_char *)&ship, EF_SHIP);
868 shell = supply_commod(ship.shp_own, ship.shp_x,
869 ship.shp_y, I_SHELL, 1);
871 if (gun == 0 || shell == 0)
873 firing = (int) (techfact(ship.shp_tech, (double)gun) * 2.0);
876 if (!nats[ship.shp_own]) {
877 /* First time here, print the message */
878 PR(ship.shp_own, "%s planes spotted over ships in %s\n",
879 cname(plane_owner), xyas(x, y, ship.shp_own));
880 PR(plane_owner, "Flying over %s ships in %s\n", cname(ship.shp_own),
881 xyas(x, y, plane_owner));
882 nats[ship.shp_own] = 1;
884 PR(ship.shp_own, "firing %d flak guns from %s...\n",
885 firing, prship(&ship));
886 putvar(V_SHELL, shell, (s_char *)&ship, EF_SHIP);
887 putship(ship.shp_uid, &ship);
893 guns = 2.0 * tfact(from, (double)guns);
894 PR(plane_owner, "Flak! Ships firing %d flak guns...\n", guns);
895 ac_fireflak(list, from, 0, guns);
900 ac_landflak(struct emp_qelem *list, coord x, coord y)
913 plp = (struct plist *)list->q_forw;
914 plane_owner = plp->plane.pln_own;
916 bzero((s_char *)nats, sizeof(nats));
918 snxtitem_xy(&ni, EF_LAND, x, y);
919 while (!QEMPTY(list) && nxtitem(&ni, (s_char *)&land)) {
920 if (land.lnd_own == 0 || land.lnd_own == plane_owner)
924 lcp = &lchr[(int)land.lnd_type];
926 if ((lcp->l_flags & L_FLAK) == 0)
929 if (land.lnd_aaf == 0)
932 rel = getrel(getnatp(land.lnd_own), plane_owner);
935 firing = (int)(techfact(land.lnd_tech, (double)land.lnd_aaf) * 3.0);
938 if (!nats[land.lnd_own]) {
939 /* First time here, print the message */
940 PR(land.lnd_own, "%s planes spotted over land units in %s\n",
941 cname(plane_owner), xyas(x, y, land.lnd_own));
942 PR(plane_owner, "Flying over %s land units in %s\n", cname(land.lnd_own),
943 xyas(x, y, plane_owner));
944 nats[land.lnd_own] = 1;
946 PR(land.lnd_own, "firing flak guns from unit %s (aa rating %d)\n",
947 prland(&land), land.lnd_aaf);
949 from = land.lnd_own; /* We always use the last owner as the from */
954 guns = 2.0 * tfact(from, (double)guns);
955 PR(plane_owner, "Flak! Land units firing %d flak guns...\n", guns);
956 ac_fireflak(list, from, 0, guns);
961 * Called from shipflak, landflak, and doflak.
964 ac_fireflak(struct emp_qelem *list, natid from, natid other, int guns)
966 extern double flakscale;
967 register struct plnstr *pp;
972 struct emp_qelem *qp;
973 struct emp_qelem *next;
976 plp = (struct plist *)list->q_forw;
978 for (qp = list->q_forw; qp != list; qp = next) {
980 * fighters don't get shot at by flak
981 * non-tactical bombers are harder to hit with flak.
982 * ('Cause they're not dive-bombing?)
985 plp = (struct plist *) qp;
987 diff = guns - pp->pln_def;
988 if ((plp->pcp->pl_flags & P_T) == 0)
990 if (plp->pcp->pl_flags & P_X)
992 if (plp->pcp->pl_flags & P_H)
995 mult = flaktable[FLAK_MAX] * 1.33;
997 mult = flaktable[0] * 0.66;
1000 mult = flaktable[diff];
1003 n = (int) ((roll(8) + 2) * mult);
1006 ac_planedamage(plp, from, n, other, 2, 1, msg);
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, struct emp_qelem *b, struct emp_qelem *c, struct emp_qelem *d)
1040 register struct plchrstr *pcp;
1041 struct plnstr plane;
1045 struct nstr_item ni;
1051 snxtitem_all(&ni, EF_PLANE);
1052 while (nxtitem(&ni, (s_char *)&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 ptr = (s_char *)&ship;
1071 if (plane.pln_land >= 0) {
1072 if (!can_fly(plane.pln_uid))
1074 getland(plane.pln_land,&land);
1075 ptr = (s_char *)&land;
1078 getsect(plane.pln_x, plane.pln_y, §);
1079 ptr = (s_char *)§
1082 if (sect.sct_effic < 60 && (pcp->pl_flags & P_V) == 0)
1085 if ((sect.sct_effic < 60 || sect.sct_type != SCT_AIRPT)
1086 && (pcp->pl_flags & P_V) == 0)
1090 if (((float)getvar(V_PETROL, ptr, type)) <
1091 (((float)pcp->pl_fuel)/2.0))
1093 /* Finally, is it in the list of planes already in
1095 if (ac_isflying(&plane, a))
1097 if (ac_isflying(&plane, b))
1099 if (ac_isflying(&plane, c))
1101 if (ac_isflying(&plane, d))
1104 ip = (struct plist *) malloc(sizeof(*ip));
1108 ip->pcp = &plchr[(int)plane.pln_type];
1109 bcopy((s_char *)&plane, (s_char *)&ip->plane, sizeof(plane));
1110 emp_insque(&ip->queue, list);
1117 can_fly(int p) /* Can this plane fly from the ship or land unit it is on? */
1120 struct plnstr plane;
1123 struct plchrstr *pcp;
1124 struct mchrstr *scp;
1125 struct lchrstr *lcp;
1128 pcp = &plchr[(int)plane.pln_type];
1130 if (plane.pln_ship >= 0){
1132 !(pcp->pl_flags & P_L) && !(pcp->pl_flags & P_M)
1133 && !(pcp->pl_flags & P_K)
1134 && !(pcp->pl_flags & P_E)
1138 getship(plane.pln_ship,&ship);
1139 scp = & mchr[(int)ship.shp_type];
1141 if ((pcp->pl_flags & P_L) && (scp->m_flags & M_FLY)){
1145 if ((pcp->pl_flags & P_M) && (scp->m_flags & M_MSL)){
1149 if ((pcp->pl_flags & P_K) && (scp->m_flags & M_CHOPPER)){
1153 if ((pcp->pl_flags & P_E) && (scp->m_flags & M_XLIGHT)){
1158 if (plane.pln_land >= 0){
1159 if (!(pcp->pl_flags & P_E))
1162 getland(plane.pln_land,&land);
1163 lcp = & lchr[(int)land.lnd_type];
1165 if ((pcp->pl_flags & P_E) && (lcp->l_flags & L_XLIGHT)){
1174 do_evade(struct emp_qelem *bomb_list, struct emp_qelem *esc_list)
1176 struct emp_qelem *qp;
1181 for (qp = bomb_list->q_forw; qp != bomb_list; qp = qp->q_forw){
1182 plp = (struct plist *) qp;
1183 if (evade > ((float)plp->pcp->pl_stealth/100.0))
1184 evade = (plp->pcp->pl_stealth/100.0);
1186 for (qp = esc_list->q_forw; qp != esc_list; qp = qp->q_forw){
1187 plp = (struct plist *) qp;
1188 if (evade > plp->pcp->pl_stealth/100.0)
1189 evade = (plp->pcp->pl_stealth/100.0);