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