]> git.pond.sub.org Git - empserver/commitdiff
Redesign automatic supply interface
authorMarkus Armbruster <armbru@pond.sub.org>
Sat, 14 Feb 2009 18:00:01 +0000 (19:00 +0100)
committerMarkus Armbruster <armbru@pond.sub.org>
Tue, 17 Feb 2009 18:31:37 +0000 (19:31 +0100)
The automatic supply interface has design flaws that make it hard to
use correctly.  Its current uses are in fact all wrong (until commit
0179fd86, the update had a few uses that might have been correct).
Some of the bugs can only bite with land unit capability combinations
that don't exist in the stock game, though.

Automatic supply draws supplies from supply sources in range.  Since
that can update any supply source in range, all copies of potential
supply sources a caller may keep can get invalidated.  Writing back
such an invalid copy wipes out the deduction of supplies and mobility
from a source, triggering a seqno mismatch oops.

This commit redesigns the interface so that callers can safely keep a
copy of the object drawing the supplies (the "supply sink").  The idea
is to pass the sink to the supply code, so it can avoid using it as
source.  The actual avoiding will be implemented in a later commit.

Copies other than the supply sink still need to be eliminated.  See
commit 65410d16 for an example.

Other improvements to help avoid common errors:

* Supply functions are commonly used to ensure the sink has a certain
  amount of supplies.  A common error is to fetch that amount
  regardless of how many the sink already has.  It's more convenient
  for such users to pass how many they need to have instead of how
  many to get.

* A common use of supply functions is to get supplies for immediate
  use.  If that use turns out not to be possible after all, the
  supplies need to be added somewhere, which is all too easy to
  forget.  Many bugs of this kind have been fixed over time, and there
  are still some left.  This class of bugs can be avoided by adding
  the supplies to the sink automatically.

In fact, this commit fixes precisely such bugs in mission_pln_equip()
and shp_missile_defense(): plane interception and support missions,
missile interception (abms), launch of ballistic missiles and
anti-sats could all lose shells, or supply more than needed.

Replace supply_commod() by new sct_supply(), shp_supply(),
lnd_supply(), and resupply_all() by new lnd_supply_all().  Simplify
users accordingly.

There's just one use of resupply_commod() left, in landmine().  Use
lnd_supply_all() there, and remove resupply_commod().

include/prototypes.h
src/lib/commands/load.c
src/lib/commands/mine.c
src/lib/commands/supp.c
src/lib/subs/attsub.c
src/lib/subs/landgun.c
src/lib/subs/mission.c
src/lib/subs/shpsub.c
src/lib/subs/supply.c

index 1d3ac26fc1a30e1e167a7754dd0bbe197164d0cc..667430e74f76c8922deafdc5f7084bbc467f9aa1 100644 (file)
@@ -679,9 +679,10 @@ extern void snxtsct_all(struct nstr_sect *);
 extern void snxtsct_rewind(struct nstr_sect *);
 extern void snxtsct_dist(struct nstr_sect *, coord, coord, int);
 /* supply.c */
-extern void resupply_all(struct lndstr *);
-extern void resupply_commod(struct lndstr *, i_type);
-extern int supply_commod(int, int, int, i_type, int);
+extern int sct_supply(struct sctstr *, i_type, int);
+extern int shp_supply(struct shpstr *, i_type, int);
+extern int lnd_supply(struct lndstr *, i_type, int);
+extern int lnd_supply_all(struct lndstr *);
 extern int lnd_in_supply(struct lndstr *);
 extern int lnd_could_be_supplied(struct lndstr *);
 /* takeover.c */
index b809a08b59f65baec1184798d6b9ccc882291267..fcdb8ffaf67ed34d2c6f77aff70d771c59b6d181 100644 (file)
@@ -644,17 +644,19 @@ load_land_ship(struct sctstr *sectp, struct shpstr *sp, int noisy,
            gift(sp->shp_own, player->cnum, &land, buf);
            land.lnd_ship = sp->shp_uid;
            land.lnd_harden = 0;
+           putland(land.lnd_uid, &land);
 #if 0
            /*
             * FIXME if this supplies from the sector, the putsect in
             * load() / lload() duplicates those supplies, causing a
             * seqno mismatch
             */
-           resupply_all(&land);
-#endif
-           putland(land.lnd_uid, &land);
+           if (!lnd_supply_all(&land))
+               pr("WARNING: %s is out of supply!\n", prland(&land));
+#else
            if (!lnd_in_supply(&land))
                pr("WARNING: %s is out of supply!\n", prland(&land));
+#endif
        } else {
            sprintf(buf, "unloaded in your %s at %s",
                    dchr[sectp->sct_type].d_name,
@@ -994,13 +996,15 @@ load_land_land(struct sctstr *sectp, struct lndstr *lp, int noisy,
            gift(lp->lnd_own, player->cnum, &land, buf);
            land.lnd_land = lp->lnd_uid;
            land.lnd_harden = 0;
+           putland(land.lnd_uid, &land);
 #if 0
            /* FIXME same issue as in load_land_ship() */
-           resupply_all(&land);
-#endif
-           putland(land.lnd_uid, &land);
+           if (!lnd_supply_all(&land))
+               pr("WARNING: %s is out of supply!\n", prland(&land));
+#else
            if (!lnd_in_supply(&land))
                pr("WARNING: %s is out of supply!\n", prland(&land));
+#endif
        } else {
            sprintf(buf, "unloaded in your %s at %s",
                    dchr[sectp->sct_type].d_name,
index 3d97136a04de98dc8ec35fbdf64a08644df5ecf1..bf232098553697f9a68d23db878d57f40c93e15b 100644 (file)
@@ -94,7 +94,7 @@ landmine(void)
     struct lndstr land;
     struct sctstr sect;
     struct nstr_item ni;
-    int shells, todo;
+    int todo;
     int mines_wanted;
     int mines_laid;
     int total_mines_laid;
@@ -137,20 +137,15 @@ landmine(void)
        todo = MIN(mines_wanted, land.lnd_mobil);
        total_mines_laid = 0;
        do {
-           shells = land.lnd_item[I_SHELL];
-           if (shells < todo)
-               shells += supply_commod(land.lnd_own,
-                                       land.lnd_x, land.lnd_y, I_SHELL,
-                                       todo - shells);
-           mines_laid = MIN(todo, shells);
-           land.lnd_item[I_SHELL] = shells - mines_laid;
+           lnd_supply(&land, I_SHELL, todo);
+           mines_laid = MIN(todo, land.lnd_item[I_SHELL]);
+           land.lnd_item[I_SHELL] -= mines_laid;
            land.lnd_mobil -= mines_laid;
            putland(land.lnd_uid, &land);
            total_mines_laid += mines_laid;
            todo -= mines_laid;
        } while (todo && mines_laid);
-       resupply_commod(&land, I_SHELL);
-       putland(land.lnd_uid, &land);
+       lnd_supply_all(&land);
        getsect(sect.sct_x, sect.sct_y, &sect);
        sect.sct_mines = MIN(sect.sct_mines + total_mines_laid, MINES_MAX);
        putsect(&sect);
index 61f64c041104039196ef3462556350561ca22849..5eed7a5cf50b5fda920be675df45cb5a4bbb2e7f 100644 (file)
@@ -51,9 +51,7 @@ supp(void)
        if (!player->owner || land.lnd_own == 0)
            continue;
        nunits++;
-       resupply_all(&land);
-       putland(land.lnd_uid, &land);
-       if (lnd_in_supply(&land))
+       if (lnd_supply_all(&land))
            pr("%s has supplies\n", prland(&land));
        else
            pr("%s is out of supply\n", prland(&land));
index 7f47f1323057d6073e0e1e00d7fc6b30027250fb..ce6ac812089a3210b6df5aed62f6e8f9deda6fee 100644 (file)
@@ -1072,9 +1072,7 @@ ask_olist(int combat_mode, struct combat *off, struct combat *def,
            pr("%s has no offensive strength\n", prland(&land));
            continue;
        }
-       resupply_all(&land);
-       putland(land.lnd_uid, &land);
-       if (!lnd_in_supply(&land)) {
+       if (!lnd_supply_all(&land)) {
            pr("%s is out of supply, and cannot %s\n",
               prland(&land), att_mode[combat_mode]);
            continue;
@@ -1235,9 +1233,7 @@ get_dlist(struct combat *def, struct emp_qelem *list, int a_spy,
        }
        memset(llp, 0, sizeof(struct ulist));
        emp_insque(&llp->queue, list);
-       resupply_all(&land);
-       putland(land.lnd_uid, &land);
-       llp->supplied = lnd_in_supply(&land);
+       llp->supplied = lnd_supply_all(&land);
        if (!get_land(A_DEFEND, def, land.lnd_uid, llp, 1))
            continue;
        if (lnd_spyval(&land) > *d_spyp)
@@ -1501,15 +1497,8 @@ att_reacting_units(struct combat *def, struct emp_qelem *list, int a_spy,
            continue;
 
        /* Only supplied units can react */
-       if (list) {
-           resupply_all(&land);
-           putland(land.lnd_uid, &land);
-           if (!lnd_in_supply(&land))
-               continue;
-       } else {
-           if (!lnd_could_be_supplied(&land))
-               continue;
-       }
+       if (list ? !lnd_supply_all(&land) : !lnd_could_be_supplied(&land))
+           continue;
 
        if (!in_oparea((struct empobj *)&land, def->x, def->y))
            continue;
index 0cddbd97a74d84778b577d62c78728d0afab12d9..ef27134613b1edd82f9d1ecf4b388c85c932db48 100644 (file)
@@ -86,18 +86,14 @@ int
 fort_fire(struct sctstr *sp)
 {
     int guns = sp->sct_item[I_GUN];
-    int shells;
 
     if (sp->sct_type != SCT_FORTR || sp->sct_effic < FORTEFF)
        return -1;
     if (sp->sct_item[I_MILIT] < 5 || guns == 0)
        return -1;
-    shells = sp->sct_item[I_SHELL];
-    shells += supply_commod(sp->sct_own, sp->sct_x, sp->sct_y,
-                           I_SHELL, 1 - shells);
-    if (shells == 0)
+    if (!sct_supply(sp, I_SHELL, 1))
        return -1;
-    sp->sct_item[I_SHELL] = shells - 1;
+    sp->sct_item[I_SHELL]--;
     return (int)fortgun(sp->sct_effic, guns);
 }
 
@@ -109,7 +105,7 @@ fort_fire(struct sctstr *sp)
 int
 shp_fire(struct shpstr *sp)
 {
-    int guns, shells;
+    int guns;
 
     if (sp->shp_effic < 60)
        return -1;
@@ -117,13 +113,11 @@ shp_fire(struct shpstr *sp)
     guns = MIN(guns, (sp->shp_item[I_MILIT] + 1) / 2);
     if (guns == 0)
        return -1;
-    shells = sp->shp_item[I_SHELL];
-    shells += supply_commod(sp->shp_own, sp->shp_x, sp->shp_y,
-                           I_SHELL, (guns + 1) / 2 - shells);
-    guns = MIN(guns, shells * 2);
+    shp_supply(sp, I_SHELL, (guns + 1) / 2);
+    guns = MIN(guns, sp->shp_item[I_SHELL] * 2);
     if (guns == 0)
        return -1;
-    sp->shp_item[I_SHELL] = shells - (guns + 1) / 2;
+    sp->shp_item[I_SHELL] -= (guns + 1) / 2;
     return (int)seagun(sp->shp_effic, guns);
 }
 
@@ -135,19 +129,17 @@ shp_fire(struct shpstr *sp)
 int
 shp_dchrg(struct shpstr *sp)
 {
-    int shells, dchrgs;
+    int dchrgs;
 
     if (sp->shp_effic < 60 || (mchr[sp->shp_type].m_flags & M_DCH) == 0)
        return -1;
     if (sp->shp_item[I_MILIT] == 0)
        return -1;
-    shells = sp->shp_item[I_SHELL];
-    shells += supply_commod(sp->shp_own, sp->shp_x, sp->shp_y,
-                           I_SHELL, 2 - shells);
-    if (shells == 0)
-       return -1;
-    dchrgs = MIN(2, shells);
-    sp->shp_item[I_SHELL] = shells - dchrgs;
+    shp_supply(sp, I_SHELL, 2);
+    dchrgs = MIN(2, sp->shp_item[I_SHELL]);
+    if (dchrgs == 0)
+       return -1;
+    sp->shp_item[I_SHELL] -= dchrgs;
     return (int)seagun(sp->shp_effic, 2 * dchrgs - 1);
 }
 
@@ -159,20 +151,15 @@ shp_dchrg(struct shpstr *sp)
 int
 shp_torp(struct shpstr *sp, int usemob)
 {
-    int shells;
-
     if (sp->shp_effic < 60 || (mchr[sp->shp_type].m_flags & M_TORP) == 0)
        return -1;
     if (sp->shp_item[I_MILIT] == 0 || sp->shp_item[I_GUN] == 0)
        return -1;
     if (usemob && sp->shp_mobil <= 0)
        return -1;
-    shells = sp->shp_item[I_SHELL];
-    shells += supply_commod(sp->shp_own, sp->shp_x, sp->shp_y,
-                           I_SHELL, SHP_TORP_SHELLS - shells);
-    if (shells < SHP_TORP_SHELLS)
-       return -1;
-    sp->shp_item[I_SHELL] = shells - SHP_TORP_SHELLS;
+    if (!shp_supply(sp, I_SHELL, SHP_TORP_SHELLS))
+       return -1;
+    sp->shp_item[I_SHELL] -= SHP_TORP_SHELLS;
     if (usemob)
        sp->shp_mobil -= (int)shp_mobcost(sp) / 2.0;
     return TORP_DAMAGE();
@@ -202,9 +189,8 @@ lnd_fire(struct lndstr *lp)
     ammo = lchr[lp->lnd_type].l_ammo;
     if (CANT_HAPPEN(ammo == 0))
        ammo = 1;
+    lnd_supply(lp, I_SHELL, ammo);
     shells = lp->lnd_item[I_SHELL];
-    shells += supply_commod(lp->lnd_own, lp->lnd_x, lp->lnd_y,
-                           I_SHELL, ammo - shells);
     if (shells == 0)
        return -1;
     d = landunitgun(lp->lnd_effic, guns);
@@ -212,7 +198,7 @@ lnd_fire(struct lndstr *lp)
        d *= (double)shells / (double)ammo;
        ammo = shells;
     }
-    lp->lnd_item[I_SHELL] = shells - ammo;
+    lp->lnd_item[I_SHELL] -= ammo;
     return d;
 }
 
index 5c7d3cd0de3f6cd6842111ed8307093a056784f3..140520dec3a27d239e2ca3e50f6c3e4ec9e31bd2 100644 (file)
@@ -939,11 +939,14 @@ mission_pln_equip(struct plist *plp, struct ichrstr *ip, int flags,
        if (itype != I_NONE && needed <= 0)
            return -1;
        if (itype != I_NONE) {
-           if (itype == I_SHELL && item[itype] < needed)
-               item[itype] += supply_commod(plp->plane.pln_own,
-                                            plp->plane.pln_x,
-                                            plp->plane.pln_y,
-                                            I_SHELL, needed);
+           if (itype == I_SHELL && item[itype] < needed) {
+               if (pp->pln_ship >= 0)
+                   shp_supply(&ship, I_SHELL, needed);
+               else if (pp->pln_land >= 0)
+                   lnd_supply(&land, I_SHELL, needed);
+               else
+                   sct_supply(&sect, I_SHELL, needed);
+           }
            if (item[itype] < needed)
                return -1;
            item[itype] -= needed;
index 1ea88f0dff8709b7edd5d63bfc93bcf2216b81c3..3798436706bdcf06d5b7bf4780b379f74a9b119b 100644 (file)
@@ -824,7 +824,6 @@ shp_missile_defense(coord dx, coord dy, natid bombown, int hardtarget)
     struct nstr_item ni;
     struct shpstr ship;
     int hitchance;
-    int shell;
     double gun, eff, teff;
 
     snxtitem_dist(&ni, EF_SHIP, dx, dy, 1);
@@ -842,17 +841,14 @@ shp_missile_defense(coord dx, coord dy, natid bombown, int hardtarget)
        if (ship.shp_effic < 60)
            continue;
 
-       shell = ship.shp_item[I_SHELL];
        if (ship.shp_item[I_MILIT] < 1) /* do we have mil? */
            continue;
-       if (shell < 2) {        /* do we need shells */
-           shell += supply_commod(ship.shp_own, ship.shp_x, ship.shp_y,
-                                  I_SHELL, 2);
-           if (shell < 2)
-               continue;
-       }
        if (ship.shp_item[I_GUN] < 1)   /* we need at least 1 gun */
            continue;
+       if (!shp_supply(&ship, I_SHELL, 2))
+           continue;
+       ship.shp_item[I_SHELL] -= 2;
+       putship(ship.shp_uid, &ship);
 
        /* now calculate the odds */
        gun = shp_usable_guns(&ship);
@@ -870,9 +866,6 @@ shp_missile_defense(coord dx, coord dy, natid bombown, int hardtarget)
        mpr(ship.shp_own, "Ship #%i anti-missile system activated!\n",
            ship.shp_uid);
        mpr(ship.shp_own, "%d%% hitchance...", hitchance);
-       /* use ammo */
-       ship.shp_item[I_SHELL] = shell - 2;
-       putship(ship.shp_uid, &ship);
 
        if (roll(100) <= hitchance) {
            mpr(bombown, "KABOOOM!! Missile destroyed\n\n");
index dbe725720dc79da39c686a451141b3fa26b69eb5..805f6a41694ed16bb5e8340d9c45dae74848e8eb 100644 (file)
@@ -28,7 +28,7 @@
  *  supply.c: Supply subroutines
  *
  *  Known contributors to this file:
- *
+ *     Markus Armbruster, 2009
  */
 
 #include <config.h>
 #include "sect.h"
 #include "ship.h"
 
-static int get_minimum(struct lndstr *, i_type);
+static int supply_commod(int, int, int, i_type, int);
 static int s_commod(int, int, int, i_type, int, int);
+static int get_minimum(struct lndstr *, i_type);
 
-/*
- * We want to get enough guns to be maxed out, enough shells to
- *     fire once, one update's worth of food.
- *
- * Firts, try to forage in the sector
- * Second look for a warehouse or headquarters to leech
- * Third, look for a ship we own in a harbor
- * Fourth, look for supplies in a supply unit we own
- *             (one good reason to do this last is that the supply
- *              unit will then call resupply, taking more time)
- *
- * May want to put code to resupply with SAMs here, later --ts
- */
-
-void
-resupply_all(struct lndstr *lp)
+int
+sct_supply(struct sctstr *sp, i_type type, int wanted)
 {
-    if (!opt_NOFOOD)
-       resupply_commod(lp, I_FOOD);
-    resupply_commod(lp, I_SHELL);
+    if (sp->sct_item[type] < wanted) {
+       sp->sct_item[type] += supply_commod(sp->sct_own,
+                                           sp->sct_x, sp->sct_y, type,
+                                           wanted - sp->sct_item[type]);
+       putsect(sp);
+    }
+    return sp->sct_item[type] >= wanted;
 }
 
-/*
- * If the unit has less than it's minimum level of a
- * certain commodity, fill it, to the best of our abilities.
- */
-
-void
-resupply_commod(struct lndstr *lp, i_type type)
+int
+shp_supply(struct shpstr *sp, i_type type, int wanted)
 {
-    int amt;
+    if (sp->shp_item[type] < wanted) {
+       sp->shp_item[type] += supply_commod(sp->shp_own,
+                                           sp->shp_x, sp->shp_y, type,
+                                           wanted - sp->shp_item[type]);
+       putship(sp->shp_uid, sp);
+    }
+    return sp->shp_item[type] >= wanted;
+}
 
-    amt = get_minimum(lp, type) - lp->lnd_item[type];
-    if (amt > 0) {
+int
+lnd_supply(struct lndstr *lp, i_type type, int wanted)
+{
+    if (lp->lnd_item[type] < wanted) {
        lp->lnd_item[type] += supply_commod(lp->lnd_own,
-                                           lp->lnd_x, lp->lnd_y,
-                                           type, amt);
+                                           lp->lnd_x, lp->lnd_y, type,
+                                           wanted - lp->lnd_item[type]);
+       putland(lp->lnd_uid, lp);
     }
+    return lp->lnd_item[type] >= wanted;
 }
 
 int
@@ -96,10 +93,21 @@ lnd_in_supply(struct lndstr *lp)
     return lp->lnd_item[I_SHELL] >= get_minimum(lp, I_SHELL);
 }
 
+int
+lnd_supply_all(struct lndstr *lp)
+{
+    int fail = 0;
+
+    if (!opt_NOFOOD)
+       fail |= !lnd_supply(lp, I_FOOD, get_minimum(lp, I_FOOD));
+    fail |= !lnd_supply(lp, I_SHELL, get_minimum(lp, I_SHELL));
+    return !fail;
+}
+
 /*
  * Actually get the commod
  */
-int
+static int
 supply_commod(int own, int x, int y, i_type type, int total_wanted)
 {
     if (total_wanted <= 0)
@@ -119,7 +127,18 @@ try_supply_commod(int own, int x, int y, i_type type, int total_wanted)
     return s_commod(own, x, y, type, total_wanted, 0);
 }
 
-/* Get supplies of a certain type */
+/*
+ * Actually get the commod
+ *
+ * First, try to forage in the sector
+ * Second look for a warehouse or headquarters to leech
+ * Third, look for a ship we own in a harbor
+ * Fourth, look for supplies in a supply unit we own
+ *             (one good reason to do this last is that the supply
+ *              unit will then call resupply, taking more time)
+ *
+ * May want to put code to resupply with SAMs here, later --ts
+ */
 static int
 s_commod(int own, int x, int y, i_type type, int total_wanted,
         int actually_doit)