1 #define INCLUDED // Define externs here
10 #define SSTDOC "sst.doc"
15 Here are Tom Almy's changes:
17 Compared to original version, I've changed the "help" command to
18 "call" and the "terminate" command to "quit" to better match
19 user expectations. The DECUS version apparently made those changes
20 as well as changing "freeze" to "save". However I like "freeze".
22 When I got a later version of Super Star Trek that I was converting
23 from, I added the emexit command.
25 That later version also mentions srscan and lrscan working when
26 docked (using the starbase's scanners), so I made some changes here
27 to do this (and indicating that fact to the player), and then realized
28 the base would have a subspace radio as well -- doing a Chart when docked
29 updates the star chart, and all radio reports will be heard. The Dock
30 command will also give a report if a base is under attack.
32 Movecom no longer reports movement if sensors are damaged so you wouldn't
37 1. Better base positioning at startup
39 2. Deathray improvement (but keeping original failure alternatives)
43 4. Enemies can ram the Enterprise. Regular Klingons and Romulans can
44 move in Expert and Emeritus games. This code could use improvement.
46 5. The deep space probe looks interesting! DECUS version
48 6. Perhaps cloaking to be added later? BSD version
50 Here are Stas Sergeev's changes:
52 1. The Space Thingy can be shoved, if you it ram, and can fire back if
55 2. The Tholian can be hit with phasers
57 3. When you are docked, base covers you with an almost invincible shields
58 (a commander can still ram you, or a Romulan can destroy the base,
59 or a SCom can even succeed with direct attack IIRC, but this rarely
62 4. SCom can't escape from you if no more enemies remain (without this,
63 chasing SCom can take an eternity).
65 5. Probe target you enter is now the destination quadrant. Before I don't
66 remember what it was, but it was something I had difficulty using)
68 6. Secret password is now autogenerated.
70 7. "Plaque" is adjusted for A4 paper :-)
72 8. Phasers now tells you how much energy needed, but only if the computer
75 9. Planets are auto-scanned when you enter the quadrant.
77 10. Mining or using crystals in presense of enemy now yields an attack.
78 There are other minor adjustments to what yields an attack
81 11. Ramming a black hole is no longer instant death. There is a
82 chance you might get timewarped instead.
84 12. "freeze" command reverts to "save", most people will understand this
87 13. Screen-oriented interface, with sensor scans always up.
89 Eric Raymond's changes:
91 1. "sos" and "call" becomes "mayday", "freeze" and "save" are both good.
96 static char line[128], *linep = line;
110 {"PHASERS", PHASERS},
112 {"TORPEDO", TORPEDO},
113 {"PHOTONS", TORPEDO},
117 {"SHIELDS", SHIELDS},
121 {"DAMAGES", DAMAGES},
125 {"IMPULSE", IMPULSE},
133 {"SENSORS", SENSORS},
137 {"TRANSPORT", TRANSPORT},
141 {"CRYSTALS", CRYSTALS},
143 {"SHUTTLE", SHUTTLE},
145 {"PLANETS", PLANETS},
149 {"COMPUTER", COMPUTER},
151 {"COMMANDS", COMMANDS},
160 {"ABANDON", ABANDON},
162 {"DESTRUCT", DESTRUCT},
164 {"DEATHRAY", DEATHRAY},
176 {"REQUEST", REQUEST},
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 void enqueue(char *s) {
271 static void makemoves(void) {
274 setwnd(LOWER_WINDOW);
275 while (TRUE) { /* command loop */
277 while (TRUE) { /* get a command */
283 setwnd(BOTTOM_WINDOW);
286 if (scan() == IHEOL) {
292 setwnd(LOWER_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 LRSCAN: // lrscan
317 case PHASERS: // phasers
319 if (ididit) hitme = TRUE;
321 case TORPEDO: // photons
323 if (ididit) hitme = TRUE;
328 case SHIELDS: // shields
337 if (ididit) attack(0);
339 case DAMAGES: // damages
345 case IMPULSE: // impulse
350 if (ididit) hitme = TRUE;
358 case SENSORS: // sensors
363 if (ididit) hitme = TRUE;
365 case TRANSPORT: // transport "beam"
370 if (ididit) hitme = TRUE;
372 case CRYSTALS: // crystals
374 if (ididit) hitme = TRUE;
376 case SHUTTLE: // shuttle
378 if (ididit) hitme = TRUE;
380 case PLANETS: // Planet list
383 case REPORT: // Game Report
386 case REQUEST: // status request
387 srscan(SCAN_REQUEST);
389 case COMPUTER: // use COMPUTER!
395 case EMEXIT: // Emergency exit
396 clrscr(); // Hide screen
397 freeze(TRUE); // forced save
398 exit(1); // And quick exit
401 probe(); // Launch probe
402 if (ididit) hitme = TRUE;
404 case ABANDON: // Abandon Ship
407 case DESTRUCT: // Self Destruct
410 case SAVE: // Save Game
414 prout("WARNING--Saved games produce no plaques!");
416 case DEATHRAY: // Try a desparation measure
418 if (ididit) hitme = TRUE;
420 case DEBUGCMD: // What do we want for debug???
425 case MAYDAY: // Call for help
427 if (ididit) hitme = TRUE;
430 alldone = 1; // quit the game
436 helpme(); // get help
439 commandhook(commands[i].name, FALSE);
441 if (alldone) break; // Game has ended
443 if (idebug) prout("2500");
447 if (alldone) break; // Events did us in
449 if (game.state.galaxy[quadx][quady] == 1000) { // Galaxy went Nova!
453 if (hitme && justin==0) {
456 if (game.state.galaxy[quadx][quady] == 1000) { // went NOVA!
469 int main(int argc, char **argv) {
470 int i, option, usecurses = TRUE;
472 while ((option = getopt(argc, argv, "t")) != -1) {
478 fprintf(stderr, "usage: sst [-t] [startcommand...].\n");
487 for (i = optind; i < argc; i++) {
488 strcat(line, argv[i]);
491 while (TRUE) { /* Play a game */
493 setup(line[0] == '\0');
503 if (tourn && alldone) {
504 proutn("Do you want your score recorded?");
510 proutn("Do you want to play again? ");
512 setwnd(FULLSCREEN_WINDOW);
517 prout("May the Great Bird of the Galaxy roost upon your home planet.");
523 /* return an enemy */
527 case IHR: s = "Romulan"; break;
528 case IHK: s = "Klingon"; break;
529 case IHC: s = "Commander"; break;
530 case IHS: s = "Super-commander"; break;
531 case IHSTAR: s = "Star"; break;
532 case IHP: s = "Planet"; break;
533 case IHB: s = "Starbase"; break;
534 case IHBLANK: s = "Black hole"; break;
535 case IHT: s = "Tholian"; break;
536 case IHWEB: s = "Tholian web"; break;
537 case IHQUEST: s = "Stranger"; break;
538 default: s = "Unknown??"; break;
543 char *cramlc(enum loctype key, int x, int y) {
546 if (key == quadrant) strcpy(buf, "Quadrant ");
547 else if (key == sector) strcpy(buf, "Sector ");
548 sprintf(buf+strlen(buf), "%d - %d", x, y);
552 void crmena(int i, int enemy, int key, int x, int y) {
553 if (i == 1) proutn("***");
556 proutn(cramlc(key, x, y));
562 case IHE: s = "Enterprise"; break;
563 case IHF: s = "Faerie Queene"; break;
564 default: s = "Ship???"; break;
570 prouts("******************************************************");
574 double expran(double avrage) {
575 return -avrage*log(1e-7 + Rand());
579 return rand()/(1.0 + (double)RAND_MAX);
582 void iran8(int *i, int *j) {
583 *i = Rand()*8.0 + 1.0;
584 *j = Rand()*8.0 + 1.0;
587 void iran10(int *i, int *j) {
588 *i = Rand()*10.0 + 1.0;
589 *j = Rand()*10.0 + 1.0;
598 /* return IHEOL next time */
611 // Read a line if nothing here
617 cgetline(line, sizeof(line));
619 if (curwnd==BOTTOM_WINDOW){
621 setwnd(LOWER_WINDOW);
626 // Skip leading white space
627 while (*linep == ' ') linep++;
633 if (isdigit(*linep) || *linep=='+' || *linep=='-' || *linep=='.') {
636 if (sscanf(linep, "%lf%n", &aaitem, &i) < 1) {
637 linep = line; // Invalid numbers are ignored
649 while (*linep && *linep!=' ') {
650 if ((cp - citem) < 9) *cp++ = tolower(*linep);
662 if (*citem == 'y') return TRUE;
663 if (*citem == 'n') return FALSE;
664 proutn("Please answer with \"Y\" or \"N\": ");
671 prout("Beg your pardon, Captain?");
675 /* New function -- compares s to scaned citem and returns true if it
676 matches to the length of s */
678 return strncasecmp(s, citem, max(1, strlen(citem))) == 0;
684 proutn("Reset levels? ");
686 if (energy < inenrg) energy = inenrg;
691 proutn("Reset damage? ");
694 for (i=0; i <= NDEVICES; i++) if (damage[i] > 0.0) damage[i] = 0.0;
697 proutn("Toggle idebug? ");
700 if (idebug) prout("Debug output ON");
701 else prout("Debug output OFF");
703 proutn("Cause selective damage? ");
706 for (i=1; i <= NDEVICES; i++) {
712 if (key == IHALPHA && isit("y")) {
714 if (i == DRADIO) stdamtim = game.state.date;
718 proutn("Examine/change events? ");
721 for (i = 1; i < NEVENTS; i++) {
723 if (future[i] == 1e30) continue;
725 case FSNOVA: proutn("Supernova "); break;
726 case FTBEAM: proutn("T Beam "); break;
727 case FSNAP: proutn("Snapshot "); break;
728 case FBATTAK: proutn("Base Attack "); break;
729 case FCDBAS: proutn("Base Destroy "); break;
730 case FSCMOVE: proutn("SC Move "); break;
731 case FSCDBAS: proutn("SC Base Destroy "); break;
733 proutn("%.2f", future[i]-game.state.date);
738 future[i] = game.state.date + aaitem;