]> git.pond.sub.org Git - empserver/blob - src/lib/commands/miss.c
Make escort mission obey op-area
[empserver] / src / lib / commands / miss.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2008, 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 buf[1024];
61
62     if ((p =
63          getstarg(player->argp[1], "Ship, plane or land unit (p,sh,la)? ",
64                   buf)) == 0)
65         return RET_SYN;
66     type = ef_byname_from(p, ef_with_missions);
67     if (type < 0) {
68         pr("Ships, land units or planes only! (s, l, p)\n");
69         return RET_SYN;
70     }
71     if (!snxtitem(&ni, type, player->argp[2], NULL))
72         return RET_SYN;
73
74     if ((p =
75          getstarg(player->argp[3],
76                   "Mission (int, sup, osup, dsup, esc, res, air, query, clear)? ",
77                   buf)) == 0)
78         return RET_SYN;
79
80 /*
81  * 'i'     interdiction
82  * 's'     support
83  * 'o'     support attacks
84  * 'd'     support defenders
85  * 'e'     escort
86  * 'r'     defensive reserve
87  * 'a'     air defense (intercepts)
88  */
89     switch (*p) {
90     case 'I':
91     case 'i':
92         mission = MI_INTERDICT;
93         break;
94     case 'O':
95     case 'o':
96         mission = MI_OSUPPORT;
97         break;
98     case 'D':
99     case 'd':
100         mission = MI_DSUPPORT;
101         break;
102     case 'S':
103     case 's':
104         mission = MI_SUPPORT;
105         break;
106     case 'C':
107     case 'c':
108         mission = 0;
109         break;
110     case 'E':
111     case 'e':
112         mission = MI_ESCORT;
113         break;
114     case 'R':
115     case 'r':
116         mission = MI_RESERVE;
117         break;
118     case 'A':
119     case 'a':
120         mission = MI_AIR_DEFENSE;
121         break;
122     case 'q':
123         show_mission(type, &ni);
124         return RET_OK;
125     default:
126         pr("bad condition\n");
127         pr("i\tinterdiction (any)\n");
128         pr("s\tsupport (tactical planes only)\n");
129         pr("o\toffensive support (tactical planes only)\n");
130         pr("d\tdefensive support (tactical planes only)\n");
131         pr("r\treserve (land units only)\n");
132         pr("e\tescort (tactical or escort planes only)\n");
133         pr("a\tair defense (intercept planes only)\n");
134         pr("c\tclear mission\n");
135         pr("q\tquery\n");
136         return RET_SYN;
137     }
138
139     if (mission && !cando(mission, type)) {
140         pr("A %s cannot do that mission!\n", ef_nameof(type));
141         pr("i\tinterdiction (any)\n");
142         pr("s\tsupport (planes only)\n");
143         pr("o\toffensive support (planes only)\n");
144         pr("d\tdefensive support (planes only)\n");
145         pr("r\treserve (land units only)\n");
146         pr("e\tescort (planes only)\n");
147         pr("a\tair defense (planes only)\n");
148         return RET_FAIL;
149     }
150
151     if (mission) {
152         if ((p = getstarg(player->argp[4], "operations point? ", buf)) == 0
153             || *p == 0)
154             return RET_SYN;
155
156         if (*p != '.') {
157             if (!sarg_xy(p, &x, &y))
158                 return RET_SYN;
159
160             if (!getsect(x, y, &opsect))
161                 return RET_FAIL;
162         }
163     } else {
164         x = 0;
165         y = 0;
166     }
167
168     if (player->argp[5] != NULL) {
169         desired_radius = atoi(player->argp[5]);
170         if (desired_radius < 0) {
171             pr("Radius must be greater than zero!\n");
172             return RET_FAIL;
173         }
174     } else {
175         desired_radius = 9999;
176     }
177
178     if ((mobmax = get_empobj_mob_max(type)) == -1)
179         return RET_FAIL;
180
181     mobused = ldround(mission_mob_cost * (double)mobmax, 1);
182
183     while (nxtitem(&ni, &item)) {
184         gp = (struct empobj *)&item;
185
186         if (!player->owner || gp->own == 0)
187             continue;
188
189         if ((mission && (gp->mobil < mobused)) && mission_mob_cost) {
190             pr("%s: not enough mobility! (needs %d)\n",
191                obj_nameof(gp), mobused);
192             continue;
193         }
194         if (mission == MI_RESERVE && !lnd_can_attack((struct lndstr *)gp)) {
195             pr("%s is not designed to fight ground troops\n",
196                obj_nameof(gp));
197             continue;
198         }
199         if (*p == '.') {
200             x = gp->x;
201             y = gp->y;
202             if (!getsect(x, y, &opsect))
203                 return RET_FAIL;
204         }
205
206         dist = mapdist(gp->x, gp->y, x, y);
207         radius = 999;
208         if (mission == MI_INTERDICT || mission == MI_SUPPORT ||
209             mission == MI_OSUPPORT || mission == MI_DSUPPORT ||
210             mission == MI_RESERVE || mission == MI_ESCORT ||
211             mission == MI_AIR_DEFENSE) {
212             radius = oprange(gp, mission);
213             if (radius < dist) {
214                 pr("%s: out of range! (range %d)\n",
215                    obj_nameof(gp), radius);
216                 continue;
217             }
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_glim == 0) {
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_dam == 0) {
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_RESERVE || mission == MI_ESCORT ||
289             mission == MI_AIR_DEFENSE)
290             gp->radius = radius;
291         else
292             gp->radius = 0;
293
294         if (mission == MI_SUPPORT || mission == MI_OSUPPORT ||
295             mission == MI_DSUPPORT || mission == MI_INTERDICT ||
296             mission == MI_RESERVE || mission == MI_ESCORT ||
297             mission == MI_AIR_DEFENSE) {
298             pr("%s on %s mission, centered on %s, radius %d\n",
299                obj_nameof(gp), mission_name(mission),
300                xyas(x, y, player->cnum), gp->radius);
301         } else if (mission) {
302             pr("%s on %s mission\n", obj_nameof(gp),
303                mission_name(mission));
304         }
305
306         if (mission)
307             gp->mobil -= mobused;
308         gp->mission = mission;
309         gp->opx = x;
310         gp->opy = y;
311         put_empobj(type, gp->uid, gp);
312     }
313     if (num == 0) {
314         pr("No %s%s\n", ef_nameof(type), splur(num));
315         return RET_FAIL;
316     }
317     pr("%d %s%s\n", num, ef_nameof(type), splur(num));
318     return RET_OK;
319 }