4bbfe74201c0b6efc92f36d8f9c5075b5f083ca3
[empserver] / src / lib / commands / arm.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2021, 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  *  arm.c: Arm planes (missiles) with nuclear devices
28  *
29  *  Known contributors to this file:
30  *     Dave Pare, 1986
31  *     Ken Stevens, 1995
32  *     Steve McClure, 2000
33  *     Markus Armbruster, 2006-2018
34  */
35
36 #include <config.h>
37
38 #include <stdio.h>
39 #include "commands.h"
40 #include "nuke.h"
41 #include "optlist.h"
42 #include "plane.h"
43
44 int
45 arm(void)
46 {
47     struct nchrstr *ncp;
48     struct plchrstr *plc;
49     struct plnstr pl;
50     struct nukstr nuke;
51     char *p;
52     int nukno;
53     struct nstr_item ni;
54     char buf[1024];
55     char prompt[128];
56
57     if (!snxtitem(&ni, EF_PLANE, player->argp[1], NULL))
58         return RET_SYN;
59     while (nxtitem(&ni, &pl)) {
60         if (!player->owner
61             && relations_with(pl.pln_own, player->cnum) != ALLIED)
62             continue;
63         plc = &plchr[(int)pl.pln_type];
64         if (!(plc->pl_flags & (P_B | P_T | P_C))
65             || (plc->pl_flags & P_MAR)) {
66             pr("A %s cannot carry nuclear devices!\n", plc->pl_name);
67             return RET_FAIL;
68         }
69         if (CANT_HAPPEN(pl.pln_flags & PLN_LAUNCHED))
70             continue;
71         if (opt_MARKET) {
72             if (ontradingblock(EF_PLANE, &pl)) {
73                 pr("You cannot arm %s while it is on the trading block!\n",
74                    prplane(&pl));
75                 return RET_FAIL;
76             }
77         }
78         if (!getnuke(nuk_on_plane(&pl), &nuke)) {
79             sprintf(prompt, "Nuclear device for %s: ", prplane(&pl));
80             p = getstarg(player->argp[2], prompt, buf);
81             if (!p || !*p)
82                 return RET_SYN;
83             if (!check_plane_ok(&pl))
84                 return RET_FAIL;
85             nukno = atoi(p);
86             if (!getnuke(nukno, &nuke) || !player->owner)
87                 return RET_FAIL;
88         }
89         ncp = &nchr[nuke.nuk_type];
90         if (pln_load(&pl) < ncp->n_weight) {
91             pr("A %s cannot carry %s devices!\n",
92                plc->pl_name, ncp->n_name);
93             return RET_FAIL;
94         }
95         p = getstarg(player->argp[3], "Airburst [n]? ", buf);
96         if (!p)
97             return RET_FAIL;
98
99         if (!check_plane_ok(&pl) || !check_nuke_ok(&nuke))
100             return RET_FAIL;
101
102         if (nuke.nuk_plane >= 0 && nuke.nuk_plane != pl.pln_uid) {
103             pr("%s is already armed on plane #%d!\n",
104                prnuke(&nuke), nuke.nuk_plane);
105             return RET_FAIL;
106         }
107         if (nuke.nuk_x != pl.pln_x || nuke.nuk_y != pl.pln_y) {
108             pr("%s isn't in the same sector as %s!\n",
109                prnuke(&nuke), prplane(&pl));
110             return RET_FAIL;
111         }
112
113         if (*p == 'y' || *p == 'Y')
114             pl.pln_flags |= PLN_AIRBURST;
115         else
116             pl.pln_flags &= ~PLN_AIRBURST;
117         pl.pln_mission = 0;
118
119         snprintf(buf, sizeof(buf), "armed on your %s in %s",
120                  prplane(&pl), xyas(pl.pln_x, pl.pln_y, pl.pln_own));
121         gift(pl.pln_own, player->cnum, &nuke, buf);
122         nuke.nuk_plane = pl.pln_uid;
123         putplane(pl.pln_uid, &pl);
124         putnuke(nuke.nuk_uid, &nuke);
125         pr("%s armed with %s.\n", prplane(&pl), prnuke(&nuke));
126         pr("Warhead on %s is programmed to %s\n",
127            prplane(&pl),
128            pl.pln_flags & PLN_AIRBURST ? "airburst" : "groundburst");
129     }
130
131     return RET_OK;
132 }
133
134 int
135 disarm(void)
136 {
137     struct plnstr pl;
138     struct nukstr nuke;
139     struct nstr_item ni;
140     struct sctstr sect;
141     char buf[128];
142
143     if (!snxtitem(&ni, EF_PLANE, player->argp[1], NULL))
144         return RET_SYN;
145     while (nxtitem(&ni, &pl)) {
146         if (!player->owner)
147             continue;
148         if (!getnuke(nuk_on_plane(&pl), &nuke))
149             continue;
150         if (CANT_HAPPEN(pl.pln_flags & PLN_LAUNCHED))
151             continue;
152         if (opt_MARKET) {
153             if (ontradingblock(EF_PLANE, &pl)) {
154                 pr("You cannot disarm %s while it is on the trading block!\n",
155                    prplane(&pl));
156                 return RET_FAIL;
157             }
158         }
159         getsect(nuke.nuk_x, nuke.nuk_y, &sect);
160         if (!player->owner
161             && relations_with(sect.sct_own, player->cnum) != ALLIED) {
162             pr("Disarming %s in sector %s requires an alliance!\n",
163                prplane(&pl), xyas(sect.sct_x, sect.sct_y, player->cnum));
164             continue;
165         }
166         snprintf(buf, sizeof(buf), "unloaded in your %s at %s",
167                  dchr[sect.sct_type].d_name,
168                  xyas(sect.sct_x, sect.sct_y, sect.sct_own));
169         gift(sect.sct_own, player->cnum, &nuke, buf);
170         nuke.nuk_plane = -1;
171         pl.pln_flags &= ~PLN_AIRBURST;
172         putplane(pl.pln_uid, &pl);
173         putnuke(nuke.nuk_uid, &nuke);
174         pr("%s removed from %s and added to %s\n",
175            prnuke(&nuke), prplane(&pl),
176            xyas(pl.pln_x, pl.pln_y, player->cnum));
177     }
178     return RET_OK;
179 }