]> git.pond.sub.org Git - empserver/blob - src/lib/subs/detonate.c
Improve bulletin for nuke destroyed by nuclear attack
[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     natid own;
67     int type;
68     int damage;
69     int fallout;
70     int rad;
71     struct nstr_sect ns;
72     struct nstr_item ni;
73     int changed = 0;
74
75     pr("Releasing RV's for %s detonation...\n",
76        airburst ? "airburst" : "groundburst");
77
78     getsect(x, y, &sect);
79     ncp = &nchr[nuketype];
80     kaboom(x, y, ncp->n_blast);
81     rad = ncp->n_blast;
82     if (!airburst)
83         rad = rad * 2 / 3;
84     if (sect.sct_type == SCT_WATER)
85         rad = 0;     /* Nukes falling on water affect only 1 sector */
86     np->nuk_effic = 0;
87     putnuke(np->nuk_uid, np);
88
89     snxtsct_dist(&ns, x, y, rad);
90     while (nxtsct(&ns, &sect)) {
91         own = sect.sct_own;
92         type = sect.sct_type;
93         if ((damage = nukedamage(ncp, ns.curdist, airburst)) <= 0)
94             continue;
95         if (type == SCT_SANCT) {
96             pr("bounced off %s\n", xyas(ns.x, ns.y, player->cnum));
97             mpr(own, "%s nuclear device bounced off %s\n",
98                 cname(player->cnum), xyas(ns.x, ns.y, own));
99             nreport(player->cnum, N_NUKE, own, 1);
100             continue;
101         }
102         sect_damage(&sect, damage);
103         if (opt_FALLOUT) {
104             fallout = sect.sct_fallout;
105             if (ncp->n_flags & N_NEUT)
106                 fallout += damage * 30;
107             else
108                 fallout += damage * 3;
109             sect.sct_fallout = MIN(fallout, FALLOUT_MAX);
110         }
111         if (damage > 100) {
112             sect.sct_oldown = 0;
113             sect.sct_own = 0;
114             if (type == SCT_WATER || type == SCT_BSPAN ||
115                 type == SCT_BTOWER) {
116                 if (type != SCT_WATER) {
117                     pr("left nothing but water in %s\n",
118                        xyas(ns.x, ns.y, player->cnum));
119                     if (own != player->cnum)
120                         mpr(own,
121                             "%s nuclear device left nothing but water in %s\n",
122                             cname(player->cnum), xyas(ns.x, ns.y, own));
123                     sect.sct_newtype = SCT_WATER;
124                     sect.sct_type = SCT_WATER;
125                 }
126             } else {
127                 sect.sct_newtype = SCT_WASTE;
128                 sect.sct_type = SCT_WASTE;
129                 pr("turned %s into a radioactive wasteland\n",
130                    xyas(ns.x, ns.y, player->cnum));
131                 if (own != player->cnum)
132                     mpr(own,
133                         "%s nuclear device turned %s into a radioactive wasteland\n",
134                         cname(player->cnum), xyas(ns.x, ns.y, own));
135             }
136             changed |= map_set(player->cnum, sect.sct_x, sect.sct_y,
137                                dchr[sect.sct_type].d_mnem, 0);
138         } else {
139             pr("did %d%% damage in %s\n",
140                damage, xyas(ns.x, ns.y, player->cnum));
141             if (own != player->cnum)
142                 mpr(own, "%s nuclear device did %d%% damage in %s\n",
143                     cname(player->cnum), damage, xyas(ns.x, ns.y, own));
144         }
145         (void)putsect(&sect);
146         if (type != SCT_WATER)
147             nreport(player->cnum, N_NUKE, own, 1);
148     }
149
150     if (changed)
151         writebmap(player->cnum);
152
153     snxtitem_dist(&ni, EF_PLANE, x, y, rad);
154     while (nxtitem(&ni, &plane)) {
155         if ((own = plane.pln_own) == 0)
156             continue;
157         if (plane.pln_flags & PLN_LAUNCHED)
158             continue;
159         damage = nukedamage(ncp, ni.curdist, airburst) - plane.pln_harden;
160         if (damage <= 0)
161             continue;
162         if (plane.pln_ship >= 0) {
163             /* Are we on a sub? */
164             getship(plane.pln_ship, &ship);
165
166             if (mchr[(int)ship.shp_type].m_flags & M_SUB) {
167                 struct sctstr sect1;
168
169                 /* Should we damage this sub? */
170                 getsect(ship.shp_x, ship.shp_y, &sect1);
171
172                 if (sect1.sct_type == SCT_BSPAN ||
173                     sect1.sct_type == SCT_BTOWER ||
174                     sect1.sct_type == SCT_WATER) {
175                     /* Ok, we're not in a harbor or trapped
176                        inland.  Now, did we get pasted
177                        directly? */
178                     if (ship.shp_x != x || ship.shp_y != y) {
179                         /* Nope, so don't mess with it */
180                         continue;
181                     }
182                 }
183             }
184         }
185         planedamage(&plane, damage);
186         if (own == player->cnum) {
187             pr("%s at %s reports %d%% damage\n",
188                prplane(&plane),
189                xyas(plane.pln_x, plane.pln_y, own), damage);
190         } else {
191             mpr(own, "%s nuclear device did %d%% damage to %s at %s\n",
192                 cname(player->cnum), damage,
193                 prplane(&plane), xyas(plane.pln_x, plane.pln_y, own));
194         }
195         putplane(ni.cur, &plane);
196     }
197
198     snxtitem_dist(&ni, EF_LAND, x, y, rad);
199     while (nxtitem(&ni, &land)) {
200         if ((own = land.lnd_own) == 0)
201             continue;
202         if ((damage = nukedamage(ncp, ni.curdist, airburst)) <= 0)
203             continue;
204
205         if (land.lnd_ship >= 0) {
206             /* Are we on a sub? */
207             getship(land.lnd_ship, &ship);
208
209             if (mchr[(int)ship.shp_type].m_flags & M_SUB) {
210                 struct sctstr sect1;
211
212                 /* Should we damage this sub? */
213                 getsect(ship.shp_x, ship.shp_y, &sect1);
214
215                 if (sect1.sct_type == SCT_BSPAN ||
216                     sect1.sct_type == SCT_BTOWER ||
217                     sect1.sct_type == SCT_WATER) {
218                     /* Ok, we're not in a harbor or trapped
219                        inland.  Now, did we get pasted
220                        directly? */
221                     if (ship.shp_x != x || ship.shp_y != y) {
222                         /* Nope, so don't mess with it */
223                         continue;
224                     }
225                 }
226             }
227         }
228         land_damage(&land, damage);
229         if (own == player->cnum) {
230             pr("%s at %s reports %d%% damage\n",
231                prland(&land), xyas(land.lnd_x, land.lnd_y, own), 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, own), 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, own));
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 }