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 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.
121 /* the input queue */
122 static char line[128], *linep = line;
128 unsigned long option;
132 {"SRSCAN", SRSCAN, OPTION_TTY},
134 {"STATUS", STATUS, OPTION_TTY},
136 {"REQUEST", REQUEST, OPTION_TTY},
138 {"LRSCAN", LRSCAN, OPTION_TTY},
140 {"PHASERS", PHASERS, 0},
142 {"TORPEDO", TORPEDO, 0},
143 {"PHOTONS", TORPEDO, 0},
147 {"SHIELDS", SHIELDS, 0},
151 {"DAMAGES", DAMAGES, 0},
155 {"IMPULSE", IMPULSE, 0},
163 {"SENSORS", SENSORS, OPTION_PLANETS},
165 {"ORBIT", ORBIT, OPTION_PLANETS},
167 {"TRANSPORT", TRANSPORT, OPTION_PLANETS},
169 {"MINE", MINE, OPTION_PLANETS},
171 {"CRYSTALS", CRYSTALS, OPTION_PLANETS},
173 {"SHUTTLE", SHUTTLE, OPTION_PLANETS},
175 {"PLANETS", PLANETS, OPTION_PLANETS},
177 {"REPORT", REPORT, 0},
179 {"COMPUTER", COMPUTER, 0},
181 {"COMMANDS", COMMANDS, 0},
183 {"EMEXIT", EMEXIT, 0},
185 {"PROBE", PROBE, OPTION_PROBE},
190 {"ABANDON", ABANDON, 0},
192 {"DESTRUCT", DESTRUCT, 0},
194 {"DEATHRAY", DEATHRAY, 0},
196 {"DEBUG", DEBUGCMD, 0},
198 {"MAYDAY", MAYDAY, 0},
207 #define NUMCOMMANDS sizeof(commands)/sizeof(commands[0])
209 static void listCommands(void) {
211 proutn("LEGAL COMMANDS ARE:");
212 for (i = 0; i < NUMCOMMANDS; i++) {
213 if (commands[i].option && !(commands[i].option & game.options))
217 proutn("%-12s ", commands[i].name);
223 static void helpme(void)
226 char cmdbuf[32], *cp;
229 /* Give help on commands */
234 setwnd(prompt_window);
235 proutn("Help on what command? ");
238 setwnd(message_window);
239 if (key == IHEOL) return;
240 for (i = 0; i < NUMCOMMANDS; i++) {
241 if (strcasecmp(commands[i].name, citem)==0) {
242 i = commands[i].value;
246 if (i != NUMCOMMANDS) break;
248 prout("Valid commands:");
255 strcpy(cmdbuf, " ABBREV");
258 for (j = 0; commands[i].name[j]; j++)
259 cmdbuf[j] = toupper(commands[i].name[j]);
262 fp = fopen(SSTDOC, "r");
264 prout("Spock- \"Captain, that information is missing from the");
265 prout(" computer.\"");
267 * This used to continue: "You need to find SST.DOC and put
268 * it in the current directory."
273 if (fgets(linebuf, sizeof(linebuf), fp) == NULL) {
274 prout("Spock- \"Captain, there is no information on that command.\"");
278 if (linebuf[0] == '%' && linebuf[1] == '%'&& linebuf[2] == ' ') {
279 for (cp = linebuf+3; isspace(*cp); cp++)
281 linebuf[strlen(linebuf)-1] = '\0';
282 if (strcasecmp(cp, cmdbuf) == 0)
288 prout("Spock- \"Captain, I've found the following information:\"");
291 while (fgets(linebuf, sizeof(linebuf),fp)) {
292 if (strstr(linebuf, "******"))
299 void enqueue(char *s)
304 static void makemoves(void)
308 setwnd(message_window);
309 while (TRUE) { /* command loop */
311 while (TRUE) { /* get a command */
317 setwnd(prompt_window);
320 if (scan() == IHEOL) {
326 setwnd(message_window);
328 for (i=0; i < ABANDON; i++)
329 if (isit(commands[i].name)) {
330 v = commands[i].value;
333 if (i < ABANDON) break;
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_PLACE) { // Galaxy went Nova!
490 if (hitme && justin==0) {
493 if (game.state.galaxy[quadx][quady] == SUPERNOVA_PLACE) { // 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=1; 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;