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