]> git.pond.sub.org Git - empserver/blob - src/lib/subs/detonate.c
Clean up superfluous includes
[empserver] / src / lib / subs / detonate.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2011, 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  *  detonate.c: Detonate a nuclear device in a sector.
28  *
29  *  Known contributors to this file:
30  *     Steve McClure, 1998-2000
31  *     Markus Armbruster, 2004-2010
32  */
33
34 #include <config.h>
35
36 #include "file.h"
37 #include "land.h"
38 #include "map.h"
39 #include "misc.h"
40 #include "nat.h"
41 #include "news.h"
42 #include "nsc.h"
43 #include "nuke.h"
44 #include "optlist.h"
45 #include "plane.h"
46 #include "player.h"
47 #include "prototypes.h"
48 #include "sect.h"
49 #include "ship.h"
50 #include "xy.h"
51
52 static void kaboom(int x, int y, int rad);
53
54 int
55 detonate(struct nukstr *np, coord x, coord y, int airburst)
56 {
57     int nuketype = np->nuk_type;
58     struct nchrstr *ncp;
59     struct plnstr plane;
60     struct sctstr sect;
61     struct shpstr ship;
62     struct lndstr land;
63     struct nukstr nuke;
64     natid own;
65     int type;
66     int damage;
67     int fallout;
68     int rad;
69     struct nstr_sect ns;
70     struct nstr_item ni;
71     int changed = 0;
72
73     pr("Releasing RV's for %s detonation...\n",
74        airburst ? "airburst" : "groundburst");
75
76     getsect(x, y, &sect);
77     ncp = &nchr[nuketype];
78     kaboom(x, y, ncp->n_blast);
79     rad = ncp->n_blast;
80     if (!airburst)
81         rad = rad * 2 / 3;
82     if (sect.sct_type == SCT_WATER)
83         rad = 0;     /* Nukes falling on water affect only 1 sector */
84     np->nuk_effic = 0;
85     putnuke(np->nuk_uid, np);
86
87     snxtsct_dist(&ns, x, y, rad);
88     while (nxtsct(&ns, &sect)) {
89         own = sect.sct_own;
90         type = sect.sct_type;
91         if ((damage = nukedamage(ncp, ns.curdist, airburst)) <= 0)
92             continue;
93         if (type == SCT_SANCT) {
94             pr("bounced off %s\n", xyas(ns.x, ns.y, player->cnum));
95             mpr(own, "%s nuclear device bounced off %s\n",
96                 cname(player->cnum), xyas(ns.x, ns.y, own));
97             nreport(player->cnum, N_NUKE, own, 1);
98             continue;
99         }
100         sect_damage(&sect, damage);
101         if (opt_FALLOUT) {
102             fallout = sect.sct_fallout;
103             if (ncp->n_flags & N_NEUT)
104                 fallout += damage * 30;
105             else
106                 fallout += damage * 3;
107             sect.sct_fallout = MIN(fallout, FALLOUT_MAX);
108         }
109         if (damage > 100) {
110             sect.sct_oldown = 0;
111             sect.sct_own = 0;
112             if (type == SCT_WATER || type == SCT_BSPAN ||
113                 type == SCT_BTOWER) {
114                 if (type != SCT_WATER) {
115                     pr("left nothing but water in %s\n",
116                        xyas(ns.x, ns.y, player->cnum));
117                     if (own != player->cnum)
118                         mpr(own,
119                             "%s nuclear device left nothing but water in %s\n",
120                             cname(player->cnum), xyas(ns.x, ns.y, own));
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                 pr("turned %s into a radioactive wasteland\n",
128                    xyas(ns.x, ns.y, player->cnum));
129                 if (own != player->cnum)
130                     mpr(own,
131                         "%s nuclear device turned %s into a radioactive wasteland\n",
132                         cname(player->cnum), xyas(ns.x, ns.y, own));
133             }
134             changed |= map_set(player->cnum, sect.sct_x, sect.sct_y,
135                                dchr[sect.sct_type].d_mnem, 0);
136         } else {
137             pr("did %d%% damage in %s\n",
138                damage, xyas(ns.x, ns.y, player->cnum));
139             if (own != player->cnum)
140                 mpr(own, "%s nuclear device did %d%% damage in %s\n",
141                     cname(player->cnum), damage, xyas(ns.x, ns.y, own));
142         }
143         (void)putsect(&sect);
144         if (type != SCT_WATER)
145             nreport(player->cnum, N_NUKE, own, 1);
146     }
147
148     if (changed)
149         writebmap(player->cnum);
150
151     snxtitem_dist(&ni, EF_PLANE, x, y, rad);
152     while (nxtitem(&ni, &plane)) {
153         if ((own = plane.pln_own) == 0)
154             continue;
155         if (plane.pln_flags & PLN_LAUNCHED)
156             continue;
157         damage = nukedamage(ncp, ni.curdist, airburst) - plane.pln_harden;
158         if (damage <= 0)
159             continue;
160         if (plane.pln_ship >= 0) {
161             /* Are we on a sub? */
162             getship(plane.pln_ship, &ship);
163
164             if (mchr[(int)ship.shp_type].m_flags & M_SUB) {
165                 struct sctstr sect1;
166
167                 /* Should we damage this sub? */
168                 getsect(ship.shp_x, ship.shp_y, &sect1);
169
170                 if (sect1.sct_type == SCT_BSPAN ||
171                     sect1.sct_type == SCT_BTOWER ||
172                     sect1.sct_type == SCT_WATER) {
173                     /* Ok, we're not in a harbor or trapped
174                        inland.  Now, did we get pasted
175                        directly? */
176                     if (ship.shp_x != x || ship.shp_y != y) {
177                         /* Nope, so don't mess with it */
178                         continue;
179                     }
180                 }
181             }
182         }
183         planedamage(&plane, damage);
184         if (own == player->cnum) {
185             pr("%s at %s reports %d%% damage\n",
186                prplane(&plane),
187                xyas(plane.pln_x, plane.pln_y, player->cnum), damage);
188         } else {
189             mpr(own, "%s nuclear device did %d%% damage to %s at %s\n",
190                 cname(player->cnum), damage,
191                 prplane(&plane), xyas(plane.pln_x, plane.pln_y, own));
192         }
193         putplane(ni.cur, &plane);
194     }
195
196     snxtitem_dist(&ni, EF_LAND, x, y, rad);
197     while (nxtitem(&ni, &land)) {
198         if ((own = land.lnd_own) == 0)
199             continue;
200         if ((damage = nukedamage(ncp, ni.curdist, airburst)) <= 0)
201             continue;
202
203         if (land.lnd_ship >= 0) {
204             /* Are we on a sub? */
205             getship(land.lnd_ship, &ship);
206
207             if (mchr[(int)ship.shp_type].m_flags & M_SUB) {
208                 struct sctstr sect1;
209
210                 /* Should we damage this sub? */
211                 getsect(ship.shp_x, ship.shp_y, &sect1);
212
213                 if (sect1.sct_type == SCT_BSPAN ||
214                     sect1.sct_type == SCT_BTOWER ||
215                     sect1.sct_type == SCT_WATER) {
216                     /* Ok, we're not in a harbor or trapped
217                        inland.  Now, did we get pasted
218                        directly? */
219                     if (ship.shp_x != x || ship.shp_y != y) {
220                         /* Nope, so don't mess with it */
221                         continue;
222                     }
223                 }
224             }
225         }
226         land_damage(&land, damage);
227         if (own == player->cnum) {
228             pr("%s at %s reports %d%% damage\n",
229                prland(&land), xyas(land.lnd_x, land.lnd_y, player->cnum),
230                damage);
231         } else {
232             mpr(own, "%s nuclear device did %d%% damage to %s at %s\n",
233                 cname(player->cnum), damage,
234                 prland(&land), xyas(land.lnd_x, land.lnd_y, own));
235         }
236         putland(land.lnd_uid, &land);
237     }
238
239     snxtitem_dist(&ni, EF_SHIP, x, y, rad);
240     while (nxtitem(&ni, &ship)) {
241         if ((own = ship.shp_own) == 0)
242             continue;
243         if ((damage = nukedamage(ncp, ni.curdist, airburst)) <= 0)
244             continue;
245         if (mchr[(int)ship.shp_type].m_flags & M_SUB) {
246             struct sctstr sect1;
247
248             /* Should we damage this sub? */
249             getsect(ship.shp_x, ship.shp_y, &sect1);
250
251             if (sect1.sct_type == SCT_BSPAN ||
252                 sect1.sct_type == SCT_BTOWER ||
253                 sect1.sct_type == SCT_WATER) {
254                 /* Ok, we're not in a harbor or trapped
255                    inland.  Now, did we get pasted
256                    directly? */
257                 if (ship.shp_x != x || ship.shp_y != y) {
258                     /* Nope, so don't mess with it */
259                     continue;
260                 }
261             }
262         }
263         ship_damage(&ship, damage);
264         if (own == player->cnum) {
265             pr("%s at %s reports %d%% damage\n",
266                prship(&ship), xyas(ship.shp_x, ship.shp_y, player->cnum),
267                damage);
268         } else {
269             mpr(own, "%s nuclear device did %d%% damage to %s at %s\n",
270                 cname(player->cnum), damage, prship(&ship),
271                 xyas(ship.shp_x, ship.shp_y, own));
272         }
273         putship(ship.shp_uid, &ship);
274     }
275
276     snxtitem_dist(&ni, EF_NUKE, x, y, rad);
277     while (nxtitem(&ni, &nuke)) {
278         if ((own = nuke.nuk_own) == 0)
279             continue;
280         if ((damage = nukedamage(ncp, ni.curdist, airburst)) <= 0)
281             continue;
282         if (roll(100) >= damage)
283             continue;
284         nuke.nuk_effic = 0;
285         if (own == player->cnum) {
286             pr("%s at %s destroyed\n",
287                prnuke(&nuke), xyas(nuke.nuk_x, nuke.nuk_y, player->cnum));
288         } else {
289             mpr(own, "%s nuclear device destroyed %s at %s\n",
290                 cname(player->cnum), prnuke(&nuke),
291                       xyas(nuke.nuk_x, nuke.nuk_y, own));
292         }
293         putnuke(ni.cur, &nuke);
294     }
295
296     return nukedamage(ncp, 0, airburst);
297 }
298
299
300 /*
301  * silly to be sure.
302  */
303 static void
304 kaboom(int x, int y, int rad)
305 {
306     pr("\n\nK A B O O ");
307     while (rad-- > 1)
308         pr("O O ");
309     pr("M ! in %s\n\n", xyas(x, y, player->cnum));
310 }