]> git.pond.sub.org Git - empserver/blob - src/lib/commands/miss.c
aa72b211cc03b93dc242290f056e10198f16f2c2
[empserver] / src / lib / commands / miss.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2006, 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  *  miss.c: set missions for ships/planes/units
29  * 
30  *  Known contributors to this file:
31  *     Thomas Ruschak, 1992
32  *     Steve McClure, 2000
33  */
34
35 #include <config.h>
36
37 #include "misc.h"
38 #include "player.h"
39 #include "xy.h"
40 #include "sect.h"
41 #include "ship.h"
42 #include "land.h"
43 #include "plane.h"
44 #include "nat.h"
45 #include "nsc.h"
46 #include "file.h"
47 #include "path.h"
48 #include "mission.h"
49 #include "genitem.h"
50 #include "commands.h"
51 #include "optlist.h"
52
53 /*
54  *  mission <type> <planes/ships/units> <mission type> <op sector> [<radius>]
55  */
56 int
57 mission(void)
58 {
59     static int ef_with_missions[] = { EF_SHIP, EF_LAND, EF_PLANE, EF_BAD };
60     s_char *p;
61     int type;
62     int mission;
63     coord x, y;
64     size_t size;
65     int desired_radius, radius;
66     struct sctstr opsect;
67     s_char *block;
68     struct genitem *gp;
69     int num = 0, mobmax, mobused, dist;
70     struct nstr_item ni;
71     s_char prompt[128];
72     s_char buf[1024];
73
74     if ((p =
75          getstarg(player->argp[1], "Ship, plane or land unit (p,sh,la)? ",
76                   buf)) == 0)
77         return RET_SYN;
78     type = ef_byname_from(p, ef_with_missions);
79     if (type < 0) {
80         pr("Ships, land units or planes only! (s, l, p)\n");
81         return RET_SYN;
82     }
83     sprintf(prompt, "%s(s)? ", ef_nameof(type));
84     p = getstarg(player->argp[2], prompt, buf);
85     if (!snxtitem(&ni, type, p))
86         return RET_SYN;
87
88     if ((p =
89          getstarg(player->argp[3],
90                   "Mission (int, sup, osup, dsup, esc, res, air, query, clear)? ",
91                   buf)) == 0)
92         return RET_SYN;
93
94 /* 
95  * 'i'     interdiction
96  * 's'     support
97  * 'o'     support attacks
98  * 'd'     support defenders
99  * 'e'     escort
100  * 'r'     defensive reserve
101  * 'a'     air defense (intercepts)
102  */
103     switch (*p) {
104     case 'I':
105     case 'i':
106         mission = MI_INTERDICT;
107         break;
108     case 'O':
109     case 'o':
110         mission = MI_OSUPPORT;
111         break;
112     case 'D':
113     case 'd':
114         mission = MI_DSUPPORT;
115         break;
116     case 'S':
117     case 's':
118         mission = MI_SUPPORT;
119         break;
120     case 'C':
121     case 'c':
122         mission = 0;
123         break;
124     case 'E':
125     case 'e':
126         mission = MI_ESCORT;
127         break;
128     case 'R':
129     case 'r':
130         mission = MI_RESERVE;
131         break;
132     case 'A':
133     case 'a':
134         mission = MI_AIR_DEFENSE;
135         break;
136     case 'q':
137         show_mission(type, &ni);
138         return RET_OK;
139     default:
140         pr("bad condition\n");
141         pr("i\tinterdiction (any)\n");
142         pr("s\tsupport (tactical planes only)\n");
143         pr("o\toffensive support (tactical planes only)\n");
144         pr("d\tdefensive support (tactical planes only)\n");
145         pr("r\treserve (land units only)\n");
146         pr("e\tescort (tactical or escort planes only)\n");
147         pr("a\tair defense (intercept planes only)\n");
148         pr("c\tclear mission\n");
149         pr("q\tquery\n");
150         return RET_SYN;
151     }
152
153     if (mission && !cando(mission, type)) {
154         pr("A %s cannot do that mission!\n", ef_nameof(type));
155         pr("i\tinterdiction (any)\n");
156         pr("s\tsupport (planes only)\n");
157         pr("o\toffensive support (planes only)\n");
158         pr("d\tdefensive support (planes only)\n");
159         pr("r\treserve (land units only)\n");
160         pr("e\tescort (planes only)\n");
161         pr("a\tair defense (planes only)\n");
162         return RET_FAIL;
163     }
164
165     if (mission && ((mission != MI_RESERVE) && (mission != MI_ESCORT))) {
166         if ((p = getstarg(player->argp[4], "operations point? ", buf)) == 0
167             || *p == 0)
168             return RET_SYN;
169
170         if (*p != '.') {
171             if (!sarg_xy(p, &x, &y))
172                 return RET_SYN;
173
174             if (!getsect(x, y, &opsect))
175                 return RET_FAIL;
176         }
177     } else {
178         x = 0;
179         y = 0;
180     }
181
182     if (player->argp[5] != NULL) {
183         desired_radius = atoi(player->argp[5]);
184         if (desired_radius < 0) {
185             pr("Radius must be greater than zero!\n");
186             return RET_FAIL;
187         }
188     } else {
189         desired_radius = 9999;
190     }
191
192     size = MAX(sizeof(struct lndstr), sizeof(struct plnstr));
193     size = MAX(size, sizeof(struct shpstr));
194     block = malloc(size);
195     switch (type) {
196     case EF_SHIP:
197         mobmax = ship_mob_max;
198         break;
199     case EF_LAND:
200         mobmax = land_mob_max;
201         break;
202     case EF_PLANE:
203         mobmax = plane_mob_max;
204         break;
205     }
206
207     mobused = ldround((mission_mob_cost * (double)mobmax), 1);
208
209     while (nxtitem(&ni, block)) {
210         gp = (struct genitem *)block;
211
212         if (!player->owner || gp->own == 0)
213             continue;
214
215         if ((mission && (gp->mobil < mobused)) && mission_mob_cost) {
216             pr("%s #%d: not enough mobility! (needs %d)\n",
217                ef_nameof(type), gp->uid, mobused);
218             continue;
219         }
220         if (mission == MI_RESERVE && !lnd_can_attack((struct lndstr *)gp)) {
221             pr("%s is not designed to fight ground troops\n",
222                prland((struct lndstr *)gp));
223             continue;
224         }
225         if (*p == '.') {
226             x = gp->x;
227             y = gp->y;
228             if (!getsect(x, y, &opsect))
229                 return RET_FAIL;
230         }
231
232         dist = mapdist(gp->x, gp->y, x, y);
233         radius = 999;
234         if ((mission == MI_INTERDICT || mission == MI_SUPPORT ||
235              mission == MI_OSUPPORT || mission == MI_DSUPPORT ||
236              mission == MI_AIR_DEFENSE) &&
237             (oprange(gp, type, &radius) < dist)) {
238             pr("%s #%d: out of range! (range %d)\n",
239                ef_nameof(type), gp->uid, oprange(gp, type, &radius));
240             continue;
241         }
242
243         if (radius > desired_radius)
244             radius = desired_radius;
245
246 /*
247                 if (mission && (gp->effic < 60)){
248                         pr("%s #%d: not efficient enough! (must be>=60%)\n",
249                                 ef_nameof(type), gp->uid);
250                         continue;
251                 }
252  */
253
254         if ((mission == MI_INTERDICT) && (type == EF_SHIP))
255             if (mchr[(int)gp->type].m_frnge < 1) {
256                 pr("%s #%d: cannot fire at range!\n",
257                    ef_nameof(type), gp->uid);
258                 continue;
259             }
260
261         if ((mission == MI_INTERDICT) && (type == EF_LAND))
262             if (lchr[(int)gp->type].l_frg < 1) {
263                 pr("%s #%d: cannot fire at range!\n",
264                    ef_nameof(type), gp->uid);
265                 continue;
266             }
267
268         if ((mission == MI_INTERDICT) && (type == EF_PLANE)) {
269             struct plchrstr *pcp;
270
271             pcp = &plchr[(int)gp->type];
272             if (!(pcp->pl_flags & P_T)) {
273                 pr("Only planes with the tactical ability can interdict.\n%s #%d is ineligible\n", pcp->pl_name, gp->uid);
274                 continue;
275             }
276         }
277
278         if ((mission == MI_AIR_DEFENSE) && (type == EF_PLANE)) {
279             struct plchrstr *pcp;
280
281             pcp = &plchr[(int)gp->type];
282             if (!(pcp->pl_flags & P_F)) {
283                 pr("Only planes with the intercept abilities can perform air defense.\n%s #%d is ineligible\n", pcp->pl_name, gp->uid);
284                 continue;
285             }
286         }
287
288         if ((mission == MI_ESCORT) && (type == EF_PLANE)) {
289             struct plchrstr *pcp;
290
291             pcp = &plchr[(int)gp->type];
292             if (!(pcp->pl_flags & P_ESC) && !(pcp->pl_flags & P_F)) {
293                 pr("Only planes with the escort or intercept abilities can escort.\n%s #%d is ineligible\n", pcp->pl_name, gp->uid);
294                 continue;
295             }
296         }
297
298         if ((mission == MI_SUPPORT || mission == MI_OSUPPORT ||
299              mission == MI_DSUPPORT) && (type == EF_PLANE)) {
300             struct plchrstr *pcp;
301
302             pcp = &plchr[(int)gp->type];
303             if (!(pcp->pl_flags & P_T)) {
304                 pr("Only planes with the tactical ability can support.\n%s #%d is ineligible\n", pcp->pl_name, gp->uid);
305                 continue;
306             }
307         }
308
309         num++;                  /* good one.. go with it */
310
311         if (mission == MI_INTERDICT || mission == MI_SUPPORT ||
312             mission == MI_OSUPPORT || mission == MI_DSUPPORT ||
313             mission == MI_AIR_DEFENSE)
314             gp->radius = radius;
315         else
316             gp->radius = 0;
317
318         if (mission == MI_SUPPORT || mission == MI_OSUPPORT ||
319             mission == MI_DSUPPORT || mission == MI_INTERDICT ||
320             mission == MI_AIR_DEFENSE) {
321             pr("%s on %s mission, centered on %s, radius %d\n",
322                nameofitem(gp, type), mission_name(mission),
323                xyas(x, y, player->cnum), gp->radius);
324         } else if (mission == MI_RESERVE) {
325             int plus = 2;
326
327             if (((struct lndstr *)gp)->lnd_rad_max == 0) {
328                 plus = 0;
329             } else {
330                 getsect(gp->x, gp->y, &opsect);
331                 if ((opsect.sct_type == SCT_HEADQ)
332                     && (opsect.sct_effic >= 60))
333                     plus++;
334                 plus += ((struct lndstr *)gp)->lnd_rad_max;
335             }
336
337             pr("%s on %s mission with maximum reaction radius %d\n",
338                nameofitem(gp, type), mission_name(mission), plus);
339         } else if (mission) {
340             pr("%s on %s mission\n", nameofitem(gp, type),
341                mission_name(mission));
342         }
343
344         if (mission)
345             gp->mobil -= mobused;
346         gp->mission = mission;
347         gp->opx = x;
348         gp->opy = y;
349         switch (type) {
350         case EF_SHIP:
351             putship(gp->uid, block);
352             break;
353         case EF_LAND:
354             putland(gp->uid, block);
355             break;
356         case EF_PLANE:
357             putplane(gp->uid, block);
358             break;
359         }
360     }
361     if (num == 0) {
362         pr("No %s%s\n", ef_nameof(type), splur(num));
363         return RET_FAIL;
364     }
365     pr("%d %s%s\n", num, ef_nameof(type), splur(num));
366     return RET_OK;
367 }