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},
198 //{"SOS", MAYDAY, 0},
206 #define NUMCOMMANDS sizeof(commands)/sizeof(commands[0])
207 #define ACCEPT(i) (!commands[i].option || (commands[i].option & game.options))
209 static void listCommands(void) {
211 proutn("LEGAL COMMANDS ARE:");
212 for (i = 0; i < NUMCOMMANDS; i++) {
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 (ACCEPT(i) && 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 (ACCEPT(i) && isit(commands[i].name)) {
330 v = commands[i].value;
333 if (i < ABANDON && (!commands[i].option || (commands[i].option & game.options)))
335 for (; i < NUMCOMMANDS; i++)
336 if (ACCEPT(i) && strcasecmp(commands[i].name, citem) == 0) {
337 v = commands[i].value;
340 if (i < NUMCOMMANDS && (!commands[i].option || (commands[i].option & game.options)))
344 commandhook(commands[i].name, TRUE);
345 switch (v) { /* command switch */
346 case SRSCAN: // srscan
349 case STATUS: // status
352 case REQUEST: // status request
353 srscan(SCAN_REQUEST);
355 case LRSCAN: // lrscan
358 case PHASERS: // phasers
360 if (ididit) hitme = TRUE;
362 case TORPEDO: // photons
364 if (ididit) hitme = TRUE;
369 case SHIELDS: // shields
378 if (ididit) attack(0);
380 case DAMAGES: // damages
386 case IMPULSE: // impulse
391 if (ididit) hitme = TRUE;
399 case SENSORS: // sensors
404 if (ididit) hitme = TRUE;
406 case TRANSPORT: // transport "beam"
411 if (ididit) hitme = TRUE;
413 case CRYSTALS: // crystals
415 if (ididit) hitme = TRUE;
417 case SHUTTLE: // shuttle
419 if (ididit) hitme = TRUE;
421 case PLANETS: // Planet list
424 case REPORT: // Game Report
427 case COMPUTER: // use COMPUTER!
433 case EMEXIT: // Emergency exit
434 clrscr(); // Hide screen
435 freeze(TRUE); // forced save
436 exit(1); // And quick exit
439 probe(); // Launch probe
440 if (ididit) hitme = TRUE;
442 case ABANDON: // Abandon Ship
445 case DESTRUCT: // Self Destruct
448 case SAVE: // Save Game
451 if (skill > SKILL_GOOD)
452 prout("WARNING--Saved games produce no plaques!");
454 case DEATHRAY: // Try a desparation measure
456 if (ididit) hitme = TRUE;
458 case DEBUGCMD: // What do we want for debug???
463 case MAYDAY: // Call for help
465 if (ididit) hitme = TRUE;
468 alldone = 1; // quit the game
474 helpme(); // get help
477 commandhook(commands[i].name, FALSE);
479 if (alldone) break; // Game has ended
481 if (idebug) prout("2500");
485 if (alldone) break; // Events did us in
487 if (game.state.galaxy[quadx][quady].supernova) { // Galaxy went Nova!
491 if (hitme && justin==0) {
494 if (game.state.galaxy[quadx][quady].supernova) { // went NOVA!
507 int main(int argc, char **argv)
511 game.options = OPTION_ALL &~ OPTION_IOMODES;
513 game.options |= OPTION_CURSES;
515 game.options |= OPTION_TTY;
517 while ((option = getopt(argc, argv, "t")) != -1) {
520 game.options |= OPTION_TTY;
521 game.options &=~ OPTION_CURSES;
524 fprintf(stderr, "usage: sst [-t] [startcommand...].\n");
533 for (i = optind; i < argc; i++) {
534 strcat(line, argv[i]);
537 while (TRUE) { /* Play a game */
538 setwnd(fullscreen_window);
540 prout("INITIAL OPTIONS: %0lx\n", game.options);
544 setup(line[0] == '\0');
554 if (tourn && alldone) {
555 proutn("Do you want your score recorded?");
561 proutn("Do you want to play again? ");
565 prout("May the Great Bird of the Galaxy roost upon your home planet.");
572 /* return an enemy */
576 case IHR: s = "Romulan"; break;
577 case IHK: s = "Klingon"; break;
578 case IHC: s = "Commander"; break;
579 case IHS: s = "Super-commander"; break;
580 case IHSTAR: s = "Star"; break;
581 case IHP: s = "Planet"; break;
582 case IHB: s = "Starbase"; break;
583 case IHBLANK: s = "Black hole"; break;
584 case IHT: s = "Tholian"; break;
585 case IHWEB: s = "Tholian web"; break;
586 case IHQUEST: s = "Stranger"; break;
587 default: s = "Unknown??"; break;
592 char *cramlc(enum loctype key, int x, int y)
596 if (key == quadrant) strcpy(buf, "Quadrant ");
597 else if (key == sector) strcpy(buf, "Sector ");
598 sprintf(buf+strlen(buf), "%d - %d", x, y);
602 void crmena(int i, int enemy, int key, int x, int y)
604 if (i == 1) proutn("***");
607 proutn(cramlc(key, x, y));
614 case IHE: s = "Enterprise"; break;
615 case IHF: s = "Faerie Queene"; break;
616 default: s = "Ship???"; break;
623 prouts("******************************************************");
627 double expran(double avrage)
629 return -avrage*log(1e-7 + Rand());
633 return rand()/(1.0 + (double)RAND_MAX);
636 void iran(int size, int *i, int *j)
638 *i = Rand()*(size*1.0) + 1.0;
639 *j = Rand()*(size*1.0) + 1.0;
650 /* return IHEOL next time */
664 // Read a line if nothing here
670 cgetline(line, sizeof(line));
672 if (curwnd==prompt_window){
674 setwnd(message_window);
679 // Skip leading white space
680 while (*linep == ' ') linep++;
686 if (isdigit(*linep) || *linep=='+' || *linep=='-' || *linep=='.') {
689 if (sscanf(linep, "%lf%n", &aaitem, &i) < 1) {
690 linep = line; // Invalid numbers are ignored
702 while (*linep && *linep!=' ') {
703 if ((cp - citem) < 9) *cp++ = tolower(*linep);
716 if (*citem == 'y') return TRUE;
717 if (*citem == 'n') return FALSE;
718 proutn("Please answer with \"Y\" or \"N\": ");
726 prout("Beg your pardon, Captain?");
731 /* New function -- compares s to scanned citem and returns true if it
732 matches to the length of s */
734 return strncasecmp(s, citem, max(1, strlen(citem))) == 0;
741 proutn("Reset levels? ");
743 if (energy < inenrg) energy = inenrg;
748 proutn("Reset damage? ");
751 for (i=0; i < NDEVICES; i++)
752 if (game.damage[i] > 0.0)
753 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;
775 proutn("Examine/change events? ");
778 for (i = 1; i < NEVENTS; i++) {
780 if (game.future[i] == FOREVER) continue;
782 case FSNOVA: proutn("Supernova "); break;
783 case FTBEAM: proutn("T Beam "); break;
784 case FSNAP: proutn("Snapshot "); break;
785 case FBATTAK: proutn("Base Attack "); break;
786 case FCDBAS: proutn("Base Destroy "); break;
787 case FSCMOVE: proutn("SC Move "); break;
788 case FSCDBAS: proutn("SC Base Destroy "); break;
790 proutn("%.2f", game.future[i]-game.state.date);
795 game.future[i] = game.state.date + aaitem;