]> git.pond.sub.org Git - empserver/blobdiff - src/lib/subs/lndsub.c
(lnd_mobtype): New.
[empserver] / src / lib / subs / lndsub.c
index 20c5c0ad610ea81a5cff2ebb9cc82669df8feff9..e8354ed49fe326680f9efed8b370d732005e4421 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  Empire - A multi-player, client/server Internet based war game.
- *  Copyright (C) 1986-2000, Dave Pare, Jeff Bailey, Thomas Ruschak,
+ *  Copyright (C) 1986-2006, Dave Pare, Jeff Bailey, Thomas Ruschak,
  *                           Ken Stevens, Steve McClure
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -19,9 +19,9 @@
  *
  *  ---
  *
- *  See the "LEGAL", "LICENSE", "CREDITS" and "README" files for all the
- *  related information and legal notices. It is expected that any future
- *  projects/authors will amend these files as needed.
+ *  See files README, COPYING and CREDITS in the root of the source
+ *  tree for related information and legal notices.  It is expected
+ *  that future projects/authors will amend these files as needed.
  *
  *  ---
  *
  *     Steve McClure, 1998-2000
  */
 
+#include <config.h>
+
 #include <math.h>
 #include "misc.h"
 #include "player.h"
 #include "file.h"
-#include "var.h"
 #include "sect.h"
 #include "path.h"
 #include "news.h"
-#include "treaty.h"
 #include "nat.h"
 #include "xy.h"
 #include "land.h"
 #include "optlist.h"
 #include "prototypes.h"
 
-extern int etu_per_update;
+static void lnd_mess(char *, struct llist *);
+static int lnd_hit_mine(struct lndstr *, struct lchrstr *);
 
 int
 attack_val(int combat_mode, struct lndstr *lp)
 {
-    extern double assault_penalty;
     int men;
-    int value;
+    double value;
     struct lchrstr *lcp;
 
-    if (((int)lp->lnd_effic) < LAND_MINEFF) {
-       makelost(EF_LAND, lp->lnd_own, lp->lnd_uid, lp->lnd_x, lp->lnd_y);
-       lp->lnd_own = 0;
+    if (lp->lnd_effic < LAND_MINEFF) {
        putland(lp->lnd_uid, lp);
        return 0;
     }
@@ -78,15 +76,12 @@ attack_val(int combat_mode, struct lndstr *lp)
     if (lcp->l_flags & L_SPY && combat_mode == A_ASSAULT)
        return 1;
 
-    men = total_mil(lp);
-
-    value = ldround(((double)men * (double)lp->lnd_att), 1);
-
-    value = (int)((double)value * ((double)lp->lnd_effic / 100.0));
+    men = lp->lnd_item[I_MILIT];
+    value = men * lp->lnd_att * lp->lnd_effic / 100.0;
 
     switch (combat_mode) {
     case A_ATTACK:
-       return value;
+       return (int)value;
     case A_ASSAULT:
        if (!(lcp->l_flags & L_MARINE))
            return (int)(assault_penalty * value);
@@ -96,65 +91,42 @@ attack_val(int combat_mode, struct lndstr *lp)
            return (int)(assault_penalty * men);
     }
 
-    return value;
+    return (int)value;
 }
 
 int
 defense_val(struct lndstr *lp)
 {
-    extern int land_mob_max;
     int men;
     double value;
     struct lchrstr *lcp;
 
-    if (((int)lp->lnd_effic) < LAND_MINEFF) {
-       makelost(EF_LAND, lp->lnd_own, lp->lnd_uid, lp->lnd_x, lp->lnd_y);
-       lp->lnd_own = 0;
+    if (lp->lnd_effic < LAND_MINEFF) {
        putland(lp->lnd_uid, lp);
        return 0;
     }
 
     lcp = &lchr[(int)lp->lnd_type];
 
-    men = total_mil(lp);
+    men = lp->lnd_item[I_MILIT];
 
-    if (men < 0)
-       men = 0;
     if ((lp->lnd_ship >= 0 || lp->lnd_land >= 0) &&
        !(lcp->l_flags & L_MARINE))
        return men;
 
-    value = men * lp->lnd_def;
-
-    value *=
-       ((double)land_mob_max + lp->lnd_harden) / (double)land_mob_max;
-    value = (int)((double)value * ((double)lp->lnd_effic / 100.0));
-    value = (int)ldround(value, 1);
+    value = men * lp->lnd_def * lp->lnd_effic / 100.0;
+    value *= ((double)land_mob_max + lp->lnd_harden) / land_mob_max;
 
     /* If there are military on the unit, you get at least a 1
        man defensive unit, except for spies */
     if (value < 1.0 && men > 0 && !(lcp->l_flags & L_SPY))
        return 1;
 
-    return (int)(value);
-}
-
-int
-total_mil(struct lndstr *lp)
-{
-    struct lchrstr *lcp;
-    double men;
-
-    lcp = &lchr[(int)lp->lnd_type];
-
-    men = lnd_getmil(lp);
-/*     men *= ((double)lp->lnd_effic)/100.0;*/
-
-    return ldround(men, 1);
+    return (int)value;
 }
 
 void
-lnd_print(struct llist *llp, s_char *s)
+lnd_print(struct llist *llp, char *s)
 {
     if (llp->land.lnd_own == player->cnum)
        pr("%s %s\n", prland(&llp->land), s);
@@ -163,13 +135,13 @@ lnd_print(struct llist *llp, s_char *s)
 }
 
 void
-lnd_delete(struct llist *llp, s_char *s)
+lnd_delete(struct llist *llp, char *s)
 {
     if (s)
        lnd_print(llp, s);
     putland(llp->land.lnd_uid, &llp->land);
     emp_remque((struct emp_qelem *)llp);
-    free((s_char *)llp);
+    free(llp);
 }
 
 int
@@ -186,39 +158,35 @@ lnd_take_casualty(int combat_mode, struct llist *llp, int cas)
     coord bx, by;
     struct sctstr sect;
     int ret_chance;
-    s_char buf[1024];
+    char buf[1024];
     int taken;
     int nowhere_to_go = 0;
     struct sctstr rsect;
-    double mobcost;
-    s_char orig;
+    double mobcost, bmcost;
+    signed char orig;
     int mob;
 
-
-
-    taken = lnd_getmil(&(llp->land));
+    taken = llp->land.lnd_item[I_MILIT];
     /* Spies always die */
     if (llp->lcp->l_flags & L_SPY) {
        eff_eq = 100;
        llp->land.lnd_effic = 0;
     } else {
-       eff_eq =
-           ldround((((double)cas * 100.0) / (double)llp->lcp->l_mil), 1);
+       eff_eq = ldround(cas * 100.0 / llp->lcp->l_mil, 1);
        llp->land.lnd_effic -= eff_eq;
-       lnd_submil(&(llp->land), cas);
+       lnd_submil(&llp->land, cas);
     }
 
     if (llp->land.lnd_effic < LAND_MINEFF) {
        sprintf(buf, "dies %s %s!",
-               combat_mode ? att_mode[combat_mode] : (s_char *)
-               "defending", xyas(llp->land.lnd_x, llp->land.lnd_y,
-                                 llp->land.lnd_own));
+               combat_mode ? att_mode[combat_mode] : "defending",
+               xyas(llp->land.lnd_x, llp->land.lnd_y, llp->land.lnd_own));
        lnd_delete(llp, buf);
        /* Since we killed the unit, we killed all the mil on it */
        return taken;
     } else {
        /* Ok, now, how many did we take off? (sould be the diff) */
-       taken = taken - lnd_getmil(&(llp->land));
+       taken = taken - llp->land.lnd_item[I_MILIT];
     }
 
     if (llp->land.lnd_effic >= llp->land.lnd_retreat)
@@ -259,12 +227,16 @@ lnd_take_casualty(int combat_mode, struct llist *llp, int cas)
                    continue;
                if (sect.sct_type == SCT_MOUNT)
                    continue;
+               mobcost = lnd_mobcost(&llp->land, &rsect);
+               if (mobcost < 0)
+                   continue;
                ++nowned;
-               civs = getvar(V_CIVIL, (s_char *)&sect, EF_SECTOR);
+               civs = sect.sct_item[I_CIVIL];
                if (civs > biggest) {
                    biggest = civs;
                    bx = sect.sct_x;
                    by = sect.sct_y;
+                   bmcost = mobcost;
                }
            }
            if (!nowned)
@@ -274,14 +246,13 @@ lnd_take_casualty(int combat_mode, struct llist *llp, int cas)
                llp->land.lnd_x = bx;
                llp->land.lnd_y = by;
                getsect(bx, by, &rsect);
-               mobcost = lnd_mobcost(&llp->land, &rsect, MOB_ROAD);
-               mob = llp->land.lnd_mobil - (int)mobcost;
+               mob = llp->land.lnd_mobil - (int)bmcost;
                if (mob < -127)
                    mob = -127;
                orig = llp->land.lnd_mobil;
-               llp->land.lnd_mobil = (s_char)mob;
+               llp->land.lnd_mobil = (signed char)mob;
                if (llp->land.lnd_mobil > orig)
-                   llp->land.lnd_mobil = (-127);
+                   llp->land.lnd_mobil = -127;
                sprintf(buf, "retreats at %d%% efficiency to %s!",
                        llp->land.lnd_effic,
                        xyas(bx, by, llp->land.lnd_own));
@@ -333,45 +304,32 @@ lnd_takemob(struct emp_qelem *list, double loss)
        new = llp->land.lnd_mobil - mcost;
        if (new < -127)
            new = -127;
-       llp->land.lnd_mobil = (s_char)new;
+       llp->land.lnd_mobil = (signed char)new;
     }
 }
-int
-lnd_getmil(struct lndstr *lp)
-{
-    int vec[I_MAX + 1];
-
-    getvec(VT_ITEM, vec, (s_char *)lp, EF_LAND);
-    return vec[I_MILIT];
-}
 
 void
 lnd_submil(struct lndstr *lp, int num)
 {
-    int vec[I_MAX + 1];
-
-    getvec(VT_ITEM, vec, (s_char *)lp, EF_LAND);
-    vec[I_MILIT] -= num;
-    if (vec[I_MILIT] < 0)
-       vec[I_MILIT] = 0;
-    putvec(VT_ITEM, vec, (s_char *)lp, EF_LAND);
+    int new = lp->lnd_item[I_MILIT] - num;
+    lp->lnd_item[I_MILIT] = new < 0 ? 0 : new;
 }
 
 int
 lnd_spyval(struct lndstr *lp)
 {
     if (lchr[(int)lp->lnd_type].l_flags & L_RECON)
-       return (lp->lnd_spy * (lp->lnd_effic / 100.0)) + 2;
+       return lp->lnd_spy * (lp->lnd_effic / 100.0) + 2;
     else
-       return (lp->lnd_spy * (lp->lnd_effic / 100.0));
+       return lp->lnd_spy * (lp->lnd_effic / 100.0);
 }
 
 int
 intelligence_report(int destination, struct lndstr *lp, int spy,
-                   s_char *mess)
+                   char *mess)
 {
     struct lchrstr *lcp;
-    s_char buf1[80], buf2[80], buf3[80];
+    char buf1[80], buf2[80], buf3[80];
     double estimate = 0.0;     /* estimated defense value */
 
     if (destination == 0)
@@ -385,29 +343,29 @@ intelligence_report(int destination, struct lndstr *lp, int spy,
     memset(buf1, 0, sizeof(buf1));
     memset(buf2, 0, sizeof(buf2));
     memset(buf3, 0, sizeof(buf3));
-    if (chance((double)(spy + lp->lnd_vis) / 10.0)) {
+    if (chance((spy + lp->lnd_vis) / 10.0)) {
        if (destination == player->cnum)
            pr("%s %s", mess, prland(lp));
        else
            sprintf(buf1, "%s %s", mess, prland(lp));
 
-       estimate = lnd_getmil(lp);
-
-       if (chance((double)(spy + lp->lnd_vis) / 20.0)) {
+       estimate = lp->lnd_item[I_MILIT];
 
+       if (chance((spy + lp->lnd_vis) / 20.0)) {
            if (destination == player->cnum)
-               pr(" (eff %d, mil %d", roundintby(lp->lnd_effic, 5),
-                  roundintby(lnd_getmil(lp), 10));
+               pr(" (eff %d, mil %d",
+                  roundintby(lp->lnd_effic, 5),
+                  roundintby(lp->lnd_item[I_MILIT], 10));
            else
                sprintf(buf2, " (eff %d, mil %d",
                        roundintby(lp->lnd_effic, 5),
-                       roundintby(lnd_getmil(lp), 10));
-           estimate = lnd_getmil(lp) * lp->lnd_effic / 100.0;
+                       roundintby(lp->lnd_item[I_MILIT], 10));
+           estimate = lp->lnd_item[I_MILIT] * lp->lnd_effic / 100.0;
 
-           if (chance((double)(spy + lp->lnd_vis) / 20.0)) {
+           if (chance((spy + lp->lnd_vis) / 20.0)) {
                int t;
                t = lp->lnd_tech - 20 + roll(40);
-               t = max(t, 0);
+               t = MAX(t, 0);
                if (destination == player->cnum)
                    pr(", tech %d)\n", t);
                else
@@ -447,7 +405,7 @@ count_sect_units(struct sctstr *sp)
     struct lndstr land;
 
     snxtitem_all(&ni, EF_LAND);
-    while (nxtitem(&ni, (s_char *)&land)) {
+    while (nxtitem(&ni, &land)) {
        if (!land.lnd_own)
            continue;
        if (land.lnd_x != sp->sct_x || land.lnd_y != sp->sct_y)
@@ -475,7 +433,7 @@ count_units(struct shpstr *sp)
        return;
 
     snxtitem_xy(&ni, EF_LAND, sp->shp_x, sp->shp_y);
-    while (nxtitem(&ni, (s_char *)&land)) {
+    while (nxtitem(&ni, &land)) {
        if (land.lnd_own == 0)
            continue;
        if (land.lnd_ship == sp->shp_uid)
@@ -499,7 +457,7 @@ lnd_count_units(struct lndstr *lp)
        return;
 
     snxtitem_xy(&ni, EF_LAND, lp->lnd_x, lp->lnd_y);
-    while (nxtitem(&ni, (s_char *)&land)) {
+    while (nxtitem(&ni, &land)) {
        if (land.lnd_own == 0)
            continue;
        if (land.lnd_land == lp->lnd_uid)
@@ -525,11 +483,11 @@ lnd_sel(struct nstr_item *ni, struct emp_qelem *list)
     struct llist *llp;
 
     emp_initque(list);
-    while (nxtitem(ni, (s_char *)&land)) {
+    while (nxtitem(ni, &land)) {
        if (!player->owner)
            continue;
        if (opt_MARKET) {
-           if (ontradingblock(EF_LAND, (int *)&land)) {
+           if (ontradingblock(EF_LAND, &land)) {
                pr("unit #%d inelligible - it's for sale.\n",
                   land.lnd_uid);
                continue;
@@ -560,10 +518,10 @@ lnd_sel(struct nstr_item *ni, struct emp_qelem *list)
        land.lnd_harden = 0;
        memset(land.lnd_rpath, 0, sizeof(land.lnd_rpath));
        putland(land.lnd_uid, &land);
-       llp = (struct llist *)malloc(sizeof(struct llist));
+       llp = malloc(sizeof(struct llist));
        llp->lcp = lcp;
        llp->land = land;
-       llp->mobil = (double)land.lnd_mobil;
+       llp->mobil = land.lnd_mobil;
        emp_insque(&llp->queue, list);
     }
 }
@@ -581,7 +539,7 @@ lnd_mar(struct emp_qelem *list, double *minmobp, double *maxmobp,
     coord allx;
     coord ally;
     int first = 1;
-    s_char mess[128];
+    char mess[128];
     int rel;
 
     *minmobp = 9876.0;
@@ -595,7 +553,7 @@ lnd_mar(struct emp_qelem *list, double *minmobp, double *maxmobp,
            mpr(actor, "%s was disbanded at %s\n",
                prland(&land), xyas(land.lnd_x, land.lnd_y, land.lnd_own));
            emp_remque((struct emp_qelem *)llp);
-           free((s_char *)llp);
+           free(llp);
            continue;
        }
        if (land.lnd_ship >= 0) {
@@ -612,7 +570,7 @@ lnd_mar(struct emp_qelem *list, double *minmobp, double *maxmobp,
        }
        if (!(lchr[(int)llp->land.lnd_type].l_flags & L_SPY) &&
            !(lchr[(int)llp->land.lnd_type].l_flags & L_TRAIN) &&
-           lnd_getmil(&llp->land) == 0) {
+           llp->land.lnd_item[I_MILIT] == 0) {
            lnd_mess("has no mil on it to guide it", llp);
            continue;
        }
@@ -632,7 +590,7 @@ lnd_mar(struct emp_qelem *list, double *minmobp, double *maxmobp,
        if (land.lnd_x != allx || land.lnd_y != ally)
            *togetherp = 0;
        if (land.lnd_mobil + 1 < (int)llp->mobil) {
-           llp->mobil = (double)land.lnd_mobil;
+           llp->mobil = land.lnd_mobil;
        }
        if (llp->mobil < *minmobp)
            *minmobp = llp->mobil;
@@ -645,8 +603,8 @@ lnd_mar(struct emp_qelem *list, double *minmobp, double *maxmobp,
 void
 lnd_put(struct emp_qelem *list, natid actor)
 {
-    register struct emp_qelem *qp;
-    register struct emp_qelem *newqp;
+    struct emp_qelem *qp;
+    struct emp_qelem *newqp;
     struct llist *llp;
 
     qp = list->q_back;
@@ -662,7 +620,7 @@ lnd_put(struct emp_qelem *list, natid actor)
        putland(llp->land.lnd_uid, &llp->land);
        newqp = qp->q_back;
        emp_remque(qp);
-       free((s_char *)qp);
+       free(qp);
        qp = newqp;
     }
 }
@@ -676,7 +634,6 @@ lnd_sweep(struct emp_qelem *land_list, int verbose, int takemob,
     struct llist *llp;
     struct sctstr sect;
     int mines, m, max, sshells, lshells;
-    double mobcost;
 
     for (qp = land_list->q_back; qp != land_list; qp = next) {
        next = qp->q_back;
@@ -706,34 +663,29 @@ lnd_sweep(struct emp_qelem *land_list, int verbose, int takemob,
            continue;
        }
        if (takemob) {
-/*                     mobcost = llp->land.lnd_effic * 0.01 * llp->lcp->l_spd;*/
-           mobcost = llp->land.lnd_spd;
-           mobcost = 480.0 / (mobcost +
-                              techfact(llp->land.lnd_tech, mobcost));
-           llp->mobil -= mobcost;
+           llp->mobil -= lnd_pathcost(&llp->land, 0.2);
            llp->land.lnd_mobil = (int)llp->mobil;
            llp->land.lnd_harden = 0;
        }
        putland(llp->land.lnd_uid, &llp->land);
-       if (!(mines = getvar(V_MINE, (s_char *)&sect, EF_SECTOR)))
+       if (!(mines = sect.sct_mines))
            continue;
-       max = vl_find(V_SHELL, llp->lcp->l_vtype,
-                     llp->lcp->l_vamt, (int)llp->lcp->l_nv);
-       lshells = getvar(V_SHELL, (s_char *)&llp->land, EF_LAND);
-       sshells = getvar(V_SHELL, (s_char *)&sect, EF_SECTOR);
+       max = llp->lcp->l_item[I_SHELL];
+       lshells = llp->land.lnd_item[I_SHELL];
+       sshells = sect.sct_item[I_SHELL];
        for (m = 0; mines > 0 && m < max * 2; m++) {
            if (chance(0.5 * llp->lcp->l_att)) {
                mpr(actor, "Sweep...\n");
                mines--;
                if (lshells < max)
                    ++lshells;
-               else
+               else if (sshells < ITEM_MAX)
                    ++sshells;
            }
        }
-       putvar(V_MINE, mines, (s_char *)&sect, EF_SECTOR);
-       putvar(V_SHELL, lshells, (s_char *)&llp->land, EF_LAND);
-       putvar(V_SHELL, sshells, (s_char *)&sect, EF_SECTOR);
+       sect.sct_mines = mines;
+       llp->land.lnd_item[I_SHELL] = lshells;
+       sect.sct_item[I_SHELL] = sshells;
        putland(llp->land.lnd_uid, &llp->land);
        putsect(&sect);
     }
@@ -762,9 +714,8 @@ lnd_check_mines(struct emp_qelem *land_list)
     struct emp_qelem *next;
     struct llist *llp;
     struct sctstr sect;
-    int mines;
     int stopping = 0;
-    int has_engineers = contains_engineer(land_list);
+    int with_eng = contains_engineer(land_list);
 
     for (qp = land_list->q_back; qp != land_list; qp = next) {
        next = qp->q_back;
@@ -774,18 +725,17 @@ lnd_check_mines(struct emp_qelem *land_list)
            continue;
        if (sect.sct_type == SCT_BSPAN)
            continue;
-       if (!(mines = getvar(V_MINE, (s_char *)&sect, EF_SECTOR)))
+       if (!sect.sct_mines)
            continue;
-       if (chance(DMINE_LHITCHANCE(mines) / (1 + 2 * has_engineers))) {
+       if (chance(DMINE_LHITCHANCE(sect.sct_mines) / (1 + 2 * with_eng))) {
            lnd_hit_mine(&llp->land, llp->lcp);
-           mines--;
-           putvar(V_MINE, mines, (s_char *)&sect, EF_SECTOR);
+           sect.sct_mines--;
            putsect(&sect);
-           putland(llp->land.lnd_uid, (s_char *)&llp->land);
+           putland(llp->land.lnd_uid, &llp->land);
            if (!llp->land.lnd_own) {
                stopping = 1;
                emp_remque(qp);
-               free((s_char *)qp);
+               free(qp);
            }
        }
     }
@@ -799,7 +749,6 @@ lnd_list(struct emp_qelem *land_list)
     struct emp_qelem *next;
     struct llist *llp;
     struct lndstr *lnd;
-    int vec[I_MAX + 1];
 
     pr("lnd#     land type       x,y    a  eff  sh gun xl  mu tech retr fuel\n");
 
@@ -810,11 +759,10 @@ lnd_list(struct emp_qelem *land_list)
        pr("%4d ", lnd->lnd_uid);
        pr("%-16.16s ", llp->lcp->l_name);
        prxy("%4d,%-4d ", lnd->lnd_x, lnd->lnd_y, llp->land.lnd_own);
-       pr("%1c", lnd->lnd_army);
+       pr("%1.1s", &lnd->lnd_army);
        pr("%4d%%", lnd->lnd_effic);
-       getvec(VT_ITEM, vec, (s_char *)lnd, EF_LAND);
-       pr("%4d", vec[I_SHELL]);
-       pr("%4d", vec[I_GUN]);
+       pr("%4d", lnd->lnd_item[I_SHELL]);
+       pr("%4d", lnd->lnd_item[I_GUN]);
        count_land_planes(lnd);
        pr("%3d", lnd->lnd_nxlight);
        pr("%4d", lnd->lnd_mobil);
@@ -824,8 +772,8 @@ lnd_list(struct emp_qelem *land_list)
     }
 }
 
-void
-lnd_mess(s_char *str, struct llist *llp)
+static void
+lnd_mess(char *str, struct llist *llp)
 {
     mpr(llp->land.lnd_own, "%s %s & stays in %s\n",
        prland(&llp->land),
@@ -835,7 +783,7 @@ lnd_mess(s_char *str, struct llist *llp)
     llp->land.lnd_mobil = llp->mobil;
     putland(llp->land.lnd_uid, &llp->land);
     emp_remque((struct emp_qelem *)llp);
-    free((s_char *)llp);
+    free(llp);
 }
 
 static int
@@ -865,7 +813,7 @@ lnd_damage(struct emp_qelem *list, int totdam)
 
     if (!totdam || !(count = lnd_count(list)))
        return 0;
-    dam = ldround(((double)totdam / (double)count), 1);
+    dam = ldround((double)totdam / count, 1);
     for (qp = list->q_back; qp != list; qp = next) {
        next = qp->q_back;
        llp = (struct llist *)qp;
@@ -875,7 +823,7 @@ lnd_damage(struct emp_qelem *list, int totdam)
        putland(llp->land.lnd_uid, &llp->land);
        if (!llp->land.lnd_own) {
            emp_remque(qp);
-           free((s_char *)qp);
+           free(qp);
        }
     }
     return dam;
@@ -936,11 +884,10 @@ static int
 lnd_fort_interdiction(struct emp_qelem *list,
                      coord newx, coord newy, natid victim)
 {
-    extern int fort_max_interdiction_range;
     struct nstr_sect ns;
     struct sctstr fsect;
-    int trange;
-    double range, range2, guneff;
+    int trange, range;
+    double guneff;
     int shell, gun;
     int dam;
     int totdam = 0;
@@ -952,30 +899,25 @@ lnd_fort_interdiction(struct emp_qelem *list,
            continue;
        if (fsect.sct_own == victim)
            continue;
-       if (fsect.sct_type != SCT_FORTR)
-           continue;
        if (getrel(getnatp(fsect.sct_own), victim) >= NEUTRAL)
            continue;
-       gun = getvar(V_GUN, (s_char *)&fsect, EF_SECTOR);
+       gun = fsect.sct_item[I_GUN];
        if (gun < 1)
            continue;
-       range = tfactfire(fsect.sct_own, (double)min(gun, 7));
-       if (fsect.sct_effic > 59)
-           range++;
-       range2 = roundrange(range);
+       range = roundrange(fortrange(&fsect));
        trange = mapdist(newx, newy, fsect.sct_x, fsect.sct_y);
-       if (trange > range2)
+       if (trange > range)
            continue;
-       if (getvar(V_MILIT, (s_char *)&fsect, EF_SECTOR) < 5)
+       if (fsect.sct_item[I_MILIT] < 5)
            continue;
-       shell = getvar(V_SHELL, (s_char *)&fsect, EF_SECTOR);
+       shell = fsect.sct_item[I_SHELL];
        if (shell < 1)
-           shell += supply_commod(fsect.sct_own,
-                                  fsect.sct_x, fsect.sct_y, I_SHELL, 1);
+           shell += supply_commod(fsect.sct_own, fsect.sct_x, fsect.sct_y,
+                                  I_SHELL, 1);
        if (shell < 1)
            continue;
        shell--;
-       putvar(V_SHELL, shell, (s_char *)&fsect, EF_SECTOR);
+       fsect.sct_item[I_SHELL] = shell;
        putsect(&fsect);
        if (gun > 7)
            gun = 7;
@@ -1025,12 +967,12 @@ lnd_hardtarget(struct lndstr *lp)
     struct sctstr sect;
 
     getsect(lp->lnd_x, lp->lnd_y, &sect);
-    return (int)(((double)lp->lnd_effic / 100.0) *
-                (10 + dchr[sect.sct_type].d_dstr * 2 +
-                 (double)lp->lnd_spd / 2.0 - lp->lnd_vis));
+    return (int)((lp->lnd_effic / 100.0) *
+                (10 + dchr[sect.sct_type].d_dstr * 2 + lp->lnd_spd / 2.0
+                 - lp->lnd_vis));
 }
 
-int
+static int
 lnd_hit_mine(struct lndstr *lp, struct lchrstr *lcp)
 {
     double m;
@@ -1040,7 +982,7 @@ lnd_hit_mine(struct lndstr *lp, struct lchrstr *lcp)
 
     nreport(lp->lnd_own, N_LHIT_MINE, 0, 1);
 
-    m = roll(20) + 10;
+    m = MINE_LDAMAGE();
     if (lcp->l_flags & L_ENGINEER)
        m /= 2.0;
 
@@ -1050,40 +992,34 @@ lnd_hit_mine(struct lndstr *lp, struct lchrstr *lcp)
 }
 
 double
-lnd_mobcost(struct lndstr *lp, struct sctstr *sp, int mobtype)
+lnd_pathcost(struct lndstr *lp, double pathcost)
 {
-    double mobcost;
-    double smobcost;
+    double effspd;
 
-    /* supply unit's speed depends on their eff, since
-       that is their purpose */
+    effspd = lp->lnd_spd;
     if (lchr[(int)lp->lnd_type].l_flags & L_SUPPLY)
-       mobcost = lp->lnd_effic * 0.01 * lp->lnd_spd;
-    else
-       mobcost = lp->lnd_spd;
-    if (mobcost < 0.01)
-       mobcost = 0.01;
-
-/* sector_mcost now takes 2 different arguments, a sector pointer, and
-   whether or not to figure in the highway bonus, rail bonus or none.
-   bridge heads, bridges and highways have built-in highways bonus
-   because they are a 1, and this will discount that. */
-
-    smobcost = (double)sector_mcost(sp, mobtype);
-    if (smobcost < 0.01)
-       smobcost = 0.01;
-
-/* marching through 0 mobility conquered sectors takes lots of mobility,
-   unless you are a train.  Capturing railways is a good thing. */
-
-    if (sp->sct_own != sp->sct_oldown && sp->sct_mobil <= 0 &&
-       smobcost < LND_MINMOBCOST && mobtype != MOB_RAIL)
-       smobcost = LND_MINMOBCOST;
+       effspd *= lp->lnd_effic * 0.01;
+
+    /*
+     * The return value must be PATHCOST times a factor that depends
+     * only on the land unit.  Anything else breaks path finding.  In
+     * particular, you can't add or enforce a minimum cost here.  Do
+     * it in sector_mcost().
+     */
+    return pathcost * 5.0 * speed_factor(effspd, lp->lnd_tech);
+}
 
-    mobcost = smobcost * 5.0 * 480.0 /
-       (mobcost + techfact(lp->lnd_tech, mobcost));
+int
+lnd_mobtype(struct lndstr *lp)
+{
+    return (lchr[(int)lp->lnd_type].l_flags & L_TRAIN)
+       ? MOB_RAIL : MOB_MARCH;
+}
 
-    return mobcost;
+double
+lnd_mobcost(struct lndstr *lp, struct sctstr *sp)
+{
+    return lnd_pathcost(lp, sector_mcost(sp, lnd_mobtype(lp)));
 }
 
 int
@@ -1095,14 +1031,15 @@ lnd_mar_one_sector(struct emp_qelem *list, int dir, natid actor,
     struct emp_qelem *qp2;
     struct emp_qelem *next;
     struct llist *llp;
+    struct emp_qelem cur, done;
     coord dx;
     coord dy;
     coord newx;
     coord newy;
     int stopping = 0;
-    int visible = 0;
+    int visible;
     int stop;
-    s_char dp[80];
+    char dp[80];
     int rel;
     int oldown;
 
@@ -1135,9 +1072,6 @@ lnd_mar_one_sector(struct emp_qelem *list, int dir, natid actor,
                continue;
            }
        }
-
-       if (!(lchr[(int)llp->land.lnd_type].l_flags & L_SPY))
-           visible = 1;
        if (sect.sct_rail == 0 &&
            lchr[(int)llp->land.lnd_type].l_flags & L_TRAIN) {
            if (together) {
@@ -1152,9 +1086,9 @@ lnd_mar_one_sector(struct emp_qelem *list, int dir, natid actor,
        }
        /* Note we check would_abandon first because we don't want
           to always have to do these checks */
-       if (would_abandon(&osect, V_CIVIL, 0, &(llp->land))) {
+       if (would_abandon(&osect, I_CIVIL, 0, &llp->land)) {
            stop = 0;
-           if (!want_to_abandon(&osect, V_CIVIL, 0, &(llp->land))) {
+           if (!want_to_abandon(&osect, I_CIVIL, 0, &llp->land)) {
                stop = 1;
            }
            /* now check stuff */
@@ -1163,7 +1097,7 @@ lnd_mar_one_sector(struct emp_qelem *list, int dir, natid actor,
            if (!check_sect_ok(&osect))
                return 1;
            for (qp2 = list->q_back; qp2 != list; qp2 = qp2->q_back) {
-               if (!check_land_ok(&(((struct llist *)qp2)->land)))
+               if (!check_land_ok(&((struct llist *)qp2)->land))
                    return 1;
            }
            if (stop) {
@@ -1177,11 +1111,7 @@ lnd_mar_one_sector(struct emp_qelem *list, int dir, natid actor,
        }
        llp->land.lnd_x = newx;
        llp->land.lnd_y = newy;
-       if (lchr[(int)llp->land.lnd_type].l_flags & L_TRAIN) {
-           llp->mobil -= lnd_mobcost(&llp->land, &sect, MOB_RAIL);
-       } else {
-           llp->mobil -= lnd_mobcost(&llp->land, &sect, MOB_ROAD);
-       }
+       llp->mobil -= lnd_mobcost(&llp->land, &sect);
        llp->land.lnd_mobil = (int)llp->mobil;
        llp->land.lnd_harden = 0;
        putland(llp->land.lnd_uid, &llp->land);
@@ -1219,8 +1149,41 @@ lnd_mar_one_sector(struct emp_qelem *list, int dir, natid actor,
     stopping |= lnd_check_mines(list);
     if (QEMPTY(list))
        return stopping;
-    if (visible)
-       stopping |= lnd_interdict(list, newx, newy, actor);
+
+    /* interdict land units sector by sector */
+    emp_initque(&cur);
+    emp_initque(&done);
+    while (!QEMPTY(list)) {
+       llp = (struct llist *)list->q_back;
+       newx = llp->land.lnd_x;
+       newy = llp->land.lnd_y;
+       /* move units in NEWX,NEWY to cur */
+       visible = 0;
+       for (qp = list->q_back; qp != list; qp = next) {
+           next = qp->q_back;
+           llp = (struct llist *)qp;
+           if (llp->land.lnd_x == newx && llp->land.lnd_y == newy) {
+               emp_remque(qp);
+               emp_insque(qp, &cur);
+               if (!(lchr[(int)llp->land.lnd_type].l_flags & L_SPY))
+                   visible = 1;
+           }
+       }
+       /* interdict them */
+       if (visible)
+           stopping |= lnd_interdict(&cur, newx, newy, actor);
+       /* move survivors to done */
+       for (qp = cur.q_back; qp != &cur; qp = next) {
+           next = qp->q_back;
+           llp = (struct llist *)qp;
+           emp_remque(qp);
+           emp_insque(qp, &done);
+       }
+    }
+    /* assign surviving land units back to list */
+    emp_insque(list, &done);
+    emp_remque(&done);
+
     return stopping;
 }
 
@@ -1228,10 +1191,9 @@ lnd_mar_one_sector(struct emp_qelem *list, int dir, natid actor,
  * find all artillery units belonging
  * to the attacker or defender that can fire.
  * Each arty unit adds +1%/damage point
- *
  */
 int
-lnd_support(natid victim, natid attacker, coord x, coord y)
+lnd_support(natid victim, natid attacker, coord x, coord y, int defending)
 {
     struct nstr_item ni;
     struct lndstr land;
@@ -1240,10 +1202,10 @@ lnd_support(natid victim, natid attacker, coord x, coord y)
     int dist;
     int shell;
     int gun;
-    double range, range2;
+    int range;
 
     snxtitem_all(&ni, EF_LAND);
-    while (nxtitem(&ni, (s_char *)&land)) {
+    while (nxtitem(&ni, &land)) {
        if (land.lnd_frg == 0)
            continue;
        if ((land.lnd_x == x) && (land.lnd_y == y))
@@ -1252,12 +1214,10 @@ lnd_support(natid victim, natid attacker, coord x, coord y)
            continue;
        if (land.lnd_land >= 0)
            continue;
-       if (land.lnd_mission > 0)
-           continue;
        if (land.lnd_effic < LAND_MINFIREEFF)
            continue;
        /* Do we have mil? */
-       if (getvar(V_MILIT, (s_char *)&land, EF_LAND) <= 0)
+       if (land.lnd_item[I_MILIT] <= 0)
            continue;
        rel = getrel(getnatp(land.lnd_own), attacker);
        rel2 = getrel(getnatp(land.lnd_own), victim);
@@ -1272,20 +1232,21 @@ lnd_support(natid victim, natid attacker, coord x, coord y)
        /* are we in range? */
        dist = mapdist(land.lnd_x, land.lnd_y, x, y);
 
-       range = techfact((int)land.lnd_tech, (double)land.lnd_frg / 2.0);
-
-       range2 = roundrange(range);
-       if (dist > range2)
+       range = roundrange(effrange(land.lnd_frg, land.lnd_tech));
+       if (dist > range)
            continue;
 
-       shell = getvar(V_SHELL, (s_char *)&land, EF_LAND);
-       gun = getvar(V_GUN, (s_char *)&land, EF_LAND);
+       shell = land.lnd_item[I_SHELL];
+       gun = land.lnd_item[I_GUN];
 
        if (shell == 0 || gun == 0)
            continue;
 
        use_supply(&land);
-       nreport(land.lnd_own, N_FIRE_L_ATTACK, victim, 1);
+       if (defending)
+           nreport(land.lnd_own, N_FIRE_BACK, victim, 1);
+       else
+           nreport(land.lnd_own, N_FIRE_L_ATTACK, victim, 1);
        if (roll(100) < land.lnd_acc) {
            dam += landunitgun(land.lnd_effic, land.lnd_dam, gun,
                               land.lnd_ammo, shell) / 2;
@@ -1301,14 +1262,15 @@ lnd_support(natid victim, natid attacker, coord x, coord y)
     return (int)dam;
 }
 
-s_char *
-lnd_path(int together, struct lndstr *lp, s_char *buf)
+char *
+lnd_path(int together, struct lndstr *lp, char *buf)
 {
     coord destx;
     coord desty;
     struct sctstr d_sect, sect;
-    s_char *cp;
+    char *cp;
     double dummy;
+    int mtype;
 
     if (!sarg_xy(buf, &destx, &desty))
        return 0;
@@ -1321,12 +1283,11 @@ lnd_path(int together, struct lndstr *lp, s_char *buf)
        return 0;
     }
     getsect(lp->lnd_x, lp->lnd_y, &sect);
-    if (lchr[(int)lp->lnd_type].l_flags & L_TRAIN)
-       cp = (s_char *)BestLandPath(buf, &sect, &d_sect, &dummy, MOB_RAIL);
-    else
-       cp = (s_char *)BestLandPath(buf, &sect, &d_sect, &dummy, MOB_ROAD);
+    mtype = lnd_mobtype(lp);
+    cp = BestLandPath(buf, &sect, &d_sect, &dummy, mtype);
     if (!cp) {
-       pr("No owned path from %s to %s!\n",
+       pr("No owned %s from %s to %s!\n",
+          mtype == MOB_RAIL ? "railway" : "path",
           xyas(lp->lnd_x, lp->lnd_y, player->cnum),
           xyas(d_sect.sct_x, d_sect.sct_y, player->cnum));
        return 0;
@@ -1340,11 +1301,6 @@ lnd_can_attack(struct lndstr *lp)
 {
     struct lchrstr *lcp = &lchr[(int)lp->lnd_type];
 
-/*     if (lcp->l_flags & L_SUPPLY ||
-           lcp->l_flags & L_SECURITY ||
-           lcp->l_flags & L_FLAK ||
-           lcp->l_frg)
-               return 0; */
     if (lcp->l_flags & L_SUPPLY)
        return 0;
 
@@ -1359,14 +1315,13 @@ lnd_can_attack(struct lndstr *lp)
 int
 lnd_fortify (struct lndstr *lp, int hard_amt)
 {
-    extern int land_mob_max;
     int mob_used;
     int eng;
 
     if ((lp->lnd_ship >= 0) || lp->lnd_land >= 0)
        return 0;
 
-    hard_amt = min(lp->lnd_mobil, hard_amt);
+    hard_amt = MIN(lp->lnd_mobil, hard_amt);
 
     if ((lp->lnd_harden + hard_amt) > land_mob_max)
        hard_amt = land_mob_max - lp->lnd_harden;
@@ -1374,7 +1329,7 @@ lnd_fortify (struct lndstr *lp, int hard_amt)
     eng = has_helpful_engineer(lp->lnd_x, lp->lnd_y, lp->lnd_own);
 
     if (eng)
-       hard_amt = ((float)hard_amt * 1.5);
+       hard_amt *= 1.5;
 
     if ((lp->lnd_harden + hard_amt) > land_mob_max)
        hard_amt = land_mob_max - lp->lnd_harden;
@@ -1385,7 +1340,7 @@ lnd_fortify (struct lndstr *lp, int hard_amt)
     /* Now, if an engineer helped, it's really only 2/3rds of
        that */
     if (eng)
-       mob_used = (int)((float)mob_used / 1.5);
+       mob_used /= 1.5;
 
     /* If we increased it, but not much, we gotta take at least 1
        mob point. */
@@ -1397,7 +1352,40 @@ lnd_fortify (struct lndstr *lp, int hard_amt)
        lp->lnd_mobil = 0;
 
     lp->lnd_harden += hard_amt;
-    lp->lnd_harden = min(lp->lnd_harden, land_mob_max);
+    lp->lnd_harden = MIN(lp->lnd_harden, land_mob_max);
 
     return hard_amt;
 }
+
+/*
+ * Set LP's tech to TLEV along with everything else that depends on it.
+ */
+void
+lnd_set_tech(struct lndstr *lp, int tlev)
+{
+    struct lchrstr *lcp = lchr + lp->lnd_type;
+    int tech_diff = tlev - lcp->l_tech;
+
+    if (CANT_HAPPEN(tech_diff < 0)) {
+      tlev -= tech_diff;
+      tech_diff = 0;
+    }
+
+    lp->lnd_tech = tlev;
+    lp->lnd_att = (float)LND_ATTDEF(lcp->l_att, tech_diff);
+    lp->lnd_def = (float)LND_ATTDEF(lcp->l_def, tech_diff);
+    lp->lnd_vul = (int)LND_VUL(lcp->l_vul, tech_diff);
+    lp->lnd_spd = (int)LND_SPD(lcp->l_spd, tech_diff);
+    lp->lnd_vis = (int)LND_VIS(lcp->l_vis, tech_diff);
+    lp->lnd_spy = (int)LND_SPY(lcp->l_spy, tech_diff);
+    lp->lnd_rad = (int)LND_RAD(lcp->l_rad, tech_diff);
+    lp->lnd_frg = (int)LND_FRG(lcp->l_frg, tech_diff);
+    lp->lnd_acc = (int)LND_ACC(lcp->l_acc, tech_diff);
+    lp->lnd_dam = (int)LND_DAM(lcp->l_dam, tech_diff);
+    lp->lnd_ammo = (int)LND_AMM(lcp->l_ammo, lcp->l_dam, tech_diff);
+    lp->lnd_aaf = (int)LND_AAF(lcp->l_aaf, tech_diff);
+    lp->lnd_fuelc = (int)LND_FC(lcp->l_fuelc, tech_diff);
+    lp->lnd_fuelu = (int)LND_FU(lcp->l_fuelu, tech_diff);
+    lp->lnd_maxlight = (int)LND_XPL(lcp->l_nxlight, tech_diff);
+    lp->lnd_maxland = (int)LND_MXL(lcp->l_nland, tech_diff);
+}