Better command suppression.
[super-star-trek.git] / sst.c
diff --git a/sst.c b/sst.c
index c8ac356eda049da1ea740374e472d98172f8773b..89e069d51696293328651b8a716f6754a14e7120 100644 (file)
--- a/sst.c
+++ b/sst.c
-#define INCLUDED       // Define externs here\r
-#include "sst.h"\r
-#include <ctype.h>\r
-\r
-#ifndef SSTDOC\r
-#define SSTDOC "sst.doc"\r
-#endif\r
-       \r
-static char line[128], *linep = line;\r
-\r
-/* Compared to original version, I've changed the "help" command to\r
-   "call" and the "terminate" command to "quit" to better match\r
-   user expectations. The DECUS version apparently made those changes\r
-   as well as changing "freeze" to "save". However I like "freeze".\r
-\r
-   When I got a later version of Super Star Trek that I was converting\r
-   from, I added the emexit command.\r
-\r
-   That later version also mentions srscan and lrscan working when\r
-   docked (using the starbase's scanners), so I made some changes here\r
-   to do this (and indicating that fact to the player), and then realized\r
-   the base would have a subspace radio as well -- doing a Chart when docked\r
-   updates the star chart, and all radio reports will be heard. The Dock\r
-   command will also give a report if a base is under attack.\r
-\r
-   Movecom no longer reports movement if sensors are damaged so you wouldn't\r
-   otherwise know it.\r
-\r
-   Also added:\r
-\r
-   1. Better base positioning at startup\r
-\r
-   2. deathray improvement (but keeping original failure alternatives)\r
-\r
-   3. Tholian Web\r
-s\r
-   4. Enemies can ram the Enterprise. Regular Klingons and Romulans can\r
-      move in Expert and Emeritus games. This code could use improvement.\r
-\r
-   5. The deep space probe looks interesting! DECUS version\r
-\r
-   6. Perhaps cloaking to be added later? BSD version\r
-\r
-\r
-   */\r
-\r
-\r
-static char *commands[] = {\r
-       "srscan",\r
-       "lrscan",\r
-       "phasers",\r
-       "photons",\r
-       "move",\r
-       "shields",\r
-       "dock",\r
-       "damages",\r
-       "chart",\r
-       "impulse",\r
-       "rest",\r
-       "warp",\r
-       "status",\r
-       "sensors",\r
-       "orbit",\r
-       "transport",\r
-       "mine",\r
-       "crystals",\r
-       "shuttle",\r
-       "planets",\r
-       "request",\r
-       "report",\r
-       "computer",\r
-       "commands",\r
-    "emexit",\r
-    "probe",\r
-       "abandon",\r
-       "destruct",\r
-       "freeze",\r
-       "deathray",\r
-       "debug",\r
-       "call",\r
-       "quit",\r
-       "help"\r
-};\r
-#define NUMCOMMANDS    sizeof(commands)/sizeof(commands[0])\r
-\r
-static void listCommands(int x) {\r
-       prout("   SRSCAN    MOVE      PHASERS   CALL\n"\r
-                 "   STATUS    IMPULSE   PHOTONS   ABANDON\n"\r
-                 "   LRSCAN    WARP      SHIELDS   DESTRUCT\n"\r
-                 "   CHART     REST      DOCK      QUIT\n"\r
-                 "   DAMAGES   REPORT    SENSORS   ORBIT\n"\r
-                 "   TRANSPORT MINE      CRYSTALS  SHUTTLE\n"\r
-                 "   PLANETS   REQUEST   DEATHRAY  FREEZE\n"\r
-                 "   COMPUTER  EMEXIT    PROBE     COMMANDS");\r
-       if (x) prout("   HELP");\r
-}\r
-\r
-static void helpme(void) {\r
-       int i, j;\r
-       char cmdbuf[32], *cp;\r
-       char linebuf[132];\r
-       FILE *fp;\r
-       /* Give help on commands */\r
-       int key;\r
-       key = scan();\r
-       while (TRUE) {\r
-               if (key == IHEOL) {\r
-                       proutn("Help on what command?");\r
-                       key = scan();\r
-               }\r
-               if (key == IHEOL) return;\r
-               for (i = 0; i < NUMCOMMANDS; i++) {\r
-                       if (strcmp(commands[i], citem)==0) break;\r
-               }\r
-               if (i != NUMCOMMANDS) break;\r
-               skip(1);\r
-               prout("Valid commands:");\r
-               listCommands(FALSE);\r
-               key = IHEOL;\r
-               chew();\r
-               skip(1);\r
-       }\r
-       if (i == 23) {\r
-               strcpy(cmdbuf, " ABBREV");\r
-       }\r
-       else {\r
-           for (j = 0; commands[i][j]; j++)\r
-               cmdbuf[j] = toupper(commands[i][j]);\r
-           cmdbuf[j] = '\0';\r
-       }\r
-       fp = fopen(SSTDOC, "r");\r
-       if (fp == NULL) {\r
-               prout("Spock-  \"Captain, that information is missing from the");\r
-               prout("   computer. You need to find SST.DOC and put it in the");\r
-               prout("   current directory.\"");\r
-               return;\r
-       }\r
-       for (;;) {\r
-           if (fgets(linebuf, sizeof(linebuf), fp) == NULL) {\r
-                       prout("Spock- \"Captain, there is no information on that command.\"");\r
-                       fclose(fp);\r
-                       return;\r
-               }\r
-           if (linebuf[0] == '%' && linebuf[1] == '%'&& linebuf[2] == ' ') {\r
-               for (cp = linebuf+3; isspace(*cp); cp++)\r
-                       continue;\r
-               linebuf[strlen(linebuf)-1] = '\0';\r
-               if (strcmp(cp, cmdbuf) == 0)\r
-                   break;\r
-           }\r
-       }\r
-\r
-       skip(1);\r
-       prout("Spock- \"Captain, I've found the following information:\"");\r
-       skip(1);\r
-\r
-       while (fgets(linebuf, sizeof(linebuf),fp)) {\r
-               if (strstr(linebuf, "******"))\r
-                       break;\r
-               proutc(linebuf);\r
-       }\r
-       fclose(fp);\r
-}\r
-\r
-static void makemoves(void) {\r
-       int i, hitme;\r
-       char ch;\r
-       while (TRUE) { /* command loop */\r
-               hitme = FALSE;\r
-               justin = 0;\r
-               Time = 0.0;\r
-               i = -1;\r
-               while (TRUE)  { /* get a command */\r
-                       chew();\r
-                       skip(1);\r
-                       proutn("COMMAND> ");\r
-                       if (scan() == IHEOL) continue;\r
-                       for (i=0; i < 26; i++)\r
-                               if (isit(commands[i]))\r
-                                       break;\r
-                       if (i < 26) break;\r
-                       for (; i < NUMCOMMANDS; i++)\r
-                               if (strcmp(commands[i], citem) == 0) break;\r
-                       if (i < NUMCOMMANDS) break;\r
-\r
-                       if (skill <= 2)  {\r
-                               prout("UNRECOGNIZED COMMAND. LEGAL COMMANDS ARE:");\r
-                               listCommands(TRUE);\r
-                       }\r
-                       else prout("UNRECOGNIZED COMMAND.");\r
-               }\r
-               switch (i) { /* command switch */\r
-                       case 0:                 // srscan\r
-                               srscan(1);\r
-                               break;\r
-                       case 1:                 // lrscan\r
-                               lrscan();\r
-                               break;\r
-                       case 2:                 // phasers\r
-                               phasers();\r
-                               if (ididit) hitme = TRUE;\r
-                               break;\r
-                       case 3:                 // photons\r
-                               photon();\r
-                               if (ididit) hitme = TRUE;\r
-                               break;\r
-                       case 4:                 // move\r
-                               warp(1);\r
-                               break;\r
-                       case 5:                 // shields\r
-                               doshield(1);\r
-                               if (ididit) {\r
-                                       attack(2);\r
-                                       shldchg = 0;\r
-                               }\r
-                               break;\r
-                       case 6:                 // dock\r
-                               dock();\r
-                               break;\r
-                       case 7:                 // damages\r
-                               dreprt();\r
-                               break;\r
-                       case 8:                 // chart\r
-                               chart(0);\r
-                               break;\r
-                       case 9:                 // impulse\r
-                               impuls();\r
-                               break;\r
-                       case 10:                // rest\r
-                               wait();\r
-                               if (ididit) hitme = TRUE;\r
-                               break;\r
-                       case 11:                // warp\r
-                               setwrp();\r
-                               break;\r
-                       case 12:                // status\r
-                               srscan(3);\r
-                               break;\r
-                       case 13:                        // sensors\r
-                               sensor();\r
-                               break;\r
-                       case 14:                        // orbit\r
-                               orbit();\r
-                               if (ididit) hitme = TRUE;\r
-                               break;\r
-                       case 15:                        // transport "beam"\r
-                               beam();\r
-                               break;\r
-                       case 16:                        // mine\r
-                               mine();\r
-                               if (ididit) hitme = TRUE;\r
-                               break;\r
-                       case 17:                        // crystals\r
-                               usecrystals();\r
-                               break;\r
-                       case 18:                        // shuttle\r
-                               shuttle();\r
-                               if (ididit) hitme = TRUE;\r
-                               break;\r
-                       case 19:                        // Planet list\r
-                               preport();\r
-                               break;\r
-                       case 20:                        // Status information\r
-                               srscan(2);\r
-                               break;\r
-                       case 21:                        // Game Report \r
-                               report(0);\r
-                               break;\r
-                       case 22:                        // use COMPUTER!\r
-                               eta();\r
-                               break;\r
-                       case 23:\r
-                               listCommands(TRUE);\r
-                               break;\r
-                       case 24:                // Emergency exit\r
-                               clearscreen();  // Hide screen\r
-                               freeze(TRUE);   // forced save\r
-                               exit(1);                // And quick exit\r
-                               break;\r
-                       case 25:\r
-                               probe();                // Launch probe\r
-                               break;\r
-                       case 26:                        // Abandon Ship\r
-                               abandn();\r
-                               break;\r
-                       case 27:                        // Self Destruct\r
-                               dstrct();\r
-                               break;\r
-                       case 28:                        // Save Game\r
-                               freeze(FALSE);\r
-                               if (skill > 3)\r
-                                       prout("WARNING--Frozen games produce no plaques!");\r
-                               break;\r
-                       case 29:                        // Try a desparation measure\r
-                               deathray();\r
-                               if (ididit) hitme = TRUE;\r
-                               break;\r
-                       case 30:                        // What do we want for debug???\r
-#ifdef DEBUG\r
-                               debugme();\r
-#endif\r
-                               break;\r
-                       case 31:                // Call for help\r
-                               help();\r
-                               break;\r
-                       case 32:\r
-                               alldone = 1;    // quit the game\r
-#ifdef DEBUG\r
-                               if (idebug) score();\r
-#endif\r
-                               break;\r
-                       case 33:\r
-                               helpme();       // get help\r
-                               break;\r
-               }\r
-               for (;;) {\r
-                       if (alldone) break;             // Game has ended\r
-#ifdef DEBUG\r
-                       if (idebug) prout("2500");\r
-#endif\r
-                       if (Time != 0.0) {\r
-                               events();\r
-                               if (alldone) break;             // Events did us in\r
-                       }\r
-                       if (game.state.galaxy[quadx][quady] == 1000) { // Galaxy went Nova!\r
-                               atover(0);\r
-                               continue;\r
-                       }\r
-                       if (nenhere == 0) movetho();\r
-                       if (hitme && justin==0) {\r
-                               attack(2);\r
-                               if (alldone) break;\r
-                               if (game.state.galaxy[quadx][quady] == 1000) {  // went NOVA! \r
-                                       atover(0);\r
-                                       hitme = TRUE;\r
-                                       continue;\r
-                               }\r
-                       }\r
-                       break;\r
-               }\r
-               if (alldone) break;\r
-       }\r
-}\r
-\r
-\r
-int main(int argc, char **argv) {\r
-       int i;\r
-       int hitme;\r
-       char ch;\r
-\r
-       iostart();\r
-       prelim(); \r
-       line[0] = '\0';\r
-       if (argc > 1) {\r
-               while (--argc > 0) {\r
-                       strcat(line, *(++argv));\r
-                       strcat(line, " ");\r
-               }\r
-       }\r
-\r
-       while (TRUE) { /* Play a game */\r
-               setup(line[0] == '\0');\r
-               if (alldone) {\r
-                       score();\r
-                       alldone = 0;\r
-               }\r
-               else makemoves();\r
-               skip(2);\r
-               stars();\r
-               skip(1);\r
-\r
-               if (tourn && alldone) {\r
-                       proutn("Do you want your score recorded?");\r
-                       if (ja()) {\r
-                               chew2();\r
-                               freeze(FALSE);\r
-                       }\r
-               }\r
-               proutn("Do you want to play again?");\r
-               if (!ja()) break;\r
-       }\r
-       skip(1);\r
-       ioend();\r
-       puts("May the Great Bird of the Galaxy roost upon your home planet.");\r
-}\r
-\r
-\r
-void cramen(int i) {\r
-       /* return an enemy */\r
-       char *s;\r
-       \r
-       switch (i) {\r
-               case IHR: s = "Romulan"; break;\r
-               case IHK: s = "Klingon"; break;\r
-               case IHC: s = "Commander"; break;\r
-               case IHS: s = "Super-commander"; break;\r
-               case IHSTAR: s = "Star"; break;\r
-               case IHP: s = "Planet"; break;\r
-               case IHB: s = "Starbase"; break;\r
-               case IHBLANK: s = "Black hole"; break;\r
-               case IHT: s = "Tholian"; break;\r
-               case IHWEB: s = "Tholian web"; break;\r
-               default: s = "Unknown??"; break;\r
-       }\r
-       proutn(s);\r
-}\r
-\r
-char *cramlc(enum loctype key, int x, int y) {\r
-       static char buf[32];\r
-       buf[0] = '\0';\r
-       if (key == quadrant) strcpy(buf, "Quadrant ");\r
-       else if (key == sector) strcpy(buf, "Sector ");\r
-       sprintf(buf+strlen(buf), "%d-%d", x, y);\r
-       return buf;\r
-}\r
-\r
-void crmena(int i, int enemy, int key, int x, int y) {\r
-       if (i == 1) proutn("***");\r
-       cramen(enemy);\r
-       proutn(" at ");\r
-       proutn(cramlc(key, x, y));\r
-}\r
-\r
-void crmshp(void) {\r
-       char *s;\r
-       switch (ship) {\r
-               case IHE: s = "Enterprise"; break;\r
-               case IHF: s = "Faerie Queene"; break;\r
-               default:  s = "Ship???"; break;\r
-       }\r
-       proutn(s);\r
-}\r
-\r
-void stars(void) {\r
-       prouts("******************************************************");\r
-       skip(1);\r
-}\r
-\r
-double expran(double avrage) {\r
-       return -avrage*log(1e-7 + Rand());\r
-}\r
-\r
-double Rand(void) {\r
-       return rand()/(1.0 + (double)RAND_MAX);\r
-}\r
-\r
-void iran8(int *i, int *j) {\r
-       *i = Rand()*8.0 + 1.0;\r
-       *j = Rand()*8.0 + 1.0;\r
-}\r
-\r
-void iran10(int *i, int *j) {\r
-       *i = Rand()*10.0 + 1.0;\r
-       *j = Rand()*10.0 + 1.0;\r
-}\r
-\r
-void chew(void) {\r
-       linep = line;\r
-       *linep = 0;\r
-}\r
-\r
-void chew2(void) {\r
-       /* return IHEOL next time */\r
-       linep = line+1;\r
-       *linep = 0;\r
-}\r
-\r
-int scan(void) {\r
-       int i;\r
-       char *cp;\r
-\r
-       // Init result\r
-       aaitem = 0.0;\r
-       *citem = 0;\r
-\r
-       // Read a line if nothing here\r
-       if (*linep == 0) {\r
-               if (linep != line) {\r
-                       chew();\r
-                       return IHEOL;\r
-               }\r
-               getline(line, sizeof(line));\r
-               linep = line;\r
-       }\r
-       // Skip leading white space\r
-       while (*linep == ' ') linep++;\r
-       // Nothing left\r
-       if (*linep == 0) {\r
-               chew();\r
-               return IHEOL;\r
-       }\r
-       if (isdigit(*linep) || *linep=='+' || *linep=='-' || *linep=='.') {\r
-               // treat as a number\r
-           if (sscanf(linep, "%lf%n", &aaitem, &i) < 1) {\r
-               linep = line; // Invalid numbers are ignored\r
-               *linep = 0;\r
-               return IHEOL;\r
-           }\r
-           else {\r
-               // skip to end\r
-               linep += i;\r
-               return IHREAL;\r
-           }\r
-       }\r
-       // Treat as alpha\r
-       cp = citem;\r
-       while (*linep && *linep!=' ') {\r
-               if ((cp - citem) < 9) *cp++ = tolower(*linep);\r
-               linep++;\r
-       }\r
-       *cp = 0;\r
-       return IHALPHA;\r
-}\r
-\r
-int ja(void) {\r
-       chew();\r
-       while (TRUE) {\r
-               scan();\r
-               chew();\r
-               if (*citem == 'y') return TRUE;\r
-               if (*citem == 'n') return FALSE;\r
-               proutn("Please answer with \"Y\" or \"N\":");\r
-       }\r
-}\r
-\r
-double square(double i) { return i*i; }\r
-                                                                       \r
-void huh(void) {\r
-       chew();\r
-       skip(1);\r
-       prout("Beg your pardon, Captain?");\r
-}\r
-\r
-int isit(char *s) {\r
-       /* New function -- compares s to scaned citem and returns true if it\r
-          matches to the length of s */\r
-\r
-       return strncmp(s, citem, max(1, strlen(citem))) == 0;\r
-\r
-}\r
-\r
-#ifdef DEBUG\r
-void debugme(void) {\r
-       proutn("Reset levels? ");\r
-       if (ja() != 0) {\r
-               if (energy < inenrg) energy = inenrg;\r
-               shield = inshld;\r
-               torps = intorps;\r
-               lsupres = inlsr;\r
-       }\r
-       proutn("Reset damage? ");\r
-       if (ja() != 0) {\r
-               int i;\r
-               for (i=0; i <= NDEVICES; i++) if (damage[i] > 0.0) damage[i] = 0.0;\r
-               stdamtim = 1e30;\r
-       }\r
-       proutn("Toggle idebug? ");\r
-       if (ja() != 0) {\r
-               idebug = !idebug;\r
-               if (idebug) prout("Debug output ON");\r
-               else prout("Debug output OFF");\r
-       }\r
-       proutn("Cause selective damage? ");\r
-       if (ja() != 0) {\r
-               int i, key;\r
-               for (i=1; i <= NDEVICES; i++) {\r
-                       proutn("Kill ");\r
-                       proutn(device[i]);\r
-                       proutn("? ");\r
-                       chew();\r
-                       key = scan();\r
-                       if (key == IHALPHA &&  isit("y")) {\r
-                               damage[i] = 10.0;\r
-                               if (i == DRADIO) stdamtim = game.state.date;\r
-                       }\r
-               }\r
-       }\r
-       proutn("Examine/change events? ");\r
-       if (ja() != 0) {\r
-               int i;\r
-               for (i = 1; i < NEVENTS; i++) {\r
-                       int key;\r
-                       if (future[i] == 1e30) continue;\r
-                       switch (i) {\r
-                               case FSNOVA:  proutn("Supernova       "); break;\r
-                               case FTBEAM:  proutn("T Beam          "); break;\r
-                               case FSNAP:   proutn("Snapshot        "); break;\r
-                               case FBATTAK: proutn("Base Attack     "); break;\r
-                               case FCDBAS:  proutn("Base Destroy    "); break;\r
-                               case FSCMOVE: proutn("SC Move         "); break;\r
-                               case FSCDBAS: proutn("SC Base Destroy "); break;\r
-                       }\r
-                       proutn("%.2f", future[i]-game.state.date);\r
-                       chew();\r
-                       proutn("  ?");\r
-                       key = scan();\r
-                       if (key == IHREAL) {\r
-                               future[i] = game.state.date + aaitem;\r
-                       }\r
-               }\r
-               chew();\r
-       }\r
-}\r
-                       \r
-\r
-#endif\r
+#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
+       
+/*
+
+Here are Tom Almy's changes:
+
+ 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".
+
+   When I got a later version of Super Star Trek that I was converting
+   from, I added the emexit command.
+
+   That later 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
+
+   2. Deathray improvement (but keeping original failure alternatives)
+
+   3. Tholian Web.
+
+   4. Enemies can ram the Enterprise. Regular Klingons and Romulans can
+      move in Expert and Emeritus games. This code could use improvement.
+
+   5. The deep space probe looks interesting! DECUS version
+
+   6. Perhaps cloaking to be added later? BSD version
+
+Here are Stas Sergeev's changes:
+
+   1. The Space Thingy can be shoved, if you it ram, and can fire back if 
+      fired upon.
+
+   2. The Tholian can be hit with phasers
+
+   3. 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,
+      or a SCom can even succeed with direct attack IIRC, but this rarely 
+      happens).
+
+   4. SCom can't escape from you if no more enemies remain (without this, 
+      chasing SCom can take an eternity).
+
+   5. 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. Secret password is now autogenerated.
+
+   7. "Plaque" is adjusted for A4 paper :-)
+
+   8. Phasers now tells you how much energy needed, but only if the computer 
+       is alive.
+
+   9. Planets are auto-scanned when you enter the quadrant.
+
+   10. 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.
+
+   11. Ramming a black hole is no longer instant death.  There is a
+       chance you might get timewarped instead.
+
+   12. "freeze" command reverts to "save", most people will understand this
+        better anyway.
+
+   13. Screen-oriented interface, with sensor scans always up.
+
+Eric Raymond's changes:
+
+   1. "sos" and "call" becomes "mayday", "freeze" and "save" are both good.
+
+   2. Status report now indicates when dilithium crystals are on board.
+
+   */
+
+/* the input queue */
+static char line[128], *linep = line;
+static usecurses = TRUE;
+
+static struct 
+{
+    char *name;
+    int value;
+}
+commands[] = {
+#define SRSCAN 0
+       {"SRSCAN",      SRSCAN},
+#define STATUS 1
+       {"STATUS",      STATUS},
+#define REQUEST        2
+       {"REQUEST",     REQUEST},
+#define LRSCAN 3
+       {"LRSCAN",      LRSCAN},
+#define PHASERS        4
+       {"PHASERS",     PHASERS},
+#define TORPEDO        5
+        {"TORPEDO",    TORPEDO},
+       {"PHOTONS",     TORPEDO},
+#define MOVE   6
+       {"MOVE",        MOVE},
+#define SHIELDS        7
+       {"SHIELDS",     SHIELDS},
+#define DOCK   8
+       {"DOCK",        DOCK},
+#define DAMAGES        9
+       {"DAMAGES",     DAMAGES},
+#define CHART  10
+       {"CHART",       CHART},
+#define IMPULSE        11
+       {"IMPULSE",     IMPULSE},
+#define REST   12
+       {"REST",        REST},
+#define WARP   13
+       {"WARP",        WARP},
+#define SCORE  14
+       {"SCORE",       SCORE},
+#define SENSORS        15
+       {"SENSORS",     SENSORS},
+#define ORBIT  16
+       {"ORBIT",       ORBIT},
+#define TRANSPORT      17
+       {"TRANSPORT",   TRANSPORT},
+#define MINE   18
+       {"MINE",        MINE},
+#define CRYSTALS       19
+       {"CRYSTALS",    CRYSTALS},
+#define SHUTTLE        20
+       {"SHUTTLE",     SHUTTLE},
+#define PLANETS        21
+       {"PLANETS",     PLANETS},
+#define REPORT 22
+       {"REPORT",      REPORT},
+#define COMPUTER       23
+       {"COMPUTER",    COMPUTER},
+#define COMMANDS       24
+       {"COMMANDS",    COMMANDS},
+#define EMEXIT 25
+       {"EMEXIT",      EMEXIT},
+#define PROBE  26
+       {"PROBE",       PROBE},
+#define SAVE   27
+       {"SAVE",        SAVE},
+       {"FREEZE",      SAVE},
+#define ABANDON        28
+       {"ABANDON",     ABANDON},
+#define DESTRUCT       29
+       {"DESTRUCT",    DESTRUCT},
+#define DEATHRAY       30
+       {"DEATHRAY",    DEATHRAY},
+#define DEBUGCMD       31
+       {"DEBUG",       DEBUGCMD},
+#define MAYDAY 32
+       {"MAYDAY",      MAYDAY},
+       {"SOS",         MAYDAY},
+       {"CALL",        MAYDAY},
+#define QUIT   33
+       {"QUIT",        QUIT},
+#define HELP   34
+       {"HELP",        HELP},
+};
+
+#define NUMCOMMANDS    sizeof(commands)/sizeof(commands[0])
+
+#define MIN_CURSES_COMMAND     PHASERS         /* might change someday */
+
+static void listCommands(int usecurses) {
+    int i, k = 0;
+    proutn("LEGAL COMMANDS ARE:");
+    for (i = usecurses ? MIN_CURSES_COMMAND : 0; i < NUMCOMMANDS; i++) {
+       if (k % 5 == 0)
+           skip(1);
+       proutn("%-12s ", commands[i].name); 
+       k++;
+    }
+    skip(1);
+}
+
+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();
+               }
+                setwnd(message_window);
+               if (key == IHEOL) return;
+               for (i = 0; i < NUMCOMMANDS; i++) {
+                   if (strcasecmp(commands[i].name, citem)==0) {
+                       i = commands[i].value;
+                       break;
+                   }
+               }
+               if (i != NUMCOMMANDS) break;
+               skip(1);
+               prout("Valid commands:");
+               listCommands(usecurses);
+               key = IHEOL;
+               chew();
+               skip(1);
+       }
+       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;
+               }
+           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);
+}
+
+void enqueue(char *s) {
+    strcpy(line, s);
+}
+
+static void makemoves(void) {
+       int i, 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 (isit(commands[i].name)) {
+                               i = commands[i].value;
+                               break;
+                           }
+                       if (i < ABANDON) break;
+                       for (; i < NUMCOMMANDS; i++)
+                           if (strcasecmp(commands[i].name, citem) == 0) {
+                                   i = commands[i].value;
+                                   break;
+                           }
+                       if (i < NUMCOMMANDS) break;
+                       listCommands(usecurses);
+               }
+               commandhook(commands[i].name, TRUE);
+               switch (i) { /* 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(usecurses);
+                               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 > 3)
+                                        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();
+#endif
+                               break;
+                       case MAYDAY:            // Call for help
+                               help();
+                                if (ididit) hitme = TRUE;
+                               break;
+                       case QUIT:
+                               alldone = 1;    // quit the game
+#ifdef DEBUG
+                               if (idebug) score();
+#endif
+                               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");
+#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 (hitme && justin==0) {
+                               attack(2);
+                               if (alldone) break;
+                               if (game.state.galaxy[quadx][quady] == 1000) {  // went NOVA! 
+                                       atover(0);
+                                       hitme = TRUE;
+                                       continue;
+                               }
+                       }
+                       break;
+               }
+               if (alldone) break;
+       }
+}
+
+
+int main(int argc, char **argv) {
+    int i, option;
+
+       while ((option = getopt(argc, argv, "t")) != -1) {
+           switch (option) {
+           case 't':
+               usecurses = FALSE;
+               break;
+           default:
+               fprintf(stderr, "usage: sst [-t] [startcommand...].\n");
+               exit(0);
+           }
+       }
+
+       randomize();
+       iostart(usecurses);
+
+       line[0] = '\0';
+       for (i = optind; i < argc;  i++) {
+               strcat(line, argv[i]);
+               strcat(line, " ");
+       }
+       while (TRUE) { /* Play a game */
+               setwnd(fullscreen_window);
+               clrscr();
+               prelim();
+               setup(line[0] == '\0');
+               if (alldone) {
+                       score();
+                       alldone = 0;
+               }
+               else makemoves();
+               skip(1);
+               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;
+       }
+       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;
+       
+       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;
+}
+
+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 stars(void) {
+       prouts("******************************************************");
+       skip(1);
+}
+
+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 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 chew2(void) {
+       /* return IHEOL next time */
+       linep = line+1;
+       *linep = 0;
+}
+
+int scan(void) {
+       int i;
+       char *cp;
+
+       // Init result
+       aaitem = 0.0;
+       *citem = 0;
+
+       // Read a line if nothing here
+       if (*linep == 0) {
+               if (linep != line) {
+                       chew();
+                       return IHEOL;
+               }
+               cgetline(line, sizeof(line));
+                fflush(stdin);
+                if (curwnd==prompt_window){
+                   clrscr();
+                   setwnd(message_window);
+                   clrscr();
+                }
+               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;
+           }
+           else {
+               // skip to end
+               linep += i;
+               return IHREAL;
+           }
+       }
+       // Treat as alpha
+       cp = citem;
+       while (*linep && *linep!=' ') {
+               if ((cp - citem) < 9) *cp++ = tolower(*linep);
+               linep++;
+       }
+       *cp = 0;
+       return IHALPHA;
+}
+
+int ja(void) {
+       chew();
+       while (TRUE) {
+               scan();
+               chew();
+               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?");
+}
+
+int isit(char *s) {
+       /* New function -- compares s to scaned citem and returns true if it
+          matches to the length of s */
+
+       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;
+                       }
+               }
+       }
+       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();
+       }
+}
+                       
+
+#endif