On Stas Sergeev's suggestion, change where the logfile is written.
[super-star-trek.git] / src / sst.c
index 75dca51ba19433a974bba33d5e1e89a74def516b..ccf7470b64ea04fc4f39152e0fa75ff6e272f5a5 100644 (file)
--- a/src/sst.c
+++ b/src/sst.c
@@ -152,34 +152,45 @@ for a lot of magic numbers and refactored the heck out of it.
 
    4. Added game option selection so you can play a close (but not bug-for-
       bug identical) approximation of older versions.
+
+   5. Half the quadrants now have inhabited planets, from which one 
+      cannot mine dilithium (there will still be the same additional number
+      of dilithium-bearing planets).  Torpedoing an inhabited world is *bad*.
+      There is BSD-Trek-like logic for Klingons to attack and enslave 
+      inhabited worlds, producing more ships (only is skill is 'good' or 
+      better). (Controlled by OPTION_WORLDS and turned off if game 
+      type is "plain" or "almy".)
+
+   6. User input is now logged so we can do regression testing.
+
+   7. More BSD-Trek features: You can now lose if your entire crew
+      dies in battle.  When abandoning ship in a game with inhabited
+      worlds enabled, they must have one in the quadrant to beam down
+      to; otherwise they die in space and this counts heavily against
+      your score.  Docking at a starbase replenishes your crew.
+
+   8. Still more BSD-Trek: we now have a weighted damage table.
+      Also, the nav subsystem (enabling automatic course
+      setting) can be damaged separately from the main computer (which
+      handles weapons targeting, ETA calculation, and self-destruct).
 */
 
 /* the input queue */
 static char line[128], *linep = line;
 
 struct game game;
-int thingx, thingy, iqhere, iqengry;
-int iscore, iskill; // Common PLAQ
+coord thing;
+bool iqhere, iqengry;
+int iscore, iskill;    // Common PLAQ
 double aaitem;
 double perdate;
 char citem[10];
+int seed;              // the random-number seed
+bool idebug;           // debug mode
+FILE *logfp, *replayfp;
 
-char *device[NDEVICES] = {
-       "S. R. Sensors",
-       "L. R. Sensors",
-       "Phasers",
-       "Photon Tubes",
-       "Life Support",
-       "Warp Engines",
-       "Impulse Engines",
-       "Shields",
-       "Subspace Radio",
-       "Shuttle Craft",
-       "Computer",
-       "Transporter",
-       "Shield Control",
-       "Death Ray",
-       "D. S. Probe"};                                                                 
+char *systnames[NINHAB + 1];
+char *device[NDEVICES];
 
 static struct 
 {
@@ -202,75 +213,83 @@ commands[] = {
 #define TORPEDO        5
         {"TORPEDO",    TORPEDO,        0},
        {"PHOTONS",     TORPEDO,        0},
-#define MOVE   6
+#define MOVE   7
        {"MOVE",        MOVE,           0},
-#define SHIELDS        7
+#define SHIELDS        8
        {"SHIELDS",     SHIELDS,        0},
-#define DOCK   8
+#define DOCK   9
        {"DOCK",        DOCK,           0},
-#define DAMAGES        9
+#define DAMAGES        10
        {"DAMAGES",     DAMAGES,        0},
-#define CHART  10
+#define CHART  11
        {"CHART",       CHART,          0},
-#define IMPULSE        11
+#define IMPULSE        12
        {"IMPULSE",     IMPULSE,        0},
-#define REST   12
+#define REST   13
        {"REST",        REST,           0},
-#define WARP   13
+#define WARP   14
        {"WARP",        WARP,           0},
-#define SCORE  14
+#define SCORE  15
        {"SCORE",       SCORE,          0},
-#define SENSORS        15
+#define SENSORS        16
        {"SENSORS",     SENSORS,        OPTION_PLANETS},
-#define ORBIT  16
+#define ORBIT  17
        {"ORBIT",       ORBIT,          OPTION_PLANETS},
-#define TRANSPORT      17
+#define TRANSPORT      18
        {"TRANSPORT",   TRANSPORT,      OPTION_PLANETS},
-#define MINE   18
+#define MINE   19
        {"MINE",        MINE,           OPTION_PLANETS},
-#define CRYSTALS       19
+#define CRYSTALS       20
        {"CRYSTALS",    CRYSTALS,       OPTION_PLANETS},
-#define SHUTTLE        20
+#define SHUTTLE        21
        {"SHUTTLE",     SHUTTLE,        OPTION_PLANETS},
-#define PLANETS        21
+#define PLANETS        22
        {"PLANETS",     PLANETS,        OPTION_PLANETS},
-#define REPORT 22
+#define REPORT 23
        {"REPORT",      REPORT,         0},
-#define COMPUTER       23
+#define COMPUTER       24
        {"COMPUTER",    COMPUTER,       0},
-#define COMMANDS       24
+#define COMMANDS       25
        {"COMMANDS",    COMMANDS,       0},
-#define EMEXIT 25
+#define EMEXIT 26
        {"EMEXIT",      EMEXIT,         0},
-#define PROBE  26
+#define PROBE  27
        {"PROBE",       PROBE,          OPTION_PROBE},
-#define SAVE   27
+#define SAVE   28
        {"SAVE",        SAVE,           0},
        {"FREEZE",      SAVE,           0},
-#define ABANDON        28
+#define ABANDON        30
        {"ABANDON",     ABANDON,        0},
-#define DESTRUCT       29
+#define DESTRUCT       31
        {"DESTRUCT",    DESTRUCT,       0},
-#define DEATHRAY       30
+#define DEATHRAY       32
        {"DEATHRAY",    DEATHRAY,       0},
-#define DEBUGCMD       31
+#define DEBUGCMD       33
        {"DEBUG",       DEBUGCMD,       0},
-#define MAYDAY 32
+#define MAYDAY 34
        {"MAYDAY",      MAYDAY,         0},
        //{"SOS",               MAYDAY,         0},
        //{"CALL",      MAYDAY,         0},
-#define QUIT   33
+#define QUIT   35
        {"QUIT",        QUIT,           0},
-#define HELP   34
+#define HELP   36
        {"HELP",        HELP,           0},
+#define SEED   37
+       {"SEED",        SEED,           0},
+#if BSD_BUG_FOR_BUG
+#define VISUAL 38
+       {"VISUAL",      VISUAL,         0},
+#endif
 };
 
 #define NUMCOMMANDS    sizeof(commands)/sizeof(commands[0])
 #define ACCEPT(i)      (!commands[i].option || (commands[i].option & game.options))
 
-static void listCommands(void) {
+static void listCommands(void) 
+/* generate a list of legal commands */
+{
     int i, k = 0;
-    proutn("LEGAL COMMANDS ARE:");
+    proutn(_("LEGAL COMMANDS ARE:"));
     for (i = 0; i < NUMCOMMANDS; i++) {
        if (!ACCEPT(i))
            continue;
@@ -282,7 +301,8 @@ static void listCommands(void) {
     skip(1);
 }
 
-static void helpme(void) 
+static void helpme(void)
+/* browse on-line help */
 {
     int i, j;
     char cmdbuf[32], *cp;
@@ -291,10 +311,10 @@ static void helpme(void)
     /* Give help on commands */
     int key;
     key = scan();
-    while (TRUE) {
+    for(;;) {
        if (key == IHEOL) {
            setwnd(prompt_window);
-           proutn("Help on what command? ");
+           proutn(_("Help on what command? "));
            key = scan();
        }
        setwnd(message_window);
@@ -307,7 +327,6 @@ static void helpme(void)
        }
        if (i != NUMCOMMANDS) break;
        skip(1);
-       prout("Valid commands:");
        listCommands();
        key = IHEOL;
        chew();
@@ -325,9 +344,13 @@ static void helpme(void)
     if (fp == NULL)
         fp = fopen(DOC_NAME, "r");
     if (fp == NULL) {
-       prout("Spock-  \"Captain, that information is missing from the");
-        prout("   computer. You need to find "DOC_NAME" and put it in the");
-        prout("   current directory or to "SSTDOC".\"");
+       prout(_("Spock-  \"Captain, that information is missing from the"));
+        proutn(_("   computer. You need to find "));
+        proutn(DOC_NAME);
+        prout(_(" and put it in the"));
+        proutn(_("   current directory or to "));
+        proutn(SSTDOC);
+        prout(".\"");
        /*
         * This used to continue: "You need to find SST.DOC and put 
         * it in the current directory."
@@ -336,7 +359,7 @@ static void helpme(void)
     }
     for (;;) {
        if (fgets(linebuf, sizeof(linebuf), fp) == NULL) {
-           prout("Spock- \"Captain, there is no information on that command.\"");
+           prout(_("Spock- \"Captain, there is no information on that command.\""));
            fclose(fp);
            return;
        }
@@ -350,33 +373,40 @@ static void helpme(void)
     }
 
     skip(1);
-    prout("Spock- \"Captain, I've found the following information:\"");
+    prout(_("Spock- \"Captain, I've found the following information:\""));
     skip(1);
 
-    while (fgets(linebuf, sizeof(linebuf),fp)) {
+    while (fgets(linebuf, sizeof(linebuf), fp)) {
+       char *eol;
        if (strstr(linebuf, "******"))
            break;
-       proutn(linebuf);
+       if ((eol = strpbrk(linebuf, "\r\n")))
+           *eol = 0;
+       prout(linebuf);
     }
     fclose(fp);
 }
 
-void enqueue(char *s) 
+void enqueue(char *s)
+/* enqueue input for the command parser */
 {
+    chew();
     strcpy(line, s);
 }
 
-static void makemoves(void) 
+static void makemoves(void)
+/* command-interpretation loop */
 {
-    int i, v = 0, hitme;
+    int key, i, v = 0;
+    bool hitme;
     clrscr();
     setwnd(message_window);
-    while (TRUE) { /* command loop */
+    for(;;) { /* command loop */
        drawmaps(1);
-       while (TRUE)  { /* get a command */
-           hitme = FALSE;
-           justin = 0;
-           Time = 0.0;
+       for(;;)  { /* get a command */
+           hitme = false;
+           game.justin = false;
+           game.optime = 0.0;
            i = -1;
            chew();
            setwnd(prompt_window);
@@ -386,7 +416,7 @@ static void makemoves(void)
                makechart();
                continue;
            }
-           ididit=0;
+           game.ididit = false;
            clrscr();
            setwnd(message_window);
            clrscr();
@@ -406,7 +436,7 @@ static void makemoves(void)
                break;
            listCommands();
        }
-       commandhook(commands[i].name, TRUE);
+       commandhook(commands[i].name, true);
        switch (v) { /* command switch */
        case SRSCAN:                 // srscan
            srscan(SCAN_FULL);
@@ -422,38 +452,38 @@ static void makemoves(void)
            break;
        case PHASERS:                   // phasers
            phasers();
-           if (ididit) hitme = TRUE;
+           if (game.ididit) hitme = true;
            break;
        case TORPEDO:                   // photons
            photon();
-           if (ididit) hitme = TRUE;
+           if (game.ididit) hitme = true;
            break;
        case MOVE:                      // move
-           warp(1);
+           warp(false);
            break;
        case SHIELDS:                   // shields
-           doshield(1);
-           if (ididit) {
-               hitme=TRUE;
-               shldchg = 0;
+           doshield(false);
+           if (game.ididit) {
+               hitme = true;
+               game.shldchg = false;
            }
            break;
        case DOCK:                      // dock
-           dock(1);
-           if (ididit) attack(0);
+           dock(true);
+           if (game.ididit) attack(false);
            break;
        case DAMAGES:                   // damages
            dreprt();
            break;
        case CHART:                     // chart
-           chart(0);
+           chart(false);
            break;
        case IMPULSE:                   // impulse
            impuls();
            break;
        case REST:                      // rest
            wait();
-           if (ididit) hitme = TRUE;
+           if (game.ididit) hitme = true;
            break;
        case WARP:                      // warp
            setwrp();
@@ -466,22 +496,22 @@ static void makemoves(void)
            break;
        case ORBIT:                     // orbit
            orbit();
-           if (ididit) hitme = TRUE;
+           if (game.ididit) hitme = true;
            break;
        case TRANSPORT:                 // transport "beam"
            beam();
            break;
        case MINE:                      // mine
            mine();
-           if (ididit) hitme = TRUE;
+           if (game.ididit) hitme = true;
            break;
        case CRYSTALS:                  // crystals
            usecrystals();
-           if (ididit) hitme = TRUE;
+           if (game.ididit) hitme = true;
            break;
        case SHUTTLE:                   // shuttle
            shuttle();
-           if (ididit) hitme = TRUE;
+           if (game.ididit) hitme = true;
            break;
        case PLANETS:                   // Planet list
            preport();
@@ -497,75 +527,78 @@ static void makemoves(void)
            break;
        case EMEXIT:                    // Emergency exit
            clrscr();                   // Hide screen
-           freeze(TRUE);               // forced save
+           freeze(true);               // forced save
            exit(1);                    // And quick exit
            break;
        case PROBE:
            probe();                    // Launch probe
-           if (ididit) hitme = TRUE;
+           if (game.ididit) hitme = true;
            break;
        case ABANDON:                   // Abandon Ship
            abandn();
            break;
        case DESTRUCT:                  // Self Destruct
-           dstrct();
+           selfdestruct();
            break;
        case SAVE:                      // Save Game
-           freeze(FALSE);
+           freeze(false);
            clrscr();
-           if (skill > SKILL_GOOD)
-               prout("WARNING--Saved games produce no plaques!");
+           if (game.skill > SKILL_GOOD)
+               prout(_("WARNING--Saved games produce no plaques!"));
            break;
        case DEATHRAY:                  // Try a desparation measure
            deathray();
-           if (ididit) hitme = TRUE;
+           if (game.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;
+           mayday();
+           if (game.ididit) hitme = true;
            break;
        case QUIT:
-           alldone = 1;                // quit the game
-#ifdef DEBUG
-           if (idebug) score();
-#endif
+           game.alldone = true;                // quit the game
            break;
        case HELP:
-           helpme();   // get help
+           helpme();                   // get help
+           break;
+       case SEED:                      // set random-number seed
+           key = scan();
+           if (key == IHREAL)
+               seed = (int)aaitem;
+           break;
+#if BSD_BUG_FOR_BUG
+       case VISUAL:
+           visual();                   // perform visual scan
            break;
+#endif
        }
-       commandhook(commands[i].name, FALSE);
+       commandhook(commands[i].name, false);
        for (;;) {
-           if (alldone) break;         // Game has ended
-#ifdef DEBUG
-           if (idebug) prout("2500");
-#endif
-           if (Time != 0.0) {
+           if (game.alldone) break;            // Game has ended
+           if (game.optime != 0.0) {
                events();
-               if (alldone) break;     // Events did us in
+               if (game.alldone) break;        // Events did us in
            }
-           if (game.state.galaxy[quadx][quady].supernova) { // Galaxy went Nova!
-               atover(0);
+           if (game.state.galaxy[game.quadrant.x][game.quadrant.y].supernova) { // Galaxy went Nova!
+               atover(false);
                continue;
            }
-           if (hitme && justin==0) {
-               attack(2);
-               if (alldone) break;
-               if (game.state.galaxy[quadx][quady].supernova) {        // went NOVA! 
-                   atover(0);
-                   hitme = TRUE;
+           if (hitme && !game.justin) {
+               attack(true);
+               if (game.alldone) break;
+               if (game.state.galaxy[game.quadrant.x][game.quadrant.y].supernova) {    // went NOVA! 
+                   atover(false);
+                   hitme = true;
                    continue;
                }
            }
            break;
        }
-       if (alldone) break;
+       if (game.alldone) break;
     }
+    if (idebug) prout("=== Ending");
 }
 
 
@@ -579,19 +612,39 @@ int main(int argc, char **argv)
     else
        game.options |= OPTION_TTY;
 
-    while ((option = getopt(argc, argv, "t")) != -1) {
+    seed = (int)time(NULL);
+    while ((option = getopt(argc, argv, "r:tx")) != -1) {
        switch (option) {
+       case 'r':
+           replayfp = fopen(optarg, "r");
+           if (replayfp == NULL) {
+               fprintf(stderr, "sst: can't open replay file %s\n", optarg);
+               exit(1);        
+           }
+           if (fscanf(replayfp, "seed %d\n", &seed) != 1) {
+               fprintf(stderr, "sst: replay file %s is ill-formed\n", optarg);
+               exit(1);        
+           }
+           /* FALL THROUGH */
        case 't':
            game.options |= OPTION_TTY;
            game.options &=~ OPTION_CURSES;
            break;
+       case 'x':
+           idebug = true;
+           break;
        default:
-           fprintf(stderr, "usage: sst [-t] [startcommand...].\n");
+           fprintf(stderr, "usage: sst [-t] [-x] [startcommand...].\n");
            exit(0);
        }
     }
+    /* where to save the input in case of bugs */
+    logfp = fopen("/usr/tmp/sst-input.log", "w");
+    setlinebuf(logfp);
+    fprintf(logfp, "seed %d\n", seed);
+    srand(seed);
 
-    randomize();
+    srand(seed);
     iostart();
 
     line[0] = '\0';
@@ -599,91 +652,94 @@ int main(int argc, char **argv)
        strcat(line, argv[i]);
        strcat(line, " ");
     }
-    while (TRUE) { /* Play a game */
+    for(;;) { /* Play a game */
        setwnd(fullscreen_window);
-#ifdef DEBUG
-       prout("INITIAL OPTIONS: %0lx", game.options);
-#endif /* DEBUG */
        clrscr();
        prelim();
        setup(line[0] == '\0');
-       if (alldone) {
+       if (game.alldone) {
            score();
-           alldone = 0;
+           game.alldone = false;
        }
        else makemoves();
        skip(1);
        stars();
        skip(1);
 
-       if (tourn && alldone) {
-           proutn("Do you want your score recorded?");
-           if (ja()) {
+       if (game.tourn && game.alldone) {
+           proutn(_("Do you want your score recorded?"));
+           if (ja() == true) {
                chew2();
-               freeze(FALSE);
+               freeze(false);
            }
        }
-       proutn("Do you want to play again? ");
+       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.");
+    prout(_("May the Great Bird of the Galaxy roost upon your home planet."));
     return 0;
 }
 
 
-void cramen(int i) 
+void cramen(feature i) 
+/* print the name of an enemy */
 {
     /* 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;
+    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;
+    case IHW: s = _("Inhabited World"); break;
     default: s = "Unknown??"; break;
     }
     proutn(s);
 }
 
-char *cramlc(enum loctype key, int x, int y)
+char *cramlc(enum loctype key, coord w)
+/* name a location */
 {
     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);
+    if (key == quadrant) strcpy(buf, _("Quadrant "));
+    else if (key == sector) strcpy(buf, _("Sector "));
+    sprintf(buf+strlen(buf), "%d - %d", w.x, w.y);
     return buf;
 }
 
-void crmena(int i, int enemy, int key, int x, int y) 
+void crmena(bool stars, feature enemy, enum loctype key, coord w) 
+/* print an enemy and his location */
 {
-    if (i == 1) proutn("***");
+    if (stars) proutn("***");
     cramen(enemy);
-    proutn(" at ");
-    proutn(cramlc(key, x, y));
+    proutn(_(" at "));
+    proutn(cramlc(key, w));
 }
 
-void crmshp(void) 
+void crmshp(void)
+/* print our ship name */
 {
     char *s;
-    switch (ship) {
-    case IHE: s = "Enterprise"; break;
-    case IHF: s = "Faerie Queene"; break;
+    switch (game.ship) {
+    case IHE: s = _("Enterprise"); break;
+    case IHF: s = _("Faerie Queene"); break;
     default:  s = "Ship???"; break;
     }
     proutn(s);
 }
 
-void stars(void) 
+void stars(void)
+/* print a line of stars */
 {
     prouts("******************************************************");
     skip(1);
@@ -694,14 +750,18 @@ double expran(double avrage)
     return -avrage*log(1e-7 + Rand());
 }
 
-double Rand(void) {
-       return rand()/(1.0 + (double)RAND_MAX);
+double Rand(void) 
+{
+    return rand()/(1.0 + (double)RAND_MAX);
 }
 
-void iran(int size, int *i, int *j) 
+coord randplace(int size)
+/* choose a random location */ 
 {
-    *i = Rand()*(size*1.0) + 1.0;
-    *j = Rand()*(size*1.0) + 1.0;
+    coord w;
+    w.x = Rand()*(size*1.0) + 1.0;
+    w.y = Rand()*(size*1.0) + 1.0;
+    return w;
 }
 
 void chew(void)
@@ -772,59 +832,58 @@ int scan(void)
     return IHALPHA;
 }
 
-int ja(void) 
+bool ja(void)
+/* yes-or-no confirmation */
 {
     chew();
-    while (TRUE) {
+    for(;;) {
        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) 
+void huh(void)
+/* complain about unparseable input */
 {
     chew();
     skip(1);
-    prout("Beg your pardon, Captain?");
+    prout(_("Beg your pardon, Captain?"));
 }
 
-int isit(char *s) 
+bool isit(char *s) 
+/* compares s to citem and returns true if it matches to the length of s */
 {
-    /* New function -- compares s to scanned citem and returns true if it
-       matches to the length of s */
-
     return strncasecmp(s, citem, max(1, strlen(citem))) == 0;
-
 }
 
-#ifdef DEBUG
-void debugme(void) 
+void debugme(void)
+/* access to the internals for debugging */
 {
     proutn("Reset levels? ");
-    if (ja() != 0) {
-       if (energy < inenrg) energy = inenrg;
-       shield = inshld;
-       torps = intorps;
-       lsupres = inlsr;
+    if (ja() == true) {
+       if (game.energy < game.inenrg) game.energy = game.inenrg;
+       game.shield = game.inshld;
+       game.torps = game.intorps;
+       game.lsupres = game.inlsr;
     }
     proutn("Reset damage? ");
-    if (ja() != 0) {
+    if (ja() == true) {
        int i;
        for (i=0; i < NDEVICES; i++) 
            if (game.damage[i] > 0.0) 
                game.damage[i] = 0.0;
     }
-    proutn("Toggle idebug? ");
-    if (ja() != 0) {
+    proutn("Toggle debug flag? ");
+    if (ja() == true) {
        idebug = !idebug;
        if (idebug) prout("Debug output ON");
        else prout("Debug output OFF");
     }
     proutn("Cause selective damage? ");
-    if (ja() != 0) {
+    if (ja() == true) {
        int i, key;
        for (i=0; i < NDEVICES; i++) {
            proutn("Kill ");
@@ -838,11 +897,12 @@ void debugme(void)
        }
     }
     proutn("Examine/change events? ");
-    if (ja() != 0) {
+    if (ja() == true) {
+       event *ev;
+       coord w;
        int i;
        for (i = 1; i < NEVENTS; i++) {
            int key;
-           if (game.future[i] == FOREVER) continue;
            switch (i) {
            case FSNOVA:  proutn("Supernova       "); break;
            case FTBEAM:  proutn("T Beam          "); break;
@@ -851,21 +911,56 @@ void debugme(void)
            case FCDBAS:  proutn("Base Destroy    "); break;
            case FSCMOVE: proutn("SC Move         "); break;
            case FSCDBAS: proutn("SC Base Destroy "); break;
+           case FDSPROB: proutn("Probe Move      "); break;
+           case FDISTR:  proutn("Distress Call   "); break;
+           case FENSLV:  proutn("Enlavement      "); break;
+           case FREPRO:  proutn("Klingon Build   "); break;
            }
-           proutn("%.2f", game.future[i]-game.state.date);
+           if (is_scheduled(i)) {
+               proutn("%.2f", scheduled(i)-game.state.date);
+               if (i == FENSLV || i == FREPRO) {
+                   ev = findevent(i);
+                   proutn(" in %d-%d", ev->quadrant.x,ev->quadrant.y);
+               }
+           } else
+               proutn("never");
+           proutn("? ");
            chew();
-           proutn("  ?");
            key = scan();
-           if (key == IHREAL) {
-               game.future[i] = game.state.date + aaitem;
+           if (key == 'n') {
+               unschedule(i);
+               chew();
+           } else if (key == IHREAL) {
+               ev = schedule(i, aaitem);
+               if (i == FENSLV || i == FREPRO) {
+                   chew();
+                   proutn("In quadrant- ");
+                   key = scan();
+                   /* IHEOL says to leave coordinates as they are */
+                   if (key != IHEOL) {
+                       if (key != IHREAL) {
+                           prout("Event %d canceled, no x coordinate.", i);
+                           unschedule(i);
+                           continue;
+                       }
+                       w.x = (int)aaitem;
+                       key = scan();
+                       if (key != IHREAL) {
+                           prout("Event %d canceled, no y coordinate.", i);
+                           unschedule(i);
+                           continue;
+                       }
+                       w.y = (int)aaitem;
+                       ev->quadrant = w;
+                   }
+               }
            }
        }
        chew();
     }
     proutn("Induce supernova here? ");
-    if (ja() != 0) {
-       game.state.galaxy[quadx][quady].supernova = TRUE;
-       atover(1);
+    if (ja() == true) {
+       game.state.galaxy[game.quadrant.x][game.quadrant.y].supernova = true;
+       atover(true);
     }
 }
-#endif