]> git.pond.sub.org Git - empserver/blob - src/lib/commands/tran.c
<string.h> is ISO C, no need to #if it.
[empserver] / src / lib / commands / tran.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2000, 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 the "LEGAL", "LICENSE", "CREDITS" and "README" files for all the
23  *  related information and legal notices. It is expected that any future
24  *  projects/authors will amend these files as needed.
25  *
26  *  ---
27  *
28  *  tran.c: Transport nuclear devices and planes
29  * 
30  *  Known contributors to this file:
31  *     Steve McClure, 2000
32  *  
33  */
34
35 #include <string.h>
36 #include "misc.h"
37 #include "player.h"
38 #include "var.h"
39 #include "sect.h"
40 #include "nuke.h"
41 #include "xy.h"
42 #include "nsc.h"
43 #include "plane.h"
44 #include "ship.h"
45 #include "file.h"
46 #include "nat.h"
47 #include "land.h"
48 #include "commands.h"
49
50 #include <stdio.h>
51
52 static int tran_map(s_char *what, coord curx, coord cury, s_char *arg);
53 static int tran_nuke(void);
54 static int tran_plane(void);
55
56 int
57 tran(void)
58 {
59     s_char *what;
60     s_char buf[1024];
61
62     what =
63         getstarg(player->argp[1], "transport what (nuke or plane): ", buf);
64     if (what == 0)
65         return RET_SYN;
66     if (*what == 'n')
67         return tran_nuke();
68     else if (*what == 'p')
69         return tran_plane();
70     return RET_SYN;
71 }
72
73 /*
74  * Kinda silly; only moves the first nuke.
75  * Maybe nukes should be made into commodities?
76  */
77 static int
78 tran_nuke(void)
79 {
80     struct nchrstr *ncp;
81     int len;
82     coord x, y;
83     coord dstx, dsty;
84     int found;
85     s_char *p;
86     int i;
87     int nuketype;
88     int moving;
89     struct nukstr nuke;
90     struct sctstr sect;
91     struct sctstr endsect;
92     int mcost, dam;
93     struct nstr_item nstr;
94     s_char buf[1024];
95
96     if (!(p = getstarg(player->argp[2], "from sector : ", buf)))
97         return RET_SYN;
98     if (!sarg_xy(p, &x, &y))
99         return RET_SYN;
100     if (!getsect(x, y, &sect) || !player->owner) {
101         pr("Not yours\n");
102         return RET_FAIL;
103     }
104 #if 0
105     if (!snxtitem_xy(&nstr, EF_NUKE, sect.sct_x, sect.sct_y)) {
106         pr("There are no nukes in %s\n",
107            xyas(sect.sct_x, sect.sct_y, player->cnum));
108         return RET_FAIL;
109     }
110 #else
111     snxtitem_xy(&nstr, EF_NUKE, sect.sct_x, sect.sct_y);
112 #endif
113     found = 0;
114     while (nxtitem(&nstr, (caddr_t)&nuke)) {
115         if (player->owner) {
116             found = 1;
117             break;
118         }
119     }
120     if (!found) {
121         pr("There are no nukes in %s\n",
122            xyas(sect.sct_x, sect.sct_y, player->cnum));
123         return RET_FAIL;
124     }
125     if (!(p = getstarg(player->argp[3], "warhead type : ", buf)))
126         return RET_SYN;
127     if (!check_sect_ok(&sect))
128         return RET_FAIL;
129     len = strlen(p);
130     for (i = 0, ncp = nchr; i < N_MAXNUKE; i++, ncp++) {
131         if (strncmp(ncp->n_name, p, len) == 0)
132             break;
133     }
134     if (i >= N_MAXNUKE) {
135         pr("No such nuke type!\n");
136         return RET_SYN;
137     }
138     nuketype = i;
139     if (!nuke.nuk_types[nuketype]) {
140         pr("No %s nukes in %s\n",
141            ncp->n_name, xyas(sect.sct_x, sect.sct_y, player->cnum));
142         return RET_FAIL;
143     }
144     p = getstarg(player->argp[4], "number of warheads : ", buf);
145     if (!check_sect_ok(&sect))
146         return RET_FAIL;
147     if (p == 0 || *p == 0 || (moving = atoi(p)) < 0)
148         return RET_FAIL;
149     if (moving > nuke.nuk_types[nuketype]) {
150         moving = nuke.nuk_types[nuketype];
151         if (moving)
152             pr("only moving %d\n", moving);
153         else
154             return RET_FAIL;
155     }
156     /*
157      * military control necessary to move
158      * goodies in occupied territory.
159      */
160     if (sect.sct_oldown != player->cnum) {
161         int tot_mil = 0;
162         struct nstr_item ni;
163         struct lndstr land;
164         snxtitem_xy(&ni, EF_LAND, sect.sct_x, sect.sct_y);
165         while (nxtitem(&ni, (s_char *)&land)) {
166             if (land.lnd_own == player->cnum)
167                 tot_mil += total_mil(&land);
168         }
169         if ((getvar(V_MILIT, (s_char *)&sect, EF_SECTOR) + tot_mil) * 10
170             < getvar(V_CIVIL, (s_char *)&sect, EF_SECTOR)) {
171             pr("Military control required to move goods.\n");
172             return RET_FAIL;
173         }
174     }
175     dam = 0;
176     mcost = move_ground((s_char *)&nuke, &sect, &endsect,
177                         (double)ncp->n_weight * moving,
178                         player->argp[5], tran_map, 0, &dam);
179
180     if (mcost < 0)
181         return 0;
182
183     if (mcost > 0)
184         pr("Total movement cost = %d\n", mcost);
185     else
186         pr("No mobility used\n");
187
188     dstx = endsect.sct_x;
189     dsty = endsect.sct_y;
190     /*
191      * decrement mobility from src sector
192      */
193     getsect(nuke.nuk_x, nuke.nuk_y, &sect);
194     sect.sct_mobil -= mcost;
195     if (sect.sct_mobil < 0)
196         sect.sct_mobil = 0;
197     putsect(&sect);
198     /*
199      * update old nuke
200      */
201     if (!getnuke(nuke.nuk_uid, &nuke)) {
202         pr("Could not find that stockpile again.\n");
203         return RET_FAIL;
204     }
205     if (nuke.nuk_types[nuketype] < moving || nuke.nuk_own != player->cnum) {
206         pr("Stockpile changed!\n");
207         return RET_FAIL;
208     }
209     nuk_delete(&nuke, nuketype, moving);
210     nuk_add(dstx, dsty, nuketype, moving);
211     return RET_OK;
212 }
213
214 static int
215 tran_plane(void)
216 {
217     int srcx, srcy;
218     int dstx, dsty;
219     int mcost;
220     int weight, count;
221     int first;
222     int type, dam;
223     struct nstr_item nstr;
224     struct plnstr plane;
225     struct sctstr sect;
226     struct sctstr endsect;
227
228     first = 1;
229     weight = 0;
230     count = 0;
231     if (!snxtitem(&nstr, EF_PLANE, player->argp[2]))
232         return RET_SYN;
233     /*
234      * First do some sanity checks: make sure that they are all in the,
235      * same sector, not on ships, owned, etc.
236      * No one could seriously want to move planes in parallel from
237      * several sectors!
238      */
239     while (nxtitem(&nstr, (s_char *)&plane)) {
240         if (!player->owner)
241             continue;
242         type = plane.pln_type;
243         if (plane.pln_ship >= 0) {
244             pr("%s is at sea and can't be transported\n", prplane(&plane));
245             return RET_FAIL;
246         } else if (plane.pln_harden != 0) {
247             pr("%s has been hardened and can't be transported\n",
248                prplane(&plane));
249             return RET_FAIL;
250         } else if ((plane.pln_flags & PLN_LAUNCHED) &&
251                    (plchr[type].pl_flags & P_O)) {
252             pr("%s is in space and can't be transported\n",
253                prplane(&plane));
254             return RET_FAIL;
255         }
256         if (first == 1) {
257             srcx = plane.pln_x;
258             srcy = plane.pln_y;
259             first = 0;
260         } else {
261             if (plane.pln_x != srcx || plane.pln_y != srcy) {
262                 pr("All planes must be in the same sector.\n");
263                 return RET_FAIL;
264             }
265         }
266         weight += plchr[type].pl_lcm + (plchr[type].pl_hcm * 2);
267         ++count;
268     }
269     if (first == 1) {
270         /* no planes */
271         return RET_FAIL;
272     }
273     getsect(srcx, srcy, &sect);
274     /*
275      * military control necessary to move
276      * goodies in occupied territory.
277      */
278     if (sect.sct_oldown != player->cnum) {
279         int tot_mil = 0;
280         struct nstr_item ni;
281         struct lndstr land;
282         snxtitem_xy(&ni, EF_LAND, sect.sct_x, sect.sct_y);
283         while (nxtitem(&ni, (s_char *)&land))
284             tot_mil += total_mil(&land);
285         if ((getvar(V_MILIT, (s_char *)&sect, EF_SECTOR) + tot_mil) * 10
286             < getvar(V_CIVIL, (s_char *)&sect, EF_SECTOR)) {
287             pr("Military control required to move goods.\n");
288             return RET_FAIL;
289         }
290     }
291     dam = 1;
292     mcost = move_ground((s_char *)&plane, &sect, &endsect,
293                         (double)weight,
294                         player->argp[3], tran_map, 0, &dam);
295     dam /= count;
296     if (mcost < 0)
297         return 0;
298
299     dstx = endsect.sct_x;
300     dsty = endsect.sct_y;
301     snxtitem_rewind(&nstr);
302     while (nxtitem(&nstr, (s_char *)&plane)) {
303         if (!player->owner)
304             continue;
305         if (dam) {
306             planedamage(&plane, dam);
307             pr("\t%s takes %d\n", prplane(&plane), dam);
308         }
309         plane.pln_x = dstx;
310         plane.pln_y = dsty;
311         plane.pln_mission = 0;
312         putplane(plane.pln_uid, &plane);
313     }
314     if (mcost > 0)
315         pr("Total movement cost = %d\n", mcost);
316     else
317         pr("No mobility used\n");
318     sect.sct_mobil -= mcost;
319     if (sect.sct_mobil < 0)
320         sect.sct_mobil = 0;
321     putsect(&sect);
322     return RET_OK;
323 }
324
325 /*
326  * Pretty tacky, but it works.
327  * If more commands start doing this, then
328  * rewrite map to do the right thing.
329  */
330 /* I think this is no longer used, check subs/move.c:move_ground() */
331 /*ARGSUSED*/
332 static int
333 tran_map(s_char *what, coord curx, coord cury, s_char *arg)
334 {
335     player->argp[1] = arg;
336     player->condarg = 0;
337     return map();
338 }