Add inhabited planets.
authorEric S. Raymond <esr@thyrsus.com>
Fri, 15 Sep 2006 18:41:16 +0000 (18:41 +0000)
committerEric S. Raymond <esr@thyrsus.com>
Fri, 15 Sep 2006 18:41:16 +0000 (18:41 +0000)
Presently this is just color, as they have no dilithium.  In the
future, this will become the basis for BSD-Trek like code that allows
Klingons to attack and enslave inhabited worlds in order to expand
their fleet.  (This feature is controlled by OPTION_WORLDS).

doc/sst-doc.xml
src/ai.c
src/battle.c
src/events.c
src/planets.c
src/reports.c
src/setup.c
src/sst.c
src/sst.h

index 92f3400989bb416a42050d3cac49fa0525806c29..ec0a208389d66a8dfb4f374cd2072a51a3eac8cd 100644 (file)
@@ -1247,9 +1247,10 @@ Mnemonic:  PLANETS
 Shortest abbreviation:  PL
 </literallayout>
 
-<para>Mr. Spock presents you a list of the available information on planets
-in the galaxy.  Since planets do not show up on long-range scans, the
-only way to obtain this information is with the <quote>SENSORS</quote> command.</para>
+<para>Mr. Spock presents you a list of the available information on
+planets in the galaxy which are potential dilithium sources.  Since
+planets do not show up on long-range scans, the only way to obtain
+this information is with the <quote>SENSORS</quote> command.</para>
 
 </sect1>
 <sect1 id="freeze"><title>Freeze</title>
index 25d58274624efd7f151058321cb3135f8e692c32..4b1aa23b274ef783850492f21d3c50ea78b1ee2d 100644 (file)
--- a/src/ai.c
+++ b/src/ai.c
@@ -351,7 +351,7 @@ static int movescom(int iqx, int iqy, int flag, int *ipage)
            game.state.plnets[i].crystals == 1) {
            /* destroy the planet */
            DESTROY(&game.state.plnets[i]);
-           game.state.galaxy[game.state.isx][game.state.isy].planets -= 1;
+           game.state.galaxy[game.state.isx][game.state.isy].planet = NULL;
            if (game.damage[DRADIO] == 0.0 || game.condit == IHDOCKED) {
                if (*ipage==0) pause_game(1);
                *ipage = 1;
index b8ffbcbb4eeb143c842a11159f4b4cc4ce5e466a..58ed4c2b997edf0541c16b281d40b3db4212144d 100644 (file)
@@ -316,7 +316,7 @@ void torpedo(double course, double r, int inx, int iny, double *hit, int i, int
            crmena(1, iquad, 2, ix, iy);
            prout(" destroyed.");
            game.state.nplankl++;
-           game.state.galaxy[game.quadx][game.quady].planets--;
+           game.state.galaxy[game.quadx][game.quady].planet = NULL;
            DESTROY(&game.state.plnets[game.iplnet]);
            game.iplnet = 0;
            game.plnetx = game.plnety = 0;
index ac674a27e581c0c749378c6fe1a547d7246de548..e7e9567c7eb46191821e864c521409e991280c67 100644 (file)
@@ -466,7 +466,7 @@ void nova(int ix, int iy)
                        game.quad[ii][jj] = IHDOT;
                        break;
                    case IHP: /* Destroy planet */
-                       game.state.galaxy[game.quadx][game.quady].planets -= 1;
+                       game.state.galaxy[game.quadx][game.quady].planet = NULL;
                        game.state.nplankl++;
                        crmena(1, IHP, 2, ii, jj);
                        prout(" destroyed.");
index 6c5f3654a7f35c5c305437b3a5eca5714359caf9..c76dace1fbffaafedd5201d345b8ccdf322a626f 100644 (file)
@@ -33,7 +33,8 @@ void preport(void)
     prout("Spock-  \"Planet report follows, Captain.\"");
     skip(1);
     for (i = 0; i < game.inplan; i++) {
-       if (game.state.plnets[i].known != unknown
+       if ((game.state.plnets[i].known != unknown
+           && game.state.plnets[i].crystals != 0)
 #ifdef DEBUG
            || ( game.idebug && game.state.plnets[i].x !=0)
 #endif
@@ -46,7 +47,7 @@ void preport(void)
            proutn("   class ");
            proutn(classes[game.state.plnets[i].pclass]);
            proutn("   ");
-           if (game.state.plnets[i].crystals == 0) proutn("no ");
+           if (game.state.plnets[i].crystals <= 0) proutn("no ");
            prout("dilithium crystals present.");
            if (game.state.plnets[i].known==shuttle_down) 
                prout("    Shuttle Craft Galileo on surface.");
@@ -206,7 +207,11 @@ void mine(void)
        prout("Mining party not on planet.");
        return;
     }
-    if (game.state.plnets[game.iplnet].crystals == 0) {
+    if (game.state.plnets[game.iplnet].crystals == MINED) {
+       prout("This planet has already been strip-mined for dilithium.");
+       return;
+    }
+    else if (game.state.plnets[game.iplnet].crystals == 0) {
        prout("No dilithium crystals on this planet.");
        return;
     }
@@ -224,6 +229,7 @@ void mine(void)
     game.optime = (0.1+0.2*Rand())*game.state.plnets[game.iplnet].pclass;
     if (consumeTime()) return;
     prout("Mining operation complete.");
+    game.state.plnets[game.iplnet].crystals = MINED;
     game.imine = 1;
     game.ididit=1;
 }
@@ -504,3 +510,79 @@ void deathray(void)
     finish(FTRIBBLE);
     return;
 }
+
+char *systemname(planet *planet)
+{
+    static char        *names[NINHAB] =
+    {
+       /*
+        * This started out life as the BSD Trek inhabited-planets list,
+        * but I used <http://www.memory-alpha.org> to weed out planets
+        * with no references in ST:TOS and to fill it out again to the
+        * required length from "The Worlds of The Federation" list,
+        * <http://memory-alpha.org/en/wiki/The_Worlds_of_the_Federation>.
+        * Some misspellings have been silently corrected.  (To be
+        * fair, there was no Web when Eric Allman did his list.)
+        *
+        * Some planets marked Class G and P here will be displayed as class M
+        * because of the way planets are generated. This is a known bug.
+        */
+       "ERROR",
+       // Added Federation Worlds
+       "Deneva",               /* TOS: "Operation -- Annihilate!" */
+       "Eminiar VII",          /* TOS: "A Taste of Armageddon" */
+       "Hansen's Planet",      /* TOS: "The Galileo Seven" */
+       "Taurus IV",            /* TOS: "The Galileo Seven" (class G) */
+       "Aldebaran III",        /* TOS: "The Deadly Years" */
+       "Vulcan (T'Khasi)",     /* many episodes */
+       "Tellar Prime (Miracht)",       /* TOS: "Journey to Babel" */
+       "Andoria (Fesoan)",     /* several episodes */
+       "Antos IV (Doraphane)", /* TOS: "Whom Gods Destroy", "Who Mourns for Adonais?" */
+       "Catulla (Cendo-Prae)", /* TOS: "The Way to Eden" */
+       "Izar",                 /* TOS: "Whom Gods Destroy" */
+       "Tiburon",              /* TOS: "The Way to Eden" */
+       "Merak II",             /* TOS: "The Cloud Minders" */
+       "Argelius II (Nelphia)",        /* TOS: "Wolf in the Fold" ("IV" in BSD) */
+       "Daran V",              /* TOS: "For the World is Hollow and I Have Touched the Sky" */
+       "Medusa",               /* TOS: "Is There in Truth No Beauty?" */
+       "Coridan (Desotriana)", /* TOS: "Journey to Babel" */
+       "Berengaria IV",        /* TOS: "This Side of Paradise" */
+       "Capella IV (Kohath)",  /* TOS: "Friday's Child" (Class G) */
+       "Gideon",               /* TOS: "The Mark of Gideon" */
+       "Iotia",                /* TOS: "A Piece of the Action" */
+       /* Worlds from BSD Trek */
+       //"Talos IV",           /* TOS: "The Cage" (interdicted world) */
+       "Rigel II",             /* TOS: "Shore Leave" ("III" in BSD) */
+       "Deneb II",             /* TOS: "Wolf in the Fold" ("IV" in BSD) */
+       //"Canopus V",          /* noncanonical */
+       //"Icarus I",           /* noncanonical */
+       //"Prometheus II",      /* noncanonical */
+       //"Omega VII",          /* noncanonical */
+       //"Elysium I",          /* noncanonical */
+       "Scalos IV",            /* TOS: "Wink of an Eye" */
+       //"Procyon IV",         /* noncanonical */
+       //"Arachnid I",         /* noncanonical */
+       //"Argo VIII",          /* noncanonical */
+       //"Triad III",          /* noncanonical */
+       //"Echo IV",            /* noncanonical */
+       //"Nimrod III",         /* noncanonical */
+       //"Nemisis IV",         /* noncanonical */
+       //"Centarurus I",       /* noncanonical */
+       //"Kronos III",         /* noncanonical */
+       //"Spectros V",         /* noncanonical */
+       "Beta III",             /* TOS: "The Return of the Archons" */
+       "Gamma Tranguli VI (Vaalel)",   /* TOS: "The Apple" */
+       "Pyris VII",            /* TOS: "Catspaw" ("III" in BSD) */
+       "Triacus",              /* TOS: "And the Children Shall Lead", */
+       "Marcos XII",           /* TOS: "And the Children Shall Lead", */
+       //"Kaland",             /* noncanonical */
+       "Ardana",               /* TOS: "The Cloud Minders" */
+       //"Stratos",            /* noncanonical */
+       //"Eden",               /* TOS: "The Way to Eden" (in Romulan space) */
+       //"Arrikis",            /* noncanonical */
+       //"Epsilon Eridani IV", /* noncanonical */
+       "Exo III",              /* TOS: "What Are Little Girls Made Of?" (Class P) */
+    };
+
+    return names[planet->inhabited];
+}
index 0948073b01a4d6a2e88bd7573184ed9d51012a94..aa642e49c1d6aaa47ede4dd42e30146522379940 100644 (file)
@@ -313,6 +313,16 @@ static void status(int req)
        proutn("Klingons Left %d", KLINGREM);
        break;
     case 10:
+       if (game.options & OPTION_WORLDS) {
+           planet *here = game.state.galaxy[game.quadx][game.quady].planet;
+           if (here && here->inhabited != UNINHABITED)
+               proutn("Major system  %s", systemname(here));
+           else
+               proutn("Sector is uninhabited");
+       }
+
+       break;
+    case 11:
        attakreport(1);
        break;
     }
@@ -320,8 +330,9 @@ static void status(int req)
                
 int srscan(int l) 
 {
+    /* the "sy" request is undocumented */
     static char requests[][3] =
-       {"","da","co","po","ls","wa","en","to","sh","kl","ti"};
+       {"","da","co","po","ls","wa","en","to","sh","kl","sy", "ti"};
     int leftside=TRUE, rightside=TRUE, i, j, jj, req=0, nn=FALSE;
     int goodScan=TRUE;
     switch (l) {
@@ -358,7 +369,7 @@ int srscan(int l)
        if (req > sizeof(requests)/sizeof(requests[0])) {
            prout("UNRECOGNIZED REQUEST. Legal requests are:");
            prout("  date, condition, position, lsupport, warpfactor,");
-           prout("  energy, torpedoes, shields, klingons, time, bases.");
+           prout("  energy, torpedoes, shields, klingons, time, system, bases.");
            return FALSE;
        }
        // no break
index 4b1ed3a325789afb472b2ce6021fae35f3d0d599..ed97fd8a962765d20210a49e74ee43555f280d9f 100644 (file)
@@ -229,7 +229,7 @@ void setup(int needprompt)
     for_quadrants(i)
        for_quadrants(j) {
            game.state.galaxy[i][j].charted = 0;
-           game.state.galaxy[i][j].planets = 0;
+           game.state.galaxy[i][j].planet = NULL;
            game.state.galaxy[i][j].romulans = 0;
            game.state.galaxy[i][j].klingons = 0;
            game.state.galaxy[i][j].starbase = 0;
@@ -328,13 +328,22 @@ void setup(int needprompt)
     }
     // Locate planets in galaxy
     for (i = 0; i < game.inplan; i++) {
-       do iran(GALSIZE, &ix, &iy); while (game.state.galaxy[ix][iy].planets);
-       game.state.galaxy[ix][iy].planets = 1;
+       do iran(GALSIZE, &ix, &iy); while (game.state.galaxy[ix][iy].planet);
        game.state.plnets[i].x = ix;
        game.state.plnets[i].y = iy;
-       game.state.plnets[i].pclass = Rand()*3.0; // Planet class M N or O
-       game.state.plnets[i].crystals = 1.5*Rand();             // 1 in 3 chance of crystals
-       game.state.plnets[i].known = unknown;
+       if (i < NINHAB) {
+           game.state.plnets[i].pclass = M;    // All inhabited planets are class M
+           game.state.plnets[i].crystals = 0;
+           game.state.plnets[i].known = known;
+           game.state.plnets[i].inhabited = i;
+       } else {
+           game.state.plnets[i].pclass = Rand()*3.0; // Planet class M N or O
+           game.state.plnets[i].crystals = 1.5*Rand();         // 1 in 3 chance of crystals
+           game.state.plnets[i].known = unknown;
+           game.state.plnets[i].inhabited = UNINHABITED;
+       }
+       if ((game.options & OPTION_WORLDS) || i >= NINHAB)
+           game.state.galaxy[ix][iy].planet = game.state.plnets + i;
     }
     // Locate Romulans
     for (i = 1; i <= game.state.nromrem; i++) {
@@ -495,7 +504,7 @@ int choose(int needprompt)
     game.state.rembase = 2.0 + Rand()*(BASEMAX-2.0);
     game.inbase = game.state.rembase;
     if (game.options & OPTION_PLANETS)
-       game.inplan = (PLNETMAX/2) + (PLNETMAX/2+1)*Rand();
+       game.inplan = NINHAB + (MAXUNINHAB/2) + (MAXUNINHAB/2+1)*Rand();
     game.state.nromrem = game.inrom = (2.0+Rand())*game.skill;
     game.state.nscrem = game.inscom = (game.skill > SKILL_FAIR ? 1 : 0);
     game.state.remtime = 7.0 * game.length;
@@ -531,7 +540,8 @@ void newcnd(void)
 
 void newqad(int shutup) 
 {
-    int i, j, ix, iy, nplan;
+    int i, j, ix, iy;
+    planet *planhere;
 
     game.iattak = 1;
     game.justin = 1;
@@ -565,7 +575,6 @@ void newqad(int shutup)
        return;
     game.klhere = game.state.galaxy[game.quadx][game.quady].klingons;
     game.irhere = game.state.galaxy[game.quadx][game.quady].romulans;
-    nplan  = game.state.galaxy[game.quadx][game.quady].planets;
     game.nenhere = game.klhere + game.irhere;
 
     // Position Starship
@@ -610,14 +619,11 @@ void newqad(int shutup)
     if (game.state.galaxy[game.quadx][game.quady].starbase)
        dropin(IHB, &game.basex, &game.basey);
        
-    if (nplan) {
-       // If quadrant needs a planet, put it in
-       for (i=0; i < game.inplan; i++)
-           if (game.state.plnets[i].x == game.quadx && game.state.plnets[i].y == game.quady) break;
-       if (i < game.inplan) {
-           game.iplnet = i;
-           dropin(IHP, &game.plnetx, &game.plnety);
-       }
+    // If quadrant needs a planet, put it in
+    planhere = game.state.galaxy[game.quadx][game.quady].planet;
+    if (planhere) {
+       game.iplnet = planhere - game.state.plnets;
+       dropin(IHP, &game.plnetx, &game.plnety);
     }
     // Check for game.condition
     newcnd();
@@ -626,7 +632,7 @@ void newqad(int shutup)
        dropin(IHSTAR, &ix, &iy);
 
     // Check for RNZ
-    if (game.irhere > 0 && game.klhere == 0) {
+    if (game.irhere > 0 && game.klhere == 0 && (!planhere || planhere->inhabited == UNINHABITED)) {
        game.neutz = 1;
        if (game.damage[DRADIO] <= 0.0) {
            skip(1);
index 3ec832c719017269199db55ee48f624d4358ff83..4288bbbd8651e7e4c2ecfbb81c421108e4700a82 100644 (file)
--- a/src/sst.c
+++ b/src/sst.c
@@ -152,6 +152,12 @@ for a lot of magic numbers and refactored the heck out of it.
 
    4. Added game option selection so you can play a close (but not bug-for-
       bug identical) approximation of older versions.
+
+   5. Half the quadrants now have inhabited planets, from which one 
+      cannot mine dilithium (there will still be the same additional number
+      of dilithium-bearing planets).  Right now this is just color, but
+      eventually we'll fold in BSD-Trek-like logic for Klingons to attack
+      and enslave inhabited worlds.
 */
 
 /* the input queue */
index 396f6dabdf054f91f8d823bf8d8d31a7eaaf3bb0..7e7d1d30dd0e9067e334a7df1f9f255c9a4de56b 100644 (file)
--- a/src/sst.h
+++ b/src/sst.h
 // #define DEBUG
 
 #define PHASEFAC (2.0)
-#define PLNETMAX (10)
 #define GALSIZE        (8)
+#define NINHAB (GALSIZE * GALSIZE / 2)
+#define MAXUNINHAB (10)
+#define PLNETMAX (NINHAB + MAXUNINHAB)
 #define QUADSIZE (10)
 #define BASEMAX        (5)
 
@@ -39,7 +41,10 @@ typedef struct {
     int x;     /* Quadrant location of planet */
     int y;
     enum {M=0, N=1, O=2} pclass;
+    int inhabited;     /* if NZ, an index into a name array */
+#define UNINHABITED    -1
     int crystals; /* has crystals */
+#define MINED  -1      /* used to have crystals, but they were mined out */
     enum {unknown, known, shuttle_down} known;
 } planet;
 
@@ -65,7 +70,7 @@ typedef struct {
            remtime;            // remaining time
     struct {
        int stars;
-       int planets;
+       planet *planet;
        int starbase;
        int klingons;
        int romulans;
@@ -108,6 +113,7 @@ typedef struct {
 #define OPTION_MVBADDY 0x00000100      /* more enemies can move */
 #define OPTION_BLKHOLE 0x00000200      /* black hole may timewarp you */
 #define OPTION_BASE    0x00000400      /* bases have good shields */
+#define OPTION_WORLDS  0x00000800      /* logic for inhabited worlds */
 #define OPTION_PLAIN   0x01000000      /* user chose plain game */
 #define OPTION_ALMY    0x02000000      /* user chose Almy variant */
 
@@ -389,6 +395,7 @@ void setpassword(void);
 void commandhook(char *, int);
 void makechart(void);
 void enqueue(char *);
+char *systemname(planet *);
 
 /* mode arguments for srscan() */
 #define SCAN_FULL              1