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.
22 Planets and dilithium crystals weren't in the original. Dave is OK
23 with this idea. He says the bit about the Galileo getting
24 turned into a McDonald's is "consistant with our original vision".
26 Dave also says the Space Thingy should not be preserved across saved
27 games, so you can't prove to others that you've seen it. He says it
28 shouldn't fire back, either. It should do nothing except scream and
29 disappear when hit by photon torpedos. It's OK that it may move
30 when attacked, but it didn't in the original.
32 The Faerie Queen, black holes, and time warping were 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 ram it, 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 and refactored the heck out of it.
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.
119 4. Per Dave Matuszek's remarks, Thingy state is not saved across games.
122 /* the input queue */
123 static char line[128], *linep = line;
129 unsigned long option;
133 {"SRSCAN", SRSCAN, OPTION_TTY},
135 {"STATUS", STATUS, OPTION_TTY},
137 {"REQUEST", REQUEST, OPTION_TTY},
139 {"LRSCAN", LRSCAN, OPTION_TTY},
141 {"PHASERS", PHASERS, 0},
143 {"TORPEDO", TORPEDO, 0},
144 {"PHOTONS", TORPEDO, 0},
148 {"SHIELDS", SHIELDS, 0},
152 {"DAMAGES", DAMAGES, 0},
156 {"IMPULSE", IMPULSE, 0},
164 {"SENSORS", SENSORS, OPTION_PLANETS},
166 {"ORBIT", ORBIT, OPTION_PLANETS},
168 {"TRANSPORT", TRANSPORT, OPTION_PLANETS},
170 {"MINE", MINE, OPTION_PLANETS},
172 {"CRYSTALS", CRYSTALS, OPTION_PLANETS},
174 {"SHUTTLE", SHUTTLE, OPTION_PLANETS},
176 {"PLANETS", PLANETS, OPTION_PLANETS},
178 {"REPORT", REPORT, 0},
180 {"COMPUTER", COMPUTER, 0},
182 {"COMMANDS", COMMANDS, 0},
184 {"EMEXIT", EMEXIT, 0},
186 {"PROBE", PROBE, OPTION_PROBE},
191 {"ABANDON", ABANDON, 0},
193 {"DESTRUCT", DESTRUCT, 0},
195 {"DEATHRAY", DEATHRAY, 0},
197 {"DEBUG", DEBUGCMD, 0},
199 {"MAYDAY", MAYDAY, 0},
208 #define NUMCOMMANDS sizeof(commands)/sizeof(commands[0])
210 static void listCommands(void) {
212 proutn("LEGAL COMMANDS ARE:");
213 for (i = 0; i < NUMCOMMANDS; i++) {
214 if (commands[i].option && !(commands[i].option & game.options))
218 proutn("%-12s ", commands[i].name);
224 static void helpme(void)
227 char cmdbuf[32], *cp;
230 /* Give help on commands */
235 setwnd(prompt_window);
236 proutn("Help on what command? ");
239 setwnd(message_window);
240 if (key == IHEOL) return;
241 for (i = 0; i < NUMCOMMANDS; i++) {
242 if (strcasecmp(commands[i].name, citem)==0) {
243 i = commands[i].value;
247 if (i != NUMCOMMANDS) break;
249 prout("Valid commands:");
256 strcpy(cmdbuf, " ABBREV");
259 for (j = 0; commands[i].name[j]; j++)
260 cmdbuf[j] = toupper(commands[i].name[j]);
263 fp = fopen(SSTDOC, "r");
265 prout("Spock- \"Captain, that information is missing from the");
266 prout(" computer.\"");
268 * This used to continue: "You need to find SST.DOC and put
269 * it in the current directory."
274 if (fgets(linebuf, sizeof(linebuf), fp) == NULL) {
275 prout("Spock- \"Captain, there is no information on that command.\"");
279 if (linebuf[0] == '%' && linebuf[1] == '%'&& linebuf[2] == ' ') {
280 for (cp = linebuf+3; isspace(*cp); cp++)
282 linebuf[strlen(linebuf)-1] = '\0';
283 if (strcasecmp(cp, cmdbuf) == 0)
289 prout("Spock- \"Captain, I've found the following information:\"");
292 while (fgets(linebuf, sizeof(linebuf),fp)) {
293 if (strstr(linebuf, "******"))
300 void enqueue(char *s)
305 static void makemoves(void)
309 setwnd(message_window);
310 while (TRUE) { /* command loop */
312 while (TRUE) { /* get a command */
318 setwnd(prompt_window);
321 if (scan() == IHEOL) {
327 setwnd(message_window);
329 for (i=0; i < ABANDON; i++)
330 if (isit(commands[i].name)) {
331 v = commands[i].value;
334 if (i < ABANDON && (!commands[i].option || (commands[i].option & game.options)))
336 for (; i < NUMCOMMANDS; i++)
337 if (strcasecmp(commands[i].name, citem) == 0) {
338 v = commands[i].value;
341 if (i < NUMCOMMANDS && (!commands[i].option || (commands[i].option & game.options)))
345 commandhook(commands[i].name, TRUE);
346 switch (v) { /* command switch */
347 case SRSCAN: // srscan
350 case STATUS: // status
353 case REQUEST: // status request
354 srscan(SCAN_REQUEST);
356 case LRSCAN: // lrscan
359 case PHASERS: // phasers
361 if (ididit) hitme = TRUE;
363 case TORPEDO: // photons
365 if (ididit) hitme = TRUE;
370 case SHIELDS: // shields
379 if (ididit) attack(0);
381 case DAMAGES: // damages
387 case IMPULSE: // impulse
392 if (ididit) hitme = TRUE;
400 case SENSORS: // sensors
405 if (ididit) hitme = TRUE;
407 case TRANSPORT: // transport "beam"
412 if (ididit) hitme = TRUE;
414 case CRYSTALS: // crystals
416 if (ididit) hitme = TRUE;
418 case SHUTTLE: // shuttle
420 if (ididit) hitme = TRUE;
422 case PLANETS: // Planet list
425 case REPORT: // Game Report
428 case COMPUTER: // use COMPUTER!
434 case EMEXIT: // Emergency exit
435 clrscr(); // Hide screen
436 freeze(TRUE); // forced save
437 exit(1); // And quick exit
440 probe(); // Launch probe
441 if (ididit) hitme = TRUE;
443 case ABANDON: // Abandon Ship
446 case DESTRUCT: // Self Destruct
449 case SAVE: // Save Game
452 if (skill > SKILL_GOOD)
453 prout("WARNING--Saved games produce no plaques!");
455 case DEATHRAY: // Try a desparation measure
457 if (ididit) hitme = TRUE;
459 case DEBUGCMD: // What do we want for debug???
464 case MAYDAY: // Call for help
466 if (ididit) hitme = TRUE;
469 alldone = 1; // quit the game
475 helpme(); // get help
478 commandhook(commands[i].name, FALSE);
480 if (alldone) break; // Game has ended
482 if (idebug) prout("2500");
486 if (alldone) break; // Events did us in
488 if (game.state.galaxy[quadx][quady] == SUPERNOVA_PLACE) { // Galaxy went Nova!
492 if (hitme && justin==0) {
495 if (game.state.galaxy[quadx][quady] == SUPERNOVA_PLACE) { // went NOVA!
508 int main(int argc, char **argv)
512 game.options = OPTION_ALL &~ OPTION_IOMODES;
514 game.options |= OPTION_CURSES;
516 game.options |= OPTION_TTY;
518 while ((option = getopt(argc, argv, "t")) != -1) {
521 game.options |= OPTION_TTY;
522 game.options &=~ OPTION_CURSES;
525 fprintf(stderr, "usage: sst [-t] [startcommand...].\n");
534 for (i = optind; i < argc; i++) {
535 strcat(line, argv[i]);
538 while (TRUE) { /* Play a game */
539 setwnd(fullscreen_window);
541 prout("INITIAL OPTIONS: %0lx\n", game.options);
545 setup(line[0] == '\0');
555 if (tourn && alldone) {
556 proutn("Do you want your score recorded?");
562 proutn("Do you want to play again? ");
566 prout("May the Great Bird of the Galaxy roost upon your home planet.");
573 /* return an enemy */
577 case IHR: s = "Romulan"; break;
578 case IHK: s = "Klingon"; break;
579 case IHC: s = "Commander"; break;
580 case IHS: s = "Super-commander"; break;
581 case IHSTAR: s = "Star"; break;
582 case IHP: s = "Planet"; break;
583 case IHB: s = "Starbase"; break;
584 case IHBLANK: s = "Black hole"; break;
585 case IHT: s = "Tholian"; break;
586 case IHWEB: s = "Tholian web"; break;
587 case IHQUEST: s = "Stranger"; break;
588 default: s = "Unknown??"; break;
593 char *cramlc(enum loctype key, int x, int y)
597 if (key == quadrant) strcpy(buf, "Quadrant ");
598 else if (key == sector) strcpy(buf, "Sector ");
599 sprintf(buf+strlen(buf), "%d - %d", x, y);
603 void crmena(int i, int enemy, int key, int x, int y)
605 if (i == 1) proutn("***");
608 proutn(cramlc(key, x, y));
615 case IHE: s = "Enterprise"; break;
616 case IHF: s = "Faerie Queene"; break;
617 default: s = "Ship???"; break;
624 prouts("******************************************************");
628 double expran(double avrage)
630 return -avrage*log(1e-7 + Rand());
634 return rand()/(1.0 + (double)RAND_MAX);
637 void iran(int size, int *i, int *j)
639 *i = Rand()*(size*1.0) + 1.0;
640 *j = Rand()*(size*1.0) + 1.0;
651 /* return IHEOL next time */
665 // Read a line if nothing here
671 cgetline(line, sizeof(line));
673 if (curwnd==prompt_window){
675 setwnd(message_window);
680 // Skip leading white space
681 while (*linep == ' ') linep++;
687 if (isdigit(*linep) || *linep=='+' || *linep=='-' || *linep=='.') {
690 if (sscanf(linep, "%lf%n", &aaitem, &i) < 1) {
691 linep = line; // Invalid numbers are ignored
703 while (*linep && *linep!=' ') {
704 if ((cp - citem) < 9) *cp++ = tolower(*linep);
717 if (*citem == 'y') return TRUE;
718 if (*citem == 'n') return FALSE;
719 proutn("Please answer with \"Y\" or \"N\": ");
727 prout("Beg your pardon, Captain?");
732 /* New function -- compares s to scanned citem and returns true if it
733 matches to the length of s */
735 return strncasecmp(s, citem, max(1, strlen(citem))) == 0;
742 proutn("Reset levels? ");
744 if (energy < inenrg) energy = inenrg;
749 proutn("Reset damage? ");
752 for (i=0; i < NDEVICES; i++)
753 if (game.damage[i] > 0.0)
754 game.damage[i] = 0.0;
757 proutn("Toggle idebug? ");
760 if (idebug) prout("Debug output ON");
761 else prout("Debug output OFF");
763 proutn("Cause selective damage? ");
766 for (i=0; i < NDEVICES; i++) {
772 if (key == IHALPHA && isit("y")) {
773 game.damage[i] = 10.0;
774 if (i == DRADIO) stdamtim = game.state.date;
778 proutn("Examine/change events? ");
781 for (i = 1; i < NEVENTS; i++) {
783 if (game.future[i] == 1e30) continue;
785 case FSNOVA: proutn("Supernova "); break;
786 case FTBEAM: proutn("T Beam "); break;
787 case FSNAP: proutn("Snapshot "); break;
788 case FBATTAK: proutn("Base Attack "); break;
789 case FCDBAS: proutn("Base Destroy "); break;
790 case FSCMOVE: proutn("SC Move "); break;
791 case FSCDBAS: proutn("SC Base Destroy "); break;
793 proutn("%.2f", game.future[i]-game.state.date);
798 game.future[i] = game.state.date + aaitem;