]> git.pond.sub.org Git - empserver/blob - src/lib/commands/bomb.c
bomb: Pass NULL instead of 0 to pln_damage()
[empserver] / src / lib / commands / bomb.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2020, Dave Pare, Jeff Bailey, Thomas Ruschak,
4  *                Ken Stevens, Steve McClure, Markus Armbruster
5  *
6  *  Empire 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 3 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, see <http://www.gnu.org/licenses/>.
18  *
19  *  ---
20  *
21  *  See files README, COPYING and CREDITS in the root of the source
22  *  tree for related information and legal notices.  It is expected
23  *  that future projects/authors will amend these files as needed.
24  *
25  *  ---
26  *
27  *  bomb.c: Fly bombing missions
28  *
29  *  Known contributors to this file:
30  *     Dave Pare, 1986
31  *     Ken Stevens, 1995
32  *     Steve McClure, 1998-2000
33  *     Markus Armbruster, 2004-2020
34  */
35
36 #include <config.h>
37
38 #include <ctype.h>
39 #include "chance.h"
40 #include "commands.h"
41 #include "damage.h"
42 #include "item.h"
43 #include "land.h"
44 #include "news.h"
45 #include "nuke.h"
46 #include "optlist.h"
47 #include "path.h"
48 #include "plane.h"
49 #include "retreat.h"
50 #include "ship.h"
51
52 static void pin_bomb(struct emp_qelem *, struct sctstr *);
53 static void eff_bomb(struct emp_qelem *, struct sctstr *);
54 static void comm_bomb(struct emp_qelem *, struct sctstr *);
55 static void ship_bomb(struct emp_qelem *, struct sctstr *);
56 static void plane_bomb(struct emp_qelem *, struct sctstr *);
57 static void land_bomb(struct emp_qelem *, struct sctstr *);
58 static void strat_bomb(struct emp_qelem *, struct sctstr *);
59 static int changed_plane_aborts(struct plist *);
60 static int pinflak_planedamage(struct plnstr *, struct plchrstr *,
61                                natid, int);
62
63 int
64 bomb(void)
65 {
66     char *p;
67     coord tx, ty;
68     coord ax, ay;
69     int ap_to_target;
70     char flightpath[MAX_PATH_LEN];
71     struct nstr_item ni_bomb;
72     struct nstr_item ni_esc;
73     struct sctstr target;
74     struct emp_qelem bomb_list;
75     struct emp_qelem esc_list;
76     struct sctstr ap_sect;
77     char mission;
78     struct plist *plp;
79     struct emp_qelem *qp, *next;
80     char buf[1024];
81
82     if (get_planes(&ni_bomb, &ni_esc, player->argp[1], player->argp[2]) < 0)
83         return RET_SYN;
84     p = getstarg(player->argp[3], "pinpoint, or strategic? ", buf);
85     if (!p || !*p)
86         return RET_SYN;
87     mission = *p;
88     if (!strchr("ps", mission))
89         return RET_SYN;
90     if (!get_assembly_point(player->argp[4], &ap_sect, buf))
91         return RET_SYN;
92     ax = ap_sect.sct_x;
93     ay = ap_sect.sct_y;
94     if (!getpath(flightpath, player->argp[5], ax, ay, 0, 0, MOB_FLY))
95         return RET_SYN;
96     tx = ax;
97     ty = ay;
98     (void)pathtoxy(flightpath, &tx, &ty, fcost);
99     pr("target sector is %s\n", xyas(tx, ty, player->cnum));
100     getsect(tx, ty, &target);
101     ap_to_target = strlen(flightpath);
102     pr("range to target is %d\n", ap_to_target);
103     /*
104      * select planes within range
105      */
106     pln_sel(&ni_bomb, &bomb_list, &ap_sect, ap_to_target, 2,
107             P_B | P_T, P_M | P_O);
108     pln_sel(&ni_esc, &esc_list, &ap_sect, ap_to_target, 2,
109             P_ESC | P_F, P_M | P_O);
110     /*
111      * now arm and equip the bombers, transports, whatever.
112      */
113     pln_arm(&bomb_list, 2 * ap_to_target, mission, NULL);
114     if (QEMPTY(&bomb_list)) {
115         pr("No planes could be equipped for the mission.\n");
116         return RET_FAIL;
117     }
118     pln_arm(&esc_list, 2 * ap_to_target, 'e', NULL);
119     ac_encounter(&bomb_list, &esc_list, ax, ay, flightpath, 0);
120     if (QEMPTY(&bomb_list)) {
121         pr("No planes got through fighter defenses\n");
122     } else if (target.sct_type == SCT_SANCT) {
123         pr("You can't bomb that sector!\n");
124     } else {
125         switch (mission) {
126         case 'p':
127             pin_bomb(&bomb_list, &target);
128             for (qp = bomb_list.q_forw; qp != &bomb_list; qp = next) {
129                 next = qp->q_forw;
130                 plp = (struct plist *)qp;
131                 changed_plane_aborts(plp);
132             }
133             for (qp = esc_list.q_forw; qp != &esc_list; qp = next) {
134                 next = qp->q_forw;
135                 plp = (struct plist *)qp;
136                 changed_plane_aborts(plp);
137             }
138             break;
139         case 's':
140             nreport(player->cnum, N_SCT_BOMB, target.sct_own, 1);
141             strat_bomb(&bomb_list, &target);
142             break;
143         default:
144             CANT_REACH();
145         }
146     }
147     pln_put(&bomb_list);
148     pln_put(&esc_list);
149     return RET_OK;
150 }
151
152 static void
153 pin_bomb(struct emp_qelem *list, struct sctstr *target)
154 {
155     struct dchrstr *dcp;
156     int nplanes;
157     int nships;
158     int type;
159     int bad;
160     char *p;
161     int nsubs;
162     int nunits;
163     char buf[1024];
164     int i;
165
166     bad = 0;
167     type = target->sct_type;
168     dcp = &dchr[type];
169     pr("Target sector is a %s constructed %s\n",
170        effadv((int)target->sct_effic), dcp->d_name);
171     nsubs = 0;
172     nships = shipsatxy(target->sct_x, target->sct_y, 0, M_SUB, 0);
173     if (pln_caps(list) & P_A) {
174         nsubs = shipsatxy(target->sct_x, target->sct_y, M_SUB, 0, 1);
175         if (nsubs > 0)
176             pr("Some subs are present in the sector.\n");
177     }
178     nplanes = planesatxy(target->sct_x, target->sct_y, 0, 0);
179     nunits = unitsatxy(target->sct_x, target->sct_y, 0, L_SPY);
180   retry:
181     p = getstring("Bomb what? (ship, plane, land unit, efficiency, commodities) ",
182                   buf);
183     if (!p)
184        return;
185     if (!*p) {
186         bad++;
187         if (bad > 2)
188             return;
189         goto retry;
190     }
191     switch (*p) {
192     case 'l':
193         if (nunits == 0) {
194             pr("no units there\n");
195             goto retry;
196         }
197         land_bomb(list, target);
198         break;
199     case 'p':
200         if (nplanes == 0) {
201             pr("no planes there\n");
202             goto retry;
203         }
204         plane_bomb(list, target);
205         break;
206     case 's':
207         if (nships == 0) {
208             if (pln_caps(list) & P_A) {
209                 if (nsubs == 0) {
210                     pr("no ships there\n");
211                     goto retry;
212                 }
213             } else {
214                 pr("no ships there\n");
215                 goto retry;
216             }
217         }
218         ship_bomb(list, target);
219         break;
220     case 'c':
221         for (i = I_NONE + 1; i <= I_MAX; i++) {
222             if (target->sct_item[i])
223                 break;
224         }
225         if (i > I_MAX) {
226             pr("No bombable commodities in %s\n",
227                xyas(target->sct_x, target->sct_y, player->cnum));
228             goto retry;
229         }
230         comm_bomb(list, target);
231         break;
232     case 'e':
233         eff_bomb(list, target);
234         break;
235     case 'q':
236         pr("Aborting mission.\n");
237         return;
238     default:
239         pr("Bad target type.\n");
240         goto retry;
241     }
242 }
243
244 static void
245 eff_bomb(struct emp_qelem *list, struct sctstr *target)
246 {
247     struct plist *plp;
248     struct emp_qelem *qp, *next;
249     struct sctstr sect;
250     int oldeff, dam = 0;
251
252     for (qp = list->q_forw; qp != list; qp = next) {
253         next = qp->q_forw;
254         plp = (struct plist *)qp;
255         if (changed_plane_aborts(plp))
256             continue;
257         dam += pln_damage(&plp->plane, 'p', "");
258     }
259     getsect(target->sct_x, target->sct_y, &sect);
260     target = &sect;
261     oldeff = target->sct_effic;
262     target->sct_effic = effdamage(target->sct_effic, dam);
263     target->sct_avail = effdamage(target->sct_avail, dam);
264     target->sct_road = effdamage(target->sct_road, dam);
265     target->sct_rail = effdamage(target->sct_rail, dam);
266     target->sct_defense = effdamage(target->sct_defense, dam);
267     pr("did %d%% damage to efficiency in %s\n",
268        oldeff - target->sct_effic,
269        xyas(target->sct_x, target->sct_y, player->cnum));
270     if (target->sct_own != player->cnum)
271         mpr(target->sct_own,
272             "%s bombing raid did %d%% damage in %s\n",
273             cname(player->cnum), oldeff - target->sct_effic,
274             xyas(target->sct_x, target->sct_y, target->sct_own));
275     bridge_damaged(target);
276     putsect(&sect);
277     collateral_damage(target->sct_x, target->sct_y, dam);
278 }
279
280 static void
281 comm_bomb(struct emp_qelem *list, struct sctstr *target)
282 {
283     struct plist *plp;
284     double b;
285     int i;
286     int amt, before;
287     struct ichrstr *ip;
288     struct emp_qelem *qp, *next;
289     struct sctstr sect;
290     int dam = 0;
291
292     for (i = I_NONE + 1; i <= I_MAX; i++) {
293         if (!target->sct_item[i])
294             continue;
295         if (opt_SUPER_BARS && i == I_BAR)
296             continue;
297         pr("some %s\n", ichr[i].i_name);
298     }
299     for (;;) {
300         ip = whatitem(NULL, "commodity to bomb? ");
301         if (player->aborted)
302             return;
303         if (!ip)
304             continue;
305         if (opt_SUPER_BARS && ip->i_uid == I_BAR) {
306             pr("You can't bomb %s!\n", ip->i_name);
307             continue;
308         }
309         break;
310     }
311     for (qp = list->q_forw; qp != list; qp = next) {
312         next = qp->q_forw;
313         plp = (struct plist *)qp;
314         if (changed_plane_aborts(plp))
315             continue;
316         dam += pln_damage(&plp->plane, 'p', "");
317     }
318     getsect(target->sct_x, target->sct_y, &sect);
319     target = &sect;
320     before = target->sct_item[ip->i_uid];
321     target->sct_item[ip->i_uid] = amt = commdamage(before, dam, ip->i_uid);
322     if (before > 0.0)
323         b = 100.0 * (1.0 - (double)amt / (double)before);
324     else
325         b = 0.0;
326     pr("did %.2f%% damage to %s in %s\n",
327        b, ip->i_name, xyas(target->sct_x, target->sct_y, player->cnum));
328     nreport(player->cnum, N_SCT_BOMB, target->sct_own, 1);
329     if (target->sct_own != player->cnum)
330         mpr(target->sct_own,
331             "%s precision bombing raid did %.2f%% damage to %s in %s\n",
332             cname(player->cnum), b, ip->i_name,
333             xyas(target->sct_x, target->sct_y, target->sct_own));
334     putsect(&sect);
335     collateral_damage(target->sct_x, target->sct_y, dam);
336 }
337
338 static void
339 ship_bomb(struct emp_qelem *list, struct sctstr *target)
340 {
341     struct plist *plp;
342     struct mchrstr *mcp;
343     int dam;
344     char *q;
345     int n;
346     struct emp_qelem *qp, *next;
347     int shipno;
348     struct shpstr ship;
349     int nships = 0;
350     struct shiplist *head = NULL;
351     char buf[1024];
352     char prompt[128];
353     int hitchance;
354     int flak;
355     int gun;
356
357     for (qp = list->q_forw; qp != list; qp = next) {
358         next = qp->q_forw;
359         free_shiplist(&head);
360         plp = (struct plist *)qp;
361         if (changed_plane_aborts(plp))
362             continue;
363         if (plp->pcp->pl_flags & P_A)
364             nships = asw_shipsatxy(target->sct_x, target->sct_y, 0, 0,
365                                    &plp->plane, &head);
366         else
367             nships = shipsatxy(target->sct_x, target->sct_y, 0, M_SUB, 0);
368         if (nships == 0) {
369             pr("%s could not find any ships!\n", prplane(&plp->plane));
370             continue;
371         }
372         (void)sprintf(prompt, "%s, %d bombs.  Target ('~' to skip)? ",
373                       prplane(&plp->plane), plp->load);
374         shipno = -1;
375         while (shipno < 0) {
376             if (!(q = getstring(prompt, buf)))
377                 goto out;
378             if (*q == 0)
379                 continue;
380             if (*q == '~')
381                 break;
382             if (*q == '?') {
383                 if (plp->pcp->pl_flags & P_A)
384                     print_shiplist(head);
385                 else
386                     shipsatxy(target->sct_x, target->sct_y, 0, M_SUB, 0);
387                 continue;
388             }
389             n = atoi(q);
390             if (n < 0)
391                 continue;
392             if ((!(plp->pcp->pl_flags & P_A) || on_shiplist(n, head)) &&
393                 getship(n, &ship) && ship.shp_own &&
394                 ship.shp_x == target->sct_x && ship.shp_y == target->sct_y)
395                 shipno = n;
396             else
397                 pr("Ship #%d not spotted\n", n);
398         }
399         if (shipno < 0)
400             continue;
401         if ((plp->pcp->pl_flags & P_A) && !on_shiplist(shipno, head))
402             continue;
403         if (changed_plane_aborts(plp))
404             continue;
405
406         gun = shp_usable_guns(&ship);
407         mcp = &mchr[(int)ship.shp_type];
408         if (gun > 0 && !(mcp->m_flags & M_SUB)) {
409             flak = (int)(techfact(ship.shp_tech, gun) * 2.0);
410             mpr(ship.shp_own, "Flak! Firing %d guns from ship %s\n",
411                 flak, prship(&ship));
412             if (pinflak_planedamage(&plp->plane, plp->pcp, ship.shp_own, flak))
413                 continue;
414         }
415
416         if (nuk_on_plane(&plp->plane) >= 0)
417             hitchance = 100;
418         else {
419             hitchance = pln_hitchance(&plp->plane,
420                                       shp_hardtarget(&ship), EF_SHIP);
421             pr("%d%% hit chance...", hitchance);
422         }
423         if (pct_chance(hitchance)) {
424             /* pin-bombing is more accurate than normal bombing */
425             dam = 2 * pln_damage(&plp->plane, 'p', "");
426         } else {
427             pr("splash\n");
428             /* Bombs that miss have to land somewhere! */
429             dam = pln_damage(&plp->plane, 'p', NULL);
430             collateral_damage(target->sct_x, target->sct_y, dam);
431             continue;
432         }
433         if (mcp->m_flags & M_SUB)
434             nreport(player->cnum, N_SUB_BOMB, ship.shp_own, 1);
435         else
436             nreport(player->cnum, N_SHP_BOMB, ship.shp_own, 1);
437         if (ship.shp_own != player->cnum) {
438             mpr(ship.shp_own, "%s bombs did %d damage to %s at %s\n",
439                 cname(player->cnum), dam,
440                 prship(&ship),
441                 xyas(target->sct_x, target->sct_y, ship.shp_own));
442         }
443         shipdamage(&ship, dam);
444         if (ship.shp_effic < SHIP_MINEFF)
445             pr("%s at %s sunk!\n",
446                prship(&ship),
447                xyas(target->sct_x, target->sct_y, player->cnum));
448         if (dam && (ship.shp_rflags & RET_INJURED))
449             retreat_ship(&ship, ship.shp_own, 'i');
450         else if (ship.shp_rflags & RET_BOMBED)
451             retreat_ship(&ship, ship.shp_own, 'b');
452         putship(ship.shp_uid, &ship);
453         collateral_damage(target->sct_x, target->sct_y, dam / 2);
454     }
455 out:
456     free_shiplist(&head);
457 }
458
459 static void
460 plane_bomb(struct emp_qelem *list, struct sctstr *target)
461 {
462     int dam;
463     char *q;
464     int n;
465     natid own;
466     struct plnstr plane;
467     struct emp_qelem *qp, *next;
468     int planeno;
469     struct plist *plp;
470     char prompt[128];
471     char buf[1024];
472     int hitchance;
473     int nplanes;
474
475     for (qp = list->q_forw; qp != list; qp = next) {
476         next = qp->q_forw;
477         plp = (struct plist *)qp;
478         if (changed_plane_aborts(plp))
479             continue;
480         nplanes = planesatxy(target->sct_x, target->sct_y, 0, 0);
481         if (nplanes == 0) {
482             pr("%s could not find any planes!\n", prplane(&plp->plane));
483             continue;
484         }
485         (void)sprintf(prompt, "%s, %d bombs.  Target ('~' to skip)? ",
486                       prplane(&plp->plane), plp->load);
487         planeno = -1;
488         while (planeno < 0) {
489             if (!(q = getstring(prompt, buf)))
490                 return;
491             if (*q == 0)
492                 continue;
493             if (*q == '~')
494                 break;
495             if (*q == '?') {
496                 planesatxy(target->sct_x, target->sct_y, 0, 0);
497                 continue;
498             }
499             n = atoi(q);
500             if (n < 0)
501                 continue;
502             if (getplane(n, &plane) && plane.pln_own &&
503                 plane.pln_x == target->sct_x &&
504                 plane.pln_y == target->sct_y &&
505                 plane.pln_ship < 0 && plane.pln_land < 0 &&
506                 !(plane.pln_flags & PLN_LAUNCHED))
507                 planeno = n;
508             else
509                 pr("Plane #%d not spotted\n", n);
510         }
511         if (planeno < 0)
512             continue;
513         if (changed_plane_aborts(plp))
514             continue;
515         if (nuk_on_plane(&plp->plane) >= 0)
516             hitchance = 100;
517         else {
518             hitchance = pln_hitchance(&plp->plane, 0, EF_PLANE);
519             pr("%d%% hit chance...", hitchance);
520         }
521         if (pct_chance(hitchance)) {
522             /* pin-bombing is more accurate than normal bombing */
523             dam = 2 * pln_damage(&plp->plane, 'p', "");
524         } else {
525             pr("thud\n");
526             /* Bombs that miss have to land somewhere! */
527             dam = pln_damage(&plp->plane, 'p', NULL);
528             collateral_damage(target->sct_x, target->sct_y, dam);
529             continue;
530         }
531         if (dam > 100)
532             dam = 100;
533         own = plane.pln_own;
534         if (dam > plane.pln_effic)
535             plane.pln_effic = 0;
536         else
537             plane.pln_effic -= dam;
538         plane.pln_mobil = damage(plane.pln_mobil, dam);
539         mpr(own, "%s bombs did %d%% damage to %s at %s\n",
540                cname(player->cnum), dam, prplane(&plane),
541                xyas(target->sct_x, target->sct_y, own));
542         nreport(player->cnum, N_DOWN_PLANE, own, 1);
543         putplane(plane.pln_uid, &plane);
544         collateral_damage(target->sct_x, target->sct_y, dam);
545     }
546 }
547
548 static void
549 land_bomb(struct emp_qelem *list, struct sctstr *target)
550 {
551     int dam;
552     char *q;
553     int n;
554     natid own;
555     char prompt[128];
556     char buf[1024];
557     struct lndstr land;
558     struct emp_qelem *qp, *next;
559     int unitno;
560     int aaf, flak, hitchance;
561     struct plist *plp;
562     int nunits;
563
564     for (qp = list->q_forw; qp != list; qp = next) {
565         next = qp->q_forw;
566         plp = (struct plist *)qp;
567         if (changed_plane_aborts(plp))
568             continue;
569         nunits = unitsatxy(target->sct_x, target->sct_y, 0, L_SPY);
570         if (nunits == 0) {
571             pr("%s could not find any units!\n", prplane(&plp->plane));
572             continue;
573         }
574         (void)sprintf(prompt, "%s, %d bombs.  Target ('~' to skip)? ",
575                       prplane(&plp->plane), plp->load);
576         unitno = -1;
577         while (unitno < 0) {
578             if (!(q = getstring(prompt, buf)))
579                 return;
580             if (*q == 0)
581                 continue;
582             if (*q == '~')
583                 break;
584             if (*q == '?') {
585                 unitsatxy(target->sct_x, target->sct_y, 0, L_SPY);
586                 continue;
587             }
588             n = atoi(q);
589             if (n < 0)
590                 continue;
591             if (getland(n, &land) && land.lnd_own &&
592                 land.lnd_ship < 0 && land.lnd_land < 0 &&
593                 !(lchr[land.lnd_type].l_flags & L_SPY) &&
594                 land.lnd_x == target->sct_x && land.lnd_y == target->sct_y)
595                 unitno = n;
596             else
597                 pr("Unit #%d not spotted\n", n);
598         }
599         if (unitno < 0)
600             continue;
601         if (changed_plane_aborts(plp))
602             continue;
603
604         aaf = lnd_aaf(&land);
605         if (aaf) {
606             flak = roundavg(techfact(land.lnd_tech,
607                                      aaf * 3.0 * land.lnd_effic / 100.0));
608             mpr(land.lnd_own,
609                 "Flak! Firing flak guns from unit %s (AA rating %d)\n",
610                 prland(&land), aaf);
611             if (pinflak_planedamage(&plp->plane, plp->pcp, land.lnd_own, flak))
612                 continue;
613         }
614
615         if (nuk_on_plane(&plp->plane) >= 0)
616             hitchance = 100;
617         else {
618             hitchance = pln_hitchance(&plp->plane,
619                                       lnd_hardtarget(&land), EF_LAND);
620             pr("%d%% hit chance...", hitchance);
621         }
622         if (pct_chance(hitchance)) {
623             dam = 2 * pln_damage(&plp->plane, 'p', "");
624         } else {
625             pr("thud\n");
626             /* Bombs that miss have to land somewhere! */
627             dam = pln_damage(&plp->plane, 'p', NULL);
628             collateral_damage(target->sct_x, target->sct_y, dam);
629             continue;
630         }
631         if (dam > 100)
632             dam = 100;
633         own = land.lnd_own;
634         if (own != player->cnum)
635             mpr(own, "%s bombs did %d%% damage to %s at %s\n",
636                 cname(player->cnum), dam, prland(&land),
637                 xyas(target->sct_x, target->sct_y, own));
638         landdamage(&land, dam);
639         if (dam && (land.lnd_rflags & RET_INJURED))
640             retreat_land(&land, own, 'i');
641         else if (land.lnd_rflags & RET_BOMBED)
642             retreat_land(&land, own, 'b');
643         nreport(player->cnum, N_UNIT_BOMB, own, 1);
644         putland(land.lnd_uid, &land);
645         collateral_damage(target->sct_x, target->sct_y, dam);
646     }
647 }
648
649 static void
650 strat_bomb(struct emp_qelem *list, struct sctstr *target)
651 {
652     struct plist *plp;
653     int dam = 0;
654     struct emp_qelem *qp;
655     struct sctstr sect;
656     struct nukstr nuke;
657
658     for (qp = list->q_forw; qp != list; qp = qp->q_forw) {
659         plp = (struct plist *)qp;
660         if (getnuke(nuk_on_plane(&plp->plane), &nuke))
661             detonate(&nuke, target->sct_x, target->sct_y,
662                      plp->plane.pln_flags & PLN_AIRBURST);
663         else
664             dam += pln_damage(&plp->plane, 's', "");
665     }
666     if (dam <= 0)
667         return;
668     getsect(target->sct_x, target->sct_y, &sect);
669     target = &sect;
670     if (target->sct_own != player->cnum)
671         mpr(target->sct_own, "%s bombing raid did %d damage in %s\n",
672             cname(player->cnum), PERCENT_DAMAGE(dam),
673             xyas(target->sct_x, target->sct_y, target->sct_own));
674
675     sectdamage(target, dam);
676
677     pr("did %d damage in %s\n", PERCENT_DAMAGE(dam),
678        xyas(target->sct_x, target->sct_y, player->cnum));
679     putsect(&sect);
680 }
681
682 static int
683 changed_plane_aborts(struct plist *plp)
684 {
685     if (check_plane_ok(&plp->plane))
686         return 0;
687     getplane(plp->plane.pln_uid, &plp->plane);
688     pln_put1(plp);
689     return 1;
690 }
691
692 static int
693 pinflak_planedamage(struct plnstr *pp, struct plchrstr *pcp, natid from,
694                     int flak)
695 {
696     int disp;
697     char dmess[14];
698     int dam;
699
700     dam = ac_flak_dam(flak, pln_def(pp), pcp->pl_flags);
701     if (dam <= 0)
702         return 0;
703     disp = ac_damage_plane(pp, from, dam, 1, dmess);
704     mpr(pp->pln_own, "    Flak! %s takes %d%s%s.\n",
705         prplane(pp), dam, *dmess ? " --" : "", dmess);
706
707     putplane(pp->pln_uid, pp);
708     return disp > 0;
709 }