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