1 ]#define INCLUDED // Define externs here
9 #define SSTDOC "sst.doc"
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.
20 Tholians weren't in the original. Dave is dubious about their merits.
21 There weren't even planets. He says the bit about the Galileo getting
22 turned into a McDonald's is "consistant with our original vision".
24 Dilithium crystals weren't in the original. Dave is OK with this idea.
26 Dave also says the Space Thingy should not be preserved across saved games,
27 so you can't prove to others that you've seen it. He says it shouldn't
28 fire back, either. It should so nothing except scream and disappear
29 when hit by photon torpedos. It's OK that it moves when rammed, but it
30 didn't in the original.
32 The Faerie Queen was in the original.
34 Here are Tom Almy's changes:
36 Compared to original version, I've changed the "help" command to
37 "call" and the "terminate" command to "quit" to better match
38 user expectations. The DECUS version apparently made those changes
39 as well as changing "freeze" to "save". However I like "freeze".
41 When I got a later version of Super Star Trek that I was converting
42 from, I added the emexit command.
44 That later version also mentions srscan and lrscan working when
45 docked (using the starbase's scanners), so I made some changes here
46 to do this (and indicating that fact to the player), and then realized
47 the base would have a subspace radio as well -- doing a Chart when docked
48 updates the star chart, and all radio reports will be heard. The Dock
49 command will also give a report if a base is under attack.
51 Movecom no longer reports movement if sensors are damaged so you wouldn't
56 1. Better base positioning at startup
58 2. Deathray improvement (but keeping original failure alternatives)
62 4. Enemies can ram the Enterprise. Regular Klingons and Romulans can
63 move in Expert and Emeritus games. This code could use improvement.
65 5. The deep space probe looks interesting! DECUS version
67 6. Perhaps cloaking to be added later? BSD version
69 Here are Stas Sergeev's changes:
71 1. The Space Thingy can be shoved, if you it ram, and can fire back if
74 2. The Tholian can be hit with phasers
76 3. When you are docked, base covers you with an almost invincible shields
77 (a commander can still ram you, or a Romulan can destroy the base,
78 or a SCom can even succeed with direct attack IIRC, but this rarely
81 4. SCom can't escape from you if no more enemies remain (without this,
82 chasing SCom can take an eternity).
84 5. Probe target you enter is now the destination quadrant. Before I don't
85 remember what it was, but it was something I had difficulty using)
87 6. Secret password is now autogenerated.
89 7. "Plaque" is adjusted for A4 paper :-)
91 8. Phasers now tells you how much energy needed, but only if the computer
94 9. Planets are auto-scanned when you enter the quadrant.
96 10. Mining or using crystals in presense of enemy now yields an attack.
97 There are other minor adjustments to what yields an attack
100 11. Ramming a black hole is no longer instant death. There is a
101 chance you might get timewarped instead.
103 12. "freeze" command reverts to "save", most people will understand this
106 13. Screen-oriented interface, with sensor scans always up.
108 Eric Raymond's changes:
110 Mainly, I translated this C code out of FORTRAN into C -- created #defines
111 for a lot of magic numbers.
113 1. "sos" and "call" becomes "mayday", "freeze" and "save" are both good.
115 2. Status report now indicates when dilithium crystals are on board.
117 3. Can now report starbases left in scrscan.
121 /* the input queue */
122 static char line[128], *linep = line;
123 static int usecurses = TRUE;
136 {"REQUEST", REQUEST},
140 {"PHASERS", PHASERS},
142 {"TORPEDO", TORPEDO},
143 {"PHOTONS", TORPEDO},
147 {"SHIELDS", SHIELDS},
151 {"DAMAGES", DAMAGES},
155 {"IMPULSE", IMPULSE},
163 {"SENSORS", SENSORS},
167 {"TRANSPORT", TRANSPORT},
171 {"CRYSTALS", CRYSTALS},
173 {"SHUTTLE", SHUTTLE},
175 {"PLANETS", PLANETS},
179 {"COMPUTER", COMPUTER},
181 {"COMMANDS", COMMANDS},
190 {"ABANDON", ABANDON},
192 {"DESTRUCT", DESTRUCT},
194 {"DEATHRAY", DEATHRAY},
207 #define NUMCOMMANDS sizeof(commands)/sizeof(commands[0])
209 #define MIN_CURSES_COMMAND PHASERS /* might change someday */
211 static void listCommands(int usecurses) {
213 proutn("LEGAL COMMANDS ARE:");
214 for (i = usecurses ? MIN_CURSES_COMMAND : 0; i < NUMCOMMANDS; i++) {
217 proutn("%-12s ", commands[i].name);
223 static void helpme(void) {
225 char cmdbuf[32], *cp;
228 /* Give help on commands */
233 setwnd(prompt_window);
234 proutn("Help on what command? ");
237 setwnd(message_window);
238 if (key == IHEOL) return;
239 for (i = 0; i < NUMCOMMANDS; i++) {
240 if (strcasecmp(commands[i].name, citem)==0) {
241 i = commands[i].value;
245 if (i != NUMCOMMANDS) break;
247 prout("Valid commands:");
248 listCommands(usecurses);
254 strcpy(cmdbuf, " ABBREV");
257 for (j = 0; commands[i].name[j]; j++)
258 cmdbuf[j] = toupper(commands[i].name[j]);
261 fp = fopen(SSTDOC, "r");
263 prout("Spock- \"Captain, that information is missing from the");
264 prout(" computer.\"");
266 * This used to continue: "You need to find SST.DOC and put
267 * it in the current directory."
272 if (fgets(linebuf, sizeof(linebuf), fp) == NULL) {
273 prout("Spock- \"Captain, there is no information on that command.\"");
277 if (linebuf[0] == '%' && linebuf[1] == '%'&& linebuf[2] == ' ') {
278 for (cp = linebuf+3; isspace(*cp); cp++)
280 linebuf[strlen(linebuf)-1] = '\0';
281 if (strcasecmp(cp, cmdbuf) == 0)
287 prout("Spock- \"Captain, I've found the following information:\"");
290 while (fgets(linebuf, sizeof(linebuf),fp)) {
291 if (strstr(linebuf, "******"))
298 void enqueue(char *s) {
302 static void makemoves(void) {
305 setwnd(message_window);
306 while (TRUE) { /* command loop */
308 while (TRUE) { /* get a command */
314 setwnd(prompt_window);
317 if (scan() == IHEOL) {
323 setwnd(message_window);
325 for (i=0; i < ABANDON; i++)
326 if (isit(commands[i].name)) {
327 i = commands[i].value;
330 if (i < ABANDON) break;
331 for (; i < NUMCOMMANDS; i++)
332 if (strcasecmp(commands[i].name, citem) == 0) {
333 i = commands[i].value;
336 if (i < NUMCOMMANDS) break;
337 listCommands(usecurses);
339 commandhook(commands[i].name, TRUE);
340 switch (i) { /* command switch */
341 case SRSCAN: // srscan
344 case STATUS: // status
347 case REQUEST: // status request
348 srscan(SCAN_REQUEST);
350 case LRSCAN: // lrscan
353 case PHASERS: // phasers
355 if (ididit) hitme = TRUE;
357 case TORPEDO: // photons
359 if (ididit) hitme = TRUE;
364 case SHIELDS: // shields
373 if (ididit) attack(0);
375 case DAMAGES: // damages
381 case IMPULSE: // impulse
386 if (ididit) hitme = TRUE;
394 case SENSORS: // sensors
399 if (ididit) hitme = TRUE;
401 case TRANSPORT: // transport "beam"
406 if (ididit) hitme = TRUE;
408 case CRYSTALS: // crystals
410 if (ididit) hitme = TRUE;
412 case SHUTTLE: // shuttle
414 if (ididit) hitme = TRUE;
416 case PLANETS: // Planet list
419 case REPORT: // Game Report
422 case COMPUTER: // use COMPUTER!
426 listCommands(usecurses);
428 case EMEXIT: // Emergency exit
429 clrscr(); // Hide screen
430 freeze(TRUE); // forced save
431 exit(1); // And quick exit
434 probe(); // Launch probe
435 if (ididit) hitme = TRUE;
437 case ABANDON: // Abandon Ship
440 case DESTRUCT: // Self Destruct
443 case SAVE: // Save Game
446 if (skill > SKILL_GOOD)
447 prout("WARNING--Saved games produce no plaques!");
449 case DEATHRAY: // Try a desparation measure
451 if (ididit) hitme = TRUE;
453 case DEBUGCMD: // What do we want for debug???
458 case MAYDAY: // Call for help
460 if (ididit) hitme = TRUE;
463 alldone = 1; // quit the game
469 helpme(); // get help
472 commandhook(commands[i].name, FALSE);
474 if (alldone) break; // Game has ended
476 if (idebug) prout("2500");
480 if (alldone) break; // Events did us in
482 if (game.state.galaxy[quadx][quady] == SUPERNOVA_PLACE) { // Galaxy went Nova!
486 if (hitme && justin==0) {
489 if (game.state.galaxy[quadx][quady] == SUPERNOVA_PLACE) { // went NOVA!
502 int main(int argc, char **argv) {
505 while ((option = getopt(argc, argv, "t")) != -1) {
511 fprintf(stderr, "usage: sst [-t] [startcommand...].\n");
520 for (i = optind; i < argc; i++) {
521 strcat(line, argv[i]);
524 while (TRUE) { /* Play a game */
525 setwnd(fullscreen_window);
528 setup(line[0] == '\0');
538 if (tourn && alldone) {
539 proutn("Do you want your score recorded?");
545 proutn("Do you want to play again? ");
549 prout("May the Great Bird of the Galaxy roost upon your home planet.");
555 /* return an enemy */
559 case IHR: s = "Romulan"; break;
560 case IHK: s = "Klingon"; break;
561 case IHC: s = "Commander"; break;
562 case IHS: s = "Super-commander"; break;
563 case IHSTAR: s = "Star"; break;
564 case IHP: s = "Planet"; break;
565 case IHB: s = "Starbase"; break;
566 case IHBLANK: s = "Black hole"; break;
567 case IHT: s = "Tholian"; break;
568 case IHWEB: s = "Tholian web"; break;
569 case IHQUEST: s = "Stranger"; break;
570 default: s = "Unknown??"; break;
575 char *cramlc(enum loctype key, int x, int y) {
578 if (key == quadrant) strcpy(buf, "Quadrant ");
579 else if (key == sector) strcpy(buf, "Sector ");
580 sprintf(buf+strlen(buf), "%d - %d", x, y);
584 void crmena(int i, int enemy, int key, int x, int y) {
585 if (i == 1) proutn("***");
588 proutn(cramlc(key, x, y));
594 case IHE: s = "Enterprise"; break;
595 case IHF: s = "Faerie Queene"; break;
596 default: s = "Ship???"; break;
602 prouts("******************************************************");
606 double expran(double avrage) {
607 return -avrage*log(1e-7 + Rand());
611 return rand()/(1.0 + (double)RAND_MAX);
614 void iran(int size, int *i, int *j) {
615 *i = Rand()*(size*1.0) + 1.0;
616 *j = Rand()*(size*1.0) + 1.0;
625 /* return IHEOL next time */
638 // Read a line if nothing here
644 cgetline(line, sizeof(line));
646 if (curwnd==prompt_window){
648 setwnd(message_window);
653 // Skip leading white space
654 while (*linep == ' ') linep++;
660 if (isdigit(*linep) || *linep=='+' || *linep=='-' || *linep=='.') {
663 if (sscanf(linep, "%lf%n", &aaitem, &i) < 1) {
664 linep = line; // Invalid numbers are ignored
676 while (*linep && *linep!=' ') {
677 if ((cp - citem) < 9) *cp++ = tolower(*linep);
689 if (*citem == 'y') return TRUE;
690 if (*citem == 'n') return FALSE;
691 proutn("Please answer with \"Y\" or \"N\": ");
698 prout("Beg your pardon, Captain?");
702 /* New function -- compares s to scaned citem and returns true if it
703 matches to the length of s */
705 return strncasecmp(s, citem, max(1, strlen(citem))) == 0;
711 proutn("Reset levels? ");
713 if (energy < inenrg) energy = inenrg;
718 proutn("Reset damage? ");
721 for (i=0; i <= NDEVICES; i++) if (damage[i] > 0.0) damage[i] = 0.0;
724 proutn("Toggle idebug? ");
727 if (idebug) prout("Debug output ON");
728 else prout("Debug output OFF");
730 proutn("Cause selective damage? ");
733 for (i=1; i <= NDEVICES; i++) {
739 if (key == IHALPHA && isit("y")) {
741 if (i == DRADIO) stdamtim = game.state.date;
745 proutn("Examine/change events? ");
748 for (i = 1; i < NEVENTS; i++) {
750 if (future[i] == 1e30) continue;
752 case FSNOVA: proutn("Supernova "); break;
753 case FTBEAM: proutn("T Beam "); break;
754 case FSNAP: proutn("Snapshot "); break;
755 case FBATTAK: proutn("Base Attack "); break;
756 case FCDBAS: proutn("Base Destroy "); break;
757 case FSCMOVE: proutn("SC Move "); break;
758 case FSCDBAS: proutn("SC Base Destroy "); break;
760 proutn("%.2f", future[i]-game.state.date);
765 future[i] = game.state.date + aaitem;