Deathray is now regressed to original 5% probability in 'plain' games.
[super-star-trek.git] / sst.c
diff --git a/sst.c b/sst.c
index b31200ecece75d2d857a83983d970aa208a57a35..8f85a764ebdca61e08d9825029f52f90c0bf625a 100644 (file)
--- a/sst.c
+++ b/sst.c
 #define INCLUDED       // Define externs here
 #include <ctype.h>
 #include <getopt.h>
+#include <time.h>
+#include "sstlinux.h"
 #include "sst.h"
 
 #ifndef SSTDOC
 #define SSTDOC "sst.doc"
 #endif
        
-static char line[128], *linep = line;
-
 /*
 
+Dave Matuszek says:
+
+   SRSCAN, MOVE, PHASERS, CALL, STATUS, IMPULSE, PHOTONS, ABANDON,
+   LRSCAN, WARP, SHIELDS, DESTRUCT, CHART, REST, DOCK, QUIT, and DAMAGE
+   were in the original non-"super" version of UT FORTRAN Star Trek.
+
+   Tholians weren't in the original. Dave is dubious about their merits.
+   (They are now controlled by OPTION_THOLIAN and turned off if the game
+   type is "plain".)
+
+   Planets and dilithium crystals weren't in the original.  Dave is OK
+   with this idea. (It's now controlled by OPTION_PLANETS and turned 
+   off if the game type is "plain".)
+
+   Dave says the bit about the Galileo getting turned into a
+   McDonald's is "consistant with our original vision".  (This has been
+   left permanently enabled, as it can only happen if OPTION_PLANETS
+   is on.)
+
+   Dave also says the Space Thingy should not be preserved across saved
+   games, so you can't prove to others that you've seen it.  He says it
+   shouldn't fire back, either.  It should do nothing except scream and
+   disappear when hit by photon torpedos.  It's OK that it may move
+   when attacked, but it didn't in the original.  (Whether the Thingy
+   can fire back is now controlled by OPTION_THINGY and turned off if the
+   game type is "plain" or "almy".  The no-save behavior has been restored.)
+
+   The Faerie Queen, black holes, and time warping were in the original.
+
 Here are Tom Almy's changes:
 
- Compared to original version, I've changed the "help" command to
  Compared to original version, I've changed the "help" command to
    "call" and the "terminate" command to "quit" to better match
    user expectations. The DECUS version apparently made those changes
    as well as changing "freeze" to "save". However I like "freeze".
+   (Both "freeze" and "save" work in SST2K.)
 
-   When I got a later version of Super Star Trek that I was converting
-   from, I added the emexit command.
+   When I got a later (1979) version of Super Star Trek that I was converting
+   from, I added the emexit command from it.
 
-   That later version also mentions srscan and lrscan working when
+   That 1979 version also mentions srscan and lrscan working when
    docked (using the starbase's scanners), so I made some changes here
    to do this (and indicating that fact to the player), and then realized
    the base would have a subspace radio as well -- doing a Chart when docked
    updates the star chart, and all radio reports will be heard. The Dock
    command will also give a report if a base is under attack.
 
-   Movecom no longer reports movement if sensors are damaged so you wouldn't
-   otherwise know it.
-
    Also added:
 
-   1. Better base positioning at startup
+   1. The experimental deathray originally had only a 5% chance of
+      success, but could be used repeatedly. I guess after a couple
+      years of use, it was less "experimental" because the 1979
+      version had a 70% success rate. However it was prone to breaking
+      after use. I upgraded the deathray, but kept the original set of
+      failure modes (great humor!).  (Now controlled by OPTION_DEATHRAY
+      and turned off if game type is "plain".)
 
-   2. Deathray improvement (but keeping original failure alternatives)
+   2. Tholian Web from the 1979 version.  (Now controlled by
+      OPTION_THOLIAN and turned off if game type is "plain".)
 
-   3. Tholian Web.
+   3. Enemies can ram the Enterprise. (Now controlled by OPTION_RAMMING
+      and turned off if game type is "plain".)
 
-   4. Enemies can ram the Enterprise. Regular Klingons and Romulans can
-      move in Expert and Emeritus games. This code could use improvement.
+   4. Regular Klingons and Romulans can move in Expert and Emeritus games. 
+      This code could use improvement. (Now controlled by OPTION_MVBADDY
+      and turned off if game type is "plain".)
 
-   5. The deep space probe looks interesting! DECUS version
+   5. The deep-space probe feature from the DECUS version.  (Now controlled
+      by OPTION_PROBE and turned off if game type is "plain").
 
-   6. Perhaps cloaking to be added later? BSD version
+   6. Bugfix: Klingon commander movements are no longer reported if long-range 
+      sensors are damaged.
 
-Here are Stas Sergeev's changes (controlled by the proprocessor symbol
-SERGEEV, not yet completely merged):
+   7. Bugfix: Better base positioning at startup (more spread out).
+      That made sense to add because most people abort games with 
+      bad base placement.
 
-   1. The Space Thingy can be shoved, if you it ram, and can fire back if 
-      fired upon.
+   In June 2002, I fixed two known bugs and a documentation typo.
+   In June 2004 I fixed a number of bugs involving: 1) parsing invalid
+   numbers, 2) manual phasers when SR scan is damaged and commander is
+   present, 3) time warping into the future, 4) hang when moving
+   klingons in crowded quadrants.  (These fixes are in SST2K.)
 
-   1 The Tholian can be hit with phasers
+Here are Stas Sergeev's changes:
 
-   2. When you are docked, base covers you with an almost invincible shields 
-      (a commander can still ram you, or a Romulan can destroy the base,
+   1. The Space Thingy can be shoved, if you ram it, and can fire back if 
+      fired upon. (Now controlled by OPTION_THINGY and turned off if game 
+      type is "plain" or "almy".)
+
+   2. When you are docked, base covers you with an almost invincible shield. 
+      (A commander can still ram you, or a Romulan can destroy the base,
       or a SCom can even succeed with direct attack IIRC, but this rarely 
-      happens).
+      happens.)  (Now controlled by OPTION_BASE and turned off if game 
+      type is "plain" or "almy".)
+
+   3. Ramming a black hole is no longer instant death.  There is a
+      chance you might get timewarped instead. (Now controlled by 
+      OPTION_BLKHOLE and turned off if game type is "plain" or "almy".)
+
+   4. The Tholian can be hit with phasers.
 
-    3. SCom can't escape from you if no more enemies remain (without this, 
-       chasing SCom can take an eternity).
+   5. SCom can't escape from you if no more enemies remain 
+      (without this, chasing SCom can take an eternity).
 
-    4. Probe target you enter is now the destination quadrant. Before I don't 
-       remember what it was, but it was something I had difficulty using)
+   6. Probe target you enter is now the destination quadrant. Before I don't 
+      remember what it was, but it was something I had difficulty using.
 
-    5. Secret password is now autogenerated.
+   7. Secret password is now autogenerated.
 
-    6. "Plaque" is adjusted for A4 paper:)
+   8. "Plaque" is adjusted for A4 paper :-)
 
-    7. Phasers now tells you how much energy needed, but only if the computer 
-       is alive.
+   9. Phasers now tells you how much energy needed, but only if the computer 
+      is alive.
 
-    8. Planets are auto-scanned when you enter the quadrant.
+   10. Planets are auto-scanned when you enter the quadrant.
 
-    9. Mining or using crystals in presense of enemy now yields an attack.
+   11. Mining or using crystals in presense of enemy now yields an attack.
        There are other minor adjustments to what yields an attack
        and what does not.
 
-    10. Ramming a black hole is no longer instant death.  There is a
-        chance you might get timewarped instead.
-
-   */
-
-static char *commands[] = {
-       "srscan",
-       "lrscan",
-       "phasers",
-       "photons",
-       "move",
-       "shields",
-       "dock",
-       "damages",
-       "chart",
-       "impulse",
-       "rest",
-       "warp",
-       "status",
-       "sensors",
-       "orbit",
-       "transport",
-       "mine",
-       "crystals",
-       "shuttle",
-       "planets",
-       "request",
-       "report",
-       "computer",
-       "commands",
-    "emexit",
-    "probe",
-       "abandon",
-       "destruct",
-       "freeze",
-       "deathray",
-       "debug",
-       "call",
-       "quit",
-       "help"
-};
-#define NUMCOMMANDS    sizeof(commands)/sizeof(commands[0])
+   12. "freeze" command reverts to "save", most people will understand this
+       better anyway. (SST2K recognizes both.)
+
+   13. Screen-oriented interface, with sensor scans always up.  (SST2K
+       supports both screen-oriented and TTY modes.)
+
+Eric Raymond's changes:
+
+Mainly, I translated this C code out of FORTRAN into C -- created #defines
+for a lot of magic numbers and refactored the heck out of it.
+
+   1. "sos" and "call" becomes "mayday", "freeze" and "save" are both good.
 
-static void listCommands(int x) {
-       prout("   SRSCAN    MOVE      PHASERS   CALL\n"
-                 "   STATUS    IMPULSE   PHOTONS   ABANDON\n"
-                 "   LRSCAN    WARP      SHIELDS   DESTRUCT\n"
-                 "   CHART     REST      DOCK      QUIT\n"
-                 "   DAMAGES   REPORT    SENSORS   ORBIT\n"
-                 "   TRANSPORT MINE      CRYSTALS  SHUTTLE\n"
-                 "   PLANETS   REQUEST   DEATHRAY  FREEZE\n"
-                 "   COMPUTER  EMEXIT    PROBE     COMMANDS");
-       if (x) prout("   HELP");
+   2. Status report now indicates when dilithium crystals are on board.
+
+   3. Per Dave Matuszek's remarks, Thingy state is never saved across games.
+
+   4. Added game option selection so you can play a close (but not bug-for-
+      bug identical) approximation of older versions.
+*/
+
+/* the input queue */
+static char line[128], *linep = line;
+
+static struct 
+{
+    char *name;
+    int value;
+    unsigned long option;
 }
+commands[] = {
+#define SRSCAN 0
+       {"SRSCAN",      SRSCAN,         OPTION_TTY},
+#define STATUS 1
+       {"STATUS",      STATUS,         OPTION_TTY},
+#define REQUEST        2
+       {"REQUEST",     REQUEST,        OPTION_TTY},
+#define LRSCAN 3
+       {"LRSCAN",      LRSCAN,         OPTION_TTY},
+#define PHASERS        4
+       {"PHASERS",     PHASERS,        0},
+#define TORPEDO        5
+        {"TORPEDO",    TORPEDO,        0},
+       {"PHOTONS",     TORPEDO,        0},
+#define MOVE   6
+       {"MOVE",        MOVE,           0},
+#define SHIELDS        7
+       {"SHIELDS",     SHIELDS,        0},
+#define DOCK   8
+       {"DOCK",        DOCK,           0},
+#define DAMAGES        9
+       {"DAMAGES",     DAMAGES,        0},
+#define CHART  10
+       {"CHART",       CHART,          0},
+#define IMPULSE        11
+       {"IMPULSE",     IMPULSE,        0},
+#define REST   12
+       {"REST",        REST,           0},
+#define WARP   13
+       {"WARP",        WARP,           0},
+#define SCORE  14
+       {"SCORE",       SCORE,          0},
+#define SENSORS        15
+       {"SENSORS",     SENSORS,        OPTION_PLANETS},
+#define ORBIT  16
+       {"ORBIT",       ORBIT,          OPTION_PLANETS},
+#define TRANSPORT      17
+       {"TRANSPORT",   TRANSPORT,      OPTION_PLANETS},
+#define MINE   18
+       {"MINE",        MINE,           OPTION_PLANETS},
+#define CRYSTALS       19
+       {"CRYSTALS",    CRYSTALS,       OPTION_PLANETS},
+#define SHUTTLE        20
+       {"SHUTTLE",     SHUTTLE,        OPTION_PLANETS},
+#define PLANETS        21
+       {"PLANETS",     PLANETS,        OPTION_PLANETS},
+#define REPORT 22
+       {"REPORT",      REPORT,         0},
+#define COMPUTER       23
+       {"COMPUTER",    COMPUTER,       0},
+#define COMMANDS       24
+       {"COMMANDS",    COMMANDS,       0},
+#define EMEXIT 25
+       {"EMEXIT",      EMEXIT,         0},
+#define PROBE  26
+       {"PROBE",       PROBE,          OPTION_PROBE},
+#define SAVE   27
+       {"SAVE",        SAVE,           0},
+       {"FREEZE",      SAVE,           0},
+#define ABANDON        28
+       {"ABANDON",     ABANDON,        0},
+#define DESTRUCT       29
+       {"DESTRUCT",    DESTRUCT,       0},
+#define DEATHRAY       30
+       {"DEATHRAY",    DEATHRAY,       0},
+#define DEBUGCMD       31
+       {"DEBUG",       DEBUGCMD,       0},
+#define MAYDAY 32
+       {"MAYDAY",      MAYDAY,         0},
+       //{"SOS",               MAYDAY,         0},
+       //{"CALL",      MAYDAY,         0},
+#define QUIT   33
+       {"QUIT",        QUIT,           0},
+#define HELP   34
+       {"HELP",        HELP,           0},
+};
 
-#ifdef SERGEEV
-void setwnd(short wndnum){
-     int cury;
-     cury=wherey()+wnds[curwnd].wndtop-wnds[wndnum].wndtop;
-     if ((curwnd==0)&&(wndnum!=0)) clrscr();
-     window(wnds[wndnum].wndleft, wnds[wndnum].wndtop, wnds[wndnum].wndright, wnds[wndnum].wndbottom);
-     if ((curwnd==wndnum)&&(cury>wnds[wndnum].wndbottom-wnds[wndnum].wndtop+1)){
-        gotoxy(wnds[wndnum].wndright-wnds[wndnum].wndleft+1,wnds[wndnum].wndbottom-wnds[wndnum].wndtop+1);
-       skip(1);
-     }
-     curwnd=wndnum;
-     gotoxy(1,cury);
+#define NUMCOMMANDS    sizeof(commands)/sizeof(commands[0])
+#define ACCEPT(i)      (!commands[i].option || (commands[i].option & game.options))
+
+static void listCommands(void) {
+    int i, k = 0;
+    proutn("LEGAL COMMANDS ARE:");
+    for (i = 0; i < NUMCOMMANDS; i++) {
+       if (!ACCEPT(i))
+           continue;
+       if (k % 5 == 0)
+           skip(1);
+       proutn("%-12s ", commands[i].name); 
+       k++;
+    }
+    skip(1);
 }
-#endif /* SERGEEV */
-
-static void helpme(void) {
-       int i, j;
-       char cmdbuf[32], *cp;
-       char linebuf[132];
-       FILE *fp;
-       /* Give help on commands */
-       int key;
-       key = scan();
-       while (TRUE) {
-               if (key == IHEOL) {
-#ifdef SERGEEV
-                        setwnd(5);
-#endif /* SERGEEV */
-                        proutn("Help on what command? ");
-                       key = scan();
-               }
-#ifdef SERGEEV
-                setwnd(4);
-#endif /* SERGEEV */
-               if (key == IHEOL) return;
-               for (i = 0; i < NUMCOMMANDS; i++) {
-                       if (strcmp(commands[i], citem)==0) break;
-               }
-               if (i != NUMCOMMANDS) break;
-               skip(1);
-               prout("Valid commands:");
-               listCommands(FALSE);
-               key = IHEOL;
-               chew();
-               skip(1);
-       }
-       if (i == 23) {
-               strcpy(cmdbuf, " ABBREV");
-       }
-       else {
-           for (j = 0; commands[i][j]; j++)
-               cmdbuf[j] = toupper(commands[i][j]);
-           cmdbuf[j] = '\0';
-       }
-       fp = fopen(SSTDOC, "r");
-       if (fp == NULL) {
-               prout("Spock-  \"Captain, that information is missing from the");
-               prout("   computer. You need to find SST.DOC and put it in the");
-               prout("   current directory.\"");
-               return;
+
+static void helpme(void) 
+{
+    int i, j;
+    char cmdbuf[32], *cp;
+    char linebuf[132];
+    FILE *fp;
+    /* Give help on commands */
+    int key;
+    key = scan();
+    while (TRUE) {
+       if (key == IHEOL) {
+           setwnd(prompt_window);
+           proutn("Help on what command? ");
+           key = scan();
        }
-       for (;;) {
-           if (fgets(linebuf, sizeof(linebuf), fp) == NULL) {
-                       prout("Spock- \"Captain, there is no information on that command.\"");
-                       fclose(fp);
-                       return;
-               }
-           if (linebuf[0] == '%' && linebuf[1] == '%'&& linebuf[2] == ' ') {
-               for (cp = linebuf+3; isspace(*cp); cp++)
-                       continue;
-               linebuf[strlen(linebuf)-1] = '\0';
-               if (strcmp(cp, cmdbuf) == 0)
-                   break;
+       setwnd(message_window);
+       if (key == IHEOL) return;
+       for (i = 0; i < NUMCOMMANDS; i++) {
+           if (ACCEPT(i) && strcasecmp(commands[i].name, citem)==0) {
+               i = commands[i].value;
+               break;
            }
        }
-
+       if (i != NUMCOMMANDS) break;
        skip(1);
-       prout("Spock- \"Captain, I've found the following information:\"");
+       prout("Valid commands:");
+       listCommands();
+       key = IHEOL;
+       chew();
        skip(1);
-
-       while (fgets(linebuf, sizeof(linebuf),fp)) {
-               if (strstr(linebuf, "******"))
-                       break;
-               proutc(linebuf);
+    }
+    if (i == COMMANDS) {
+       strcpy(cmdbuf, " ABBREV");
+    }
+    else {
+       for (j = 0; commands[i].name[j]; j++)
+           cmdbuf[j] = toupper(commands[i].name[j]);
+       cmdbuf[j] = '\0';
+    }
+    fp = fopen(SSTDOC, "r");
+    if (fp == NULL) {
+       prout("Spock-  \"Captain, that information is missing from the");
+       prout("   computer.\"");
+       /*
+        * This used to continue: "You need to find SST.DOC and put 
+        * it in the current directory."
+        */
+       return;
+    }
+    for (;;) {
+       if (fgets(linebuf, sizeof(linebuf), fp) == NULL) {
+           prout("Spock- \"Captain, there is no information on that command.\"");
+           fclose(fp);
+           return;
        }
-       fclose(fp);
+       if (linebuf[0] == '%' && linebuf[1] == '%'&& linebuf[2] == ' ') {
+           for (cp = linebuf+3; isspace(*cp); cp++)
+               continue;
+           linebuf[strlen(linebuf)-1] = '\0';
+           if (strcasecmp(cp, cmdbuf) == 0)
+               break;
+       }
+    }
+
+    skip(1);
+    prout("Spock- \"Captain, I've found the following information:\"");
+    skip(1);
+
+    while (fgets(linebuf, sizeof(linebuf),fp)) {
+       if (strstr(linebuf, "******"))
+           break;
+       proutn(linebuf);
+    }
+    fclose(fp);
 }
 
-#ifdef SERGEEV
-void drawmaps(short l){
-     _setcursortype(_NOCURSOR);
-     if (l==1) sensor();
-     if (l!=2) setwnd(1);
-     gotoxy(1,1);
-     strcpy(line,"s");
-     srscan(1);
-     if (l!=2){
-        setwnd(2);
-        clrscr();
-        srscan(2);
-        setwnd(3);
-        clrscr();
-        strcpy(line,"l");
-        lrscan();
-        _setcursortype(_NORMALCURSOR);
-     }
+void enqueue(char *s) 
+{
+    strcpy(line, s);
 }
-#endif /* SERGEEV */
-
-static void makemoves(void) {
-       int i, hitme;
-       while (TRUE) { /* command loop */
-               hitme = FALSE;
-               justin = 0;
-               Time = 0.0;
-               i = -1;
-               while (TRUE)  { /* get a command */
-                       chew();
-                       skip(1);
-                       proutn("COMMAND> ");
-                       if (scan() == IHEOL) continue;
-                       for (i=0; i < 26; i++)
-                               if (isit(commands[i]))
-                                       break;
-                       if (i < 26) break;
-                       for (; i < NUMCOMMANDS; i++)
-                               if (strcmp(commands[i], citem) == 0) break;
-                       if (i < NUMCOMMANDS) break;
-
-                       if (skill <= 2)  {
-                               prout("UNRECOGNIZED COMMAND. LEGAL COMMANDS ARE:");
-                               listCommands(TRUE);
-                       }
-                       else prout("UNRECOGNIZED COMMAND.");
+
+static void makemoves(void) 
+{
+    int i, v = 0, hitme;
+    clrscr();
+    setwnd(message_window);
+    while (TRUE) { /* command loop */
+       drawmaps(1);
+       while (TRUE)  { /* get a command */
+           hitme = FALSE;
+           justin = 0;
+           Time = 0.0;
+           i = -1;
+           chew();
+           setwnd(prompt_window);
+           clrscr();
+           proutn("COMMAND> ");
+           if (scan() == IHEOL) {
+               makechart();
+               continue;
+           }
+           ididit=0;
+           clrscr();
+           setwnd(message_window);
+           clrscr();
+           for (i=0; i < ABANDON; i++)
+               if (ACCEPT(i) && isit(commands[i].name)) {
+                   v = commands[i].value;
+                   break;
+               }
+           if (i < ABANDON && (!commands[i].option || (commands[i].option & game.options))) 
+               break;
+           for (; i < NUMCOMMANDS; i++)
+               if (ACCEPT(i) && strcasecmp(commands[i].name, citem) == 0) {
+                   v = commands[i].value;
+                   break;
                }
-               commandhook(commands[i], TRUE);
-               switch (i) { /* command switch */
-                       case 0:                 // srscan
-                               srscan(1);
-                               break;
-                       case 1:                 // lrscan
-                               lrscan();
-                               break;
-                       case 2:                 // phasers
-                               phasers();
-                               if (ididit) hitme = TRUE;
-                               break;
-                       case 3:                 // photons
-                               photon();
-                               if (ididit) hitme = TRUE;
-                               break;
-                       case 4:                 // move
-                               warp(1);
-                               break;
-                       case 5:                 // shields
-                               doshield(1);
-                               if (ididit) {
-                                       attack(2);
-                                       shldchg = 0;
-                               }
-                               break;
-                       case 6:                 // dock
-                               dock(1);
-                                if (ididit) attack(0);
-                               break;
-                       case 7:                 // damages
-                               dreprt();
-                               break;
-                       case 8:                 // chart
-                               chart(0);
-                               break;
-                       case 9:                 // impulse
-                               impuls();
-                               break;
-                       case 10:                // rest
-                               wait();
-                               if (ididit) hitme = TRUE;
-                               break;
-                       case 11:                // warp
-                               setwrp();
-                               break;
-                       case 12:                // status
-                               srscan(3);
-                               break;
-                       case 13:                        // sensors
-                               sensor();
-                               break;
-                       case 14:                        // orbit
-                               orbit();
-                               if (ididit) hitme = TRUE;
-                               break;
-                       case 15:                        // transport "beam"
-                               beam();
-                               break;
-                       case 16:                        // mine
-                               mine();
-                               if (ididit) hitme = TRUE;
-                               break;
-                       case 17:                        // crystals
-                               usecrystals();
-                               break;
-                       case 18:                        // shuttle
-                               shuttle();
-                               if (ididit) hitme = TRUE;
-                               break;
-                       case 19:                        // Planet list
-                               preport();
-                               break;
-                       case 20:                        // Status information
-                               srscan(2);
-                               break;
-                       case 21:                        // Game Report 
-                               report(0);
-                               break;
-                       case 22:                        // use COMPUTER!
-                               eta();
-                               break;
-                       case 23:
-                               listCommands(TRUE);
-                               break;
-                       case 24:                // Emergency exit
-                               clearscreen();  // Hide screen
-                               freeze(TRUE);   // forced save
-                               exit(1);                // And quick exit
-                               break;
-                       case 25:
-                               probe();                // Launch probe
-                               break;
-                       case 26:                        // Abandon Ship
-                               abandn();
-                               break;
-                       case 27:                        // Self Destruct
-                               dstrct();
-                               break;
-                       case 28:                        // Save Game
-                               freeze(FALSE);
-                               if (skill > 3)
-                                       prout("WARNING--Frozen games produce no plaques!");
-                               break;
-                       case 29:                        // Try a desparation measure
-                               deathray();
-                               if (ididit) hitme = TRUE;
-                               break;
-                       case 30:                        // What do we want for debug???
+           if (i < NUMCOMMANDS && (!commands[i].option || (commands[i].option & game.options))) 
+               break;
+           listCommands();
+       }
+       commandhook(commands[i].name, TRUE);
+       switch (v) { /* command switch */
+       case SRSCAN:                 // srscan
+           srscan(SCAN_FULL);
+           break;
+       case STATUS:                 // status
+           srscan(SCAN_STATUS);
+           break;
+       case REQUEST:                   // status request 
+           srscan(SCAN_REQUEST);
+           break;
+       case LRSCAN:                    // lrscan
+           lrscan();
+           break;
+       case PHASERS:                   // phasers
+           phasers();
+           if (ididit) hitme = TRUE;
+           break;
+       case TORPEDO:                   // photons
+           photon();
+           if (ididit) hitme = TRUE;
+           break;
+       case MOVE:                      // move
+           warp(1);
+           break;
+       case SHIELDS:                   // shields
+           doshield(1);
+           if (ididit) {
+               hitme=TRUE;
+               shldchg = 0;
+           }
+           break;
+       case DOCK:                      // dock
+           dock(1);
+           if (ididit) attack(0);
+           break;
+       case DAMAGES:                   // damages
+           dreprt();
+           break;
+       case CHART:                     // chart
+           chart(0);
+           break;
+       case IMPULSE:                   // impulse
+           impuls();
+           break;
+       case REST:                      // rest
+           wait();
+           if (ididit) hitme = TRUE;
+           break;
+       case WARP:                      // warp
+           setwrp();
+           break;
+       case SCORE:                     // score
+           score();
+           break;
+       case SENSORS:                   // sensors
+           sensor();
+           break;
+       case ORBIT:                     // orbit
+           orbit();
+           if (ididit) hitme = TRUE;
+           break;
+       case TRANSPORT:                 // transport "beam"
+           beam();
+           break;
+       case MINE:                      // mine
+           mine();
+           if (ididit) hitme = TRUE;
+           break;
+       case CRYSTALS:                  // crystals
+           usecrystals();
+           if (ididit) hitme = TRUE;
+           break;
+       case SHUTTLE:                   // shuttle
+           shuttle();
+           if (ididit) hitme = TRUE;
+           break;
+       case PLANETS:                   // Planet list
+           preport();
+           break;
+       case REPORT:                    // Game Report 
+           report();
+           break;
+       case COMPUTER:                  // use COMPUTER!
+           eta();
+           break;
+       case COMMANDS:
+           listCommands();
+           break;
+       case EMEXIT:                    // Emergency exit
+           clrscr();                   // Hide screen
+           freeze(TRUE);               // forced save
+           exit(1);                    // And quick exit
+           break;
+       case PROBE:
+           probe();                    // Launch probe
+           if (ididit) hitme = TRUE;
+           break;
+       case ABANDON:                   // Abandon Ship
+           abandn();
+           break;
+       case DESTRUCT:                  // Self Destruct
+           dstrct();
+           break;
+       case SAVE:                      // Save Game
+           freeze(FALSE);
+           clrscr();
+           if (skill > SKILL_GOOD)
+               prout("WARNING--Saved games produce no plaques!");
+           break;
+       case DEATHRAY:                  // Try a desparation measure
+           deathray();
+           if (ididit) hitme = TRUE;
+           break;
+       case DEBUGCMD:                  // What do we want for debug???
 #ifdef DEBUG
-                               debugme();
+           debugme();
 #endif
-                               break;
-                       case 31:                // Call for help
-                               help();
-                               break;
-                       case 32:
-                               alldone = 1;    // quit the game
+           break;
+       case MAYDAY:                    // Call for help
+           help();
+           if (ididit) hitme = TRUE;
+           break;
+       case QUIT:
+           alldone = 1;                // quit the game
 #ifdef DEBUG
-                               if (idebug) score();
+           if (idebug) score();
 #endif
-                               break;
-                       case 33:
-                               helpme();       // get help
-                               break;
-               }
-               commandhook(commands[i], FALSE);
-               for (;;) {
-                       if (alldone) break;             // Game has ended
+           break;
+       case HELP:
+           helpme();   // get help
+           break;
+       }
+       commandhook(commands[i].name, FALSE);
+       for (;;) {
+           if (alldone) break;         // Game has ended
 #ifdef DEBUG
-                       if (idebug) prout("2500");
+           if (idebug) prout("2500");
 #endif
-                       if (Time != 0.0) {
-                               events();
-                               if (alldone) break;             // Events did us in
-                       }
-                       if (game.state.galaxy[quadx][quady] == 1000) { // Galaxy went Nova!
-                               atover(0);
-                               continue;
-                       }
-                       if (nenhere == 0) movetho();
-                       if (hitme && justin==0) {
-                               attack(2);
-                               if (alldone) break;
-                               if (game.state.galaxy[quadx][quady] == 1000) {  // went NOVA! 
-                                       atover(0);
-                                       hitme = TRUE;
-                                       continue;
-                               }
-                       }
-                       break;
-               }
+           if (Time != 0.0) {
+               events();
+               if (alldone) break;     // Events did us in
+           }
+           if (game.state.galaxy[quadx][quady].supernova) { // Galaxy went Nova!
+               atover(0);
+               continue;
+           }
+           if (hitme && justin==0) {
+               attack(2);
                if (alldone) break;
+               if (game.state.galaxy[quadx][quady].supernova) {        // went NOVA! 
+                   atover(0);
+                   hitme = TRUE;
+                   continue;
+               }
+           }
+           break;
        }
+       if (alldone) break;
+    }
 }
 
 
-int main(int argc, char **argv) {
-    int i, option, usecurses = TRUE;
-       while ((option = getopt(argc, argv, "t")) != -1) {
-           switch (option) {
-           case 't':
-               usecurses = FALSE;
-               break;
-           default:
-               fprintf(stderr, "usage: sst [-t] [startcommand...].\n");
-               exit(0);
-           }
+int main(int argc, char **argv) 
+{
+    int i, option;
+
+    game.options = OPTION_ALL &~ (OPTION_IOMODES | OPTION_SHOWME | OPTION_PLAIN | OPTION_ALMY);
+    if (getenv("TERM"))
+       game.options |= OPTION_CURSES | OPTION_SHOWME;
+    else
+       game.options |= OPTION_TTY;
+
+    while ((option = getopt(argc, argv, "t")) != -1) {
+       switch (option) {
+       case 't':
+           game.options |= OPTION_TTY;
+           game.options &=~ OPTION_CURSES;
+           break;
+       default:
+           fprintf(stderr, "usage: sst [-t] [startcommand...].\n");
+           exit(0);
        }
-
-       iostart(usecurses);
-       prelim(); 
-       line[0] = '\0';
-       for (i = optind; i < argc;  i++) {
-               strcat(line, argv[i]);
-               strcat(line, " ");
-       }
-       while (TRUE) { /* Play a game */
-               setup(line[0] == '\0');
-               if (alldone) {
-                       score();
-                       alldone = 0;
-               }
-               else makemoves();
-               skip(2);
-               stars();
-               skip(1);
-
-               if (tourn && alldone) {
-                       proutn("Do you want your score recorded?");
-                       if (ja()) {
-                               chew2();
-                               freeze(FALSE);
-                       }
-               }
-               proutn("Do you want to play again? ");
-               if (!ja()) break;
-#ifdef SERGEEV
-               setwnd(0);
-               clrscr();
-#endif /* SERGEEV */
+    }
+
+    randomize();
+    iostart();
+
+    line[0] = '\0';
+    for (i = optind; i < argc;  i++) {
+       strcat(line, argv[i]);
+       strcat(line, " ");
+    }
+    while (TRUE) { /* Play a game */
+       setwnd(fullscreen_window);
+#ifdef DEBUG
+       prout("INITIAL OPTIONS: %0lx", game.options);
+#endif /* DEBUG */
+       clrscr();
+       prelim();
+       setup(line[0] == '\0');
+       if (alldone) {
+           score();
+           alldone = 0;
        }
+       else makemoves();
+       skip(1);
+       stars();
        skip(1);
-#ifndef SERGEEV
-       ioend();
-#endif /* SERGEEV */
-       puts("May the Great Bird of the Galaxy roost upon your home planet.");
-       exit(0);
+
+       if (tourn && alldone) {
+           proutn("Do you want your score recorded?");
+           if (ja()) {
+               chew2();
+               freeze(FALSE);
+           }
+       }
+       proutn("Do you want to play again? ");
+       if (!ja()) break;
+    }
+    skip(1);
+    prout("May the Great Bird of the Galaxy roost upon your home planet.");
+    return 0;
 }
 
 
-void cramen(int i) {
-       /* return an enemy */
-       char *s;
+void cramen(int i) 
+{
+    /* return an enemy */
+    char *s;
        
-       switch (i) {
-               case IHR: s = "Romulan"; break;
-               case IHK: s = "Klingon"; break;
-               case IHC: s = "Commander"; break;
-               case IHS: s = "Super-commander"; break;
-               case IHSTAR: s = "Star"; break;
-               case IHP: s = "Planet"; break;
-               case IHB: s = "Starbase"; break;
-               case IHBLANK: s = "Black hole"; break;
-               case IHT: s = "Tholian"; break;
-               case IHWEB: s = "Tholian web"; break;
-                case IHQUEST: s = "Stranger"; break;
-               default: s = "Unknown??"; break;
-       }
-       proutn(s);
+    switch (i) {
+    case IHR: s = "Romulan"; break;
+    case IHK: s = "Klingon"; break;
+    case IHC: s = "Commander"; break;
+    case IHS: s = "Super-commander"; break;
+    case IHSTAR: s = "Star"; break;
+    case IHP: s = "Planet"; break;
+    case IHB: s = "Starbase"; break;
+    case IHBLANK: s = "Black hole"; break;
+    case IHT: s = "Tholian"; break;
+    case IHWEB: s = "Tholian web"; break;
+    case IHQUEST: s = "Stranger"; break;
+    default: s = "Unknown??"; break;
+    }
+    proutn(s);
 }
 
-char *cramlc(enum loctype key, int x, int y) {
-       static char buf[32];
-       buf[0] = '\0';
-       if (key == quadrant) strcpy(buf, "Quadrant ");
-       else if (key == sector) strcpy(buf, "Sector ");
-       sprintf(buf+strlen(buf), "%d-%d", x, y);
-       return buf;
+char *cramlc(enum loctype key, int x, int y)
+{
+    static char buf[32];
+    buf[0] = '\0';
+    if (key == quadrant) strcpy(buf, "Quadrant ");
+    else if (key == sector) strcpy(buf, "Sector ");
+    sprintf(buf+strlen(buf), "%d - %d", x, y);
+    return buf;
 }
 
-void crmena(int i, int enemy, int key, int x, int y) {
-       if (i == 1) proutn("***");
-       cramen(enemy);
-       proutn(" at ");
-       proutn(cramlc(key, x, y));
+void crmena(int i, int enemy, int key, int x, int y) 
+{
+    if (i == 1) proutn("***");
+    cramen(enemy);
+    proutn(" at ");
+    proutn(cramlc(key, x, y));
 }
 
-void crmshp(void) {
-       char *s;
-       switch (ship) {
-               case IHE: s = "Enterprise"; break;
-               case IHF: s = "Faerie Queene"; break;
-               default:  s = "Ship???"; break;
-       }
-       proutn(s);
+void crmshp(void) 
+{
+    char *s;
+    switch (ship) {
+    case IHE: s = "Enterprise"; break;
+    case IHF: s = "Faerie Queene"; break;
+    default:  s = "Ship???"; break;
+    }
+    proutn(s);
 }
 
-void stars(void) {
-       prouts("******************************************************");
-       skip(1);
+void stars(void) 
+{
+    prouts("******************************************************");
+    skip(1);
 }
 
-double expran(double avrage) {
-       return -avrage*log(1e-7 + Rand());
+double expran(double avrage) 
+{
+    return -avrage*log(1e-7 + Rand());
 }
 
 double Rand(void) {
        return rand()/(1.0 + (double)RAND_MAX);
 }
 
-void iran8(int *i, int *j) {
-       *i = Rand()*8.0 + 1.0;
-       *j = Rand()*8.0 + 1.0;
+void iran(int size, int *i, int *j) 
+{
+    *i = Rand()*(size*1.0) + 1.0;
+    *j = Rand()*(size*1.0) + 1.0;
 }
 
-void iran10(int *i, int *j) {
-       *i = Rand()*10.0 + 1.0;
-       *j = Rand()*10.0 + 1.0;
+void chew(void)
+{
+    linep = line;
+    *linep = 0;
 }
 
-void chew(void) {
-       linep = line;
-       *linep = 0;
+void chew2(void) 
+{
+    /* return IHEOL next time */
+    linep = line+1;
+    *linep = 0;
 }
 
-void chew2(void) {
-       /* return IHEOL next time */
-       linep = line+1;
-       *linep = 0;
-}
-
-int scan(void) {
-       int i;
-       char *cp;
+int scan(void) 
+{
+    int i;
+    char *cp;
 
-       // Init result
-       aaitem = 0.0;
-       *citem = 0;
+    // Init result
+    aaitem = 0.0;
+    *citem = 0;
 
-       // Read a line if nothing here
-       if (*linep == 0) {
-               if (linep != line) {
-                       chew();
-                       return IHEOL;
-               }
-               getline(line, sizeof(line));
-               linep = line;
+    // Read a line if nothing here
+    if (*linep == 0) {
+       if (linep != line) {
+           chew();
+           return IHEOL;
        }
-       // Skip leading white space
-       while (*linep == ' ') linep++;
-       // Nothing left
-       if (*linep == 0) {
-               chew();
-               return IHEOL;
+       cgetline(line, sizeof(line));
+       fflush(stdin);
+       if (curwnd==prompt_window){
+           clrscr();
+           setwnd(message_window);
+           clrscr();
        }
-       if (isdigit(*linep) || *linep=='+' || *linep=='-' || *linep=='.') {
-               // treat as a number
-           i = 0;
-           if (sscanf(linep, "%lf%n", &aaitem, &i) < 1) {
-               linep = line; // Invalid numbers are ignored
-               *linep = 0;
-               return IHEOL;
-           }
-           else {
-               // skip to end
-               linep += i;
-               return IHREAL;
-           }
+       linep = line;
+    }
+    // Skip leading white space
+    while (*linep == ' ') linep++;
+    // Nothing left
+    if (*linep == 0) {
+       chew();
+       return IHEOL;
+    }
+    if (isdigit(*linep) || *linep=='+' || *linep=='-' || *linep=='.') {
+       // treat as a number
+       i = 0;
+       if (sscanf(linep, "%lf%n", &aaitem, &i) < 1) {
+           linep = line; // Invalid numbers are ignored
+           *linep = 0;
+           return IHEOL;
        }
-       // Treat as alpha
-       cp = citem;
-       while (*linep && *linep!=' ') {
-               if ((cp - citem) < 9) *cp++ = tolower(*linep);
-               linep++;
+       else {
+           // skip to end
+           linep += i;
+           return IHREAL;
        }
-       *cp = 0;
-       return IHALPHA;
+    }
+    // Treat as alpha
+    cp = citem;
+    while (*linep && *linep!=' ') {
+       if ((cp - citem) < 9) *cp++ = tolower(*linep);
+       linep++;
+    }
+    *cp = 0;
+    return IHALPHA;
 }
 
-int ja(void) {
+int ja(void) 
+{
+    chew();
+    while (TRUE) {
+       scan();
        chew();
-       while (TRUE) {
-               scan();
-               chew();
-               if (*citem == 'y') return TRUE;
-               if (*citem == 'n') return FALSE;
-               proutn("Please answer with \"Y\" or \"N\": ");
-       }
+       if (*citem == 'y') return TRUE;
+       if (*citem == 'n') return FALSE;
+       proutn("Please answer with \"Y\" or \"N\": ");
+    }
 }
 
-void huh(void) {
-       chew();
-       skip(1);
-       prout("Beg your pardon, Captain?");
+void huh(void) 
+{
+    chew();
+    skip(1);
+    prout("Beg your pardon, Captain?");
 }
 
-int isit(char *s) {
-       /* New function -- compares s to scaned citem and returns true if it
-          matches to the length of s */
+int isit(char *s) 
+{
+    /* New function -- compares s to scanned citem and returns true if it
+       matches to the length of s */
 
-       return strncmp(s, citem, max(1, strlen(citem))) == 0;
+    return strncasecmp(s, citem, max(1, strlen(citem))) == 0;
 
 }
 
 #ifdef DEBUG
-void debugme(void) {
-       proutn("Reset levels? ");
-       if (ja() != 0) {
-               if (energy < inenrg) energy = inenrg;
-               shield = inshld;
-               torps = intorps;
-               lsupres = inlsr;
-       }
-       proutn("Reset damage? ");
-       if (ja() != 0) {
-               int i;
-               for (i=0; i <= NDEVICES; i++) if (damage[i] > 0.0) damage[i] = 0.0;
-               stdamtim = 1e30;
-       }
-       proutn("Toggle idebug? ");
-       if (ja() != 0) {
-               idebug = !idebug;
-               if (idebug) prout("Debug output ON");
-               else prout("Debug output OFF");
-       }
-       proutn("Cause selective damage? ");
-       if (ja() != 0) {
-               int i, key;
-               for (i=1; i <= NDEVICES; i++) {
-                       proutn("Kill ");
-                       proutn(device[i]);
-                       proutn("? ");
-                       chew();
-                       key = scan();
-                       if (key == IHALPHA &&  isit("y")) {
-                               damage[i] = 10.0;
-                               if (i == DRADIO) stdamtim = game.state.date;
-                       }
-               }
+void debugme(void) 
+{
+    proutn("Reset levels? ");
+    if (ja() != 0) {
+       if (energy < inenrg) energy = inenrg;
+       shield = inshld;
+       torps = intorps;
+       lsupres = inlsr;
+    }
+    proutn("Reset damage? ");
+    if (ja() != 0) {
+       int i;
+       for (i=0; i < NDEVICES; i++) 
+           if (game.damage[i] > 0.0) 
+               game.damage[i] = 0.0;
+    }
+    proutn("Toggle idebug? ");
+    if (ja() != 0) {
+       idebug = !idebug;
+       if (idebug) prout("Debug output ON");
+       else prout("Debug output OFF");
+    }
+    proutn("Cause selective damage? ");
+    if (ja() != 0) {
+       int i, key;
+       for (i=0; i < NDEVICES; i++) {
+           proutn("Kill ");
+           proutn(device[i]);
+           proutn("? ");
+           chew();
+           key = scan();
+           if (key == IHALPHA &&  isit("y")) {
+               game.damage[i] = 10.0;
+           }
        }
-       proutn("Examine/change events? ");
-       if (ja() != 0) {
-               int i;
-               for (i = 1; i < NEVENTS; i++) {
-                       int key;
-                       if (future[i] == 1e30) continue;
-                       switch (i) {
-                               case FSNOVA:  proutn("Supernova       "); break;
-                               case FTBEAM:  proutn("T Beam          "); break;
-                               case FSNAP:   proutn("Snapshot        "); break;
-                               case FBATTAK: proutn("Base Attack     "); break;
-                               case FCDBAS:  proutn("Base Destroy    "); break;
-                               case FSCMOVE: proutn("SC Move         "); break;
-                               case FSCDBAS: proutn("SC Base Destroy "); break;
-                       }
-                       proutn("%.2f", future[i]-game.state.date);
-                       chew();
-                       proutn("  ?");
-                       key = scan();
-                       if (key == IHREAL) {
-                               future[i] = game.state.date + aaitem;
-                       }
-               }
-               chew();
+    }
+    proutn("Examine/change events? ");
+    if (ja() != 0) {
+       int i;
+       for (i = 1; i < NEVENTS; i++) {
+           int key;
+           if (game.future[i] == FOREVER) continue;
+           switch (i) {
+           case FSNOVA:  proutn("Supernova       "); break;
+           case FTBEAM:  proutn("T Beam          "); break;
+           case FSNAP:   proutn("Snapshot        "); break;
+           case FBATTAK: proutn("Base Attack     "); break;
+           case FCDBAS:  proutn("Base Destroy    "); break;
+           case FSCMOVE: proutn("SC Move         "); break;
+           case FSCDBAS: proutn("SC Base Destroy "); break;
+           }
+           proutn("%.2f", game.future[i]-game.state.date);
+           chew();
+           proutn("  ?");
+           key = scan();
+           if (key == IHREAL) {
+               game.future[i] = game.state.date + aaitem;
+           }
        }
+       chew();
+    }
+    proutn("Induce supernova here? ");
+    if (ja() != 0) {
+       game.state.galaxy[quadx][quady].supernova = TRUE;
+       atover(1);
+    }
 }
-                       
-
 #endif