]> git.pond.sub.org Git - empserver/blobdiff - src/lib/subs/shpsub.c
COPYING duplicates information from README. Remove. Move GPL from
[empserver] / src / lib / subs / shpsub.c
index 6509700d385d6859c480a25edddf92798b8ec3b3..c1b021142c400a8d3557667a9994f2b77f35ece8 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  Empire - A multi-player, client/server Internet based war game.
- *  Copyright (C) 1986-1999, 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, 1996-2000
  */
 
+#include <config.h>
+
+#include <math.h>
 #include "misc.h"
 #include "queue.h"
 #include "player.h"
-#include "var.h"
 #include "sect.h"
 #include "ship.h"
 #include "plane.h"
 #include "mission.h"
 #include "optlist.h"
 #include "damage.h"
+#include "server.h"
 #include "prototypes.h"
 
-extern double tfactfire(natid, double);
-
-extern int etu_per_update;
-
-static int shp_check_nav(struct sctstr *);
 static int shp_check_one_mines(struct mlist *);
 static int shp_hit_mine(struct shpstr *, struct mchrstr *);
 static void shp_mess(s_char *, struct mlist *);
@@ -74,7 +72,7 @@ shp_sel(struct nstr_item *ni, struct emp_qelem *list)
     struct mlist *mlp;
 
     emp_initque(list);
-    while (nxtitem(ni, (s_char *)&ship)) {
+    while (nxtitem(ni, &ship)) {
        if (!player->owner)
            continue;
        mcp = &mchr[(int)ship.shp_type];
@@ -106,7 +104,7 @@ shp_sel(struct nstr_item *ni, struct emp_qelem *list)
        ship.shp_rflags = 0;
        memset(ship.shp_rpath, 0, sizeof(ship.shp_rpath));
        putship(ship.shp_uid, &ship);
-       mlp = (struct mlist *)malloc(sizeof(struct mlist));
+       mlp = malloc(sizeof(struct mlist));
        mlp->mcp = mcp;
        mlp->ship = ship;
        mlp->mobil = (double)ship.shp_mobil;
@@ -119,13 +117,11 @@ void
 shp_nav(struct emp_qelem *list, double *minmobp, double *maxmobp,
        int *togetherp, natid actor)
 {
-    extern int update_pending;
     struct emp_qelem *qp;
     struct emp_qelem *next;
     struct mlist *mlp;
     struct sctstr sect;
     struct shpstr ship;
-    int vec[I_MAX + 1];
     coord allx;
     coord ally;
     int first = 1;
@@ -141,7 +137,7 @@ shp_nav(struct emp_qelem *list, double *minmobp, double *maxmobp,
            mpr(actor, "%s was sunk at %s\n",
                prship(&ship), xyas(ship.shp_x, ship.shp_y, actor));
            emp_remque((struct emp_qelem *)mlp);
-           free((s_char *)mlp);
+           free(mlp);
            continue;
        }
        if (opt_SAIL) {
@@ -152,8 +148,7 @@ shp_nav(struct emp_qelem *list, double *minmobp, double *maxmobp,
            }
        }
        /* check crew - uws don't count */
-       getvec(VT_ITEM, vec, (s_char *)&ship, EF_SHIP);
-       if (vec[I_MILIT] == 0 && vec[I_CIVIL] == 0) {
+       if (ship.shp_item[I_MILIT] == 0 && ship.shp_item[I_CIVIL] == 0) {
            shp_mess("is crewless", mlp);
            continue;
        }
@@ -167,7 +162,7 @@ shp_nav(struct emp_qelem *list, double *minmobp, double *maxmobp,
            continue;
        case CN_LANDLOCKED:
            shp_mess("is landlocked", mlp);
-           break;
+           continue;
        case CN_NAVIGABLE:
            break;
        case CN_ERROR:
@@ -196,8 +191,8 @@ shp_nav(struct emp_qelem *list, double *minmobp, double *maxmobp,
 void
 shp_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 mlist *mlp;
 
     qp = list->q_back;
@@ -209,7 +204,7 @@ shp_put(struct emp_qelem *list, natid actor)
        putship(mlp->ship.shp_uid, &mlp->ship);
        newqp = qp->q_back;
        emp_remque(qp);
-       free((s_char *)qp);
+       free(qp);
        qp = newqp;
     }
 }
@@ -253,25 +248,24 @@ shp_sweep(struct emp_qelem *ship_list, int verbose, natid actor)
        mlp->mobil -= mobcost;
        mlp->ship.shp_mobil = (int)mlp->mobil;
        putship(mlp->ship.shp_uid, &mlp->ship);
-       if (!(mines = getvar(V_MINE, (s_char *)&sect, EF_SECTOR)))
+       if (!(mines = sect.sct_mines))
            continue;
-       max = vl_find(V_SHELL, mlp->mcp->m_vtype,
-                     mlp->mcp->m_vamt, (int)mlp->mcp->m_nv);
-       shells = getvar(V_SHELL, (s_char *)&mlp->ship, EF_SHIP);
+       max = mlp->mcp->m_item[I_SHELL];
+       shells = mlp->ship.shp_item[I_SHELL];
        for (m = 0; mines > 0 && m < 5; m++) {
            if (chance(0.66)) {
                mpr(actor, "Sweep...\n");
                mines--;
-               shells = min(max, shells + 1);
+               shells = MIN(max, shells + 1);
                changed |= map_set(actor, sect.sct_x, sect.sct_y, 'X', 0);
            }
        }
-       putvar(V_MINE, mines, (s_char *)&sect, EF_SECTOR);
-       putvar(V_SHELL, shells, (s_char *)&mlp->ship, EF_SHIP);
+       sect.sct_mines = mines;
+       mlp->ship.shp_item[I_SHELL] = shells;
        if (shp_check_one_mines(mlp)) {
            stopping = 1;
            emp_remque(qp);
-           free((s_char *)qp);
+           free(qp);
        }
        putship(mlp->ship.shp_uid, &mlp->ship);
        putsect(&sect);
@@ -285,25 +279,23 @@ static int
 shp_check_one_mines(struct mlist *mlp)
 {
     struct sctstr sect;
-    int mines;
     int changed = 0;
     int actor;
 
     getsect(mlp->ship.shp_x, mlp->ship.shp_y, &sect);
     if (sect.sct_type != SCT_WATER)
        return 0;
-    if (!(mines = getvar(V_MINE, (s_char *)&sect, EF_SECTOR)))
+    if (!sect.sct_mines)
        return 0;
-    if (chance(DMINE_HITCHANCE(mines))) {
+    if (chance(DMINE_HITCHANCE(sect.sct_mines))) {
        actor = mlp->ship.shp_own;
        shp_hit_mine(&mlp->ship, mlp->mcp);
-       mines--;
+       sect.sct_mines--;
        changed |= map_set(actor, sect.sct_x, sect.sct_y, 'X', 0);
        if (changed)
            writemap(actor);
-       putvar(V_MINE, mines, (s_char *)&sect, EF_SECTOR);
        putsect(&sect);
-       putship(mlp->ship.shp_uid, (s_char *)&mlp->ship);
+       putship(mlp->ship.shp_uid, &mlp->ship);
        if (!mlp->ship.shp_own)
            return 1;
     }
@@ -324,7 +316,7 @@ shp_check_mines(struct emp_qelem *ship_list)
        if (shp_check_one_mines(mlp)) {
            stopping = 1;
            emp_remque(qp);
-           free((s_char *)qp);
+           free(qp);
        }
     }
     return stopping;
@@ -337,7 +329,6 @@ shp_list(struct emp_qelem *ship_list)
     struct emp_qelem *next;
     struct mlist *mlp;
     struct shpstr *shp;
-    int vec[I_MAX + 1];
 
     pr("shp#     ship type       x,y   fl  eff mil  sh gun pn he xl ln mob tech\n");
 
@@ -348,12 +339,11 @@ shp_list(struct emp_qelem *ship_list)
        pr("%4d ", shp->shp_uid);
        pr("%-16.16s ", mlp->mcp->m_name);
        prxy("%4d,%-4d ", shp->shp_x, shp->shp_y, mlp->ship.shp_own);
-       pr("%1c", shp->shp_fleet);
+       pr("%c", shp->shp_fleet);
        pr("%4d%%", shp->shp_effic);
-       getvec(VT_ITEM, vec, (s_char *)shp, EF_SHIP);
-       pr("%4d", vec[I_MILIT]);
-       pr("%4d", vec[I_SHELL]);
-       pr("%4d", vec[I_GUN]);
+       pr("%4d", shp->shp_item[I_MILIT]);
+       pr("%4d", shp->shp_item[I_SHELL]);
+       pr("%4d", shp->shp_item[I_GUN]);
        count_planes(shp);
        pr("%3d", shp->shp_nplane);
        pr("%3d", shp->shp_nchoppers);
@@ -374,13 +364,13 @@ shp_mess(s_char *str, struct mlist *mlp)
     mlp->ship.shp_mobil = (int)mlp->mobil;
     putship(mlp->ship.shp_uid, &mlp->ship);
     emp_remque((struct emp_qelem *)mlp);
-    free((s_char *)mlp);
+    free(mlp);
 }
 
-static int
+int
 shp_check_nav(struct sctstr *sect)
 {
-    switch (dchr[sect->sct_type].d_flg & 03) {
+    switch (dchr[sect->sct_type].d_nav) {
     case NAVOK:
        break;
 
@@ -398,6 +388,17 @@ shp_check_nav(struct sctstr *sect)
     return CN_NAVIGABLE;
 }
 
+int
+sect_has_dock(struct sctstr *sect)
+{
+    switch (dchr[sect->sct_type].d_nav) {
+    case NAV_02:
+       return 1;
+    default:
+       return 0;
+    }
+}
+
 static int
 shp_count(struct emp_qelem *list, int wantflags, int nowantflags, int x,
          int y)
@@ -428,7 +429,7 @@ shp_damage_one(struct mlist *mlp, int dam)
     putship(mlp->ship.shp_uid, &mlp->ship);
     if (!mlp->ship.shp_own) {
        emp_remque((struct emp_qelem *)mlp);
-       free((s_char *)mlp);
+       free(mlp);
     }
 }
 
@@ -602,25 +603,19 @@ notify_coastguard(struct emp_qelem *list, int trange, struct sctstr *sectp)
     if (vrange < trange)
        return 0;
 
-    /* We got here, so we could theoretically see the ship.  Now,
-     * do we want to see it in our telebox? If not, return positive
-     * since we could see the ship and want forts to fire. */
-    if (!(natp->nat_flags & NF_COASTWATCH))
-       return 1;
-
     for (qp = list->q_back; qp != list; qp = next) {
        next = qp->q_back;
        mlp = (struct mlist *)qp;
        if (mlp->mcp->m_flags & M_SUB)
            continue;
-       wu(0, sectp->sct_own,
-          "%s %s sighted at %s\n",
-          cname(mlp->ship.shp_own),
-          prship(&mlp->ship),
-          xyas(mlp->ship.shp_x, mlp->ship.shp_y, sectp->sct_own));
-       if (opt_HIDDEN) {
-           setcont(sectp->sct_own, mlp->ship.shp_own, FOUND_LOOK);
-       }
+       if (natp->nat_flags & NF_COASTWATCH)
+           wu(0, sectp->sct_own,
+              "%s %s sighted at %s\n",
+              cname(mlp->ship.shp_own),
+              prship(&mlp->ship),
+              xyas(mlp->ship.shp_x, mlp->ship.shp_y, sectp->sct_own));
+       if (opt_HIDDEN)
+           setcont(sectp->sct_own, mlp->ship.shp_own, FOUND_COAST);
     }
 
     return 1;
@@ -673,26 +668,26 @@ shp_fort_interdiction(struct emp_qelem *list, coord newx, coord newy,
            continue;
        if (fsect.sct_type != SCT_FORTR)
            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));
+       range = tfactfire(fsect.sct_own, (double)MIN(gun, 7));
        if (fsect.sct_effic > 59)
            range++;
        range2 = roundrange(range);
        trange = mapdist(newx, newy, fsect.sct_x, fsect.sct_y);
        if (trange > range2)
            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);
        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;
@@ -729,10 +724,9 @@ shp_interdict(struct emp_qelem *list, coord newx, coord newy, natid victim)
            stopping |=
                shp_damage(list,
                           unit_interdict(newx, newy, victim, "ships",
-                                         shp_easiest_target(list, 0,
-                                                            M_SUB),
-                                         MI_INTERDICT), 0, M_SUB, newx,
-                          newy);
+                                         shp_easiest_target(list, 0, M_SUB),
+                                         MI_INTERDICT),
+                          0, M_SUB, newx, newy);
            if (most_valuable_ship(list)) {
                stopping |=
                    shp_missile_interdiction(list, newx, newy, victim);
@@ -744,8 +738,8 @@ shp_interdict(struct emp_qelem *list, coord newx, coord newy, natid victim)
            shp_damage(list,
                       unit_interdict(newx, newy, victim, "subs",
                                      shp_easiest_target(list, M_SUB, 0),
-                                     MI_SINTERDICT), M_SUB, 0, newx,
-                      newy);
+                                     MI_SINTERDICT),
+                      M_SUB, 0, newx, newy);
     }
     return stopping;
 }
@@ -816,9 +810,8 @@ shp_nav_one_sector(struct emp_qelem *list, int dir, natid actor,
     struct sctstr sect;
     struct emp_qelem *qp;
     struct emp_qelem *next;
-    struct emp_qelem *nqp;
-    struct emp_qelem *nnext;
     struct mlist *mlp;
+    struct emp_qelem done;
     coord dx;
     coord dy;
     coord newx;
@@ -853,8 +846,8 @@ shp_nav_one_sector(struct emp_qelem *list, int dir, natid actor,
                continue;
            }
        }
-       if (opt_BIG_CITY && sect.sct_type == SCT_CAPIT) {
-           if (mlp->mcp->m_lcm + 2 * mlp->mcp->m_hcm >= 60) {
+       if (IS_BIG_CITY(sect.sct_type)) {
+           if (!(mlp->mcp->m_flags & M_CANAL)) {
                sprintf(dp,
                        "is too large to fit into the canal system at %s",
                        xyas(newx, newy, actor));
@@ -878,7 +871,6 @@ shp_nav_one_sector(struct emp_qelem *list, int dir, natid actor,
        }
        mlp->ship.shp_mobil = (int)mlp->mobil;
        putship(mlp->ship.shp_uid, &mlp->ship);
-       mlp->done = 0;          /* We haven't interdicted this ship yet */
 
        /* Now update the map for this ship */
        tech = techfact(mlp->ship.shp_tech, (double)mlp->mcp->m_vrnge);
@@ -898,26 +890,26 @@ shp_nav_one_sector(struct emp_qelem *list, int dir, natid actor,
     if (QEMPTY(list))
        return stopping;
 
-/* Ok, run through each ship and interdict each coordinate */
-    for (qp = list->q_back; qp != list; qp = next) {
-       next = qp->q_back;
-       mlp = (struct mlist *)qp;
-/* Has this ship been interdicted yet? */
-       if (mlp->done)
-           continue;
+    /* interdict ships sector by sector */
+    emp_initque(&done);
+    while (!QEMPTY(list)) {
+       mlp = (struct mlist *)list->q_back;
        newx = mlp->ship.shp_x;
        newy = mlp->ship.shp_y;
        stopping |= shp_interdict(list, newx, newy, actor);
-       if (QEMPTY(list))
-           return stopping;
-/* Now, set all ships in this coordinate to done */
-       for (nqp = list->q_back; nqp != list; nqp = nnext) {
-           nnext = nqp->q_back;
-           mlp = (struct mlist *)nqp;
-           if (mlp->ship.shp_x == newx && mlp->ship.shp_y == newy)
-               mlp->done = 1;
+       /* move survivors in this sector to done */
+       for (qp = list->q_back; qp != list; qp = next) {
+           next = qp->q_back;
+           mlp = (struct mlist *)qp;
+           if (mlp->ship.shp_x == newx && mlp->ship.shp_y == newy) {
+               emp_remque(qp);
+               emp_insque(qp, &done);
+           }
        }
     }
+    /* assign surviving ships back to list */
+    emp_insque(list, &done);
+    emp_remque(&done);
 
     return stopping;
 }
@@ -937,12 +929,12 @@ shp_missile_defense(coord dx, coord dy, natid bombown, int hardtarget)
     struct nstr_item ni;
     struct shpstr ship;
     int hitchance;
-    int vec[I_MAX + 1];
+    int shell;
     double gun, eff, teff;
 
     snxtitem_dist(&ni, EF_SHIP, dx, dy, 1);
 
-    while (nxtitem(&ni, (caddr_t)&ship)) {
+    while (nxtitem(&ni, &ship)) {
        if (!ship.shp_own)
            continue;
 
@@ -955,21 +947,20 @@ shp_missile_defense(coord dx, coord dy, natid bombown, int hardtarget)
        if (ship.shp_effic < 60)
            continue;
 
-       if (getvec(VT_ITEM, vec, (caddr_t)&ship, EF_SHIP) < 0)
+       shell = ship.shp_item[I_SHELL];
+       if (ship.shp_item[I_MILIT] < 1) /* do we have mil? */
            continue;
-       if (vec[I_MILIT] < 1)   /* do we have mil? */
-           continue;
-       if (vec[I_SHELL] < 2) { /* do we need shells */
-           if (vec[I_SHELL] += supply_commod(ship.shp_own,
-                                             ship.shp_x,
-                                             ship.shp_y, I_SHELL, 2) < 2)
+       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 (vec[I_GUN] < 1)     /* we need at least 1 gun */
+       if (ship.shp_item[I_GUN] < 1)   /* we need at least 1 gun */
            continue;
 
        /* now calculate the odds */
-       gun = ((double)min(vec[I_GUN], ship.shp_glim));
+       gun = MIN(ship.shp_item[I_GUN], ship.shp_glim);
        eff = (double)ship.shp_effic / 100.0;
        teff =
            (((double)ship.shp_tech) / (((double)ship.shp_tech) + 200.0));
@@ -986,7 +977,7 @@ shp_missile_defense(coord dx, coord dy, natid bombown, int hardtarget)
            ship.shp_uid);
        mpr(ship.shp_own, "%d%% hitchance...", hitchance);
        /* use ammo */
-       putvar(V_SHELL, vec[I_SHELL] - 2, (caddr_t)&ship, EF_SHIP);
+       ship.shp_item[I_SHELL] = shell - 2;
        putship(ship.shp_uid, &ship);
 
        if (roll(100) <= hitchance) {
@@ -1023,8 +1014,8 @@ shp_path(int together, struct shpstr *shp, s_char *buf)
        return 0;
     }
 
-    cp = (s_char *)BestShipPath(buf, shp->shp_x, shp->shp_y,
-                               d_sect.sct_x, d_sect.sct_y, player->cnum);
+    cp = BestShipPath(buf, shp->shp_x, shp->shp_y,
+                     d_sect.sct_x, d_sect.sct_y, player->cnum);
     if (!cp || shp->shp_mobil <= 0) {
        mpr(shp->shp_own, "Can't get to '%s' right now.\n",
            xyas(d_sect.sct_x, d_sect.sct_y, player->cnum));
@@ -1044,7 +1035,7 @@ shp_missdef(struct shpstr *sp, natid victim)
 
     emp_initque(&list);
 
-    mlp = (struct mlist *)malloc(sizeof(struct mlist));
+    mlp = malloc(sizeof(struct mlist));
     mlp->mcp = &mchr[(int)sp->shp_type];
     mlp->ship = *sp;
     mlp->mobil = (double)sp->shp_mobil;
@@ -1070,3 +1061,25 @@ shp_missdef(struct shpstr *sp, natid victim)
     if (!QEMPTY(&list))
        free(mlp);
 }
+
+/*
+ * Set SP's tech to TLEV along with everything else that depends on it.
+ */
+void
+shp_set_tech(struct shpstr *sp, int tlev)
+{
+    struct mchrstr *mcp = mchr + sp->shp_type;
+    int tech_diff = tlev - mcp->m_tech;
+
+    if (CANT_HAPPEN(tech_diff < 0)) {
+      tlev -= tech_diff;
+      tech_diff = 0;
+    }
+
+    sp->shp_tech = tlev;
+    sp->shp_armor = (short)SHP_DEF(mcp->m_armor, tech_diff);
+    sp->shp_speed = (short)SHP_SPD(mcp->m_speed, tech_diff);
+    sp->shp_visib = (short)SHP_VIS(mcp->m_visib, tech_diff);
+    sp->shp_frnge = (short)SHP_RNG(mcp->m_frnge, tech_diff);
+    sp->shp_glim  = (short)SHP_FIR(mcp->m_glim, tech_diff);
+}