src/lib/subs/mslsub.c

Go to the documentation of this file.
00001 /*
00002  *  Empire - A multi-player, client/server Internet based war game.
00003  *  Copyright (C) 1986-2007, Dave Pare, Jeff Bailey, Thomas Ruschak,
00004  *                           Ken Stevens, Steve McClure
00005  *
00006  *  This program is free software; you can redistribute it and/or modify
00007  *  it under the terms of the GNU General Public License as published by
00008  *  the Free Software Foundation; either version 2 of the License, or
00009  *  (at your option) any later version.
00010  *
00011  *  This program is distributed in the hope that it will be useful,
00012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  *  GNU General Public License for more details.
00015  *
00016  *  You should have received a copy of the GNU General Public License
00017  *  along with this program; if not, write to the Free Software
00018  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019  *
00020  *  ---
00021  *
00022  *  See files README, COPYING and CREDITS in the root of the source
00023  *  tree for related information and legal notices.  It is expected
00024  *  that future projects/authors will amend these files as needed.
00025  *
00026  *  ---
00027  *
00028  *  mslsub.c: Missile subroutine stuff
00029  * 
00030  *  Known contributors to this file:
00031  *     Ken Stevens, 1995
00032  *     Steve McClure, 1996-2000
00033  */
00034 
00035 #include <config.h>
00036 
00037 #include <stdlib.h>
00038 #include "file.h"
00039 #include "land.h"
00040 #include "misc.h"
00041 #include "mission.h"
00042 #include "nat.h"
00043 #include "news.h"
00044 #include "nsc.h"
00045 #include "optlist.h"
00046 #include "path.h"
00047 #include "plane.h"
00048 #include "player.h"
00049 #include "prototypes.h"
00050 #include "queue.h"
00051 #include "sect.h"
00052 #include "ship.h"
00053 #include "xy.h"
00054 
00055 int
00056 msl_equip(struct plnstr *pp)
00057 {
00058     struct plist pl;
00059 
00060     memset(&pl, 0, sizeof(struct plist));
00061     pl.pcp = plchr + pp->pln_type;
00062     pl.plane = *pp;
00063     return mission_pln_equip(&pl, 0, 0, 'p');
00064 }
00065 
00066 int
00067 msl_hit(struct plnstr *pp, int hardtarget, int type, int news_item,
00068         int snews_item, char *what, coord x, coord y, int victim)
00069 {
00070     int hit;
00071     struct shpstr ship;
00072     struct sctstr sect;
00073     int sublaunch = 0;
00074     struct plchrstr *pcp = plchr + pp->pln_type;
00075     int hitchance = pln_hitchance(pp, hardtarget, type);
00076     char *from;
00077     int dam, dummyi;
00078 
00079     mpr(pp->pln_own, "Preparing to launch %s at %s %s %s%s\n",
00080         prplane(pp),
00081         cname(victim),
00082         what,
00083         (type == EF_SHIP || type == EF_PLANE) ? "in " : "",
00084         xyas(x, y, pp->pln_own));
00085     mpr(pp->pln_own, "\tLaunching from ");
00086     if (pp->pln_ship >= 0) {
00087         getship(pp->pln_ship, &ship);
00088         mpr(pp->pln_own, "%s in ", prship(&ship));
00089         if (mchr[(int)ship.shp_type].m_flags & M_SUB) {
00090             sublaunch = 1;
00091             from = "in hatch";
00092         } else
00093             from = "on deck";
00094         mpr(pp->pln_own, "%s\n",
00095             xyas(ship.shp_x, ship.shp_y, pp->pln_own));
00096     } else {
00097         if (pp->pln_harden > 0) {
00098             mpr(pp->pln_own, "missile silo at ");
00099             from = "in silo";
00100         } else
00101             from = "on launch pad";
00102         mpr(pp->pln_own, "%s\n", xyas(pp->pln_x, pp->pln_y, pp->pln_own));
00103     }
00104 
00105     if (chance((0.05 + (100 - pp->pln_effic) / 100.0)
00106                * (1 - techfact(pp->pln_tech, 1.0)))) {
00107         mpr(pp->pln_own, "KABOOOOM!  Missile explodes %s!\n", from);
00108         if (chance(0.33)) {
00109             dam = pln_damage(pp, pp->pln_x, pp->pln_y,
00110                              'p', &dummyi, 1) / 2;
00111             if (dam) {
00112                 if (pp->pln_ship >= 0) {
00113                     shipdamage(&ship, dam);
00114                     putship(ship.shp_uid, &ship);
00115                 } else {
00116                     pr("Explosion damages %s %d%%",
00117                        xyas(pp->pln_x, pp->pln_y, pp->pln_own), dam);
00118                     getsect(pp->pln_x, pp->pln_y, &sect);
00119                     sectdamage(&sect, dam, 0);
00120                     putsect(&sect);
00121                 }
00122             }
00123         }
00124         return 0;
00125     }
00126 
00127     mpr(pp->pln_own, "\tSHWOOOOOSH!  Missile launched!\n");
00128 
00129     if (pp->pln_nuketype != -1)
00130         mpr(pp->pln_own, "\tArming nuclear warheads...\n");
00131 
00132     if (pcp->pl_flags & P_T)
00133         mpr(victim, "Incoming %s missile sighted at %s...\n",
00134             sublaunch ? "sub-launched" : cname(pp->pln_own),
00135             xyas(x, y, victim));
00136 
00137     if (opt_PINPOINTMISSILE == 0 ||
00138         (pcp->pl_flags & P_T && !(pcp->pl_flags & P_MAR))) {
00139         if (msl_intercept(x, y, pp->pln_own, pcp->pl_def,
00140                           sublaunch, P_N, P_O)) {
00141             return 0;
00142         }
00143     }
00144     if (pcp->pl_flags & P_MAR) {
00145         if (shp_missile_defense(x, y, pp->pln_own, pcp->pl_def)) {
00146             return 0;
00147         }
00148     }
00149 
00150     if (pp->pln_nuketype != -1)
00151         hitchance = 100;
00152 
00153     mpr(pp->pln_own, "\t%d%% hitchance...", hitchance);
00154     hit = (roll(100) <= hitchance);
00155 
00156     mpr(pp->pln_own, hit ? "HIT!\n" : "miss\n");
00157     if (pcp->pl_flags & P_T)
00158         mpr(victim, "...Incoming %s missile %s\n",
00159             sublaunch ? "" : cname(pp->pln_own),
00160             hit ? "HIT!\n" : "missed\n");
00161     if (hit && news_item) {
00162         if (sublaunch)
00163             nreport(victim, snews_item, 0, 1);
00164         else
00165             nreport(pp->pln_own, news_item, victim, 1);
00166     }
00167     return hit;
00168 }
00169 
00170 void
00171 msl_sel(struct emp_qelem *list, coord x, coord y, natid victim,
00172         int wantflags, int nowantflags, int mission)
00173 {
00174     struct plchrstr *pcp;
00175     struct plnstr plane;
00176     struct plist *irv;
00177     struct nstr_item ni;
00178 
00179     emp_initque(list);
00180     snxtitem_all(&ni, EF_PLANE);
00181     while (nxtitem(&ni, &plane)) {
00182         if (!plane.pln_own)
00183             continue;
00184 
00185         pcp = &plchr[(int)plane.pln_type];
00186         if (!(pcp->pl_flags & P_M))
00187             continue;
00188         if (wantflags && (pcp->pl_flags & wantflags) != wantflags)
00189             continue;
00190         if (nowantflags && pcp->pl_flags & nowantflags)
00191             continue;
00192         if (mission && plane.pln_mission != mission)
00193             continue;
00194         if (getrel(getnatp(plane.pln_own), victim) >= NEUTRAL)
00195             continue;
00196         /* missiles go one way, so we can use all the range */
00197         if (plane.pln_range < mapdist(x, y, plane.pln_x, plane.pln_y))
00198             continue;
00199         if (plane.pln_mobil <= 0)
00200             continue;
00201         if (plane.pln_effic < 100)
00202             continue;
00203         /* got a valid interceptor */
00204         irv = malloc(sizeof(*irv));
00205         irv->bombs = 0;
00206         irv->misc = 0;
00207         irv->pcp = &plchr[(int)plane.pln_type];
00208         irv->plane = plane;
00209         emp_insque(&irv->queue, list);
00210     }
00211 }
00212 
00213 int
00214 msl_intercept(coord x, coord y, natid bombown, int hardtarget,
00215               int sublaunch, int wantflags, int nowantflags)
00216 {
00217     struct plnstr *pp;
00218     struct plchrstr *pcp;
00219     struct sctstr sect;
00220     struct emp_qelem *irvlist;
00221     struct emp_qelem foo;
00222     struct emp_qelem *intlist;
00223     struct emp_qelem intfoo;
00224     struct emp_qelem *qp;
00225     struct emp_qelem *next;
00226     struct plist *ip;
00227     int icount = 0;
00228     short destroyed = 0;
00229     char *att_name;
00230     char *def_name;
00231     int news_item;
00232     char *who = sublaunch ? "" : cname(bombown);
00233 
00234     getsect(x, y, &sect);
00235     if (wantflags == P_O && !nowantflags) {
00236         att_name = "satellite";
00237         def_name = "a-sat missile";
00238         news_item = N_SAT_KILL;
00239         if (sect.sct_own) {
00240             mpr(sect.sct_own, "%s has positioned a satellite over %s\n",
00241                 sublaunch ? "someone" : cname(bombown),
00242                 xyas(x, y, sect.sct_own));
00243         }
00244     } else if (wantflags == P_N && nowantflags == P_O) {
00245         att_name = "warhead";
00246         def_name = "abm";
00247         news_item = sublaunch ? N_NUKE_SSTOP : N_NUKE_STOP;
00248     } else {
00249         att_name = "elephant";
00250         def_name = "tomato";    /* heh -KHS */
00251         news_item = N_NUKE_STOP;
00252     }
00253     irvlist = &foo;
00254 
00255     /* get all hostile abms in range */
00256     msl_sel(irvlist, x, y, bombown, wantflags, nowantflags, 0);
00257     intlist = &intfoo;
00258     emp_initque(intlist);
00259     /* First choose interceptors belonging to the target sector */
00260     /* only allow two defense missiles per missile attack */
00261     for (qp = irvlist->q_forw; qp != irvlist && icount < 2; qp = next) {
00262         next = qp->q_forw;
00263         ip = (struct plist *)qp;
00264         pp = &ip->plane;
00265         if (pp->pln_own != sect.sct_own)
00266             continue;
00267         pcp = ip->pcp;
00268         if (mission_pln_equip(ip, 0, 0, 'i') < 0) {
00269             emp_remque(qp);
00270             free(qp);
00271             continue;
00272         }
00273         /* got one interceptor, delete from irv_list and
00274          * add to  int_list.
00275          */
00276         emp_remque(qp);
00277         emp_insque(qp, intlist);
00278         putplane(pp->pln_uid, pp);
00279         icount++;
00280     }
00281     /* only allow two defense missiles per missile attack */
00282     for (qp = irvlist->q_forw; qp != irvlist && icount < 2; qp = next) {
00283         next = qp->q_forw;
00284         ip = (struct plist *)qp;
00285         pp = &ip->plane;
00286         pcp = ip->pcp;
00287         if (mission_pln_equip(ip, 0, 0, 'i') < 0) {
00288             emp_remque(qp);
00289             free(qp);
00290             continue;
00291         }
00292         /* got one interceptor, delete from irv_list and
00293          * add to  int_list.
00294          */
00295         emp_remque(qp);
00296         emp_insque(qp, intlist);
00297         putplane(pp->pln_uid, pp);
00298         icount++;
00299     }
00300     /* Now, clean out the queue */
00301     while (!QEMPTY(irvlist)) {
00302         qp = irvlist->q_forw;
00303         emp_remque(qp);
00304         free(qp);
00305     }
00306     if (icount == 0) {
00307         if (sect.sct_own != 0)
00308             mpr(sect.sct_own, "No %ss launched to intercept.\n", def_name);
00309         return destroyed;
00310     }
00311 
00312     /* attempt to destroy incoming missile */
00313 
00314     while (!QEMPTY(intlist)) {
00315         qp = intlist->q_forw;
00316         ip = (struct plist *)qp;
00317         pp = &ip->plane;
00318         pcp = ip->pcp;
00319 
00320         mpr(bombown, "%s %s launched in defense!\n",
00321             cname(pp->pln_own), def_name);
00322         if (sect.sct_own == pp->pln_own) {
00323             mpr(sect.sct_own, "%s launched to intercept %s %s!\n",
00324                 def_name, who, att_name);
00325         } else {
00326             if (sect.sct_own)
00327                 mpr(sect.sct_own,
00328                     "%s launched an %s to intercept the %s %s!\n",
00329                     cname(pp->pln_own), def_name, who, att_name);
00330             mpr(pp->pln_own,
00331                 "%s launched to intercept %s %s arcing towards %s territory!\n",
00332                 def_name, who, att_name, cname(sect.sct_own));
00333         }
00334 
00335         if (!destroyed &&
00336             msl_hit(pp, hardtarget, EF_PLANE, news_item, news_item,
00337                     att_name, x, y, bombown)) {
00338             mpr(bombown, "%s destroyed by %s %s!\n",
00339                 att_name, cname(pp->pln_own), def_name);
00340             if (sect.sct_own)
00341                 mpr(sect.sct_own, "%s %s intercepted!\n", who, att_name);
00342             if (sect.sct_own != pp->pln_own)
00343                 mpr(pp->pln_own, "%s %s intercepted!\n", who, att_name);
00344             destroyed = 1;
00345         }
00346         /* zap the missile */
00347         pp->pln_effic = 0;
00348         putplane(pp->pln_uid, pp);
00349         emp_remque(qp);
00350         free(qp);
00351         if (destroyed)
00352             break;
00353     }
00354     /* Clean out what is left in the list */
00355     while (!QEMPTY(intlist)) {
00356         qp = intlist->q_forw;
00357         emp_remque(qp);
00358         free(qp);
00359     }
00360     if (destroyed)
00361         return destroyed;
00362     if (icount) {
00363         mpr(bombown, "%s made it through %s defenses!\n",
00364             att_name, def_name);
00365         if (sect.sct_own)
00366             mpr(sect.sct_own, "%s made it through %s defenses!\n",
00367                 att_name, def_name);
00368     }
00369     return destroyed;
00370 }
00371 
00372 /* Keep launching missiles on list until mindam damage has been done */
00373 int
00374 msl_launch_mindam(struct emp_qelem *list, coord x, coord y, int hardtarget,
00375                   int type, int mindam, char *whatp, int victim,
00376                   int mission)
00377 {
00378     struct emp_qelem *qp;
00379     struct emp_qelem *next;
00380     struct plist *plp;
00381     int newdam, dam = 0;
00382     int nukedam = 0;
00383     int news_item;
00384     int snews_item;
00385 
00386     if (type == EF_SHIP) {
00387         news_item = N_SHP_MISS;
00388         snews_item = N_SHP_SMISS;
00389     } else if (type == EF_LAND) {
00390         news_item = N_LND_MISS;
00391         snews_item = N_LND_SMISS;
00392     } else {
00393         news_item = N_SCT_MISS;
00394         snews_item = N_SCT_SMISS;
00395     }
00396 
00397     for (qp = list->q_back; qp != list && dam < mindam && !nukedam;
00398          qp = next) {
00399         next = qp->q_back;
00400         plp = (struct plist *)qp;
00401 
00402         if (mission_pln_equip(plp, 0, 0, 'p') >= 0) {
00403             if (msl_hit(&plp->plane,
00404                         hardtarget, type, news_item, snews_item,
00405                         whatp, x, y, victim)) {
00406                 newdam = pln_damage(&plp->plane, x, y, 'p', &nukedam, 1);
00407                 if (nukedam) {
00408                     if (mission == MI_INTERDICT && type == EF_SECTOR)
00409                         dam += nukedam;
00410                 } else
00411                     dam += newdam;
00412             } else {
00413                 /* Missiles that miss have to hit somewhere! */
00414                 newdam = pln_damage(&plp->plane, x, y, 'p', &nukedam, 0);
00415                 collateral_damage(x, y, newdam, 0);
00416             }
00417             plp->plane.pln_effic = 0;
00418             putplane(plp->plane.pln_uid, &plp->plane);
00419             emp_remque(qp);
00420             free(qp);
00421         }
00422     }
00423     return dam;
00424 }

Generated on Fri Mar 28 11:01:15 2008 for empserver by  doxygen 1.5.2