]> git.pond.sub.org Git - empserver/blobdiff - src/lib/subs/plnsub.c
Update copyright notice
[empserver] / src / lib / subs / plnsub.c
index cdc0c4828766bad864fa786108f0e4ffef7397ff..deebbe3dd9673f89851664dc37b5ad940b5c71e2 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  Empire - A multi-player, client/server Internet based war game.
- *  Copyright (C) 1986-2011, Dave Pare, Jeff Bailey, Thomas Ruschak,
+ *  Copyright (C) 1986-2016, Dave Pare, Jeff Bailey, Thomas Ruschak,
  *                Ken Stevens, Steve McClure, Markus Armbruster
  *
  *  Empire is free software: you can redistribute it and/or modify
  *     Dave Pare, 1986
  *     Ken Stevens, 1995
  *     Steve McClure, 1998-2000
- *     Markus Armbruster, 2004-2010
+ *     Markus Armbruster, 2004-2015
  */
 
 #include <config.h>
 
+#include "chance.h"
+#include "empobj.h"
 #include "file.h"
 #include "item.h"
 #include "land.h"
@@ -44,6 +46,7 @@
 #include "nsc.h"
 #include "nuke.h"
 #include "optlist.h"
+#include "plague.h"
 #include "plane.h"
 #include "player.h"
 #include "prototypes.h"
 #include "ship.h"
 #include "xy.h"
 
-static int fit_plane_on_ship(struct plnstr *, struct shpstr *);
+static int ship_can_carry(struct shpstr *, int, int, int, int);
+static int inc_shp_nplane(struct plnstr *, int *, int *, int *);
 
 /*
  * Get planes and escorts argument.
- * Read planes into *NI_BOMB, and (optional) escorts into *NI_ESC.
- * If INPUT_BOMB is not empty, use it, else prompt for more input.
- * Same for INPUT_ESC.
- * If we got a plane argument, initialize *NI_BOMB and *NI_ESC, and
+ * Read planes into *@ni_bomb, and (optional) escorts into *@ni_esc.
+ * If @input_bomb is not empty, use it, else prompt for more input.
+ * Same for @input_esc.
+ * If we got a plane argument, initialize *@ni_bomb and *@ni_esc, and
  * return 0.
- * Else return -1 (*NI_BOMB and *NI_ESC may be modified).
+ * Else return -1 (*@ni_bomb and *@ni_esc may be modified).
  */
 int
 get_planes(struct nstr_item *ni_bomb, struct nstr_item *ni_esc,
@@ -78,11 +82,12 @@ get_planes(struct nstr_item *ni_bomb, struct nstr_item *ni_esc,
 
 /*
  * Get assembly point argument.
- * If INPUT is not empty, use it, else prompt for more input using PROMPT.
- * If this yields a valid assembly point, read it into *AP_SECT and
- * return AP_SECT.
+ * If @input is not empty, use it.
+ * Else prompt for more input using @prompt.
+ * If this yields a valid assembly point, read it into *@ap_sect and
+ * return @ap_sect.
  * Else complain and return NULL.
- * *AP_SECT and BUF[1024] may be modified in either case.
+ * *@ap_sect and @buf[1024] may be modified in either case.
  */
 struct sctstr *
 get_assembly_point(char *input, struct sctstr *ap_sect, char *buf)
@@ -115,20 +120,25 @@ get_assembly_point(char *input, struct sctstr *ap_sect, char *buf)
     return NULL;
 }
 
+/*
+ * Find out whether planes can fly one-way to @x,@y.
+ * Offer the player any carriers there.  If he chooses one, read it
+ * into @target->ship.  Else read the target sector into @target->sect.
+ * If planes can land there, set required plane flags in *@flagsp, and
+ * return 0.  Else return -1.
+ */
 int
-pln_onewaymission(struct sctstr *target, int *shipno, int *flagp)
+pln_where_to_land(coord x, coord y,
+                 union empobj_storage *target, int *flagsp)
 {
     int nships;
     int cno;
-    int flags, fl;
-    struct shpstr ship;
+    int fl;
     char buf[1024];
     char *p;
 
-    flags = *flagp;
-
     /* offer carriers */
-    nships = carriersatxy(target->sct_x, target->sct_y, player->cnum);
+    nships = carriersatxy(x, y, player->cnum);
     if (nships) {
        for (;;) {
            p = getstring("Carrier #? ", buf);
@@ -137,63 +147,56 @@ pln_onewaymission(struct sctstr *target, int *shipno, int *flagp)
            if (!*p)
                break;
            cno = atoi(p);
-           if (cno < 0
-               || !getship(cno, &ship)
+           if (!getship(cno, &target->ship)
                || (!player->owner
-                   && (relations_with(ship.shp_own, player->cnum)
+                   && (relations_with(target->ship.shp_own, player->cnum)
                        != ALLIED))) {
                pr("Not yours\n");
                continue;
            }
-           if (ship.shp_x != target->sct_x || ship.shp_y != target->sct_y) {
-               pr("Ship #%d not in %s\n", cno,
-                  xyas(target->sct_x, target->sct_y, player->cnum));
+           if (target->ship.shp_x != x || target->ship.shp_y != y) {
+               pr("Ship #%d not in %s\n", cno, xyas(x, y, player->cnum));
                continue;
            }
-           fl = carrier_planes(&ship, 0);
+           fl = carrier_planes(&target->ship, 0);
            if (fl == 0) {
-               pr("Can't land on %s.\n", prship(&ship));
+               pr("Can't land on %s.\n", prship(&target->ship));
                continue;
            }
            /* clear to land on ship#CNO */
            pr("landing on carrier %d\n", cno);
-           flags |= fl;
-           *shipno = cno;
-           *flagp = flags;
+           *flagsp |= fl;
            return 0;
        }
     }
 
     /* try to land at sector */
-    if (relations_with(target->sct_own, player->cnum) != ALLIED) {
-       pr("Nowhere to land at sector %s!\n",
-          xyas(target->sct_x, target->sct_y, player->cnum));
+    getsect(x, y, &target->sect);
+    if (relations_with(target->sect.sct_own, player->cnum) != ALLIED) {
+       pr("Nowhere to land at sector %s!\n", xyas(x, y, player->cnum));
        return -1;
     }
-    if (target->sct_type == SCT_MOUNT) {
-       pr("Nowhere to land at sector %s!\n",
-          xyas(target->sct_x, target->sct_y, player->cnum));
+    if (target->sect.sct_type == SCT_MOUNT) {
+       pr("Nowhere to land at sector %s!\n", xyas(x, y, player->cnum));
        return -1;
     }
-    if (target->sct_type != SCT_AIRPT || target->sct_effic < 60)
-       flags |= P_V;
-
     /* clear to land at sector */
-    *shipno = -1;
-    *flagp = flags;
+    if (target->sect.sct_type != SCT_AIRPT || target->sect.sct_effic < 60)
+       *flagsp |= P_V;
     return 0;
 }
 
 int
-pln_oneway_to_carrier_ok(struct emp_qelem *bomb_list,
-                        struct emp_qelem *esc_list, int cno)
+pln_can_land_on_carrier(struct emp_qelem *bomb_list,
+                       struct emp_qelem *esc_list,
+                       struct shpstr *sp)
+
 {
+    int n, nch, nxl, nmsl;
     struct emp_qelem *list, *qp;
     struct plist *plp;
-    struct shpstr ship;
 
-    if (cno < 0 || !getship(cno, &ship))
-       return 0;
+    n = shp_nplane(sp, &nch, &nxl, &nmsl);
 
     /* for both lists */
     for (list = bomb_list;
@@ -201,13 +204,14 @@ pln_oneway_to_carrier_ok(struct emp_qelem *bomb_list,
         list = list == bomb_list ? esc_list : NULL) {
        for (qp = list->q_forw; qp != list; qp = qp->q_forw) {
            plp = (struct plist *)qp;
-           if (plp->plane.pln_ship == ship.shp_uid)
+           if (plp->plane.pln_ship == sp->shp_uid)
                continue;
-           if (!fit_plane_on_ship(&plp->plane, &ship))
+           n++;
+           if (!inc_shp_nplane(&plp->plane, &nch, &nxl, &nmsl))
                return 0;
        }
     }
-    return 1;
+    return ship_can_carry(sp, n, nch, nxl, nmsl);
 }
 
 void
@@ -223,7 +227,7 @@ pln_newlanding(struct emp_qelem *list, coord tx, coord ty, int cno)
     for (qp = list->q_forw; qp != list; qp = qp->q_forw) {
        plp = (struct plist *)qp;
        if (cno >= 0) {
-           if (!could_be_on_ship(&plp->plane, &ship, 0, 0, 0, 0))
+           if (!could_be_on_ship(&plp->plane, &ship))
                pr("\t%s cannot land on ship #%d! %s aborts!\n",
                   prplane(&plp->plane), cno, prplane(&plp->plane));
            else if (!put_plane_on_ship(&plp->plane, &ship))
@@ -235,6 +239,9 @@ pln_newlanding(struct emp_qelem *list, coord tx, coord ty, int cno)
                       cname(player->cnum), prplane(&plp->plane),
                       prship(&ship));
                }
+               if (plp->pcp->pl_crew && plp->pstage == PLG_INFECT
+                   && ship.shp_pstage == PLG_HEALTHY)
+                   ship.shp_pstage = PLG_EXPOSED;
            }
        } else {
            plp->plane.pln_x = tx;
@@ -246,6 +253,9 @@ pln_newlanding(struct emp_qelem *list, coord tx, coord ty, int cno)
                   cname(player->cnum),
                   prplane(&plp->plane), xyas(tx, ty, sect.sct_own));
            }
+           if (plp->pcp->pl_crew && plp->pstage == PLG_INFECT
+               && sect.sct_pstage == PLG_HEALTHY)
+               sect.sct_pstage = PLG_EXPOSED;
            plp->plane.pln_ship = cno;
        }
     }
@@ -262,14 +272,10 @@ pln_dropoff(struct emp_qelem *list, struct ichrstr *ip, coord tx, coord ty,
     struct shpstr ship;
     int there;
     int max;
+    int pstage;
 
     if (!ip)
        return;
-    amt = 0;
-    for (qp = list->q_forw; qp != list; qp = qp->q_forw) {
-       plp = (struct plist *)qp;
-       amt += plp->load;
-    }
     if (cno < 0) {
        getsect(tx, ty, &sect);
        if (!sect.sct_own) {
@@ -291,11 +297,23 @@ pln_dropoff(struct emp_qelem *list, struct ichrstr *ip, coord tx, coord ty,
        }
        there = sect.sct_item[ip->i_uid];
        max = ITEM_MAX;
+       pstage = sect.sct_pstage;
     } else {
        getship(cno, &ship);
        there = ship.shp_item[ip->i_uid];
        max = mchr[ship.shp_type].m_item[ip->i_uid];
+       pstage = ship.shp_pstage;
     }
+
+    amt = 0;
+    for (qp = list->q_forw; qp != list; qp = qp->q_forw) {
+       plp = (struct plist *)qp;
+       amt += plp->load;
+       if (plp->load
+           && plp->pstage == PLG_INFECT && pstage == PLG_HEALTHY)
+           pstage = PLG_EXPOSED;
+    }
+
     there += amt;
     if (there > max) {
        pr("%d excess %s discarded\n", there - max, ip->i_name);
@@ -305,6 +323,7 @@ pln_dropoff(struct emp_qelem *list, struct ichrstr *ip, coord tx, coord ty,
     pr("%d %s landed safely", amt, ip->i_name);
     if (cno < 0) {
        sect.sct_item[ip->i_uid] = there;
+       sect.sct_pstage = pstage;
        if (sect.sct_own != player->cnum)
            wu(0, sect.sct_own, "%s planes drop %d %s in %s\n",
               cname(player->cnum), amt, ip->i_name,
@@ -313,6 +332,7 @@ pln_dropoff(struct emp_qelem *list, struct ichrstr *ip, coord tx, coord ty,
        putsect(&sect);
     } else {
        ship.shp_item[ip->i_uid] = there;
+       ship.shp_pstage = pstage;
        if (ship.shp_own != player->cnum)
            wu(0, ship.shp_own, "%s planes land %d %s on carrier %d\n",
               cname(player->cnum), amt, ip->i_name, ship.shp_uid);
@@ -350,13 +370,13 @@ pln_mine(struct emp_qelem *list, coord tx, coord ty)
 }
 
 /*
- * Has PP's type capabilities satisfying WANTFLAGS and NOWANTFLAGS?
+ * Has @pp's type capabilities satisfying @wantflags and @nowantflags?
  * A plane type is capable unless
- * - it lacks all of the P_B, P_T in WANTFLAGS, or
- * - it lacks all of the P_F, P_ESC in WANTFLAGS, or
- * - it lacks all of the P_E, P_L, P_K in WANTFLAGS, or
- * - it lacks any of the other capabilities in WANTFLAGS, or
- * - it has any of the capabilities in NOWANTFLAGS.
+ * - it lacks all of the P_B, P_T in @wantflags, or
+ * - it lacks all of the P_F, P_ESC in @wantflags, or
+ * - it lacks all of the P_E, P_L, P_K in @wantflags, or
+ * - it lacks any of the other capabilities in @wantflags, or
+ * - it has any of the capabilities in @nowantflags.
  */
 int
 pln_capable(struct plnstr *pp, int wantflags, int nowantflags)
@@ -391,7 +411,7 @@ pln_capable(struct plnstr *pp, int wantflags, int nowantflags)
 }
 
 /*
- * Return union of capabilities of planes in LIST.
+ * Return union of capabilities of planes in @list.
  */
 int
 pln_caps(struct emp_qelem *list)
@@ -410,10 +430,10 @@ pln_caps(struct emp_qelem *list)
 }
 
 /*
- * Find plane types that can operate from carrier SP.
- * If MSL find missile types, else non-missile types.
+ * Find plane types that can operate from carrier @sp.
+ * If @msl find missile types, else non-missile types.
  * Return a combination of P_L, P_K, P_E.
- * It's zero if SP can't support air operations due to its type or
+ * It's zero if @sp can't support air operations due to its type or
  * state (low efficiency).
  */
 int
@@ -575,6 +595,7 @@ pln_sel(struct nstr_item *ni, struct emp_qelem *list, struct sctstr *ap,
        putplane(plane.pln_uid, &plane);
        plp = malloc(sizeof(struct plist));
        plp->load = 0;
+       plp->pstage = PLG_HEALTHY;
        plp->pcp = pcp;
        plp->plane = plane;
        emp_insque(&plp->queue, list);
@@ -625,14 +646,17 @@ pln_equip(struct plist *plp, struct ichrstr *ip, char mission)
     pcp = plp->pcp;
     if (pp->pln_ship >= 0) {
        getship(pp->pln_ship, &ship);
+       plp->pstage = ship.shp_pstage;
        item = ship.shp_item;
        own = ship.shp_own;
     } else if (pp->pln_land >= 0) {
        getland(pp->pln_land, &land);
+       plp->pstage = land.lnd_pstage;
        item = land.lnd_item;
        own = land.lnd_own;
     } else {
        getsect(pp->pln_x, pp->pln_y, &sect);
+       plp->pstage = sect.sct_pstage;
        item = sect.sct_item;
        own = sect.sct_oldown;
     }
@@ -814,29 +838,16 @@ pln_put1(struct plist *plp)
 }
 
 /*
- * Can PP be loaded on a ship of SP's type?
- * Assume that it already carries N planes, of which NCH are choppers,
- * NXL xlight, NMSL light missiles, and the rest are light fixed-wing
+ * Can a carrier of @sp's type carry this load of planes?
+ * The load consists of @n planes, of which @nch are choppers, @nxl
+ * xlight, @nmsl light missiles, and the rest are light fixed-wing
  * planes.
  */
-int
-could_be_on_ship(struct plnstr *pp, struct shpstr *sp,
-                int n, int nch, int nxl, int nmsl)
+static int
+ship_can_carry(struct shpstr *sp, int n, int nch, int nxl, int nmsl)
 {
-    struct plchrstr *pcp = &plchr[pp->pln_type];
     struct mchrstr *mcp = &mchr[sp->shp_type];
-    int nfw;
-
-    if (pcp->pl_flags & P_K)
-       nch++;
-    else if (pcp->pl_flags & P_E)
-       nxl++;
-    else if (!(pcp->pl_flags & P_L))
-       return 0;
-    else if (pcp->pl_flags & P_M)
-       nmsl++;
-    n++;
-    nfw = n - nch - nxl - nmsl;
+    int nfw = n - nch - nxl - nmsl;
 
     if (nch > mcp->m_nchoppers) /* overflow into fixed-wing slots */
        nfw += nch - mcp->m_nchoppers;
@@ -850,27 +861,54 @@ could_be_on_ship(struct plnstr *pp, struct shpstr *sp,
 }
 
 /*
- * Fit a plane of PP's type on ship SP.
- * Updating the plane accordingly is the caller's job.
- * Return whether it fits.
+ * Increment carrier plane counters for @pp.
+ * If it's a chopper, increment *@nch.
+ * Else, if it's x-light, increment *@nxl.
+ * Else, if it's a light missile, increment *@msl.
+ * Return non-zero if it's a chopper, x-light or light.
  */
 static int
-fit_plane_on_ship(struct plnstr *pp, struct shpstr *sp)
+inc_shp_nplane(struct plnstr *pp, int *nch, int *nxl, int *nmsl)
 {
-    int n, nch, nxl, nmsl;
+    struct plchrstr *pcp = &plchr[pp->pln_type];
 
-    n = shp_nplane(sp, &nch, &nxl, &nmsl);
-    return could_be_on_ship(pp, sp, n, nch, nxl, nmsl);
+    if (pcp->pl_flags & P_K)
+       (*nch)++;
+    else if (pcp->pl_flags & P_E)
+       (*nxl)++;
+    else if (!(pcp->pl_flags & P_L))
+       return 0;
+    else if (pcp->pl_flags & P_M)
+       (*nmsl)++;
+    return 1;
+}
+
+/*
+ * Can @pp be loaded on a ship of @sp's type?
+ */
+int
+could_be_on_ship(struct plnstr *pp, struct shpstr *sp)
+{
+    int nch = 0, nxl = 0, nmsl = 0;
+
+    if (!inc_shp_nplane(pp, &nch, &nxl, &nmsl))
+       return 0;
+    return ship_can_carry(sp, 1, nch, nxl, nmsl);
 }
 
 int
 put_plane_on_ship(struct plnstr *plane, struct shpstr *ship)
 {
+    int n, nch, nxl, nmsl;
+
     if (plane->pln_ship == ship->shp_uid)
        return 1;               /* Already on ship */
 
-    if (!fit_plane_on_ship(plane, ship))
-       return 0;
+    n = shp_nplane(ship, &nch, &nxl, &nmsl);
+    if (!inc_shp_nplane(plane, &nch, &nxl, &nmsl))
+       return 0;               /* not a carrier plane */
+    if (!ship_can_carry(ship, n + 1, nch, nxl, nmsl))
+       return 0;               /* no space */
 
     plane->pln_x = ship->shp_x;
     plane->pln_y = ship->shp_y;
@@ -879,27 +917,14 @@ put_plane_on_ship(struct plnstr *plane, struct shpstr *ship)
     return 1;
 }
 
-/*
- * Fit a plane of PP's type on land unit LP.
- * Updating the plane accordingly is the caller's job.
- * Return whether it fits.
- */
-static int
-fit_plane_on_land(struct plnstr *pp, struct lndstr *lp)
-{
-    struct plchrstr *pcp = plchr + pp->pln_type;
-    struct lchrstr *lcp = lchr + lp->lnd_type;
-
-    return (pcp->pl_flags & P_E) && lnd_nxlight(lp) < lcp->l_nxlight;
-}
-
 int
 put_plane_on_land(struct plnstr *plane, struct lndstr *land)
 {
     if (plane->pln_land == land->lnd_uid)
        return 1;               /* Already on unit */
-
-    if (!fit_plane_on_land(plane, land))
+    if (!(plchr[plane->pln_type].pl_flags & P_E))
+       return 0;
+    if (lnd_nxlight(land) >= lchr[land->lnd_type].l_nxlight)
        return 0;
 
     plane->pln_x = land->lnd_x;
@@ -980,7 +1005,7 @@ pln_hitchance(struct plnstr *pp, int hardtarget, int type)
 }
 
 int
-pln_damage(struct plnstr *pp, char type, int noisy)
+pln_damage(struct plnstr *pp, char type, char *noisy)
 {
     struct plchrstr *pcp = plchr + pp->pln_type;
     int load, i, hitroll, aim, len;
@@ -1015,8 +1040,14 @@ pln_damage(struct plnstr *pp, char type, int noisy)
        aim = 100 - aim;
     }
 
-    len = 0;
+    len = snprintf(buf, sizeof(buf), "%s", noisy);
     while (i--) {
+       if (noisy) {
+           if (len > 75) {
+               mpr(pp->pln_own, "%s\n", buf);
+               len = 0;
+           }
+       }
        dam += roll(6);
        hitroll = roll(100);
        if (hitroll >= 90) {
@@ -1033,10 +1064,6 @@ pln_damage(struct plnstr *pp, char type, int noisy)
                len += sprintf(buf + len, "blam");
        }
        if (noisy) {
-           if (len > 75) {
-               mpr(pp->pln_own, "%s\n", buf);
-               len = 0;
-           }
            if (i)
                len += sprintf(buf + len, "-");
        }
@@ -1076,7 +1103,7 @@ pln_is_in_orbit(struct plnstr *pp)
 }
 
 /*
- * Set PP's tech to TLEV along with everything else that depends on it.
+ * Set @pp's tech to @tlev along with everything else that depends on it.
  */
 void
 pln_set_tech(struct plnstr *pp, int tlev)