]> git.pond.sub.org Git - empserver/blob - src/lib/subs/detonate.c
Fix empty lines in bulletin reporting nuclear damage to sectors
[empserver] / src / lib / subs / detonate.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2010, Dave Pare, Jeff Bailey, Thomas Ruschak,
4  *                           Ken Stevens, Steve McClure
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  *  ---
21  *
22  *  See files README, COPYING and CREDITS in the root of the source
23  *  tree for related information and legal notices.  It is expected
24  *  that future projects/authors will amend these files as needed.
25  *
26  *  ---
27  *
28  *  detonate.c: Detonate a nuclear device in a sector.
29  *
30  *  Known contributors to this file:
31  *     Steve McClure, 1998-2000
32  *     Markus Armbruster, 2004-2009
33  */
34
35 #include <config.h>
36
37 #include "file.h"
38 #include "land.h"
39 #include "lost.h"
40 #include "map.h"
41 #include "misc.h"
42 #include "nat.h"
43 #include "news.h"
44 #include "nsc.h"
45 #include "nuke.h"
46 #include "optlist.h"
47 #include "plane.h"
48 #include "player.h"
49 #include "prototypes.h"
50 #include "sect.h"
51 #include "ship.h"
52 #include "xy.h"
53
54 static void kaboom(int x, int y, int rad);
55
56 int
57 detonate(struct nukstr *np, coord x, coord y, int airburst)
58 {
59     int nuketype = np->nuk_type;
60     struct nchrstr *ncp;
61     struct plnstr plane;
62     struct sctstr sect;
63     struct shpstr ship;
64     struct lndstr land;
65     struct nukstr nuke;
66     char *bp;
67     char buf[128];
68     char buf2[128];
69     natid own;
70     int type;
71     int damage;
72     int fallout;
73     int rad;
74     struct nstr_sect ns;
75     struct nstr_item ni;
76     int changed = 0;
77
78     pr("Releasing RV's for %s detonation...\n",
79        airburst ? "airburst" : "groundburst");
80
81     getsect(x, y, &sect);
82     ncp = &nchr[nuketype];
83     kaboom(x, y, ncp->n_blast);
84     rad = ncp->n_blast;
85     if (!airburst)
86         rad = rad * 2 / 3;
87     if (sect.sct_type == SCT_WATER)
88         rad = 0;     /* Nukes falling on water affect only 1 sector */
89     np->nuk_effic = 0;
90     putnuke(np->nuk_uid, np);
91
92     snxtsct_dist(&ns, x, y, rad);
93     while (nxtsct(&ns, &sect)) {
94         own = sect.sct_own;
95         type = sect.sct_type;
96         if ((damage = nukedamage(ncp, ns.curdist, airburst)) <= 0)
97             continue;
98         if (type == SCT_SANCT) {
99             pr("bounced off %s\n", xyas(ns.x, ns.y, player->cnum));
100             mpr(own, "%s nuclear device bounced off %s\n",
101                 cname(player->cnum), xyas(ns.x, ns.y, own));
102             nreport(player->cnum, N_NUKE, own, 1);
103             continue;
104         }
105         sect_damage(&sect, damage);
106         if (opt_FALLOUT) {
107             fallout = sect.sct_fallout;
108             if (ncp->n_flags & N_NEUT)
109                 fallout += damage * 30;
110             else
111                 fallout += damage * 3;
112             sect.sct_fallout = MIN(fallout, FALLOUT_MAX);
113         }
114         if (damage > 100) {
115             sect.sct_oldown = 0;
116             sect.sct_own = 0;
117             if (type == SCT_WATER || type == SCT_BSPAN ||
118                 type == SCT_BTOWER) {
119                 bp = "left nothing but water in %s\n";
120                 if (type != SCT_WATER) {
121                     sect.sct_newtype = SCT_WATER;
122                     sect.sct_type = SCT_WATER;
123                 }
124             } else {
125                 sect.sct_newtype = SCT_WASTE;
126                 sect.sct_type = SCT_WASTE;
127                 bp = "turned %s into a radioactive wasteland\n";
128             }
129             changed |= map_set(player->cnum, sect.sct_x, sect.sct_y,
130                                dchr[sect.sct_type].d_mnem, 0);
131         } else {
132             sprintf(buf, "did %d%%%% damage in %%s\n", damage);
133             bp = buf;
134         }
135         (void)putsect(&sect);
136         if (type != SCT_WATER)
137             nreport(player->cnum, N_NUKE, own, 1);
138         pr(bp, xyas(ns.x, ns.y, player->cnum));
139         if (own != player->cnum && own != 0) {
140             (void)sprintf(buf2, bp, xyas(ns.x, ns.y, own));
141             mpr(own, "%s nuclear device %s", cname(player->cnum), buf2);
142         }
143     }
144
145     if (changed)
146         writebmap(player->cnum);
147
148     snxtitem_dist(&ni, EF_PLANE, x, y, rad);
149     while (nxtitem(&ni, &plane)) {
150         if ((own = plane.pln_own) == 0)
151             continue;
152         if (plane.pln_flags & PLN_LAUNCHED)
153             continue;
154         damage = nukedamage(ncp, ni.curdist, airburst) - plane.pln_harden;
155         if (damage <= 0)
156             continue;
157         if (plane.pln_ship >= 0) {
158             /* Are we on a sub? */
159             getship(plane.pln_ship, &ship);
160
161             if (mchr[(int)ship.shp_type].m_flags & M_SUB) {
162                 struct sctstr sect1;
163
164                 /* Should we damage this sub? */
165                 getsect(ship.shp_x, ship.shp_y, &sect1);
166
167                 if (sect1.sct_type == SCT_BSPAN ||
168                     sect1.sct_type == SCT_BTOWER ||
169                     sect1.sct_type == SCT_WATER) {
170                     /* Ok, we're not in a harbor or trapped
171                        inland.  Now, did we get pasted
172                        directly? */
173                     if (ship.shp_x != x || ship.shp_y != y) {
174                         /* Nope, so don't mess with it */
175                         continue;
176                     }
177                 }
178             }
179         }
180         planedamage(&plane, damage);
181         if (own == player->cnum) {
182             pr("%s at %s reports %d%% damage\n",
183                prplane(&plane),
184                xyas(plane.pln_x, plane.pln_y, own), damage);
185         } else {
186             mpr(own, "%s nuclear device did %d%% damage to %s at %s\n",
187                 cname(player->cnum), damage,
188                 prplane(&plane), xyas(plane.pln_x, plane.pln_y, own));
189         }
190         putplane(ni.cur, &plane);
191     }
192
193     snxtitem_dist(&ni, EF_LAND, x, y, rad);
194     while (nxtitem(&ni, &land)) {
195         if ((own = land.lnd_own) == 0)
196             continue;
197         if ((damage = nukedamage(ncp, ni.curdist, airburst)) <= 0)
198             continue;
199
200         if (land.lnd_ship >= 0) {
201             /* Are we on a sub? */
202             getship(land.lnd_ship, &ship);
203
204             if (mchr[(int)ship.shp_type].m_flags & M_SUB) {
205                 struct sctstr sect1;
206
207                 /* Should we damage this sub? */
208                 getsect(ship.shp_x, ship.shp_y, &sect1);
209
210                 if (sect1.sct_type == SCT_BSPAN ||
211                     sect1.sct_type == SCT_BTOWER ||
212                     sect1.sct_type == SCT_WATER) {
213                     /* Ok, we're not in a harbor or trapped
214                        inland.  Now, did we get pasted
215                        directly? */
216                     if (ship.shp_x != x || ship.shp_y != y) {
217                         /* Nope, so don't mess with it */
218                         continue;
219                     }
220                 }
221             }
222         }
223         land_damage(&land, damage);
224         if (own == player->cnum) {
225             pr("%s at %s reports %d%% damage\n",
226                prland(&land), xyas(land.lnd_x, land.lnd_y, own), damage);
227         } else {
228             mpr(own, "%s nuclear device did %d%% damage to %s at %s\n",
229                 cname(player->cnum), damage,
230                 prland(&land), xyas(land.lnd_x, land.lnd_y, own));
231         }
232         putland(land.lnd_uid, &land);
233     }
234
235     snxtitem_dist(&ni, EF_SHIP, x, y, rad);
236     while (nxtitem(&ni, &ship)) {
237         if ((own = ship.shp_own) == 0)
238             continue;
239         if ((damage = nukedamage(ncp, ni.curdist, airburst)) <= 0)
240             continue;
241         if (mchr[(int)ship.shp_type].m_flags & M_SUB) {
242             struct sctstr sect1;
243
244             /* Should we damage this sub? */
245             getsect(ship.shp_x, ship.shp_y, &sect1);
246
247             if (sect1.sct_type == SCT_BSPAN ||
248                 sect1.sct_type == SCT_BTOWER ||
249                 sect1.sct_type == SCT_WATER) {
250                 /* Ok, we're not in a harbor or trapped
251                    inland.  Now, did we get pasted
252                    directly? */
253                 if (ship.shp_x != x || ship.shp_y != y) {
254                     /* Nope, so don't mess with it */
255                     continue;
256                 }
257             }
258         }
259         ship_damage(&ship, damage);
260         if (own == player->cnum) {
261             pr("%s at %s reports %d%% damage\n",
262                prship(&ship), xyas(ship.shp_x, ship.shp_y, own), damage);
263         } else {
264             mpr(own, "%s nuclear device did %d%% damage to %s at %s\n",
265                 cname(player->cnum), damage, prship(&ship),
266                 xyas(ship.shp_x, ship.shp_y, own));
267         }
268         putship(ship.shp_uid, &ship);
269     }
270
271     snxtitem_dist(&ni, EF_NUKE, x, y, rad);
272     while (nxtitem(&ni, &nuke)) {
273         if ((own = nuke.nuk_own) == 0)
274             continue;
275         if ((damage = nukedamage(ncp, ni.curdist, airburst)) <= 0)
276             continue;
277         if (roll(100) >= damage)
278             continue;
279         nuke.nuk_effic = 0;
280         if (own == player->cnum) {
281             pr("%s at %s destroyed\n",
282                prnuke(&nuke), xyas(nuke.nuk_x, nuke.nuk_y, own));
283         } else {
284             mpr(own, "%s at %s destroyed\n",
285                 prnuke(&nuke), xyas(nuke.nuk_x, nuke.nuk_y, own));
286         }
287         putnuke(ni.cur, &nuke);
288     }
289
290     return nukedamage(ncp, 0, airburst);
291 }
292
293
294 /*
295  * silly to be sure.
296  */
297 static void
298 kaboom(int x, int y, int rad)
299 {
300     pr("\n\nK A B O O ");
301     while (rad-- > 1)
302         pr("O O ");
303     pr("M ! in %s\n\n", xyas(x, y, player->cnum));
304 }