1 #define INCLUDED // Define externs here
9 #define SSTDOC "sst.doc"
14 Here are Tom Almy's changes:
16 Compared to original version, I've changed the "help" command to
17 "call" and the "terminate" command to "quit" to better match
18 user expectations. The DECUS version apparently made those changes
19 as well as changing "freeze" to "save". However I like "freeze".
21 When I got a later version of Super Star Trek that I was converting
22 from, I added the emexit command.
24 That later version also mentions srscan and lrscan working when
25 docked (using the starbase's scanners), so I made some changes here
26 to do this (and indicating that fact to the player), and then realized
27 the base would have a subspace radio as well -- doing a Chart when docked
28 updates the star chart, and all radio reports will be heard. The Dock
29 command will also give a report if a base is under attack.
31 Movecom no longer reports movement if sensors are damaged so you wouldn't
36 1. Better base positioning at startup
38 2. Deathray improvement (but keeping original failure alternatives)
42 4. Enemies can ram the Enterprise. Regular Klingons and Romulans can
43 move in Expert and Emeritus games. This code could use improvement.
45 5. The deep space probe looks interesting! DECUS version
47 6. Perhaps cloaking to be added later? BSD version
49 Here are Stas Sergeev's changes:
51 1. The Space Thingy can be shoved, if you it ram, and can fire back if
54 2. The Tholian can be hit with phasers
56 3. When you are docked, base covers you with an almost invincible shields
57 (a commander can still ram you, or a Romulan can destroy the base,
58 or a SCom can even succeed with direct attack IIRC, but this rarely
61 4. SCom can't escape from you if no more enemies remain (without this,
62 chasing SCom can take an eternity).
64 5. Probe target you enter is now the destination quadrant. Before I don't
65 remember what it was, but it was something I had difficulty using)
67 6. Secret password is now autogenerated.
69 7. "Plaque" is adjusted for A4 paper :-)
71 8. Phasers now tells you how much energy needed, but only if the computer
74 9. Planets are auto-scanned when you enter the quadrant.
76 10. Mining or using crystals in presense of enemy now yields an attack.
77 There are other minor adjustments to what yields an attack
80 11. Ramming a black hole is no longer instant death. There is a
81 chance you might get timewarped instead.
83 12. "freeze" command reverts to "save", most people will understand this
86 13. Screen-oriented interface, with sensor scans always up.
88 Eric Raymond's changes:
90 1. "sos" and "call" becomes "mayday", "freeze" and "save" are both good.
95 static char line[128], *linep = line;
108 {"REQUEST", REQUEST},
112 {"PHASERS", PHASERS},
114 {"TORPEDO", TORPEDO},
115 {"PHOTONS", TORPEDO},
119 {"SHIELDS", SHIELDS},
123 {"DAMAGES", DAMAGES},
127 {"IMPULSE", IMPULSE},
135 {"SENSORS", SENSORS},
139 {"TRANSPORT", TRANSPORT},
143 {"CRYSTALS", CRYSTALS},
145 {"SHUTTLE", SHUTTLE},
147 {"PLANETS", PLANETS},
151 {"COMPUTER", COMPUTER},
153 {"COMMANDS", COMMANDS},
162 {"ABANDON", ABANDON},
164 {"DESTRUCT", DESTRUCT},
166 {"DEATHRAY", DEATHRAY},
179 #define NUMCOMMANDS sizeof(commands)/sizeof(commands[0])
181 static void listCommands(int x) {
183 prout("LEGAL COMMANDS ARE:");
184 for (i = 0; i < NUMCOMMANDS; i++) {
185 proutn("%-12s ", commands[i].name);
192 static void helpme(void) {
194 char cmdbuf[32], *cp;
197 /* Give help on commands */
202 setwnd(prompt_window);
203 proutn("Help on what command? ");
206 setwnd(message_window);
207 if (key == IHEOL) return;
208 for (i = 0; i < NUMCOMMANDS; i++) {
209 if (strcasecmp(commands[i].name, citem)==0) {
210 i = commands[i].value;
214 if (i != NUMCOMMANDS) break;
216 prout("Valid commands:");
223 strcpy(cmdbuf, " ABBREV");
226 for (j = 0; commands[i].name[j]; j++)
227 cmdbuf[j] = toupper(commands[i].name[j]);
230 fp = fopen(SSTDOC, "r");
232 prout("Spock- \"Captain, that information is missing from the");
233 prout(" computer.\"");
235 * This used to continue: "You need to find SST.DOC and put
236 * it in the current directory."
241 if (fgets(linebuf, sizeof(linebuf), fp) == NULL) {
242 prout("Spock- \"Captain, there is no information on that command.\"");
246 if (linebuf[0] == '%' && linebuf[1] == '%'&& linebuf[2] == ' ') {
247 for (cp = linebuf+3; isspace(*cp); cp++)
249 linebuf[strlen(linebuf)-1] = '\0';
250 if (strcasecmp(cp, cmdbuf) == 0)
256 prout("Spock- \"Captain, I've found the following information:\"");
259 while (fgets(linebuf, sizeof(linebuf),fp)) {
260 if (strstr(linebuf, "******"))
267 void enqueue(char *s) {
271 static void makemoves(void) {
274 setwnd(message_window);
275 while (TRUE) { /* command loop */
277 while (TRUE) { /* get a command */
283 setwnd(prompt_window);
286 if (scan() == IHEOL) {
292 setwnd(message_window);
294 for (i=0; i < ABANDON; i++)
295 if (isit(commands[i].name)) {
296 i = commands[i].value;
299 if (i < ABANDON) break;
300 for (; i < NUMCOMMANDS; i++)
301 if (strcasecmp(commands[i].name, citem) == 0) {
302 i = commands[i].value;
305 if (i < NUMCOMMANDS) break;
309 commandhook(commands[i].name, TRUE);
310 switch (i) { /* command switch */
311 case SRSCAN: // srscan
314 case STATUS: // status
317 case REQUEST: // status request
318 srscan(SCAN_REQUEST);
320 case LRSCAN: // lrscan
323 case PHASERS: // phasers
325 if (ididit) hitme = TRUE;
327 case TORPEDO: // photons
329 if (ididit) hitme = TRUE;
334 case SHIELDS: // shields
343 if (ididit) attack(0);
345 case DAMAGES: // damages
351 case IMPULSE: // impulse
356 if (ididit) hitme = TRUE;
364 case SENSORS: // sensors
369 if (ididit) hitme = TRUE;
371 case TRANSPORT: // transport "beam"
376 if (ididit) hitme = TRUE;
378 case CRYSTALS: // crystals
380 if (ididit) hitme = TRUE;
382 case SHUTTLE: // shuttle
384 if (ididit) hitme = TRUE;
386 case PLANETS: // Planet list
389 case REPORT: // Game Report
392 case COMPUTER: // use COMPUTER!
398 case EMEXIT: // Emergency exit
399 clrscr(); // Hide screen
400 freeze(TRUE); // forced save
401 exit(1); // And quick exit
404 probe(); // Launch probe
405 if (ididit) hitme = TRUE;
407 case ABANDON: // Abandon Ship
410 case DESTRUCT: // Self Destruct
413 case SAVE: // Save Game
417 prout("WARNING--Saved games produce no plaques!");
419 case DEATHRAY: // Try a desparation measure
421 if (ididit) hitme = TRUE;
423 case DEBUGCMD: // What do we want for debug???
428 case MAYDAY: // Call for help
430 if (ididit) hitme = TRUE;
433 alldone = 1; // quit the game
439 helpme(); // get help
442 commandhook(commands[i].name, FALSE);
444 if (alldone) break; // Game has ended
446 if (idebug) prout("2500");
450 if (alldone) break; // Events did us in
452 if (game.state.galaxy[quadx][quady] == 1000) { // Galaxy went Nova!
456 if (hitme && justin==0) {
459 if (game.state.galaxy[quadx][quady] == 1000) { // went NOVA!
472 int main(int argc, char **argv) {
473 int i, option, usecurses = TRUE;
475 while ((option = getopt(argc, argv, "t")) != -1) {
481 fprintf(stderr, "usage: sst [-t] [startcommand...].\n");
490 for (i = optind; i < argc; i++) {
491 strcat(line, argv[i]);
494 while (TRUE) { /* Play a game */
495 setwnd(fullscreen_window);
498 setup(line[0] == '\0');
508 if (tourn && alldone) {
509 proutn("Do you want your score recorded?");
515 proutn("Do you want to play again? ");
519 prout("May the Great Bird of the Galaxy roost upon your home planet.");
525 /* return an enemy */
529 case IHR: s = "Romulan"; break;
530 case IHK: s = "Klingon"; break;
531 case IHC: s = "Commander"; break;
532 case IHS: s = "Super-commander"; break;
533 case IHSTAR: s = "Star"; break;
534 case IHP: s = "Planet"; break;
535 case IHB: s = "Starbase"; break;
536 case IHBLANK: s = "Black hole"; break;
537 case IHT: s = "Tholian"; break;
538 case IHWEB: s = "Tholian web"; break;
539 case IHQUEST: s = "Stranger"; break;
540 default: s = "Unknown??"; break;
545 char *cramlc(enum loctype key, int x, int y) {
548 if (key == quadrant) strcpy(buf, "Quadrant ");
549 else if (key == sector) strcpy(buf, "Sector ");
550 sprintf(buf+strlen(buf), "%d - %d", x, y);
554 void crmena(int i, int enemy, int key, int x, int y) {
555 if (i == 1) proutn("***");
558 proutn(cramlc(key, x, y));
564 case IHE: s = "Enterprise"; break;
565 case IHF: s = "Faerie Queene"; break;
566 default: s = "Ship???"; break;
572 prouts("******************************************************");
576 double expran(double avrage) {
577 return -avrage*log(1e-7 + Rand());
581 return rand()/(1.0 + (double)RAND_MAX);
584 void iran8(int *i, int *j) {
585 *i = Rand()*8.0 + 1.0;
586 *j = Rand()*8.0 + 1.0;
589 void iran10(int *i, int *j) {
590 *i = Rand()*10.0 + 1.0;
591 *j = Rand()*10.0 + 1.0;
600 /* return IHEOL next time */
613 // Read a line if nothing here
619 cgetline(line, sizeof(line));
621 if (curwnd==prompt_window){
623 setwnd(message_window);
628 // Skip leading white space
629 while (*linep == ' ') linep++;
635 if (isdigit(*linep) || *linep=='+' || *linep=='-' || *linep=='.') {
638 if (sscanf(linep, "%lf%n", &aaitem, &i) < 1) {
639 linep = line; // Invalid numbers are ignored
651 while (*linep && *linep!=' ') {
652 if ((cp - citem) < 9) *cp++ = tolower(*linep);
664 if (*citem == 'y') return TRUE;
665 if (*citem == 'n') return FALSE;
666 proutn("Please answer with \"Y\" or \"N\": ");
673 prout("Beg your pardon, Captain?");
677 /* New function -- compares s to scaned citem and returns true if it
678 matches to the length of s */
680 return strncasecmp(s, citem, max(1, strlen(citem))) == 0;
686 proutn("Reset levels? ");
688 if (energy < inenrg) energy = inenrg;
693 proutn("Reset damage? ");
696 for (i=0; i <= NDEVICES; i++) if (damage[i] > 0.0) damage[i] = 0.0;
699 proutn("Toggle idebug? ");
702 if (idebug) prout("Debug output ON");
703 else prout("Debug output OFF");
705 proutn("Cause selective damage? ");
708 for (i=1; i <= NDEVICES; i++) {
714 if (key == IHALPHA && isit("y")) {
716 if (i == DRADIO) stdamtim = game.state.date;
720 proutn("Examine/change events? ");
723 for (i = 1; i < NEVENTS; i++) {
725 if (future[i] == 1e30) continue;
727 case FSNOVA: proutn("Supernova "); break;
728 case FTBEAM: proutn("T Beam "); break;
729 case FSNAP: proutn("Snapshot "); break;
730 case FBATTAK: proutn("Base Attack "); break;
731 case FCDBAS: proutn("Base Destroy "); break;
732 case FSCMOVE: proutn("SC Move "); break;
733 case FSCDBAS: proutn("SC Base Destroy "); break;
735 proutn("%.2f", future[i]-game.state.date);
740 future[i] = game.state.date + aaitem;