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. Per Dave Matuszek's remarks, Thingy state is not saved across games.
120 /* the input queue */
121 static char line[128], *linep = line;
127 unsigned long option;
131 {"SRSCAN", SRSCAN, OPTION_TTY},
133 {"STATUS", STATUS, OPTION_TTY},
135 {"REQUEST", REQUEST, OPTION_TTY},
137 {"LRSCAN", LRSCAN, OPTION_TTY},
139 {"PHASERS", PHASERS, 0},
141 {"TORPEDO", TORPEDO, 0},
142 {"PHOTONS", TORPEDO, 0},
146 {"SHIELDS", SHIELDS, 0},
150 {"DAMAGES", DAMAGES, 0},
154 {"IMPULSE", IMPULSE, 0},
162 {"SENSORS", SENSORS, OPTION_PLANETS},
164 {"ORBIT", ORBIT, OPTION_PLANETS},
166 {"TRANSPORT", TRANSPORT, OPTION_PLANETS},
168 {"MINE", MINE, OPTION_PLANETS},
170 {"CRYSTALS", CRYSTALS, OPTION_PLANETS},
172 {"SHUTTLE", SHUTTLE, OPTION_PLANETS},
174 {"PLANETS", PLANETS, OPTION_PLANETS},
176 {"REPORT", REPORT, 0},
178 {"COMPUTER", COMPUTER, 0},
180 {"COMMANDS", COMMANDS, 0},
182 {"EMEXIT", EMEXIT, 0},
184 {"PROBE", PROBE, OPTION_PROBE},
189 {"ABANDON", ABANDON, 0},
191 {"DESTRUCT", DESTRUCT, 0},
193 {"DEATHRAY", DEATHRAY, 0},
195 {"DEBUG", DEBUGCMD, 0},
197 {"MAYDAY", MAYDAY, 0},
206 #define NUMCOMMANDS sizeof(commands)/sizeof(commands[0])
208 static void listCommands(void) {
210 proutn("LEGAL COMMANDS ARE:");
211 for (i = 0; i < NUMCOMMANDS; i++) {
212 if (commands[i].option && !(commands[i].option & game.options))
216 proutn("%-12s ", commands[i].name);
222 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:");
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)
303 static void makemoves(void)
307 setwnd(message_window);
308 while (TRUE) { /* command loop */
310 while (TRUE) { /* get a command */
316 setwnd(prompt_window);
319 if (scan() == IHEOL) {
325 setwnd(message_window);
327 for (i=0; i < ABANDON; i++)
328 if (isit(commands[i].name)) {
329 v = commands[i].value;
332 if (i < ABANDON && (!commands[i].option || (commands[i].option & game.options)))
334 for (; i < NUMCOMMANDS; i++)
335 if (strcasecmp(commands[i].name, citem) == 0) {
336 v = commands[i].value;
339 if (i < NUMCOMMANDS && (!commands[i].option || (commands[i].option & game.options)))
343 commandhook(commands[i].name, TRUE);
344 switch (v) { /* command switch */
345 case SRSCAN: // srscan
348 case STATUS: // status
351 case REQUEST: // status request
352 srscan(SCAN_REQUEST);
354 case LRSCAN: // lrscan
357 case PHASERS: // phasers
359 if (ididit) hitme = TRUE;
361 case TORPEDO: // photons
363 if (ididit) hitme = TRUE;
368 case SHIELDS: // shields
377 if (ididit) attack(0);
379 case DAMAGES: // damages
385 case IMPULSE: // impulse
390 if (ididit) hitme = TRUE;
398 case SENSORS: // sensors
403 if (ididit) hitme = TRUE;
405 case TRANSPORT: // transport "beam"
410 if (ididit) hitme = TRUE;
412 case CRYSTALS: // crystals
414 if (ididit) hitme = TRUE;
416 case SHUTTLE: // shuttle
418 if (ididit) hitme = TRUE;
420 case PLANETS: // Planet list
423 case REPORT: // Game Report
426 case COMPUTER: // use COMPUTER!
432 case EMEXIT: // Emergency exit
433 clrscr(); // Hide screen
434 freeze(TRUE); // forced save
435 exit(1); // And quick exit
438 probe(); // Launch probe
439 if (ididit) hitme = TRUE;
441 case ABANDON: // Abandon Ship
444 case DESTRUCT: // Self Destruct
447 case SAVE: // Save Game
450 if (skill > SKILL_GOOD)
451 prout("WARNING--Saved games produce no plaques!");
453 case DEATHRAY: // Try a desparation measure
455 if (ididit) hitme = TRUE;
457 case DEBUGCMD: // What do we want for debug???
462 case MAYDAY: // Call for help
464 if (ididit) hitme = TRUE;
467 alldone = 1; // quit the game
473 helpme(); // get help
476 commandhook(commands[i].name, FALSE);
478 if (alldone) break; // Game has ended
480 if (idebug) prout("2500");
484 if (alldone) break; // Events did us in
486 if (game.state.galaxy[quadx][quady].supernova) { // Galaxy went Nova!
490 if (hitme && justin==0) {
493 if (game.state.galaxy[quadx][quady].supernova) { // went NOVA!
506 int main(int argc, char **argv)
510 game.options = OPTION_ALL &~ OPTION_IOMODES;
512 game.options |= OPTION_CURSES;
514 game.options |= OPTION_TTY;
516 while ((option = getopt(argc, argv, "t")) != -1) {
519 game.options |= OPTION_TTY;
520 game.options &=~ OPTION_CURSES;
523 fprintf(stderr, "usage: sst [-t] [startcommand...].\n");
532 for (i = optind; i < argc; i++) {
533 strcat(line, argv[i]);
536 while (TRUE) { /* Play a game */
537 setwnd(fullscreen_window);
539 prout("INITIAL OPTIONS: %0lx\n", game.options);
543 setup(line[0] == '\0');
553 if (tourn && alldone) {
554 proutn("Do you want your score recorded?");
560 proutn("Do you want to play again? ");
564 prout("May the Great Bird of the Galaxy roost upon your home planet.");
571 /* return an enemy */
575 case IHR: s = "Romulan"; break;
576 case IHK: s = "Klingon"; break;
577 case IHC: s = "Commander"; break;
578 case IHS: s = "Super-commander"; break;
579 case IHSTAR: s = "Star"; break;
580 case IHP: s = "Planet"; break;
581 case IHB: s = "Starbase"; break;
582 case IHBLANK: s = "Black hole"; break;
583 case IHT: s = "Tholian"; break;
584 case IHWEB: s = "Tholian web"; break;
585 case IHQUEST: s = "Stranger"; break;
586 default: s = "Unknown??"; break;
591 char *cramlc(enum loctype key, int x, int y)
595 if (key == quadrant) strcpy(buf, "Quadrant ");
596 else if (key == sector) strcpy(buf, "Sector ");
597 sprintf(buf+strlen(buf), "%d - %d", x, y);
601 void crmena(int i, int enemy, int key, int x, int y)
603 if (i == 1) proutn("***");
606 proutn(cramlc(key, x, y));
613 case IHE: s = "Enterprise"; break;
614 case IHF: s = "Faerie Queene"; break;
615 default: s = "Ship???"; break;
622 prouts("******************************************************");
626 double expran(double avrage)
628 return -avrage*log(1e-7 + Rand());
632 return rand()/(1.0 + (double)RAND_MAX);
635 void iran(int size, int *i, int *j)
637 *i = Rand()*(size*1.0) + 1.0;
638 *j = Rand()*(size*1.0) + 1.0;
649 /* return IHEOL next time */
663 // Read a line if nothing here
669 cgetline(line, sizeof(line));
671 if (curwnd==prompt_window){
673 setwnd(message_window);
678 // Skip leading white space
679 while (*linep == ' ') linep++;
685 if (isdigit(*linep) || *linep=='+' || *linep=='-' || *linep=='.') {
688 if (sscanf(linep, "%lf%n", &aaitem, &i) < 1) {
689 linep = line; // Invalid numbers are ignored
701 while (*linep && *linep!=' ') {
702 if ((cp - citem) < 9) *cp++ = tolower(*linep);
715 if (*citem == 'y') return TRUE;
716 if (*citem == 'n') return FALSE;
717 proutn("Please answer with \"Y\" or \"N\": ");
725 prout("Beg your pardon, Captain?");
730 /* New function -- compares s to scanned citem and returns true if it
731 matches to the length of s */
733 return strncasecmp(s, citem, max(1, strlen(citem))) == 0;
740 proutn("Reset levels? ");
742 if (energy < inenrg) energy = inenrg;
747 proutn("Reset damage? ");
750 for (i=0; i < NDEVICES; i++)
751 if (game.damage[i] > 0.0)
752 game.damage[i] = 0.0;
755 proutn("Toggle idebug? ");
758 if (idebug) prout("Debug output ON");
759 else prout("Debug output OFF");
761 proutn("Cause selective damage? ");
764 for (i=0; i < NDEVICES; i++) {
770 if (key == IHALPHA && isit("y")) {
771 game.damage[i] = 10.0;
772 if (i == DRADIO) stdamtim = game.state.date;
776 proutn("Examine/change events? ");
779 for (i = 1; i < NEVENTS; i++) {
781 if (game.future[i] == 1e30) continue;
783 case FSNOVA: proutn("Supernova "); break;
784 case FTBEAM: proutn("T Beam "); break;
785 case FSNAP: proutn("Snapshot "); break;
786 case FBATTAK: proutn("Base Attack "); break;
787 case FCDBAS: proutn("Base Destroy "); break;
788 case FSCMOVE: proutn("SC Move "); break;
789 case FSCDBAS: proutn("SC Base Destroy "); break;
791 proutn("%.2f", game.future[i]-game.state.date);
796 game.future[i] = game.state.date + aaitem;