b8aa18301215b5165f40dddfb7daca67dd7618d8
[super-star-trek.git] / sst.c
1 #define INCLUDED        // Define externs here
2 #include <ctype.h>
3 #include <getopt.h>
4 #include <time.h>
5 #include "sstlinux.h"
6 #include "sst.h"
7
8 #ifndef SSTDOC
9 #define SSTDOC  "sst.doc"
10 #endif
11         
12 /*
13
14 Dave Matuszek says:
15
16    SRSCAN, MOVE, PHASERS, CALL, STATUS, IMPULSE, PHOTONS, ABANDON,
17    LRSCAN, WARP, SHIELDS, DESTRUCT, CHART, REST, DOCK, QUIT, and DAMAGE
18    were in the original non-"super" version of UT FORTRAN Star Trek.
19
20    Tholians weren't in the original. Dave is dubious about their merits.
21    (They are now controlled by OPTION_THOLIAN and turned off if the game
22    type is "plain".)
23
24    Planets and dilithium crystals weren't in the original.  Dave is OK
25    with this idea. (It's now controlled by OPTION_PLANETS and turned 
26    off if the game type is "plain".)
27
28    Dave says the bit about the Galileo getting turned into a
29    McDonald's is "consistant with our original vision".  (This has been
30    left permanently enabled, as it can only happen if OPTION_PLANETS
31    is on.)
32
33    Dave also says the Space Thingy should not be preserved across saved
34    games, so you can't prove to others that you've seen it.  He says it
35    shouldn't fire back, either.  It should do nothing except scream and
36    disappear when hit by photon torpedos.  It's OK that it may move
37    when attacked, but it didn't in the original.  (Whether the Thingy
38    can fire back is now controlled by OPTION_THINGY and turned off if the
39    game type is "plain" or "almy".  The no-save behavior has been restored.)
40
41    The Faerie Queen, black holes, and time warping were in the original.
42
43 Here are Tom Almy's changes:
44
45    Compared to original version, I've changed the "help" command to
46    "call" and the "terminate" command to "quit" to better match
47    user expectations. The DECUS version apparently made those changes
48    as well as changing "freeze" to "save". However I like "freeze".
49    (Both "freeze" and "save" work in SST2K.)
50
51    When I got a later version of Super Star Trek that I was converting
52    from, I added the emexit command.
53
54    That later version also mentions srscan and lrscan working when
55    docked (using the starbase's scanners), so I made some changes here
56    to do this (and indicating that fact to the player), and then realized
57    the base would have a subspace radio as well -- doing a Chart when docked
58    updates the star chart, and all radio reports will be heard. The Dock
59    command will also give a report if a base is under attack.
60
61    Klingon commander movements are no longer reported if long-range 
62    sensors are damaged.
63
64    Also added:
65
66    1. Better base positioning at startup.
67
68    2. Deathray improvement (but keeping original failure alternatives).
69
70    3. Tholian Web.  (Now controlled by OPTION_THOLIAN and turned off 
71       if game type is "plain".)
72
73    4. Enemies can ram the Enterprise. (Now controlled by OPTION_RAMMING
74       and turned off if game type is "plain".)
75
76    5. Regular Klingons and Romulans can move in Expert and Emeritus games. 
77       This code could use improvement. (Now controlled by OPTION_MVBADDY
78       and turned off if game type is "plain".)
79
80    6. The deep-space probe feature from the DECUS version.  (Now controlled
81       by OPTION_PROBE and turned off if game type is "plain").
82
83    In June 2004 I fixed a number of bugs involving: 1) parsing invalid
84    numbers, 2) manual phasers when SR scan is damaged and commander is
85    present, 3) time warping into the future, 4) hang when moving
86    klingons in crowded quadrants.  (These fixes are in SST2K.)
87
88 Here are Stas Sergeev's changes:
89
90    1. The Space Thingy can be shoved, if you ram it, and can fire back if 
91       fired upon. (Now controlled by OPTION_THINGY and turned off if game 
92       type is "plain" or "almy".)
93
94    2. When you are docked, base covers you with an almost invincible shield. 
95       (A commander can still ram you, or a Romulan can destroy the base,
96       or a SCom can even succeed with direct attack IIRC, but this rarely 
97       happens.)  (Now controlled by OPTION_BASE and turned off if game 
98       type is "plain" or "almy".)
99
100    3. Ramming a black hole is no longer instant death.  There is a
101       chance you might get timewarped instead. (Now controlled by 
102       OPTION_BLKHOLE and turned off if game type is "plain" or "almy".)
103
104    4. The Tholian can be hit with phasers.
105
106    5. SCom can't escape from you if no more enemies remain (without this, 
107       chasing SCom can take an eternity).
108
109    6. Probe target you enter is now the destination quadrant. Before I don't 
110       remember what it was, but it was something I had difficulty using.
111
112    7. Secret password is now autogenerated.
113
114    8. "Plaque" is adjusted for A4 paper :-)
115
116    9. Phasers now tells you how much energy needed, but only if the computer 
117       is alive.
118
119    10. Planets are auto-scanned when you enter the quadrant.
120
121    11. Mining or using crystals in presense of enemy now yields an attack.
122        There are other minor adjustments to what yields an attack
123        and what does not.
124
125    12. "freeze" command reverts to "save", most people will understand this
126        better anyway. (SST2K recognizes both.)
127
128    13. Screen-oriented interface, with sensor scans always up.  (SST2K
129        supports both screen-oriented and TTY modes.)
130
131 Eric Raymond's changes:
132
133 Mainly, I translated this C code out of FORTRAN into C -- created #defines
134 for a lot of magic numbers and refactored the heck out of it.
135
136    1. "sos" and "call" becomes "mayday", "freeze" and "save" are both good.
137
138    2. Status report now indicates when dilithium crystals are on board.
139
140    3. Per Dave Matuszek's remarks, Thingy state is never saved across games.
141
142    4. Added game option selection so you can play a close (but not bug-for-
143       bug identical) approximation of older versions.
144 */
145
146 /* the input queue */
147 static char line[128], *linep = line;
148
149 static struct 
150 {
151     char *name;
152     int value;
153     unsigned long option;
154 }
155 commands[] = {
156 #define SRSCAN  0
157         {"SRSCAN",      SRSCAN,         OPTION_TTY},
158 #define STATUS  1
159         {"STATUS",      STATUS,         OPTION_TTY},
160 #define REQUEST 2
161         {"REQUEST",     REQUEST,        OPTION_TTY},
162 #define LRSCAN  3
163         {"LRSCAN",      LRSCAN,         OPTION_TTY},
164 #define PHASERS 4
165         {"PHASERS",     PHASERS,        0},
166 #define TORPEDO 5
167         {"TORPEDO",     TORPEDO,        0},
168         {"PHOTONS",     TORPEDO,        0},
169 #define MOVE    6
170         {"MOVE",        MOVE,           0},
171 #define SHIELDS 7
172         {"SHIELDS",     SHIELDS,        0},
173 #define DOCK    8
174         {"DOCK",        DOCK,           0},
175 #define DAMAGES 9
176         {"DAMAGES",     DAMAGES,        0},
177 #define CHART   10
178         {"CHART",       CHART,          0},
179 #define IMPULSE 11
180         {"IMPULSE",     IMPULSE,        0},
181 #define REST    12
182         {"REST",        REST,           0},
183 #define WARP    13
184         {"WARP",        WARP,           0},
185 #define SCORE   14
186         {"SCORE",       SCORE,          0},
187 #define SENSORS 15
188         {"SENSORS",     SENSORS,        OPTION_PLANETS},
189 #define ORBIT   16
190         {"ORBIT",       ORBIT,          OPTION_PLANETS},
191 #define TRANSPORT       17
192         {"TRANSPORT",   TRANSPORT,      OPTION_PLANETS},
193 #define MINE    18
194         {"MINE",        MINE,           OPTION_PLANETS},
195 #define CRYSTALS        19
196         {"CRYSTALS",    CRYSTALS,       OPTION_PLANETS},
197 #define SHUTTLE 20
198         {"SHUTTLE",     SHUTTLE,        OPTION_PLANETS},
199 #define PLANETS 21
200         {"PLANETS",     PLANETS,        OPTION_PLANETS},
201 #define REPORT  22
202         {"REPORT",      REPORT,         0},
203 #define COMPUTER        23
204         {"COMPUTER",    COMPUTER,       0},
205 #define COMMANDS        24
206         {"COMMANDS",    COMMANDS,       0},
207 #define EMEXIT  25
208         {"EMEXIT",      EMEXIT,         0},
209 #define PROBE   26
210         {"PROBE",       PROBE,          OPTION_PROBE},
211 #define SAVE    27
212         {"SAVE",        SAVE,           0},
213         {"FREEZE",      SAVE,           0},
214 #define ABANDON 28
215         {"ABANDON",     ABANDON,        0},
216 #define DESTRUCT        29
217         {"DESTRUCT",    DESTRUCT,       0},
218 #define DEATHRAY        30
219         {"DEATHRAY",    DEATHRAY,       0},
220 #define DEBUGCMD        31
221         {"DEBUG",       DEBUGCMD,       0},
222 #define MAYDAY  32
223         {"MAYDAY",      MAYDAY,         0},
224         //{"SOS",               MAYDAY,         0},
225         //{"CALL",      MAYDAY,         0},
226 #define QUIT    33
227         {"QUIT",        QUIT,           0},
228 #define HELP    34
229         {"HELP",        HELP,           0},
230 };
231
232 #define NUMCOMMANDS     sizeof(commands)/sizeof(commands[0])
233 #define ACCEPT(i)       (!commands[i].option || (commands[i].option & game.options))
234
235 static void listCommands(void) {
236     int i, k = 0;
237     proutn("LEGAL COMMANDS ARE:");
238     for (i = 0; i < NUMCOMMANDS; i++) {
239         if (!ACCEPT(i))
240             continue;
241         if (k % 5 == 0)
242             skip(1);
243         proutn("%-12s ", commands[i].name); 
244         k++;
245     }
246     skip(1);
247 }
248
249 static void helpme(void) 
250 {
251     int i, j;
252     char cmdbuf[32], *cp;
253     char linebuf[132];
254     FILE *fp;
255     /* Give help on commands */
256     int key;
257     key = scan();
258     while (TRUE) {
259         if (key == IHEOL) {
260             setwnd(prompt_window);
261             proutn("Help on what command? ");
262             key = scan();
263         }
264         setwnd(message_window);
265         if (key == IHEOL) return;
266         for (i = 0; i < NUMCOMMANDS; i++) {
267             if (ACCEPT(i) && strcasecmp(commands[i].name, citem)==0) {
268                 i = commands[i].value;
269                 break;
270             }
271         }
272         if (i != NUMCOMMANDS) break;
273         skip(1);
274         prout("Valid commands:");
275         listCommands();
276         key = IHEOL;
277         chew();
278         skip(1);
279     }
280     if (i == COMMANDS) {
281         strcpy(cmdbuf, " ABBREV");
282     }
283     else {
284         for (j = 0; commands[i].name[j]; j++)
285             cmdbuf[j] = toupper(commands[i].name[j]);
286         cmdbuf[j] = '\0';
287     }
288     fp = fopen(SSTDOC, "r");
289     if (fp == NULL) {
290         prout("Spock-  \"Captain, that information is missing from the");
291         prout("   computer.\"");
292         /*
293          * This used to continue: "You need to find SST.DOC and put 
294          * it in the current directory."
295          */
296         return;
297     }
298     for (;;) {
299         if (fgets(linebuf, sizeof(linebuf), fp) == NULL) {
300             prout("Spock- \"Captain, there is no information on that command.\"");
301             fclose(fp);
302             return;
303         }
304         if (linebuf[0] == '%' && linebuf[1] == '%'&& linebuf[2] == ' ') {
305             for (cp = linebuf+3; isspace(*cp); cp++)
306                 continue;
307             linebuf[strlen(linebuf)-1] = '\0';
308             if (strcasecmp(cp, cmdbuf) == 0)
309                 break;
310         }
311     }
312
313     skip(1);
314     prout("Spock- \"Captain, I've found the following information:\"");
315     skip(1);
316
317     while (fgets(linebuf, sizeof(linebuf),fp)) {
318         if (strstr(linebuf, "******"))
319             break;
320         proutn(linebuf);
321     }
322     fclose(fp);
323 }
324
325 void enqueue(char *s) 
326 {
327     strcpy(line, s);
328 }
329
330 static void makemoves(void) 
331 {
332     int i, v = 0, hitme;
333     clrscr();
334     setwnd(message_window);
335     while (TRUE) { /* command loop */
336         drawmaps(1);
337         while (TRUE)  { /* get a command */
338             hitme = FALSE;
339             justin = 0;
340             Time = 0.0;
341             i = -1;
342             chew();
343             setwnd(prompt_window);
344             clrscr();
345             proutn("COMMAND> ");
346             if (scan() == IHEOL) {
347                 makechart();
348                 continue;
349             }
350             ididit=0;
351             clrscr();
352             setwnd(message_window);
353             clrscr();
354             for (i=0; i < ABANDON; i++)
355                 if (ACCEPT(i) && isit(commands[i].name)) {
356                     v = commands[i].value;
357                     break;
358                 }
359             if (i < ABANDON && (!commands[i].option || (commands[i].option & game.options))) 
360                 break;
361             for (; i < NUMCOMMANDS; i++)
362                 if (ACCEPT(i) && strcasecmp(commands[i].name, citem) == 0) {
363                     v = commands[i].value;
364                     break;
365                 }
366             if (i < NUMCOMMANDS && (!commands[i].option || (commands[i].option & game.options))) 
367                 break;
368             listCommands();
369         }
370         commandhook(commands[i].name, TRUE);
371         switch (v) { /* command switch */
372         case SRSCAN:                 // srscan
373             srscan(SCAN_FULL);
374             break;
375         case STATUS:                 // status
376             srscan(SCAN_STATUS);
377             break;
378         case REQUEST:                   // status request 
379             srscan(SCAN_REQUEST);
380             break;
381         case LRSCAN:                    // lrscan
382             lrscan();
383             break;
384         case PHASERS:                   // phasers
385             phasers();
386             if (ididit) hitme = TRUE;
387             break;
388         case TORPEDO:                   // photons
389             photon();
390             if (ididit) hitme = TRUE;
391             break;
392         case MOVE:                      // move
393             warp(1);
394             break;
395         case SHIELDS:                   // shields
396             doshield(1);
397             if (ididit) {
398                 hitme=TRUE;
399                 shldchg = 0;
400             }
401             break;
402         case DOCK:                      // dock
403             dock(1);
404             if (ididit) attack(0);
405             break;
406         case DAMAGES:                   // damages
407             dreprt();
408             break;
409         case CHART:                     // chart
410             chart(0);
411             break;
412         case IMPULSE:                   // impulse
413             impuls();
414             break;
415         case REST:                      // rest
416             wait();
417             if (ididit) hitme = TRUE;
418             break;
419         case WARP:                      // warp
420             setwrp();
421             break;
422         case SCORE:                     // score
423             score();
424             break;
425         case SENSORS:                   // sensors
426             sensor();
427             break;
428         case ORBIT:                     // orbit
429             orbit();
430             if (ididit) hitme = TRUE;
431             break;
432         case TRANSPORT:                 // transport "beam"
433             beam();
434             break;
435         case MINE:                      // mine
436             mine();
437             if (ididit) hitme = TRUE;
438             break;
439         case CRYSTALS:                  // crystals
440             usecrystals();
441             if (ididit) hitme = TRUE;
442             break;
443         case SHUTTLE:                   // shuttle
444             shuttle();
445             if (ididit) hitme = TRUE;
446             break;
447         case PLANETS:                   // Planet list
448             preport();
449             break;
450         case REPORT:                    // Game Report 
451             report();
452             break;
453         case COMPUTER:                  // use COMPUTER!
454             eta();
455             break;
456         case COMMANDS:
457             listCommands();
458             break;
459         case EMEXIT:                    // Emergency exit
460             clrscr();                   // Hide screen
461             freeze(TRUE);               // forced save
462             exit(1);                    // And quick exit
463             break;
464         case PROBE:
465             probe();                    // Launch probe
466             if (ididit) hitme = TRUE;
467             break;
468         case ABANDON:                   // Abandon Ship
469             abandn();
470             break;
471         case DESTRUCT:                  // Self Destruct
472             dstrct();
473             break;
474         case SAVE:                      // Save Game
475             freeze(FALSE);
476             clrscr();
477             if (skill > SKILL_GOOD)
478                 prout("WARNING--Saved games produce no plaques!");
479             break;
480         case DEATHRAY:                  // Try a desparation measure
481             deathray();
482             if (ididit) hitme = TRUE;
483             break;
484         case DEBUGCMD:                  // What do we want for debug???
485 #ifdef DEBUG
486             debugme();
487 #endif
488             break;
489         case MAYDAY:                    // Call for help
490             help();
491             if (ididit) hitme = TRUE;
492             break;
493         case QUIT:
494             alldone = 1;                // quit the game
495 #ifdef DEBUG
496             if (idebug) score();
497 #endif
498             break;
499         case HELP:
500             helpme();   // get help
501             break;
502         }
503         commandhook(commands[i].name, FALSE);
504         for (;;) {
505             if (alldone) break;         // Game has ended
506 #ifdef DEBUG
507             if (idebug) prout("2500");
508 #endif
509             if (Time != 0.0) {
510                 events();
511                 if (alldone) break;     // Events did us in
512             }
513             if (game.state.galaxy[quadx][quady].supernova) { // Galaxy went Nova!
514                 atover(0);
515                 continue;
516             }
517             if (hitme && justin==0) {
518                 attack(2);
519                 if (alldone) break;
520                 if (game.state.galaxy[quadx][quady].supernova) {        // went NOVA! 
521                     atover(0);
522                     hitme = TRUE;
523                     continue;
524                 }
525             }
526             break;
527         }
528         if (alldone) break;
529     }
530 }
531
532
533 int main(int argc, char **argv) 
534 {
535     int i, option;
536
537     game.options = OPTION_ALL &~ (OPTION_IOMODES | OPTION_SHOWME);
538     if (getenv("TERM"))
539         game.options |= OPTION_CURSES | OPTION_SHOWME;
540     else
541         game.options |= OPTION_TTY;
542
543     while ((option = getopt(argc, argv, "t")) != -1) {
544         switch (option) {
545         case 't':
546             game.options |= OPTION_TTY;
547             game.options &=~ OPTION_CURSES;
548             break;
549         default:
550             fprintf(stderr, "usage: sst [-t] [startcommand...].\n");
551             exit(0);
552         }
553     }
554
555     randomize();
556     iostart();
557
558     line[0] = '\0';
559     for (i = optind; i < argc;  i++) {
560         strcat(line, argv[i]);
561         strcat(line, " ");
562     }
563     while (TRUE) { /* Play a game */
564         setwnd(fullscreen_window);
565 #ifdef DEBUG
566         prout("INITIAL OPTIONS: %0lx", game.options);
567 #endif /* DEBUG */
568         clrscr();
569         prelim();
570         setup(line[0] == '\0');
571         if (alldone) {
572             score();
573             alldone = 0;
574         }
575         else makemoves();
576         skip(1);
577         stars();
578         skip(1);
579
580         if (tourn && alldone) {
581             proutn("Do you want your score recorded?");
582             if (ja()) {
583                 chew2();
584                 freeze(FALSE);
585             }
586         }
587         proutn("Do you want to play again? ");
588         if (!ja()) break;
589     }
590     skip(1);
591     prout("May the Great Bird of the Galaxy roost upon your home planet.");
592     return 0;
593 }
594
595
596 void cramen(int i) 
597 {
598     /* return an enemy */
599     char *s;
600         
601     switch (i) {
602     case IHR: s = "Romulan"; break;
603     case IHK: s = "Klingon"; break;
604     case IHC: s = "Commander"; break;
605     case IHS: s = "Super-commander"; break;
606     case IHSTAR: s = "Star"; break;
607     case IHP: s = "Planet"; break;
608     case IHB: s = "Starbase"; break;
609     case IHBLANK: s = "Black hole"; break;
610     case IHT: s = "Tholian"; break;
611     case IHWEB: s = "Tholian web"; break;
612     case IHQUEST: s = "Stranger"; break;
613     default: s = "Unknown??"; break;
614     }
615     proutn(s);
616 }
617
618 char *cramlc(enum loctype key, int x, int y)
619 {
620     static char buf[32];
621     buf[0] = '\0';
622     if (key == quadrant) strcpy(buf, "Quadrant ");
623     else if (key == sector) strcpy(buf, "Sector ");
624     sprintf(buf+strlen(buf), "%d - %d", x, y);
625     return buf;
626 }
627
628 void crmena(int i, int enemy, int key, int x, int y) 
629 {
630     if (i == 1) proutn("***");
631     cramen(enemy);
632     proutn(" at ");
633     proutn(cramlc(key, x, y));
634 }
635
636 void crmshp(void) 
637 {
638     char *s;
639     switch (ship) {
640     case IHE: s = "Enterprise"; break;
641     case IHF: s = "Faerie Queene"; break;
642     default:  s = "Ship???"; break;
643     }
644     proutn(s);
645 }
646
647 void stars(void) 
648 {
649     prouts("******************************************************");
650     skip(1);
651 }
652
653 double expran(double avrage) 
654 {
655     return -avrage*log(1e-7 + Rand());
656 }
657
658 double Rand(void) {
659         return rand()/(1.0 + (double)RAND_MAX);
660 }
661
662 void iran(int size, int *i, int *j) 
663 {
664     *i = Rand()*(size*1.0) + 1.0;
665     *j = Rand()*(size*1.0) + 1.0;
666 }
667
668 void chew(void)
669 {
670     linep = line;
671     *linep = 0;
672 }
673
674 void chew2(void) 
675 {
676     /* return IHEOL next time */
677     linep = line+1;
678     *linep = 0;
679 }
680
681 int scan(void) 
682 {
683     int i;
684     char *cp;
685
686     // Init result
687     aaitem = 0.0;
688     *citem = 0;
689
690     // Read a line if nothing here
691     if (*linep == 0) {
692         if (linep != line) {
693             chew();
694             return IHEOL;
695         }
696         cgetline(line, sizeof(line));
697         fflush(stdin);
698         if (curwnd==prompt_window){
699             clrscr();
700             setwnd(message_window);
701             clrscr();
702         }
703         linep = line;
704     }
705     // Skip leading white space
706     while (*linep == ' ') linep++;
707     // Nothing left
708     if (*linep == 0) {
709         chew();
710         return IHEOL;
711     }
712     if (isdigit(*linep) || *linep=='+' || *linep=='-' || *linep=='.') {
713         // treat as a number
714         i = 0;
715         if (sscanf(linep, "%lf%n", &aaitem, &i) < 1) {
716             linep = line; // Invalid numbers are ignored
717             *linep = 0;
718             return IHEOL;
719         }
720         else {
721             // skip to end
722             linep += i;
723             return IHREAL;
724         }
725     }
726     // Treat as alpha
727     cp = citem;
728     while (*linep && *linep!=' ') {
729         if ((cp - citem) < 9) *cp++ = tolower(*linep);
730         linep++;
731     }
732     *cp = 0;
733     return IHALPHA;
734 }
735
736 int ja(void) 
737 {
738     chew();
739     while (TRUE) {
740         scan();
741         chew();
742         if (*citem == 'y') return TRUE;
743         if (*citem == 'n') return FALSE;
744         proutn("Please answer with \"Y\" or \"N\": ");
745     }
746 }
747
748 void huh(void) 
749 {
750     chew();
751     skip(1);
752     prout("Beg your pardon, Captain?");
753 }
754
755 int isit(char *s) 
756 {
757     /* New function -- compares s to scanned citem and returns true if it
758        matches to the length of s */
759
760     return strncasecmp(s, citem, max(1, strlen(citem))) == 0;
761
762 }
763
764 #ifdef DEBUG
765 void debugme(void) 
766 {
767     proutn("Reset levels? ");
768     if (ja() != 0) {
769         if (energy < inenrg) energy = inenrg;
770         shield = inshld;
771         torps = intorps;
772         lsupres = inlsr;
773     }
774     proutn("Reset damage? ");
775     if (ja() != 0) {
776         int i;
777         for (i=0; i < NDEVICES; i++) 
778             if (game.damage[i] > 0.0) 
779                 game.damage[i] = 0.0;
780     }
781     proutn("Toggle idebug? ");
782     if (ja() != 0) {
783         idebug = !idebug;
784         if (idebug) prout("Debug output ON");
785         else prout("Debug output OFF");
786     }
787     proutn("Cause selective damage? ");
788     if (ja() != 0) {
789         int i, key;
790         for (i=0; i < NDEVICES; i++) {
791             proutn("Kill ");
792             proutn(device[i]);
793             proutn("? ");
794             chew();
795             key = scan();
796             if (key == IHALPHA &&  isit("y")) {
797                 game.damage[i] = 10.0;
798             }
799         }
800     }
801     proutn("Examine/change events? ");
802     if (ja() != 0) {
803         int i;
804         for (i = 1; i < NEVENTS; i++) {
805             int key;
806             if (game.future[i] == FOREVER) continue;
807             switch (i) {
808             case FSNOVA:  proutn("Supernova       "); break;
809             case FTBEAM:  proutn("T Beam          "); break;
810             case FSNAP:   proutn("Snapshot        "); break;
811             case FBATTAK: proutn("Base Attack     "); break;
812             case FCDBAS:  proutn("Base Destroy    "); break;
813             case FSCMOVE: proutn("SC Move         "); break;
814             case FSCDBAS: proutn("SC Base Destroy "); break;
815             }
816             proutn("%.2f", game.future[i]-game.state.date);
817             chew();
818             proutn("  ?");
819             key = scan();
820             if (key == IHREAL) {
821                 game.future[i] = game.state.date + aaitem;
822             }
823         }
824         chew();
825     }
826     proutn("Induce supernova here? ");
827     if (ja() != 0) {
828         game.state.galaxy[quadx][quady].supernova = TRUE;
829         atover(1);
830     }
831 }
832 #endif