]> git.pond.sub.org Git - empserver/blobdiff - src/lib/subs/shpsub.c
Update copyright notice
[empserver] / src / lib / subs / shpsub.c
index 2c8423c3a35428ceb77e646aaf0a94513e9048b2..7b1902005679d4402fdfb6cd6f57f3736bded8a2 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  Empire - A multi-player, client/server Internet based war game.
- *  Copyright (C) 1986-2014, Dave Pare, Jeff Bailey, Thomas Ruschak,
+ *  Copyright (C) 1986-2020, Dave Pare, Jeff Bailey, Thomas Ruschak,
  *                Ken Stevens, Steve McClure, Markus Armbruster
  *
  *  Empire is free software: you can redistribute it and/or modify
@@ -29,7 +29,7 @@
  *  Known contributors to this file:
  *     Ken Stevens, 1995
  *     Steve McClure, 1996-2000
- *     Markus Armbruster, 2006-2014
+ *     Markus Armbruster, 2006-2015
  */
 
 #include <config.h>
@@ -38,7 +38,6 @@
 #include "chance.h"
 #include "damage.h"
 #include "empobj.h"
-#include "file.h"
 #include "map.h"
 #include "misc.h"
 #include "mission.h"
 #include "player.h"
 #include "prototypes.h"
 #include "queue.h"
-#include "server.h"
 #include "unit.h"
 #include "xy.h"
 
 static void shp_nav_put_one(struct ulist *);
 static int shp_check_one_mines(struct ulist *);
 static int shp_hit_mine(struct shpstr *);
-static void shp_stays(natid, char *, struct ulist *);
 
 static struct ulist *
 shp_find_capable(struct emp_qelem *list, int flags)
@@ -72,10 +69,56 @@ shp_find_capable(struct emp_qelem *list, int flags)
     return NULL;
 }
 
+int
+shp_may_nav(struct shpstr *sp, struct shpstr *flg, char *suffix)
+{
+    struct sctstr sect;
+
+    if (!sp->shp_own || !getsect(sp->shp_x, sp->shp_y, &sect)) {
+       CANT_REACH();
+       return 0;
+    }
+
+    if (opt_MARKET && ontradingblock(EF_SHIP, sp)) {
+       mpr(sp->shp_own, "%s is on the trading block%s\n",
+           prship(sp), suffix);
+       return 0;
+    }
+
+    if (sp->shp_item[I_MILIT] == 0 && sp->shp_item[I_CIVIL] == 0) {
+       mpr(sp->shp_own, "%s is crewless%s\n", prship(sp), suffix);
+       return 0;
+    }
+
+    switch (shp_check_nav(sp, &sect)) {
+    case SHP_STUCK_NOT:
+       break;
+    case SHP_STUCK_CONSTRUCTION:
+       mpr(sp->shp_own, "%s is caught in a construction zone%s\n",
+           prship(sp), suffix);
+       return 0;
+    default:
+       CANT_REACH();
+       /* fall through */
+    case SHP_STUCK_CANAL:
+    case SHP_STUCK_IMPASSABLE:
+       mpr(sp->shp_own, "%s is landlocked%s\n", prship(sp), suffix);
+       return 0;
+    }
+
+    if (flg && (sp->shp_x != flg->shp_x || sp->shp_y != flg->shp_y)) {
+       mpr(sp->shp_own, "%s is not with the flagship%s\n",
+           prship(sp), suffix);
+       return 0;
+    }
+    return 1;
+}
+
 void
 shp_sel(struct nstr_item *ni, struct emp_qelem *list)
 {
-    struct shpstr ship;
+    struct shpstr ship, *flg = NULL;
+    struct ulist *mlp;
 
     emp_initque(list);
     while (nxtitem(ni, &ship)) {
@@ -86,23 +129,21 @@ shp_sel(struct nstr_item *ni, struct emp_qelem *list)
         */
        if (!ship.shp_own || ship.shp_own != player->cnum)
            continue;
-       if (opt_MARKET) {
-           if (ontradingblock(EF_SHIP, &ship)) {
-               pr("ship #%d inelligible - it's for sale.\n",
-                  ship.shp_uid);
-               continue;
-           }
-       }
+       if (!shp_may_nav(&ship, flg, ""))
+           continue;
+
        ship.shp_mission = 0;
        ship.shp_rflags = 0;
        memset(ship.shp_rpath, 0, sizeof(ship.shp_rpath));
        putship(ship.shp_uid, &ship);
-       shp_insque(&ship, list);
+       mlp = shp_insque(&ship, list);
+       if (!flg)
+           flg = &mlp->unit.ship;
     }
 }
 
 /*
- * Append SP to LIST.
+ * Append @sp to @list.
  * Return the new list link.
  */
 struct ulist *
@@ -116,24 +157,21 @@ shp_insque(struct shpstr *sp, struct emp_qelem *list)
     return mlp;
 }
 
-/* This function assumes that the list was created by shp_sel */
 void
-shp_nav(struct emp_qelem *list, double *minmobp, double *maxmobp,
-       natid actor)
+shp_nav_stay_behind(struct emp_qelem *list, natid actor)
 {
     struct emp_qelem *qp;
     struct emp_qelem *next;
     struct ulist *mlp;
     struct shpstr *sp, *flg = NULL;
-    struct sctstr sect;
+    char and_stays[32];
 
-    *minmobp = 9876.0;
-    *maxmobp = -9876.0;
     for (qp = list->q_back; qp != list; qp = next) {
        next = qp->q_back;
        mlp = (struct ulist *)qp;
        sp = &mlp->unit.ship;
        getship(sp->shp_uid, sp);
+
        if (sp->shp_own != actor) {
            mpr(actor, "%s was sunk at %s\n",
                prship(sp), xyas(sp->shp_x, sp->shp_y, actor));
@@ -141,46 +179,23 @@ shp_nav(struct emp_qelem *list, double *minmobp, double *maxmobp,
            free(mlp);
            continue;
        }
-       /* check crew - uws don't count */
-       if (sp->shp_item[I_MILIT] == 0 && sp->shp_item[I_CIVIL] == 0) {
-           shp_stays(actor, "is crewless", mlp);
-           continue;
-       }
-       if (!getsect(sp->shp_x, sp->shp_y, &sect)) {
-           shp_stays(actor, "was sucked into the sky by a strange looking spaceship", mlp);    /* heh -KHS */
-           continue;
-       }
-       switch (shp_check_nav(sp, &sect)) {
-       case SHP_STUCK_NOT:
-           break;
-       case SHP_STUCK_CONSTRUCTION:
-           shp_stays(actor, "is caught in a construction zone", mlp);
-           continue;
-       default:
-           CANT_REACH();
-           /* fall through */
-       case SHP_STUCK_CANAL:
-       case SHP_STUCK_IMPASSABLE:
-           shp_stays(actor, "is landlocked", mlp);
+
+       snprintf(and_stays, sizeof(and_stays), " & stays in %s",
+                xyas(sp->shp_x, sp->shp_y, actor));
+       if (!shp_may_nav(sp, flg, and_stays)) {
+           shp_nav_put_one(mlp);
            continue;
        }
+
        if (!flg)
            flg = sp;
-       else if (sp->shp_x != flg->shp_x || sp->shp_y != flg->shp_y) {
-           shp_stays(actor, "is not with the flagship", mlp);
-           continue;
-       }
        if (sp->shp_mobil + 1 < (int)mlp->mobil) {
            mlp->mobil = sp->shp_mobil;
        }
-       if (mlp->mobil < *minmobp)
-           *minmobp = mlp->mobil;
-       if (mlp->mobil > *maxmobp)
-           *maxmobp = mlp->mobil;
     }
 }
 
-static void
+void
 shp_nav_put(struct emp_qelem *list, natid actor)
 {
     struct emp_qelem *qp, *next;
@@ -207,11 +222,11 @@ shp_nav_put_one(struct ulist *mlp)
 }
 
 /*
- * Sweep seamines with engineers in SHIP_LIST for ACTOR.
- * All ships in SHIP_LIST must be in the same sector.
- * If EXPLICIT is non-zero, this is for an explicit sweep command from
+ * Sweep sea mines with engineers in @ship_list for @actor.
+ * All ships in @ship_list must be in the same sector.
+ * If @explicit is non-zero, this is for an explicit sweep command from
  * a player.  Else it's an automatic "on the move" sweep.
- * If TAKEMOB is non-zero, require and charge mobility.
+ * If @takemob is non-zero, require and charge mobility.
  * Return non-zero when the ships should stop.
  */
 int
@@ -224,7 +239,7 @@ shp_sweep(struct emp_qelem *ship_list, int explicit, int takemob,
     struct sctstr sect;
     int mines, m, max, shells;
     int changed = 0;
-    int stopping = 0;
+    int stopping = 0, first = 1;
 
     mlp = shp_find_capable(ship_list, M_SWEEP);
     if (!mlp) {
@@ -236,7 +251,7 @@ shp_sweep(struct emp_qelem *ship_list, int explicit, int takemob,
     getsect(mlp->unit.ship.shp_x, mlp->unit.ship.shp_y, &sect);
     if (sect.sct_type != SCT_WATER) {
        if (explicit)
-           mpr(actor, "%s is a %s.  No seamines there!\n",
+           mpr(actor, "%s is a %s.  No sea mines there!\n",
               xyas(sect.sct_x, sect.sct_y, actor),
               dchr[sect.sct_type].d_name);
        return 0;
@@ -265,6 +280,11 @@ shp_sweep(struct emp_qelem *ship_list, int explicit, int takemob,
        shells = mlp->unit.ship.shp_item[I_SHELL];
        for (m = 0; mines > 0 && m < 5; m++) {
            if (chance(0.66)) {
+               if (first) {
+                   mpr(actor, "Approaching minefield at %s...\n",
+                       xyas(sect.sct_x, sect.sct_y, actor));
+                   first = 0;
+               }
                mpr(actor, "Sweep...\n");
                mines--;
                shells = MIN(max, shells + 1);
@@ -275,11 +295,7 @@ shp_sweep(struct emp_qelem *ship_list, int explicit, int takemob,
        mlp->unit.ship.shp_item[I_SHELL] = shells;
        putship(mlp->unit.ship.shp_uid, &mlp->unit.ship);
        putsect(&sect);
-       if (shp_check_one_mines(mlp)) {
-           stopping = 1;
-           emp_remque(qp);
-           free(qp);
-       }
+       stopping |= shp_check_one_mines(mlp);
     }
     if (changed)
        writemap(actor);
@@ -305,8 +321,11 @@ shp_check_one_mines(struct ulist *mlp)
            writemap(actor);
        putsect(&sect);
        putship(mlp->unit.ship.shp_uid, &mlp->unit.ship);
-       if (!mlp->unit.ship.shp_own)
-           return 1;
+       if (!mlp->unit.ship.shp_own) {
+           emp_remque(&mlp->queue);
+           free(mlp);
+       }
+       return 1;
     }
     return 0;
 }
@@ -316,33 +335,17 @@ shp_check_mines(struct emp_qelem *ship_list)
 {
     struct emp_qelem *qp;
     struct emp_qelem *next;
-    struct ulist *mlp;
     int stopping = 0;
 
     for (qp = ship_list->q_back; qp != ship_list; qp = next) {
        next = qp->q_back;
-       mlp = (struct ulist *)qp;
-       if (shp_check_one_mines(mlp)) {
-           stopping = 1;
-           emp_remque(qp);
-           free(qp);
-       }
+       stopping |= shp_check_one_mines((struct ulist *)qp);
     }
     return stopping;
 }
 
-
-static void
-shp_stays(natid actor, char *str, struct ulist *mlp)
-{
-    mpr(actor, "%s %s & stays in %s\n",
-       prship(&mlp->unit.ship), str,
-       xyas(mlp->unit.ship.shp_x, mlp->unit.ship.shp_y, actor));
-    shp_nav_put_one(mlp);
-}
-
 /*
- * Return whether and why SP would be stuck in SECTP.
+ * Return whether and why @sp would be stuck in @sectp.
  */
 enum shp_stuck
 shp_check_nav(struct shpstr *sp, struct sctstr *sectp)
@@ -564,13 +567,13 @@ shp_missile_interdiction(struct emp_qelem *list, coord newx, coord newy,
            if (msl_hit(&plp->plane,
                        shp_hardtarget(&mvs->unit.ship), EF_SHIP,
                        N_SHP_MISS, N_SHP_SMISS, sublaunch, victim)) {
-               dam = pln_damage(&plp->plane, 'p', 1);
+               dam = pln_damage(&plp->plane, 'p', "");
                mpr(victim,
                    "missile interdiction mission does %d damage to %s!\n",
                    dam, prship(&mvs->unit.ship));
                shp_damage_one(mvs, dam);
            } else {
-               dam = pln_damage(&plp->plane, 'p', 0);
+               dam = pln_damage(&plp->plane, 'p', NULL);
                collateral_damage(newx, newy, dam);
            }
            mvs = most_valuable_ship(list, newx, newy);
@@ -772,7 +775,7 @@ shp_hit_mine(struct shpstr *sp)
 }
 
 int
-shp_nav_one_sector(struct emp_qelem *list, int dir, natid actor)
+shp_nav_dir(struct emp_qelem *list, int dir, natid actor)
 {
     struct sctstr sect;
     struct emp_qelem *qp;
@@ -784,14 +787,13 @@ shp_nav_one_sector(struct emp_qelem *list, int dir, natid actor)
     coord newy;
     int move;
     enum shp_stuck stuck;
-    int stopping = 0;
     double mobcost;
-    char dp[80];
 
     if (CANT_HAPPEN(QEMPTY(list)))
        return 1;
 
-    if (dir <= DIR_STOP || dir >= DIR_VIEW) {
+    if (dir <= DIR_STOP || dir > DIR_LAST) {
+       CANT_HAPPEN(dir != DIR_STOP);
        shp_nav_put(list, actor);
        return 1;
     }
@@ -838,19 +840,26 @@ shp_nav_one_sector(struct emp_qelem *list, int dir, natid actor)
        mlp = (struct ulist *)qp;
        stuck = shp_check_nav(&mlp->unit.ship, &sect);
        if (stuck == SHP_STUCK_CANAL) {
-           sprintf(dp,
-                   "is too large to fit into the canal system at %s",
-                   xyas(newx, newy, actor));
-           shp_stays(actor, dp, mlp);
+           mpr(actor,
+               "%s is too large to fit into the canal system at %s"
+               " & stays in %s\n",
+               prship(&mlp->unit.ship), xyas(newx, newy, actor),
+               xyas(mlp->unit.ship.shp_x, mlp->unit.ship.shp_y, actor));
+           shp_nav_put_one(mlp);
            continue;
        } else if (CANT_HAPPEN(stuck != SHP_STUCK_NOT)) {
-           sprintf(dp, "can't go to %s", xyas(newx, newy, actor));
-           shp_stays(actor, dp, mlp);
+           mpr(actor, "%s can't go to %s & stays in %s\n",
+               prship(&mlp->unit.ship), xyas(newx, newy, actor),
+               xyas(mlp->unit.ship.shp_x, mlp->unit.ship.shp_y, actor));
+           shp_nav_put_one(mlp);
            continue;
        }
 
        if (mlp->mobil <= 0.0) {
-           shp_stays(actor, "is out of mobility", mlp);
+           mpr(actor, "%s is out of mobility & stays in %s\n",
+               prship(&mlp->unit.ship),
+               xyas(mlp->unit.ship.shp_x, mlp->unit.ship.shp_y, actor));
+           shp_nav_put_one(mlp);
            continue;
        }
        mobcost = shp_mobcost(&mlp->unit.ship);
@@ -863,22 +872,30 @@ shp_nav_one_sector(struct emp_qelem *list, int dir, natid actor)
        }
        mlp->unit.ship.shp_mobil = (int)mlp->mobil;
        putship(mlp->unit.ship.shp_uid, &mlp->unit.ship);
-
-       /* Now update the map for this ship */
-       rad_map_set(mlp->unit.ship.shp_own,
-                   mlp->unit.ship.shp_x, mlp->unit.ship.shp_y,
-                   mlp->unit.ship.shp_effic, mlp->unit.ship.shp_tech,
-                   mchr[mlp->unit.ship.shp_type].m_vrnge);
     }
+
+    return QEMPTY(list);
+}
+
+int
+shp_nav_gauntlet(struct emp_qelem *list, int interdict, natid actor)
+{
+    struct ulist *mlp = (struct ulist *)list->q_back;
+    coord newx, newy;
+    int stopping;
+
+    if (CANT_HAPPEN(QEMPTY(list)))
+       return 1;
+    newx = mlp->unit.ship.shp_x;
+    newy = mlp->unit.ship.shp_y;
+    stopping = shp_sweep(list, 0, 0, actor);
     if (QEMPTY(list))
-       return stopping;
-    stopping |= shp_sweep(list, 0, 0, actor);
-    if (QEMPTY(list))
-       return stopping;
+       return 1;
     stopping |= shp_check_mines(list);
     if (QEMPTY(list))
-       return stopping;
-    stopping |= shp_interdict(list, newx, newy, actor);
+       return 1;
+    if (interdict)
+       stopping |= shp_interdict(list, newx, newy, actor);
 
     return stopping;
 }
@@ -937,9 +954,9 @@ shp_missile_defense(coord dx, coord dy, natid bombown, int hardtarget)
            cname(ship.shp_own),
            hit ? "KABOOOM!! Missile destroyed\n"
            : "SWOOSH!!  anti-missile system failed!!");
-       mpr(ship.shp_own, "Ship #%i anti-missile system activated!\n",
+       mpr(ship.shp_own, "Ship #%d anti-missile system activated!\n",
            ship.shp_uid);
-       mpr(ship.shp_own, "%d%% hitchance...%s\n", hitchance,
+       mpr(ship.shp_own, "%d%% hit chance...%s\n", hitchance,
            hit ? "KABOOOM!!  Incoming missile destroyed!\n"
            : "SWOOSH!!  Missile evades anti-missile systems\n");
 
@@ -989,7 +1006,7 @@ shp_mobcost(struct shpstr *sp)
 }
 
 /*
- * Set SP's tech to TLEV along with everything else that depends on it.
+ * Set @sp's tech to @tlev along with everything else that depends on it.
  */
 void
 shp_set_tech(struct shpstr *sp, int tlev)