Chase more booleans and enums.
[super-star-trek.git] / src / sst.c
index 36f444959238493d6414a44f1ab3b6c9e13671b3..d19698491d71a64611cf7b7a0fd6a99591a9d6cd 100644 (file)
--- a/src/sst.c
+++ b/src/sst.c
@@ -162,6 +162,17 @@ for a lot of magic numbers and refactored the heck out of it.
       type is "plain" or "almy".)
 
    6. User input is now logged so we can do regression testing.
+
+   7. More BSD-Trek features: You can now lose if your entire crew
+      dies in battle.  When abandoning ship in a game with inhabited
+      worlds enabled, they must have one in the quadrant to beam down
+      to; otherwise they die in space and this counts heavily against
+      your score.  Docking at a starbase replenishes your crew.
+
+   8. Still more BSD-Trek: we now have a weighted damage table.
+      Also, the nav subsystem (enabling automatic course
+      setting) can be damaged separately from the main computer (which
+      handles weapons targeting, ETA calculation, and self-destruct).
 */
 
 /* the input queue */
@@ -169,15 +180,14 @@ static char line[128], *linep = line;
 
 struct game game;
 coord thing;
-int iqhere, iqengry;
+bool iqhere, iqengry;
 int iscore, iskill;    // Common PLAQ
 double aaitem;
 double perdate;
 char citem[10];
 int seed;              // the random-number seed
 bool idebug;           // debug mode
-bool randready;                // Has the random-number generator initialized?
-FILE *logfp;
+FILE *logfp, *replayfp;
 
 char *device[NDEVICES] = {
        "S. R. Sensors",
@@ -191,6 +201,7 @@ char *device[NDEVICES] = {
        "Subspace Radio",
        "Shuttle Craft",
        "Computer",
+       "Navigation System",
        "Transporter",
        "Shield Control",
        "Death Ray",
@@ -285,7 +296,9 @@ commands[] = {
 #define NUMCOMMANDS    sizeof(commands)/sizeof(commands[0])
 #define ACCEPT(i)      (!commands[i].option || (commands[i].option & game.options))
 
-static void listCommands(void) {
+static void listCommands(void) 
+/* generate a list of legal commands */
+{
     int i, k = 0;
     proutn("LEGAL COMMANDS ARE:");
     for (i = 0; i < NUMCOMMANDS; i++) {
@@ -299,7 +312,8 @@ static void listCommands(void) {
     skip(1);
 }
 
-static void helpme(void) 
+static void helpme(void)
+/* browse on-line help */
 {
     int i, j;
     char cmdbuf[32], *cp;
@@ -378,12 +392,14 @@ static void helpme(void)
     fclose(fp);
 }
 
-void enqueue(char *s) 
+void enqueue(char *s)
+/* enqueue input for the command parser */
 {
     strcpy(line, s);
 }
 
-static void makemoves(void) 
+static void makemoves(void)
+/* command-interpretation loop */
 {
     int key, i, v = 0;
     bool hitme;
@@ -393,7 +409,7 @@ static void makemoves(void)
        drawmaps(1);
        for(;;)  { /* get a command */
            hitme = false;
-           game.justin = 0;
+           game.justin = false;
            game.optime = 0.0;
            i = -1;
            chew();
@@ -404,7 +420,7 @@ static void makemoves(void)
                makechart();
                continue;
            }
-           game.ididit=0;
+           game.ididit = false;
            clrscr();
            setwnd(message_window);
            clrscr();
@@ -450,10 +466,10 @@ static void makemoves(void)
            warp(false);
            break;
        case SHIELDS:                   // shields
-           doshield(1);
+           doshield(false);
            if (game.ididit) {
-               hitme=true;
-               game.shldchg = 0;
+               hitme = true;
+               game.shldchg = false;
            }
            break;
        case DOCK:                      // dock
@@ -464,7 +480,7 @@ static void makemoves(void)
            dreprt();
            break;
        case CHART:                     // chart
-           chart(0);
+           chart(false);
            break;
        case IMPULSE:                   // impulse
            impuls();
@@ -526,7 +542,7 @@ static void makemoves(void)
            abandn();
            break;
        case DESTRUCT:                  // Self Destruct
-           dstrct();
+           selfdestruct();
            break;
        case SAVE:                      // Save Game
            freeze(false);
@@ -546,7 +562,7 @@ static void makemoves(void)
            if (game.ididit) hitme = true;
            break;
        case QUIT:
-           game.alldone = 1;           // quit the game
+           game.alldone = true;                // quit the game
            break;
        case HELP:
            helpme();                   // get help
@@ -565,14 +581,14 @@ static void makemoves(void)
                if (game.alldone) break;        // Events did us in
            }
            if (game.state.galaxy[game.quadrant.x][game.quadrant.y].supernova) { // Galaxy went Nova!
-               atover(0);
+               atover(false);
                continue;
            }
-           if (hitme && game.justin==0) {
+           if (hitme && !game.justin) {
                attack(2);
                if (game.alldone) break;
                if (game.state.galaxy[game.quadrant.x][game.quadrant.y].supernova) {    // went NOVA! 
-                   atover(0);
+                   atover(false);
                    hitme = true;
                    continue;
                }
@@ -595,8 +611,20 @@ int main(int argc, char **argv)
     else
        game.options |= OPTION_TTY;
 
-    while ((option = getopt(argc, argv, "tx")) != -1) {
+    seed = (int)time(NULL);
+    while ((option = getopt(argc, argv, "r:tx")) != -1) {
        switch (option) {
+       case 'r':
+           replayfp = fopen(optarg, "r");
+           if (replayfp == NULL) {
+               fprintf(stderr, "sst: can't open replay file %s\n", optarg);
+               exit(1);        
+           }
+           if (fscanf(replayfp, "seed %d\n", &seed) != 1) {
+               fprintf(stderr, "sst: replay file %s is ill-formed\n", optarg);
+               exit(1);        
+           }
+           /* FALL THROUGH */
        case 't':
            game.options |= OPTION_TTY;
            game.options &=~ OPTION_CURSES;
@@ -612,8 +640,10 @@ int main(int argc, char **argv)
     /* where to save the input in case of bugs */
     logfp = fopen("sst-input.log", "w");
     setlinebuf(logfp);
+    fprintf(logfp, "seed %d\n", seed);
+    srand(seed);
 
-    randomize();
+    srand(seed);
     iostart();
 
     line[0] = '\0';
@@ -628,7 +658,7 @@ int main(int argc, char **argv)
        setup(line[0] == '\0');
        if (game.alldone) {
            score();
-           game.alldone = 0;
+           game.alldone = false;
        }
        else makemoves();
        skip(1);
@@ -637,7 +667,7 @@ int main(int argc, char **argv)
 
        if (game.tourn && game.alldone) {
            proutn("Do you want your score recorded?");
-           if (ja()) {
+           if (ja() == true) {
                chew2();
                freeze(false);
            }
@@ -651,7 +681,8 @@ int main(int argc, char **argv)
 }
 
 
-void cramen(int i) 
+void cramen(feature i) 
+/* print the name of an enemy */
 {
     /* return an enemy */
     char *s;
@@ -674,6 +705,7 @@ void cramen(int i)
 }
 
 char *cramlc(enum loctype key, coord w)
+/* name a location */
 {
     static char buf[32];
     buf[0] = '\0';
@@ -683,15 +715,17 @@ char *cramlc(enum loctype key, coord w)
     return buf;
 }
 
-void crmena(int i, int enemy, int key, coord w) 
+void crmena(bool stars, feature enemy, enum loctype key, coord w) 
+/* print an enemy and his location */
 {
-    if (i == 1) proutn("***");
+    if (stars) proutn("***");
     cramen(enemy);
     proutn(" at ");
     proutn(cramlc(key, w));
 }
 
-void crmshp(void) 
+void crmshp(void)
+/* print our ship name */
 {
     char *s;
     switch (game.ship) {
@@ -702,7 +736,8 @@ void crmshp(void)
     proutn(s);
 }
 
-void stars(void) 
+void stars(void)
+/* print a line of stars */
 {
     prouts("******************************************************");
     skip(1);
@@ -715,21 +750,16 @@ double expran(double avrage)
 
 double Rand(void) 
 {
-    if (!randready) {
-       if (seed == 0)
-           seed = (unsigned)time(NULL);
-       if (logfp)
-           fprintf(logfp, "seed %d\n", seed);
-       srand(seed);
-       randready = true;
-    }
     return rand()/(1.0 + (double)RAND_MAX);
 }
 
-void iran(int size, int *i, int *j) 
+coord randplace(int size)
+/* choose a random location */ 
 {
-    *i = Rand()*(size*1.0) + 1.0;
-    *j = Rand()*(size*1.0) + 1.0;
+    coord w;
+    w.x = Rand()*(size*1.0) + 1.0;
+    w.y = Rand()*(size*1.0) + 1.0;
+    return w;
 }
 
 void chew(void)
@@ -800,7 +830,8 @@ int scan(void)
     return IHALPHA;
 }
 
-bool ja(void) 
+bool ja(void)
+/* yes-or-no confirmation */
 {
     chew();
     for(;;) {
@@ -812,46 +843,45 @@ bool ja(void)
     }
 }
 
-void huh(void) 
+void huh(void)
+/* complain about unparseable input */
 {
     chew();
     skip(1);
     prout("Beg your pardon, Captain?");
 }
 
-int isit(char *s) 
+bool isit(char *s) 
+/* compares s to citem and returns true if it matches to the length of s */
 {
-    /* New function -- compares s to scanned citem and returns true if it
-       matches to the length of s */
-
     return strncasecmp(s, citem, max(1, strlen(citem))) == 0;
-
 }
 
-void debugme(void) 
+void debugme(void)
+/* access to the internals for debugging */
 {
     proutn("Reset levels? ");
-    if (ja() != 0) {
+    if (ja() == true) {
        if (game.energy < game.inenrg) game.energy = game.inenrg;
        game.shield = game.inshld;
        game.torps = game.intorps;
        game.lsupres = game.inlsr;
     }
     proutn("Reset damage? ");
-    if (ja() != 0) {
+    if (ja() == true) {
        int i;
        for (i=0; i < NDEVICES; i++) 
            if (game.damage[i] > 0.0) 
                game.damage[i] = 0.0;
     }
     proutn("Toggle debug flag? ");
-    if (ja() != 0) {
+    if (ja() == true) {
        idebug = !idebug;
        if (idebug) prout("Debug output ON");
        else prout("Debug output OFF");
     }
     proutn("Cause selective damage? ");
-    if (ja() != 0) {
+    if (ja() == true) {
        int i, key;
        for (i=0; i < NDEVICES; i++) {
            proutn("Kill ");
@@ -865,13 +895,12 @@ void debugme(void)
        }
     }
     proutn("Examine/change events? ");
-    if (ja() != 0) {
+    if (ja() == true) {
        event *ev;
        coord w;
        int i;
        for (i = 1; i < NEVENTS; i++) {
            int key;
-           if (!is_scheduled(i)) continue;
            switch (i) {
            case FSNOVA:  proutn("Supernova       "); break;
            case FTBEAM:  proutn("T Beam          "); break;
@@ -880,43 +909,56 @@ void debugme(void)
            case FCDBAS:  proutn("Base Destroy    "); break;
            case FSCMOVE: proutn("SC Move         "); break;
            case FSCDBAS: proutn("SC Base Destroy "); break;
-           //case FDSPROB:proutn("Probe Move      "); break;
+           case FDSPROB: proutn("Probe Move      "); break;
            case FDISTR:  proutn("Distress Call   "); break;
            case FENSLV:  proutn("Enlavement      "); break;
            case FREPRO:  proutn("Klingon Build   "); break;
            }
-           proutn("%.2f", scheduled(i)-game.state.date);
+           if (is_scheduled(i)) {
+               proutn("%.2f", scheduled(i)-game.state.date);
+               if (i == FENSLV || i == FREPRO) {
+                   ev = findevent(i);
+                   proutn(" in %d-%d", ev->quadrant.x,ev->quadrant.y);
+               }
+           } else
+               proutn("never");
+           proutn("? ");
            chew();
-           proutn("  ?");
            key = scan();
-           if (key == IHREAL) {
+           if (key == 'n') {
+               unschedule(i);
+               chew();
+           } else if (key == IHREAL) {
                ev = schedule(i, aaitem);
                if (i == FENSLV || i == FREPRO) {
                    chew();
                    proutn("In quadrant- ");
                    key = scan();
-                   if (key != IHREAL) {
-                       prout("Event %d canceled, no y coordinate.", i);
-                       unschedule(i);
-                       continue;
-                   }
-                   w.y = (int)aaitem;
-                   key = scan();
-                   if (key != IHREAL) {
-                       prout("Event %d canceled, no x coordinate.", i);
-                       unschedule(i);
-                       continue;
+                   /* IHEOL says to leave coordinates as they are */
+                   if (key != IHEOL) {
+                       if (key != IHREAL) {
+                           prout("Event %d canceled, no x coordinate.", i);
+                           unschedule(i);
+                           continue;
+                       }
+                       w.x = (int)aaitem;
+                       key = scan();
+                       if (key != IHREAL) {
+                           prout("Event %d canceled, no y coordinate.", i);
+                           unschedule(i);
+                           continue;
+                       }
+                       w.y = (int)aaitem;
+                       ev->quadrant = w;
                    }
-                   w.x = (int)aaitem;
-                   ev->quadrant = w;
                }
            }
        }
        chew();
     }
     proutn("Induce supernova here? ");
-    if (ja() != 0) {
+    if (ja() == true) {
        game.state.galaxy[game.quadrant.x][game.quadrant.y].supernova = true;
-       atover(1);
+       atover(true);
     }
 }