]> git.pond.sub.org Git - empserver/blob - src/lib/commands/miss.c
Fix trailing whitespace
[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 && ((mission != MI_RESERVE) && (mission != MI_ESCORT))) {
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_AIR_DEFENSE) &&
211             (oprange(gp, &radius) < dist)) {
212             pr("%s: out of range! (range %d)\n",
213                obj_nameof(gp), oprange(gp, &radius));
214             continue;
215         }
216
217         if (radius > desired_radius)
218             radius = desired_radius;
219
220         if ((mission == MI_INTERDICT) && (type == EF_SHIP))
221             if (mchr[(int)gp->type].m_glim == 0) {
222                 pr("%s: cannot fire at range!\n", obj_nameof(gp));
223                 continue;
224             }
225
226         if ((mission == MI_INTERDICT) && (type == EF_LAND))
227             if (lchr[(int)gp->type].l_dam == 0) {
228                 pr("%s: cannot fire at range!\n", obj_nameof(gp));
229                 continue;
230             }
231
232         if ((mission == MI_INTERDICT) && (type == EF_PLANE)) {
233             struct plchrstr *pcp;
234
235             pcp = &plchr[(int)gp->type];
236             if (!(pcp->pl_flags & P_T)) {
237                 pr("Only planes with the tactical ability can interdict.\n"
238                    "%s #%d is ineligible\n",
239                    pcp->pl_name, gp->uid);
240                 continue;
241             }
242         }
243
244         if ((mission == MI_AIR_DEFENSE) && (type == EF_PLANE)) {
245             struct plchrstr *pcp;
246
247             pcp = &plchr[(int)gp->type];
248             if (!(pcp->pl_flags & P_F)) {
249                 pr("Only planes with the intercept abilities can perform air defense.\n"
250                    "%s #%d is ineligible\n",
251                    pcp->pl_name, gp->uid);
252                 continue;
253             }
254         }
255
256         if ((mission == MI_ESCORT) && (type == EF_PLANE)) {
257             struct plchrstr *pcp;
258
259             pcp = &plchr[(int)gp->type];
260             if (!(pcp->pl_flags & P_ESC) && !(pcp->pl_flags & P_F)) {
261                 pr("Only planes with the escort or intercept abilities can escort.\n"
262                    "%s #%d is ineligible\n",
263                    pcp->pl_name, gp->uid);
264                 continue;
265             }
266         }
267
268         if ((mission == MI_SUPPORT || mission == MI_OSUPPORT ||
269              mission == MI_DSUPPORT) && (type == EF_PLANE)) {
270             struct plchrstr *pcp;
271
272             pcp = &plchr[(int)gp->type];
273             if (!(pcp->pl_flags & P_T)) {
274                 pr("Only planes with the tactical ability can support.\n"
275                    "%s #%d is ineligible\n",
276                    pcp->pl_name, gp->uid);
277                 continue;
278             }
279         }
280
281         num++;                  /* good one.. go with it */
282
283         if (mission == MI_INTERDICT || mission == MI_SUPPORT ||
284             mission == MI_OSUPPORT || mission == MI_DSUPPORT ||
285             mission == MI_AIR_DEFENSE)
286             gp->radius = radius;
287         else
288             gp->radius = 0;
289
290         if (mission == MI_SUPPORT || mission == MI_OSUPPORT ||
291             mission == MI_DSUPPORT || mission == MI_INTERDICT ||
292             mission == MI_AIR_DEFENSE) {
293             pr("%s on %s mission, centered on %s, radius %d\n",
294                obj_nameof(gp), mission_name(mission),
295                xyas(x, y, player->cnum), gp->radius);
296         } else if (mission == MI_RESERVE) {
297             int plus = 2;
298
299             if (((struct lndstr *)gp)->lnd_rad_max == 0) {
300                 plus = 0;
301             } else {
302                 getsect(gp->x, gp->y, &opsect);
303                 if ((opsect.sct_type == SCT_HEADQ)
304                     && (opsect.sct_effic >= 60))
305                     plus++;
306                 plus += ((struct lndstr *)gp)->lnd_rad_max;
307             }
308
309             pr("%s on %s mission with maximum reaction radius %d\n",
310                obj_nameof(gp), mission_name(mission), plus);
311         } else if (mission) {
312             pr("%s on %s mission\n", obj_nameof(gp),
313                mission_name(mission));
314         }
315
316         if (mission)
317             gp->mobil -= mobused;
318         gp->mission = mission;
319         gp->opx = x;
320         gp->opy = y;
321         put_empobj(type, gp->uid, gp);
322     }
323     if (num == 0) {
324         pr("No %s%s\n", ef_nameof(type), splur(num));
325         return RET_FAIL;
326     }
327     pr("%d %s%s\n", num, ef_nameof(type), splur(num));
328     return RET_OK;
329 }