1 #define INCLUDED // Define externs here
10 #define SSTDOC "sst.doc"
13 static char line[128], *linep = line;
17 Here are Tom Almy's changes:
19 Compared to original version, I've changed the "help" command to
20 "call" and the "terminate" command to "quit" to better match
21 user expectations. The DECUS version apparently made those changes
22 as well as changing "freeze" to "save". However I like "freeze".
24 When I got a later version of Super Star Trek that I was converting
25 from, I added the emexit command.
27 That later version also mentions srscan and lrscan working when
28 docked (using the starbase's scanners), so I made some changes here
29 to do this (and indicating that fact to the player), and then realized
30 the base would have a subspace radio as well -- doing a Chart when docked
31 updates the star chart, and all radio reports will be heard. The Dock
32 command will also give a report if a base is under attack.
34 Movecom no longer reports movement if sensors are damaged so you wouldn't
39 1. Better base positioning at startup
41 2. Deathray improvement (but keeping original failure alternatives)
45 4. Enemies can ram the Enterprise. Regular Klingons and Romulans can
46 move in Expert and Emeritus games. This code could use improvement.
48 5. The deep space probe looks interesting! DECUS version
50 6. Perhaps cloaking to be added later? BSD version
52 Here are Stas Sergeev's changes (controlled by the proprocessor symbol
53 SERGEEV, not yet completely merged):
55 1. The Space Thingy can be shoved, if you it ram, and can fire back if
58 1 The Tholian can be hit with phasers
60 2. When you are docked, base covers you with an almost invincible shields
61 (a commander can still ram you, or a Romulan can destroy the base,
62 or a SCom can even succeed with direct attack IIRC, but this rarely
65 3. SCom can't escape from you if no more enemies remain (without this,
66 chasing SCom can take an eternity).
68 4. Probe target you enter is now the destination quadrant. Before I don't
69 remember what it was, but it was something I had difficulty using)
71 5. Secret password is now autogenerated.
73 6. "Plaque" is adjusted for A4 paper:)
75 7. Phasers now tells you how much energy needed, but only if the computer
78 8. Planets are auto-scanned when you enter the quadrant.
80 9. Mining or using crystals in presense of enemy now yields an attack.
81 There are other minor adjustments to what yields an attack
84 10. Ramming a black hole is no longer instant death. There is a
85 chance you might get timewarped instead.
87 11. "freeze" command reverts to "save", most people will understand this
90 Eric Raymond's changes:
92 1. "sos" and "call" becomes "mayday", "freeze" and "save" are both good.
110 {"PHASERS", PHASERS},
112 {"TORPEDO", TORPEDO},
113 {"PHOTONS", TORPEDO},
117 {"SHIELDS", SHIELDS},
121 {"DAMAGES", DAMAGES},
125 {"IMPULSE", IMPULSE},
134 {"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(BOTTOM_WINDOW);
203 proutn("Help on what command? ");
206 setwnd(LOWER_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 static void makemoves(void) {
270 setwnd(LOWER_WINDOW);
271 while (TRUE) { /* command loop */
273 while (TRUE) { /* get a command */
279 setwnd(BOTTOM_WINDOW);
282 if (scan() == IHEOL) {
284 _setcursortype(_NOCURSOR);
285 setwnd(LOWER_WINDOW);
288 _setcursortype(_NORMALCURSOR);
294 setwnd(LOWER_WINDOW);
296 for (i=0; i < ABANDON; i++)
297 if (isit(commands[i].name)) {
298 i = commands[i].value;
301 if (i < ABANDON) break;
302 for (; i < NUMCOMMANDS; i++)
303 if (strcasecmp(commands[i].name, citem) == 0) {
304 i = commands[i].value;
307 if (i < NUMCOMMANDS) break;
311 commandhook(commands[i].name, TRUE);
312 switch (i) { /* command switch */
314 case SRSCAN: // srscan
317 case LRSCAN: // lrscan
321 case PHASERS: // phasers
323 if (ididit) hitme = TRUE;
325 case TORPEDO: // photons
327 if (ididit) hitme = TRUE;
332 case SHIELDS: // shields
341 if (ididit) attack(0);
343 case DAMAGES: // damages
349 case IMPULSE: // impulse
354 if (ididit) hitme = TRUE;
363 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 */
496 setup(line[0] == '\0');
506 if (tourn && alldone) {
507 proutn("Do you want your score recorded?");
513 proutn("Do you want to play again? ");
515 setwnd(FULLSCREEN_WINDOW);
520 prout("May the Great Bird of the Galaxy roost upon your home planet.");
526 /* return an enemy */
530 case IHR: s = "Romulan"; break;
531 case IHK: s = "Klingon"; break;
532 case IHC: s = "Commander"; break;
533 case IHS: s = "Super-commander"; break;
534 case IHSTAR: s = "Star"; break;
535 case IHP: s = "Planet"; break;
536 case IHB: s = "Starbase"; break;
537 case IHBLANK: s = "Black hole"; break;
538 case IHT: s = "Tholian"; break;
539 case IHWEB: s = "Tholian web"; break;
540 case IHQUEST: s = "Stranger"; break;
541 default: s = "Unknown??"; break;
546 char *cramlc(enum loctype key, int x, int y) {
549 if (key == quadrant) strcpy(buf, "Quadrant ");
550 else if (key == sector) strcpy(buf, "Sector ");
551 sprintf(buf+strlen(buf), "%d - %d", x, y);
555 void crmena(int i, int enemy, int key, int x, int y) {
556 if (i == 1) proutn("***");
559 proutn(cramlc(key, x, y));
565 case IHE: s = "Enterprise"; break;
566 case IHF: s = "Faerie Queene"; break;
567 default: s = "Ship???"; break;
573 prouts("******************************************************");
577 double expran(double avrage) {
578 return -avrage*log(1e-7 + Rand());
582 return rand()/(1.0 + (double)RAND_MAX);
585 void iran8(int *i, int *j) {
586 *i = Rand()*8.0 + 1.0;
587 *j = Rand()*8.0 + 1.0;
590 void iran10(int *i, int *j) {
591 *i = Rand()*10.0 + 1.0;
592 *j = Rand()*10.0 + 1.0;
601 /* return IHEOL next time */
614 // Read a line if nothing here
620 cgetline(line, sizeof(line));
622 if (curwnd==BOTTOM_WINDOW){
624 setwnd(LOWER_WINDOW);
629 // Skip leading white space
630 while (*linep == ' ') linep++;
636 if (isdigit(*linep) || *linep=='+' || *linep=='-' || *linep=='.') {
639 if (sscanf(linep, "%lf%n", &aaitem, &i) < 1) {
640 linep = line; // Invalid numbers are ignored
652 while (*linep && *linep!=' ') {
653 if ((cp - citem) < 9) *cp++ = tolower(*linep);
665 if (*citem == 'y') return TRUE;
666 if (*citem == 'n') return FALSE;
667 proutn("Please answer with \"Y\" or \"N\": ");
674 prout("Beg your pardon, Captain?");
678 /* New function -- compares s to scaned citem and returns true if it
679 matches to the length of s */
681 return strncasecmp(s, citem, max(1, strlen(citem))) == 0;
687 proutn("Reset levels? ");
689 if (energy < inenrg) energy = inenrg;
694 proutn("Reset damage? ");
697 for (i=0; i <= NDEVICES; i++) if (damage[i] > 0.0) damage[i] = 0.0;
700 proutn("Toggle idebug? ");
703 if (idebug) prout("Debug output ON");
704 else prout("Debug output OFF");
706 proutn("Cause selective damage? ");
709 for (i=1; i <= NDEVICES; i++) {
715 if (key == IHALPHA && isit("y")) {
717 if (i == DRADIO) stdamtim = game.state.date;
721 proutn("Examine/change events? ");
724 for (i = 1; i < NEVENTS; i++) {
726 if (future[i] == 1e30) continue;
728 case FSNOVA: proutn("Supernova "); break;
729 case FTBEAM: proutn("T Beam "); break;
730 case FSNAP: proutn("Snapshot "); break;
731 case FBATTAK: proutn("Base Attack "); break;
732 case FCDBAS: proutn("Base Destroy "); break;
733 case FSCMOVE: proutn("SC Move "); break;
734 case FSCDBAS: proutn("SC Base Destroy "); break;
736 proutn("%.2f", future[i]-game.state.date);
741 future[i] = game.state.date + aaitem;