]> git.pond.sub.org Git - empserver/blob - src/lib/commands/laun.c
Import of Empire 4.2.12
[empserver] / src / lib / commands / laun.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  *  laun.c: Launch missiles from land or sea
29  * 
30  *  Known contributors to this file:
31  *     Dave Pare, 1986
32  *     Ken Stevens, 1995
33  *     Steve McClure, 1998-2000
34  */
35
36 #include "misc.h"
37 #include "player.h"
38 #include "xy.h"
39 #include "var.h"
40 #include "sect.h"
41 #include "item.h"
42 #include "plane.h"
43 #include "nuke.h"
44 #include "news.h"
45 #include "retreat.h"
46 #include "mission.h"
47 #include "ship.h"
48 #include "nsc.h"
49 #include "nat.h"
50 #include "path.h"
51 #include "file.h"
52 #include "optlist.h"
53 #include "damage.h"
54 #include "commands.h"
55
56 static  int launch_as(struct plnstr *pp);
57 static  int launch_missile(struct plnstr *pp, int sublaunch);
58 static  int launch_sat(struct plnstr *pp, int sublaunch);
59
60 /*
61  * laun <PLANES>
62  */
63 int
64 laun(void)
65 {
66         struct  nstr_item nstr;
67         struct  plnstr plane;
68         struct  shpstr ship;
69         struct  sctstr sect;
70         int     sublaunch;
71         struct  plchrstr *pcp;
72         int     rel;
73         struct natstr   *natp;
74
75         if (!snxtitem(&nstr, EF_PLANE, player->argp[1]))
76                 return RET_SYN;
77         while (nxtitem(&nstr, (s_char *)&plane)) {
78                 if (plane.pln_own != player->cnum)
79                         continue;
80                 pcp = &plchr[(int)plane.pln_type];
81                 if ((pcp->pl_flags & (P_M|P_O)) == 0) {
82                         pr("%s isn't a missile!\n", prplane(&plane));
83                         continue;
84                 }
85                 if (pcp->pl_flags & P_F) {
86                         pr("%s is a surface-to-air missile!\n",
87                            prplane(&plane));
88                         continue;
89                 }
90                 if (pcp->pl_flags & P_N) {
91                         pr("%s is an anti-ballistic-missile missile!\n",
92                            prplane(&plane));
93                         continue;
94                 }
95                 if ((plane.pln_flags & PLN_LAUNCHED) && (pcp->pl_flags & P_O)) {
96                         pr("%s already in orbit!\n", prplane(&plane));
97                         continue;
98                 }
99                 if (opt_MARKET) {
100                     if (ontradingblock(EF_PLANE,(int *) &plane)) {
101                         pr("plane #%d inelligible - it's for sale.\n", plane.pln_uid);
102                         continue;
103                     }
104                 }
105
106                 sublaunch = 0;
107                 if (plane.pln_ship >= 0) {
108                         getship(plane.pln_ship, &ship);
109                         if (!ship.shp_own) {
110                                 pr("%s: ship #%d was sunk!\n",
111                                    prplane(&plane),
112                                    ship.shp_uid);
113                                 makelost(EF_PLANE, plane.pln_own, plane.pln_uid, plane.pln_x, plane.pln_y);
114                                 plane.pln_own = 0;
115                                 putplane(plane.pln_uid, &plane);
116                                 continue;
117                         }
118                         natp = getnatp(ship.shp_own);
119                         rel = getrel(natp, player->cnum);
120                         if (ship.shp_own != player->cnum && rel != ALLIED) {
121                                 pr("%s: you or an ally do not own ship #%d\n",
122                                    prplane(&plane), ship.shp_uid);
123                                 makelost(EF_PLANE, plane.pln_own, plane.pln_uid, plane.pln_x, plane.pln_y);
124                                 plane.pln_own = 0;
125                                 putplane(plane.pln_uid, &plane);
126                                 continue;
127                         }
128                         if (mchr[(int)ship.shp_type].m_flags & M_SUB)
129                                 sublaunch = 1;
130                 } else {
131                         sublaunch = 0;
132                         getsect(plane.pln_x, plane.pln_y, &sect);
133                         natp = getnatp(sect.sct_own);
134                         rel = getrel(natp, player->cnum);
135                         if (sect.sct_own && sect.sct_own != player->cnum && rel != ALLIED) {
136                                 pr("%s: you or an ally do not own sector %s!\n",
137                                    prplane(&plane),
138                                    xyas(plane.pln_x, plane.pln_y, player->cnum));
139                                 continue;
140                         }
141                 }
142                 if (plane.pln_effic < 60) {
143                         pr("%s is damaged (%d%%)\n",
144                            prplane(&plane), plane.pln_effic);
145                         continue;
146                 }
147                 pr("%s at %s; range %d, eff %d%%\n", prplane(&plane),
148                         xyas(plane.pln_x, plane.pln_y, player->cnum),
149                         plane.pln_range,
150                         plane.pln_effic);
151                 if (!(pcp->pl_flags & P_O)) {
152                         if (launch_missile(&plane, sublaunch) < 0)
153                                 continue;
154                 } else if ((pcp->pl_flags & (P_M|P_O)) == (P_M|P_O)) {
155                         if (launch_as(&plane) < 0) /* anti-sat */
156                                 continue;
157                 } else {                        /* satellites */
158                         if (launch_sat(&plane, sublaunch) < 0)
159                                 continue;
160                 }
161                 makelost(EF_PLANE, plane.pln_own, plane.pln_uid, plane.pln_x, plane.pln_y);
162                 plane.pln_own = 0;
163                 putplane(plane.pln_uid, &plane);
164         }
165         return RET_OK;
166 }
167
168 /*
169  * Launch an anti-sat weapon.
170  * Return -1 on failure, 0 on success (even if missile explodes).
171  */
172
173 static int
174 launch_as(struct plnstr *pp)
175 {
176         coord   sx, sy;
177         s_char  *cp, buf[1024];
178         struct  plnstr plane;
179         struct  nstr_item ni;
180         int     goodtarget;
181         int     dam, nukedam;
182         natid   oldown;
183
184         if (msl_equip(pp) < 0) {
185                 pr("%s not enough petrol or shells!\n", prplane(pp));
186                 return -1;
187         }
188         for (;;) {
189                 cp = getstarg(player->argp[2], "Target sector? ", buf);
190                 if (!check_plane_ok(pp))
191                     return -1;
192                 player->argp[2] = 0;
193                 if (!cp || !*cp)
194                         return -1;
195                 if (!sarg_xy(cp, &sx, &sy)) {
196                         pr("Bad sector designation; try again!\n");
197                         continue;
198                 }
199                 if (mapdist(pp->pln_x, pp->pln_y, sx, sy) >
200                     pp->pln_range) {
201                         pr("Range too great; try again!\n");
202                         continue;
203                 }
204                 break;
205         }
206         goodtarget=0;
207         snxtitem_dist(&ni, EF_PLANE, sx, sy, 0);
208         while (!goodtarget && nxtitem(&ni, (caddr_t)&plane)) {
209                 if (!plane.pln_own)
210                         continue;
211                 if (!(plane.pln_flags & PLN_LAUNCHED))
212                         continue;
213                 goodtarget = 1;
214                 
215         }
216         if (!goodtarget) {
217                 pr("No satellites there!\n");
218                 return -1;
219         }
220         if (msl_hit(pp, plane.pln_def, EF_PLANE, N_SAT_KILL, N_SAT_KILL, prplane(&plane), sx, sy, plane.pln_own)) {
221                 dam = pln_damage(pp,sx,sy,'p',&nukedam,1);
222                 oldown = plane.pln_own;
223                 planedamage(&plane, dam);
224                 pr("Hit satellite for %d%% damage!\n", dam);
225                 mpr(oldown,
226                     "%s anti-sat did %d%% damage to %s over %s\n",
227                     cname(player->cnum), dam, prplane(&plane),
228                     xyas(plane.pln_x, plane.pln_y, plane.pln_own));
229                 putplane(plane.pln_uid,&plane);
230                 if (!plane.pln_own)
231                         mpr(oldown, "Satellite shot down\n");
232         }
233         return 0;
234 }
235
236 /*
237  * Launch a missile
238  * Return -1 on failure, 0 on success (even if missile explodes).
239  */
240 static int
241 launch_missile(struct plnstr *pp, int sublaunch)
242 {
243         struct  plchrstr *pcp = plchr + pp->pln_type;
244         coord   sx, sy;
245         int     n, dam;
246         s_char  *cp;
247         struct  mchrstr *mcp;
248         struct  shpstr  target_ship;
249         struct  sctstr  sect;
250         int     nukedam;
251         int     rel;
252         struct natstr   *natp;
253         s_char  buf[1024];
254
255         for (;;) {
256                 if (pcp->pl_flags & P_MAR)
257                         cp = getstarg(player->argp[2], "Target ship? ", buf);
258                 else
259                         cp = getstarg(player->argp[2], "Target sector? ", buf);
260                 player->argp[2] = 0;
261                 if (!cp || !*cp)
262                         return -1;
263                 if (!check_plane_ok(pp))
264                     return -1;
265                 if (opt_PINPOINTMISSILE && sarg_type(cp) == NS_LIST) {
266                         if (!(pcp->pl_flags & P_MAR)) {
267                                 pr("Missile not designed to attack ships!\n");
268                                 continue;
269                         }
270                         n = atoi(cp);
271                         if ((n < 0) || !getship(n,&target_ship) ||
272                             !target_ship.shp_own) {
273                                 pr("Bad ship number; try again!\n");
274                                 continue;
275                         }
276                         sx = target_ship.shp_x;
277                         sy = target_ship.shp_y;
278                         mcp = &mchr[(int)target_ship.shp_type];
279                         if (mcp->m_flags & M_SUB) {
280                                 pr("Bad ship number; try again!\n");
281                                 continue;
282                         }
283                 } /* not PINPOINTMISSILE for ships */
284                 else if (!sarg_xy(cp, &sx, &sy)) {
285                         pr("That's no good! try again!\n");
286                         continue;
287                 }
288                 else if (opt_PINPOINTMISSILE)
289                 {
290                         if (pcp->pl_flags & P_MAR) {
291                                 pr("Missile designed to attack ships!\n");
292                                 continue;
293                         }
294                 } /* end PINPOINTMISSILE */
295
296                 if (mapdist(pp->pln_x, pp->pln_y, sx, sy) >
297                     pp->pln_range) {
298                         pr("Range too great; try again!\n");
299                         continue;
300                 }
301                 break;
302         }
303         if (msl_equip(pp) < 0) {
304                 pr("%s not enough shells!\n", prplane(pp));
305                 return -1;
306         }
307         if (opt_PINPOINTMISSILE == 0 || !(pcp->pl_flags & P_MAR))
308         {
309                 getsect(sx,sy,&sect);
310                 if (opt_SLOW_WAR) {
311                   natp = getnatp(player->cnum);
312                   rel = getrel(natp,sect.sct_own);
313                   if ((rel != AT_WAR) && (sect.sct_own != player->cnum) &&
314                       (sect.sct_own) && (sect.sct_oldown != player->cnum)){
315                         pr("You are not at war with the player->owner of the target sector!\n");
316                         pr_beep();
317                         pr("Kaboom!!!\n");
318                         pr("Missile monitoring officer destroys RV before detonation.\n");
319                         return 0;
320                   }
321                 }
322                 if (!msl_hit(pp, SECT_HARDTARGET, EF_SECTOR, N_SCT_MISS,
323                              N_SCT_SMISS, "sector", sx, sy, sect.sct_own)) {
324                   /*
325                     dam = pln_damage(pp, sect.sct_x, sect.sct_y, 's', &nukedam, 0);
326                     collateral_damage(sect.sct_x, sect.sct_y, dam, 0);
327                   */
328                     return 0;
329                 }
330                 dam = pln_damage(pp, sect.sct_x, sect.sct_y, 's', &nukedam, 1);
331                 if (!nukedam) {
332                         pr("did %d damage in %s\n", PERCENT_DAMAGE(dam),
333                            xyas(sx, sy, player->cnum));
334                         if (sect.sct_own != 0) {
335                                 if (sublaunch)
336                                         wu(0, sect.sct_own,
337                                            "Sub missile attack did %d damage in %s\n",
338                                            dam, xyas(sx, sy, sect.sct_own));
339                                 else
340                                         wu(0, sect.sct_own,
341                                            "%s missile attack did %d damage in %s\n",
342                                            cname(player->cnum), dam,
343                                            xyas(sx, sy, sect.sct_own));
344                         }
345                         sectdamage(&sect, dam, 0);
346                         putsect(&sect);
347                 }
348         } /* end PINPOINTMISSILE conditional */
349         else if (opt_PINPOINTMISSILE)
350         { /* else */ 
351                   if (!msl_hit(pp, shp_hardtarget(&target_ship), EF_SHIP, 
352                                N_SHP_MISS, N_SHP_SMISS, prship(&target_ship),
353                                target_ship.shp_x, target_ship.shp_y,
354                                target_ship.shp_own)) {
355                         pr("splash\n");
356                         /*
357                         dam = pln_damage(pp,target_ship.shp_x,target_ship.shp_y,'p',&nukedam, 0);
358                         collateral_damage(target_ship.shp_x, target_ship.shp_y, dam, 0);
359                         */
360                         return 0;
361                   } 
362                 dam = pln_damage(pp,target_ship.shp_x,target_ship.shp_y,'p',&nukedam, 1);
363                 if (!nukedam) {
364                         check_retreat_and_do_shipdamage(&target_ship, dam);
365                         if (target_ship.shp_effic < SHIP_MINEFF)
366                                 pr("\t%s sunk!\n", prship(&target_ship));
367                         putship(target_ship.shp_uid, &target_ship);
368                 }
369                 getship(n, &target_ship);
370                 if (!target_ship.shp_own)
371                         pr("%s sunk!\n", prship(&target_ship));
372         }
373         /* end PINPOINTMISSILE */
374         return 0;
375 }
376
377 /*
378  * Launch a satellite.
379  * Return -1 on error, 0 on success (even if the satellite fails).
380  */
381 static int
382 launch_sat(struct plnstr *pp, int sublaunch)
383 {
384         struct  plchrstr *pcp = plchr + pp->pln_type;
385         coord   sx, sy;
386         int     i;
387         int     dist;
388         int     dir;
389         s_char  *cp;
390         s_char  *p;
391         s_char  buf[1024];
392
393         pr("\n");
394         while (1) {
395                 cp = getstarg(player->argp[2], "Target sector? ", buf);
396                 if (!check_plane_ok(pp))
397                     return -1;
398                 player->argp[2] = 0;
399                 if (!cp || !*cp)
400                         return -1;
401                 if (!sarg_xy(cp, &sx, &sy)) {
402                         pr("Bad sector designation; try again!\n");
403                         continue;
404                 }
405                 if ((dist = mapdist(pp->pln_x, pp->pln_y, sx, sy)) >
406                     pp->pln_range) {
407                         pr("Range too great; try again!\n");
408                         continue;
409                 }
410                 break;
411         }
412         if (opt_ORBIT) {
413                 p = getstring("Geostationary orbit? ", buf);
414                 if (p == 0)
415                         return -1;
416                 if (!check_plane_ok(pp))
417                     return -1;
418                 pp->pln_theta = 0;
419                 pp->pln_flags |= PLN_SYNCHRONOUS;
420                 if (*p == 0 || *p == 'n')
421                         pp->pln_flags &= ~(PLN_SYNCHRONOUS);
422         } /* end opt_ORBIT */
423
424         pr("3... 2... 1... Blastoff!!!\n");
425         if (chance(0.07 + (100 - pp->pln_effic)/100.0)) {
426                 pr("KABOOOOM!  Range safety officer detonates booster!\n");
427                 makelost(EF_PLANE, pp->pln_own, pp->pln_uid, pp->pln_x, pp->pln_y);
428                 pp->pln_own = 0;
429                 return 0;
430         }
431         i = pp->pln_tech + pp->pln_effic;
432         if (chance(1.0 - (i/(i+50.0)))) {
433                 dir = (random() % 6) + 1;
434                 sx += diroff[dir][0];
435                 sy += diroff[dir][1];
436                 pr("Your trajectory was a little off.\n");
437         }
438         nreport(player->cnum, N_LAUNCH, 0, 1);
439         pr("%s positioned over %s", prplane(pp),
440            xyas(sx, sy, player->cnum));
441         if (msl_intercept(sx, sy, pp->pln_own, pcp->pl_def, sublaunch, P_O, 0)) {
442                 return 0;
443         }
444         pp->pln_x = sx;
445         pp->pln_y = sy;
446         pp->pln_flags |= PLN_LAUNCHED;
447         pp->pln_mobil = (pp->pln_mobil > dist) ? 
448                 (pp->pln_mobil - dist) : 0;
449         putplane(pp->pln_uid, pp);
450         pr(", will be ready for use in %d time units\n",
451                 127 - pp->pln_mobil);
452         return -1;
453 }