src/lib/subs/shpsub.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  *  shpsub.c: Ship subroutine stuff
00029  * 
00030  *  Known contributors to this file:
00031  *     Ken Stevens, 1995
00032  *     Steve McClure, 1996-2000
00033  *     Markus Armbruster, 2006
00034  */
00035 
00036 #include <config.h>
00037 
00038 #include <math.h>
00039 #include <stdlib.h>
00040 #include "damage.h"
00041 #include "file.h"
00042 #include "map.h"
00043 #include "misc.h"
00044 #include "mission.h"
00045 #include "nsc.h"
00046 #include "optlist.h"
00047 #include "path.h"
00048 #include "player.h"
00049 #include "prototypes.h"
00050 #include "queue.h"
00051 #include "server.h"
00052 #include "xy.h"
00053 #include "empobj.h"
00054 #include "unit.h"
00055 
00056 static int shp_check_one_mines(struct ulist *);
00057 static int shp_hit_mine(struct shpstr *, struct mchrstr *);
00058 static void shp_mess(char *, struct ulist *);
00059 
00060 void
00061 shp_sel(struct nstr_item *ni, struct emp_qelem *list)
00062 
00063 
00064     /*  int     wantflags;
00065        int      nowantflags;
00066      */
00067 {
00068     struct shpstr ship;
00069     struct mchrstr *mcp;
00070     struct ulist *mlp;
00071 
00072     emp_initque(list);
00073     while (nxtitem(ni, &ship)) {
00074         if (!player->owner)
00075             continue;
00076         mcp = &mchr[(int)ship.shp_type];
00077         /* if (wantflags && (mcp->m_flags & wantflags) != wantflags)
00078            continue;
00079            if (nowantflags && mcp->m_flags & nowantflags)
00080            continue;
00081          */
00082         if (opt_MARKET) {
00083             if (ontradingblock(EF_SHIP, &ship)) {
00084                 pr("ship #%d inelligible - it's for sale.\n",
00085                    ship.shp_uid);
00086                 continue;
00087             }
00088         }
00089         /* This abuse is better fixed by building a ship with the normal negative
00090            mobility that everything else is built with */
00091 /*
00092         if (opt_MOB_ACCESS) {
00093           if (ship.shp_effic < 21 &&
00094             ship.shp_mobil < etu_per_update) {
00095             pr("%s needs at least %d mob to navigate.\n",
00096                prship(&ship), etu_per_update);
00097             continue;
00098           }
00099         }
00100 */
00101         ship.shp_mission = 0;
00102         ship.shp_rflags = 0;
00103         memset(ship.shp_rpath, 0, sizeof(ship.shp_rpath));
00104         putship(ship.shp_uid, &ship);
00105         mlp = malloc(sizeof(struct ulist));
00106         mlp->chrp = (struct empobj_chr *)mcp;
00107         mlp->unit.ship = ship;
00108         mlp->mobil = ship.shp_mobil;
00109         emp_insque(&mlp->queue, list);
00110     }
00111 }
00112 
00113 /* This function assumes that the list was created by shp_sel */
00114 void
00115 shp_nav(struct emp_qelem *list, double *minmobp, double *maxmobp,
00116         int *togetherp, natid actor)
00117 {
00118     struct emp_qelem *qp;
00119     struct emp_qelem *next;
00120     struct ulist *mlp;
00121     struct sctstr sect;
00122     struct shpstr ship;
00123     coord allx;
00124     coord ally;
00125     int first = 1;
00126 
00127     *minmobp = 9876.0;
00128     *maxmobp = -9876.0;
00129     *togetherp = 1;
00130     for (qp = list->q_back; qp != list; qp = next) {
00131         next = qp->q_back;
00132         mlp = (struct ulist *)qp;
00133         getship(mlp->unit.ship.shp_uid, &ship);
00134         if (ship.shp_own != actor) {
00135             mpr(actor, "%s was sunk at %s\n",
00136                 prship(&ship), xyas(ship.shp_x, ship.shp_y, actor));
00137             emp_remque((struct emp_qelem *)mlp);
00138             free(mlp);
00139             continue;
00140         }
00141         if (opt_SAIL) {
00142             if (*ship.shp_path && !update_running) {
00143                 shp_mess("has a sail path", mlp);
00144                 mpr(actor, "Use `sail <#> -' to reset\n");
00145                 continue;
00146             }
00147         }
00148         /* check crew - uws don't count */
00149         if (ship.shp_item[I_MILIT] == 0 && ship.shp_item[I_CIVIL] == 0) {
00150             shp_mess("is crewless", mlp);
00151             continue;
00152         }
00153         if (!getsect(ship.shp_x, ship.shp_y, &sect)) {
00154             shp_mess("was sucked into the sky by a strange looking spaceship", mlp);    /* heh -KHS */
00155             continue;
00156         }
00157         switch (shp_check_nav(&sect, &ship)) {
00158         case CN_CONSTRUCTION:
00159             shp_mess("is caught in a construction zone", mlp);
00160             continue;
00161         case CN_LANDLOCKED:
00162             shp_mess("is landlocked", mlp);
00163             continue;
00164         case CN_NAVIGABLE:
00165             break;
00166         case CN_ERROR:
00167         default:
00168             shp_mess("was just swallowed by a big green worm", mlp);
00169             continue;
00170         }
00171         if (first) {
00172             allx = ship.shp_x;
00173             ally = ship.shp_y;
00174             first = 0;
00175         }
00176         if (ship.shp_x != allx || ship.shp_y != ally)
00177             *togetherp = 0;
00178         if (ship.shp_mobil + 1 < (int)mlp->mobil) {
00179             mlp->mobil = ship.shp_mobil;
00180         }
00181         if (mlp->mobil < *minmobp)
00182             *minmobp = mlp->mobil;
00183         if (mlp->mobil > *maxmobp)
00184             *maxmobp = mlp->mobil;
00185         mlp->unit.ship = ship;
00186     }
00187 }
00188 
00189 int
00190 shp_sweep(struct emp_qelem *ship_list, int verbose, int takemob, natid actor)
00191 {
00192     struct emp_qelem *qp;
00193     struct emp_qelem *next;
00194     struct ulist *mlp;
00195     struct sctstr sect;
00196     int mines, m, max, shells;
00197     int changed = 0;
00198     int stopping = 0;
00199 
00200     for (qp = ship_list->q_back; qp != ship_list; qp = next) {
00201         next = qp->q_back;
00202         mlp = (struct ulist *)qp;
00203         if (!(((struct mchrstr *)mlp->chrp)->m_flags & M_SWEEP)) {
00204             if (verbose)
00205                 mpr(actor, "%s doesn't have minesweeping capability!\n",
00206                     prship(&mlp->unit.ship));
00207             continue;
00208         }
00209         if (takemob && mlp->mobil <= 0.0) {
00210             if (verbose)
00211                 mpr(actor, "%s is out of mobility!\n",
00212                     prship(&mlp->unit.ship));
00213             continue;
00214         }
00215         getsect(mlp->unit.ship.shp_x, mlp->unit.ship.shp_y, &sect);
00216         if (sect.sct_type != SCT_WATER) {
00217             if (verbose)
00218                 mpr(actor, "%s is not at sea.  No mines there!\n",
00219                     prship(&mlp->unit.ship));
00220             continue;
00221         }
00222         if (takemob) {
00223             mlp->mobil -= shp_mobcost(&mlp->unit.ship);
00224             mlp->unit.ship.shp_mobil = (int)mlp->mobil;
00225         }
00226         putship(mlp->unit.ship.shp_uid, &mlp->unit.ship);
00227         if (!(mines = sect.sct_mines))
00228             continue;
00229         max = ((struct mchrstr *)mlp->chrp)->m_item[I_SHELL];
00230         shells = mlp->unit.ship.shp_item[I_SHELL];
00231         for (m = 0; mines > 0 && m < 5; m++) {
00232             if (chance(0.66)) {
00233                 mpr(actor, "Sweep...\n");
00234                 mines--;
00235                 shells = MIN(max, shells + 1);
00236                 changed |= map_set(actor, sect.sct_x, sect.sct_y, 'X', 0);
00237             }
00238         }
00239         sect.sct_mines = mines;
00240         mlp->unit.ship.shp_item[I_SHELL] = shells;
00241         if (shp_check_one_mines(mlp)) {
00242             stopping = 1;
00243             emp_remque(qp);
00244             free(qp);
00245         }
00246         putship(mlp->unit.ship.shp_uid, &mlp->unit.ship);
00247         putsect(&sect);
00248     }
00249     if (changed)
00250         writemap(actor);
00251     return stopping;
00252 }
00253 
00254 static int
00255 shp_check_one_mines(struct ulist *mlp)
00256 {
00257     struct sctstr sect;
00258     int actor;
00259 
00260     getsect(mlp->unit.ship.shp_x, mlp->unit.ship.shp_y, &sect);
00261     if (sect.sct_type != SCT_WATER)
00262         return 0;
00263     if (!sect.sct_mines)
00264         return 0;
00265     if (chance(DMINE_HITCHANCE(sect.sct_mines))) {
00266         actor = mlp->unit.ship.shp_own;
00267         shp_hit_mine(&mlp->unit.ship, ((struct mchrstr *)mlp->chrp));
00268         sect.sct_mines--;
00269         if (map_set(actor, sect.sct_x, sect.sct_y, 'X', 0))
00270             writemap(actor);
00271         putsect(&sect);
00272         putship(mlp->unit.ship.shp_uid, &mlp->unit.ship);
00273         if (!mlp->unit.ship.shp_own)
00274             return 1;
00275     }
00276     return 0;
00277 }
00278 
00279 static int
00280 shp_check_mines(struct emp_qelem *ship_list)
00281 {
00282     struct emp_qelem *qp;
00283     struct emp_qelem *next;
00284     struct ulist *mlp;
00285     int stopping = 0;
00286 
00287     for (qp = ship_list->q_back; qp != ship_list; qp = next) {
00288         next = qp->q_back;
00289         mlp = (struct ulist *)qp;
00290         if (shp_check_one_mines(mlp)) {
00291             stopping = 1;
00292             emp_remque(qp);
00293             free(qp);
00294         }
00295     }
00296     return stopping;
00297 }
00298 
00299 
00300 static void
00301 shp_mess(char *str, struct ulist *mlp)
00302 {
00303     mpr(mlp->unit.ship.shp_own, "%s %s & stays in %s\n",
00304         prship(&mlp->unit.ship),
00305         str, xyas(mlp->unit.ship.shp_x, mlp->unit.ship.shp_y,
00306                   mlp->unit.ship.shp_own));
00307     mlp->unit.ship.shp_mobil = (int)mlp->mobil;
00308     putship(mlp->unit.ship.shp_uid, &mlp->unit.ship);
00309     emp_remque((struct emp_qelem *)mlp);
00310     free(mlp);
00311 }
00312 
00313 int
00314 shp_check_nav(struct sctstr *sect, struct shpstr *shp)
00315 {
00316     switch (dchr[sect->sct_type].d_nav) {
00317     case NAVOK:
00318         break;
00319     case NAV_CANAL:
00320         if (mchr[(int)shp->shp_type].m_flags & M_CANAL) {
00321             if (sect->sct_effic < 2)
00322                 return CN_CONSTRUCTION;
00323         } else
00324             return CN_LANDLOCKED;
00325         break;
00326     case NAV_02:
00327         if (sect->sct_effic < 2)
00328             return CN_CONSTRUCTION;
00329         break;
00330     case NAV_60:
00331         if (sect->sct_effic < 60)
00332             return CN_CONSTRUCTION;
00333         break;
00334     default:
00335         return CN_LANDLOCKED;
00336     }
00337     return CN_NAVIGABLE;
00338 }
00339 
00340 int
00341 sect_has_dock(struct sctstr *sect)
00342 {
00343     switch (dchr[sect->sct_type].d_nav) {
00344     case NAV_02:
00345     case NAV_CANAL:
00346         return 1;
00347     default:
00348         return 0;
00349     }
00350 }
00351 
00352 static int
00353 shp_count(struct emp_qelem *list, int wantflags, int nowantflags,
00354           int x, int y)
00355 {
00356     struct emp_qelem *qp;
00357     struct emp_qelem *next;
00358     struct ulist *mlp;
00359     int count = 0;
00360 
00361     for (qp = list->q_back; qp != list; qp = next) {
00362         next = qp->q_back;
00363         mlp = (struct ulist *)qp;
00364         if (mlp->unit.ship.shp_x != x || mlp->unit.ship.shp_y != y)
00365             continue;
00366         if (wantflags &&
00367             (((struct mchrstr *)mlp->chrp)->m_flags & wantflags) != wantflags)
00368             continue;
00369         if (nowantflags &&
00370             ((struct mchrstr *)mlp->chrp)->m_flags & nowantflags)
00371             continue;
00372         ++count;
00373     }
00374     return count;
00375 }
00376 
00377 static void
00378 shp_damage_one(struct ulist *mlp, int dam)
00379 {
00380     shipdamage(&mlp->unit.ship, dam);
00381     putship(mlp->unit.ship.shp_uid, &mlp->unit.ship);
00382     if (!mlp->unit.ship.shp_own) {
00383         emp_remque((struct emp_qelem *)mlp);
00384         free(mlp);
00385     }
00386 }
00387 
00388 static int
00389 shp_damage(struct emp_qelem *list, int totdam, int wantflags,
00390            int nowantflags, int x, int y)
00391 {
00392     struct emp_qelem *qp;
00393     struct emp_qelem *next;
00394     struct ulist *mlp;
00395     int dam;
00396     int count;
00397 
00398     if (!totdam
00399         || !(count = shp_count(list, wantflags, nowantflags, x, y)))
00400         return 0;
00401     dam = ldround((double)totdam / count, 1);
00402     for (qp = list->q_back; qp != list; qp = next) {
00403         next = qp->q_back;
00404         mlp = (struct ulist *)qp;
00405         if (mlp->unit.ship.shp_x != x || mlp->unit.ship.shp_y != y)
00406             continue;
00407         if (wantflags &&
00408             (((struct mchrstr *)mlp->chrp)->m_flags & wantflags) != wantflags)
00409             continue;
00410         if (nowantflags &&
00411             ((struct mchrstr *)mlp->chrp)->m_flags & nowantflags)
00412             continue;
00413         shp_damage_one(mlp, dam);
00414     }
00415     return dam;
00416 }
00417 
00418 static int
00419 shp_contains(struct emp_qelem *list, int newx, int newy, int wantflags,
00420              int nowantflags)
00421 {
00422     struct emp_qelem *qp;
00423     struct emp_qelem *next;
00424     struct ulist *mlp;
00425 
00426     for (qp = list->q_back; qp != list; qp = next) {
00427         next = qp->q_back;
00428         mlp = (struct ulist *)qp;
00429 /* If the ship isn't in the requested sector, then continue */
00430         if (newx != mlp->unit.ship.shp_x || newy != mlp->unit.ship.shp_y)
00431             continue;
00432         if (wantflags &&
00433             (((struct mchrstr *)mlp->chrp)->m_flags & wantflags) != wantflags)
00434             continue;
00435         if (nowantflags &&
00436             ((struct mchrstr *)mlp->chrp)->m_flags & nowantflags)
00437             continue;
00438         return 1;
00439     }
00440     return 0;
00441 }
00442 
00443 static struct ulist *
00444 most_valuable_ship(struct emp_qelem *list)
00445 {
00446     struct emp_qelem *qp;
00447     struct emp_qelem *next;
00448     struct ulist *mlp;
00449     struct ulist *mvs = 0;
00450 
00451     for (qp = list->q_back; qp != list; qp = next) {
00452         next = qp->q_back;
00453         mlp = (struct ulist *)qp;
00454         if (((struct mchrstr *)mlp->chrp)->m_flags & M_SUB)
00455             continue;
00456         if (!((struct mchrstr *)mlp->chrp)->m_nxlight &&
00457             !((struct mchrstr *)mlp->chrp)->m_nchoppers &&
00458             ((struct mchrstr *)mlp->chrp)->m_cost < 1000 &&
00459             !((struct mchrstr *)mlp->chrp)->m_nplanes &&
00460             !((struct mchrstr *)mlp->chrp)->m_nland)
00461             continue;
00462         if (!mvs) {
00463             mvs = mlp;
00464             continue;
00465         }
00466         if (((struct mchrstr *)mlp->chrp)->m_cost * mlp->unit.ship.shp_effic >
00467             ((struct mchrstr *)mlp->chrp)->m_cost * mvs->unit.ship.shp_effic)
00468             mvs = mlp;
00469     }
00470     return mvs;
00471 }
00472 
00473 static int
00474 shp_easiest_target(struct emp_qelem *list, int wantflags, int nowantflags)
00475 {
00476     struct emp_qelem *qp;
00477     struct emp_qelem *next;
00478     struct ulist *mlp;
00479     int hard;
00480     int easiest = 9876;         /* things start great for victim */
00481     int count = 0;
00482 
00483     for (qp = list->q_back; qp != list; qp = next) {
00484         next = qp->q_back;
00485         mlp = (struct ulist *)qp;
00486         if (wantflags &&
00487             (((struct mchrstr *)mlp->chrp)->m_flags & wantflags) != wantflags)
00488             continue;
00489         if (nowantflags &&
00490             ((struct mchrstr *)mlp->chrp)->m_flags & nowantflags)
00491             continue;
00492         hard = shp_hardtarget(&mlp->unit.ship);
00493         if (hard < easiest)
00494             easiest = hard;     /* things get worse for victim */
00495         ++count;
00496     }
00497     return easiest - count;
00498 }
00499 
00500 static int
00501 shp_missile_interdiction(struct emp_qelem *list, coord newx, coord newy,
00502                          natid victim)
00503 {
00504     int dam;
00505     int twotries;
00506     int stopping = 0;
00507     struct emp_qelem msl_list, *qp, *newqp;
00508     struct ulist *mvs;
00509     char what[512];
00510 
00511     msl_sel(&msl_list, newx, newy, victim, P_T | P_MAR, 0, MI_INTERDICT);
00512 
00513     twotries = 0;
00514     while (!QEMPTY(&msl_list) && (mvs = most_valuable_ship(list))) {
00515         sprintf(what, "%s", prship(&mvs->unit.ship));
00516         dam = msl_launch_mindam(&msl_list, newx, newy,
00517                                 shp_hardtarget(&mvs->unit.ship),
00518                                 EF_SHIP, 1, what, victim, MI_INTERDICT);
00519         if (dam) {
00520             mpr(victim,
00521                 "missile interdiction mission does %d damage to %s!\n",
00522                 dam, what);
00523             shp_damage_one(mvs, dam);
00524             twotries = 0;
00525             stopping |= 1;
00526         } else if (++twotries >= 2) {
00527             break;
00528         }
00529     }
00530     qp = msl_list.q_forw;
00531     while (qp != msl_list.q_forw) {
00532         newqp = qp->q_forw;
00533         emp_remque(qp);
00534         free(qp);
00535         qp = newqp;
00536     }
00537 
00538     return stopping;
00539 }
00540 
00541 /* Note that this function has a side effect - it uses coastwatch
00542  * ranges to see if it should fire upon a ship.  So, this function
00543  * is expected to return positive if a ship is in range, and 0 if a
00544  * ship is not in range. */
00545 static int
00546 notify_coastguard(struct emp_qelem *list, int trange, struct sctstr *sectp)
00547 {
00548     struct emp_qelem *qp;
00549     struct emp_qelem *next;
00550     struct ulist *mlp;
00551     struct natstr *natp;
00552     int vrange;
00553 
00554     natp = getnatp(sectp->sct_own);
00555 
00556     vrange = sectp->sct_type == SCT_RADAR ? 14 : 4;
00557     vrange *= tfact(sectp->sct_own, 1.0) * sectp->sct_effic / 100.0;
00558 
00559     if (vrange < 1)
00560         vrange = 1;
00561 
00562     if (vrange < trange)
00563         return 0;
00564 
00565     for (qp = list->q_back; qp != list; qp = next) {
00566         next = qp->q_back;
00567         mlp = (struct ulist *)qp;
00568         if (((struct mchrstr *)mlp->chrp)->m_flags & M_SUB)
00569             continue;
00570         if (natp->nat_flags & NF_COASTWATCH)
00571             wu(0, sectp->sct_own,
00572                "%s %s sighted at %s\n",
00573                cname(mlp->unit.ship.shp_own),
00574                prship(&mlp->unit.ship),
00575                xyas(mlp->unit.ship.shp_x, mlp->unit.ship.shp_y,
00576                     sectp->sct_own));
00577         if (opt_HIDDEN)
00578             setcont(sectp->sct_own, mlp->unit.ship.shp_own, FOUND_COAST);
00579     }
00580 
00581     return 1;
00582 }
00583 
00584 static int
00585 shp_fort_interdiction(struct emp_qelem *list, coord newx, coord newy,
00586                       natid victim)
00587 {
00588     struct nstr_sect ns;
00589     struct sctstr fsect;
00590     int trange, range;
00591     double guneff;
00592     int shell, gun;
00593     int dam;
00594     int totdam = 0;
00595     signed char notified[MAXNOC];
00596     int i;
00597 
00598     /* Inform neutral and worse */
00599     for (i = 0; i < MAXNOC; ++i) {
00600         if (getrel(getnatp(i), victim) <= NEUTRAL)
00601             notified[i] = 0;
00602         else
00603             notified[i] = 1;
00604     }
00605 
00606     snxtsct_dist(&ns, newx, newy, fort_max_interdiction_range);
00607     while (nxtsct(&ns, &fsect)) {
00608         if (!fsect.sct_own)
00609             continue;
00610         if (fsect.sct_own == victim)
00611             continue;
00612         if (notified[fsect.sct_own])
00613             continue;
00614         trange = mapdist(newx, newy, fsect.sct_x, fsect.sct_y);
00615         if (notify_coastguard(list, trange, &fsect))
00616             notified[fsect.sct_own] = 1;
00617     }
00618     if (opt_NO_FORT_FIRE)
00619         return 0;               /* Only coastwatch notify in nofortfire */
00620     /* Only fire at Hostile ships */
00621     for (i = 0; i < MAXNOC; ++i) {
00622         if (getrel(getnatp(i), victim) >= NEUTRAL)
00623             notified[i] = 0;
00624     }
00625     snxtsct_dist(&ns, newx, newy, fort_max_interdiction_range);
00626     while (nxtsct(&ns, &fsect)) {
00627         if (!notified[fsect.sct_own])
00628             continue;
00629         gun = fsect.sct_item[I_GUN];
00630         if (gun < 1)
00631             continue;
00632         range = roundrange(fortrange(&fsect));
00633         trange = mapdist(newx, newy, fsect.sct_x, fsect.sct_y);
00634         if (trange > range)
00635             continue;
00636         if (fsect.sct_item[I_MILIT] < 5)
00637             continue;
00638         shell = fsect.sct_item[I_SHELL];
00639         if (shell < 1)
00640             shell += supply_commod(fsect.sct_own, fsect.sct_x, fsect.sct_y,
00641                                    I_SHELL, 1);
00642         if (shell < 1)
00643             continue;
00644         shell--;
00645         fsect.sct_item[I_SHELL] = shell;
00646         putsect(&fsect);
00647         if (gun > 7)
00648             gun = 7;
00649         guneff = landgun((int)fsect.sct_effic, gun);
00650         dam = (int)guneff;
00651         totdam += dam;
00652         mpr(victim, "Incoming fire does %d damage!\n", dam);
00653 /*
00654   mpr(victim, "%s fires at you for %d!\n",
00655   xyas(fsect.sct_x,fsect.sct_y,victim),
00656   dam);
00657 */
00658         wu(0, fsect.sct_own,
00659            "%s fires at %s ships in %s for %d!\n",
00660            xyas(fsect.sct_x, fsect.sct_y,
00661                 fsect.sct_own),
00662            cname(victim), xyas(newx, newy, fsect.sct_own), dam);
00663         nreport(fsect.sct_own, N_SHP_SHELL, victim, 1);
00664     }
00665     if (totdam > 0)
00666         return shp_damage(list, totdam, 0, M_SUB, newx, newy);
00667     return 0;
00668 }
00669 
00670 static int
00671 shp_interdict(struct emp_qelem *list, coord newx, coord newy, natid victim)
00672 {
00673     int stopping = 0;
00674 
00675     if (shp_contains(list, newx, newy, 0, M_SUB)) {
00676         stopping |= shp_fort_interdiction(list, newx, newy, victim);
00677 
00678         if (shp_contains(list, newx, newy, 0, M_SUB)) {
00679             stopping |=
00680                 shp_damage(list,
00681                            unit_interdict(newx, newy, victim, "ships",
00682                                           shp_easiest_target(list, 0, M_SUB),
00683                                           MI_INTERDICT),
00684                            0, M_SUB, newx, newy);
00685             if (most_valuable_ship(list)) {
00686                 stopping |=
00687                     shp_missile_interdiction(list, newx, newy, victim);
00688             }
00689         }
00690     }
00691     if (shp_contains(list, newx, newy, M_SUB, 0)) {
00692         stopping |=
00693             shp_damage(list,
00694                        unit_interdict(newx, newy, victim, "subs",
00695                                       shp_easiest_target(list, M_SUB, 0),
00696                                       MI_SINTERDICT),
00697                        M_SUB, 0, newx, newy);
00698     }
00699     return stopping;
00700 }
00701 
00702 /* high value of hardtarget is harder to hit */
00703 int
00704 shp_hardtarget(struct shpstr *sp)
00705 {
00706     struct sctstr sect;
00707     int vis, onsea;
00708     struct mchrstr *mcp = mchr + sp->shp_type;
00709 
00710     vis = sp->shp_visib;
00711     getsect(sp->shp_x, sp->shp_y, &sect);
00712     onsea = sect.sct_type == SCT_WATER;
00713     if (mcp->m_flags & M_SUB)
00714         vis *= 4;
00715     return (int)((sp->shp_effic / 100.0) *
00716                  (20 + sp->shp_speed * onsea / 2.0 - vis));
00717 }
00718 
00719 static int
00720 shp_hit_mine(struct shpstr *sp, struct mchrstr *mcp)
00721 {
00722     double m;
00723 
00724     mpr(sp->shp_own, "Kawhomp! Mine detected in %s!\n",
00725         xyas(sp->shp_x, sp->shp_y, sp->shp_own));
00726 
00727     nreport(sp->shp_own, N_HIT_MINE, 0, 1);
00728 
00729     m = MINE_DAMAGE();
00730     if (mcp->m_flags & M_SWEEP)
00731         m /= 2.0;
00732 
00733     shipdamage(sp, ldround(m, 1));
00734 
00735     return (int)m;
00736 }
00737 
00738 int
00739 shp_nav_one_sector(struct emp_qelem *list, int dir, natid actor,
00740                    int together)
00741 {
00742     struct sctstr sect;
00743     struct emp_qelem *qp;
00744     struct emp_qelem *next;
00745     struct ulist *mlp;
00746     struct emp_qelem done;
00747     coord dx;
00748     coord dy;
00749     coord newx;
00750     coord newy;
00751     int stopping = 0;
00752     double mobcost;
00753     double tech;                /* for mapping */
00754     double tf;                  /* for mapping */
00755     char dp[80];
00756     int navigate;
00757 
00758     if (dir <= DIR_STOP || dir >= DIR_VIEW) {
00759         unit_put(list, actor);
00760         return 1;
00761     }
00762     dx = diroff[dir][0];
00763     dy = diroff[dir][1];
00764     for (qp = list->q_back; qp != list; qp = next) {
00765         next = qp->q_back;
00766         mlp = (struct ulist *)qp;
00767         newx = xnorm(mlp->unit.ship.shp_x + dx);
00768         newy = ynorm(mlp->unit.ship.shp_y + dy);
00769         getsect(newx, newy, &sect);
00770         navigate = shp_check_nav(&sect, &mlp->unit.ship);
00771         if (navigate != CN_NAVIGABLE ||
00772             (sect.sct_own && actor != sect.sct_own &&
00773              getrel(getnatp(sect.sct_own), actor) < FRIENDLY)) {
00774             if (dchr[sect.sct_type].d_nav == NAV_CANAL &&
00775                 !(((struct mchrstr *)mlp->chrp)->m_flags & M_CANAL) &&
00776                 navigate == CN_LANDLOCKED)
00777                 sprintf(dp,
00778                         "is too large to fit into the canal system at %s",
00779                         xyas(newx, newy, actor));
00780             else
00781                 sprintf(dp, "can't go to %s", xyas(newx, newy, actor));
00782             if (together) {
00783                 mpr(actor, "%s\n", dp);
00784                 return 2;
00785             } else {
00786                 shp_mess(dp, mlp);
00787                 continue;
00788             }
00789         }
00790 
00791         if (mlp->mobil <= 0.0) {
00792             shp_mess("is out of mobility", mlp);
00793             continue;
00794         }
00795         mobcost = shp_mobcost(&mlp->unit.ship);
00796         mlp->unit.ship.shp_x = newx;
00797         mlp->unit.ship.shp_y = newy;
00798         if (mlp->mobil - mobcost < -127) {
00799             mlp->mobil = -127;
00800         } else {
00801             mlp->mobil -= mobcost;
00802         }
00803         mlp->unit.ship.shp_mobil = (int)mlp->mobil;
00804         putship(mlp->unit.ship.shp_uid, &mlp->unit.ship);
00805 
00806         /* Now update the map for this ship */
00807         tech = techfact(mlp->unit.ship.shp_tech,
00808                         ((struct mchrstr *)mlp->chrp)->m_vrnge);
00809         if (((struct mchrstr *)mlp->chrp)->m_flags & M_SONAR)
00810             tf = techfact(mlp->unit.ship.shp_tech, 1.0);
00811         else
00812             tf = 0.0;
00813         radmapupd(mlp->unit.ship.shp_own,
00814                   mlp->unit.ship.shp_x, mlp->unit.ship.shp_y,
00815                   (int)mlp->unit.ship.shp_effic, (int)tech, tf);
00816     }
00817     if (QEMPTY(list))
00818         return stopping;
00819     stopping |= shp_sweep(list, 0, 0, actor);
00820     if (QEMPTY(list))
00821         return stopping;
00822     stopping |= shp_check_mines(list);
00823     if (QEMPTY(list))
00824         return stopping;
00825 
00826     /* interdict ships sector by sector */
00827     emp_initque(&done);
00828     while (!QEMPTY(list)) {
00829         mlp = (struct ulist *)list->q_back;
00830         newx = mlp->unit.ship.shp_x;
00831         newy = mlp->unit.ship.shp_y;
00832         stopping |= shp_interdict(list, newx, newy, actor);
00833         /* move survivors in this sector to done */
00834         for (qp = list->q_back; qp != list; qp = next) {
00835             next = qp->q_back;
00836             mlp = (struct ulist *)qp;
00837             if (mlp->unit.ship.shp_x == newx &&
00838                 mlp->unit.ship.shp_y == newy) {
00839                 emp_remque(qp);
00840                 emp_insque(qp, &done);
00841             }
00842         }
00843     }
00844     /* assign surviving ships back to list */
00845     emp_insque(list, &done);
00846     emp_remque(&done);
00847 
00848     return stopping;
00849 }
00850 
00851 /*
00852  * shp_miss_defence 
00853  * Check for incoming missiles with a P_MAR flag. 
00854  * Return True=1 if the missile was shotdown.
00855  * Or False=0
00856  * 
00857  * Chad Zabel, July 95
00858  */
00859 
00860 int
00861 shp_missile_defense(coord dx, coord dy, natid bombown, int hardtarget)
00862 {
00863     struct nstr_item ni;
00864     struct shpstr ship;
00865     int hitchance;
00866     int shell;
00867     double gun, eff, teff;
00868 
00869     snxtitem_dist(&ni, EF_SHIP, dx, dy, 1);
00870 
00871     while (nxtitem(&ni, &ship)) {
00872         if (!ship.shp_own)
00873             continue;
00874 
00875         if (!(mchr[(int)ship.shp_type].m_flags & M_ANTIMISSILE))
00876             continue;
00877 
00878         if (getrel(getnatp(ship.shp_own), bombown) >= NEUTRAL)
00879             continue;
00880 
00881         if (ship.shp_effic < 60)
00882             continue;
00883 
00884         shell = ship.shp_item[I_SHELL];
00885         if (ship.shp_item[I_MILIT] < 1) /* do we have mil? */
00886             continue;
00887         if (shell < 2) {        /* do we need shells */
00888             shell += supply_commod(ship.shp_own, ship.shp_x, ship.shp_y,
00889                                    I_SHELL, 2);
00890             if (shell < 2)
00891                 continue;
00892         }
00893         if (ship.shp_item[I_GUN] < 1)   /* we need at least 1 gun */
00894             continue;
00895 
00896         /* now calculate the odds */
00897         gun = MIN(ship.shp_item[I_GUN], ship.shp_glim);
00898         eff = ship.shp_effic / 100.0;
00899         teff = ship.shp_tech / (ship.shp_tech + 200.0);
00900         /* raise 4.5 for better interception -KHS */
00901         hitchance = (int)(gun * eff * teff * 4.5) - hardtarget;
00902         if (hitchance < 0)
00903             hitchance = 0;
00904         if (hitchance > 100)
00905             hitchance = 100;
00906 
00907         mpr(bombown, "%s anti-missile system activated...",
00908             cname(ship.shp_own));
00909         mpr(ship.shp_own, "Ship #%i anti-missile system activated!\n",
00910             ship.shp_uid);
00911         mpr(ship.shp_own, "%d%% hitchance...", hitchance);
00912         /* use ammo */
00913         ship.shp_item[I_SHELL] = shell - 2;
00914         putship(ship.shp_uid, &ship);
00915 
00916         if (roll(100) <= hitchance) {
00917             mpr(bombown, "KABOOOM!! Missile destroyed\n\n");
00918             mpr(ship.shp_own,
00919                 "KABOOOM!!  Incoming missile destroyed!\n\n");
00920             return 1;
00921         } else {
00922             mpr(bombown, "SWOOSH!!  anti-missile system failed!!\n");
00923             mpr(ship.shp_own,
00924                 "SWOOSH!!  Missile evades anti-missile systems\n\n");
00925         }
00926     }
00927     return 0;                   /* all attempts failed */
00928 }
00929 
00930 
00931 /* Fire missiles at a ship which has fired shells */
00932 void
00933 shp_missdef(struct shpstr *sp, natid victim)
00934 {
00935     struct emp_qelem list;
00936     struct ulist *mlp;
00937     int eff;
00938     char buf[512];
00939 
00940     emp_initque(&list);
00941 
00942     mlp = malloc(sizeof(struct ulist));
00943     mlp->chrp = (struct empobj_chr *)&mchr[(int)sp->shp_type];
00944     mlp->unit.ship = *sp;
00945     mlp->mobil = sp->shp_mobil;
00946     emp_insque(&mlp->queue, &list);
00947     sprintf(buf, "%s", prship(&mlp->unit.ship));
00948 
00949     eff = sp->shp_effic;
00950     if (most_valuable_ship(&list)) {
00951         shp_missile_interdiction(&list, sp->shp_x, sp->shp_y, sp->shp_own);
00952         getship(sp->shp_uid, sp);
00953 
00954         if (!sp->shp_own) {
00955             wu(0, victim,
00956                "missiles launched in defense did 100%% damage to %s\n",
00957                buf);
00958             wu(0, victim, "%s sunk!\n", buf);
00959         } else if (eff > 0 && sp->shp_effic < eff) {
00960             wu(0, victim,
00961                "missiles launched in defense did %d%% damage to %s\n",
00962                100 * (eff - sp->shp_effic) / eff, buf);
00963         }
00964     }
00965     if (!QEMPTY(&list))
00966         free(mlp);
00967 }
00968 
00969 double
00970 shp_mobcost(struct shpstr *sp)
00971 {
00972     return speed_factor(sp->shp_effic * 0.01 * sp->shp_speed,
00973                         sp->shp_tech);
00974 }
00975 
00976 /*
00977  * Set SP's tech to TLEV along with everything else that depends on it.
00978  */
00979 void
00980 shp_set_tech(struct shpstr *sp, int tlev)
00981 {
00982     struct mchrstr *mcp = mchr + sp->shp_type;
00983     int tech_diff = tlev - mcp->m_tech;
00984 
00985     if (CANT_HAPPEN(tech_diff < 0)) {
00986       tlev -= tech_diff;
00987       tech_diff = 0;
00988     }
00989 
00990     sp->shp_tech = tlev;
00991     sp->shp_armor = (short)SHP_DEF(mcp->m_armor, tech_diff);
00992     sp->shp_speed = (short)SHP_SPD(mcp->m_speed, tech_diff);
00993     sp->shp_visib = (short)SHP_VIS(mcp->m_visib, tech_diff);
00994     sp->shp_frnge = (short)SHP_RNG(mcp->m_frnge, tech_diff);
00995     sp->shp_glim  = (short)SHP_FIR(mcp->m_glim, tech_diff);
00996 }

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