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},
177 #define NUMCOMMANDS sizeof(commands)/sizeof(commands[0])
179 static void listCommands(int x) {
181 prout("LEGAL COMMANDS ARE:");
182 for (i = 0; i < NUMCOMMANDS; i++) {
183 proutn("%-12s ", commands[i].name);
190 static void helpme(void) {
192 char cmdbuf[32], *cp;
195 /* Give help on commands */
200 setwnd(BOTTOM_WINDOW);
201 proutn("Help on what command? ");
204 setwnd(LOWER_WINDOW);
205 if (key == IHEOL) return;
206 for (i = 0; i < NUMCOMMANDS; i++) {
207 if (strcasecmp(commands[i].name, citem)==0) {
208 i = commands[i].value;
212 if (i != NUMCOMMANDS) break;
214 prout("Valid commands:");
221 strcpy(cmdbuf, " ABBREV");
224 for (j = 0; commands[i].name[j]; j++)
225 cmdbuf[j] = toupper(commands[i].name[j]);
228 fp = fopen(SSTDOC, "r");
230 prout("Spock- \"Captain, that information is missing from the");
231 prout(" computer.\"");
233 * This used to continue: "You need to find SST.DOC and put
234 * it in the current directory."
239 if (fgets(linebuf, sizeof(linebuf), fp) == NULL) {
240 prout("Spock- \"Captain, there is no information on that command.\"");
244 if (linebuf[0] == '%' && linebuf[1] == '%'&& linebuf[2] == ' ') {
245 for (cp = linebuf+3; isspace(*cp); cp++)
247 linebuf[strlen(linebuf)-1] = '\0';
248 if (strcasecmp(cp, cmdbuf) == 0)
254 prout("Spock- \"Captain, I've found the following information:\"");
257 while (fgets(linebuf, sizeof(linebuf),fp)) {
258 if (strstr(linebuf, "******"))
265 void enqueue(char *s) {
269 static void makemoves(void) {
272 setwnd(LOWER_WINDOW);
273 while (TRUE) { /* command loop */
275 while (TRUE) { /* get a command */
281 setwnd(BOTTOM_WINDOW);
284 if (scan() == IHEOL) {
290 setwnd(LOWER_WINDOW);
292 for (i=0; i < ABANDON; i++)
293 if (isit(commands[i].name)) {
294 i = commands[i].value;
297 if (i < ABANDON) break;
298 for (; i < NUMCOMMANDS; i++)
299 if (strcasecmp(commands[i].name, citem) == 0) {
300 i = commands[i].value;
303 if (i < NUMCOMMANDS) break;
307 commandhook(commands[i].name, TRUE);
308 switch (i) { /* command switch */
309 case SRSCAN: // srscan
312 case LRSCAN: // lrscan
315 case PHASERS: // phasers
317 if (ididit) hitme = TRUE;
319 case TORPEDO: // photons
321 if (ididit) hitme = TRUE;
326 case SHIELDS: // shields
335 if (ididit) attack(0);
337 case DAMAGES: // damages
343 case IMPULSE: // impulse
348 if (ididit) hitme = TRUE;
356 case SENSORS: // sensors
361 if (ididit) hitme = TRUE;
363 case TRANSPORT: // transport "beam"
368 if (ididit) hitme = TRUE;
370 case CRYSTALS: // crystals
372 if (ididit) hitme = TRUE;
374 case SHUTTLE: // shuttle
376 if (ididit) hitme = TRUE;
378 case PLANETS: // Planet list
381 case REPORT: // Game Report
384 case COMPUTER: // use COMPUTER!
390 case EMEXIT: // Emergency exit
391 clrscr(); // Hide screen
392 freeze(TRUE); // forced save
393 exit(1); // And quick exit
396 probe(); // Launch probe
397 if (ididit) hitme = TRUE;
399 case ABANDON: // Abandon Ship
402 case DESTRUCT: // Self Destruct
405 case SAVE: // Save Game
409 prout("WARNING--Saved games produce no plaques!");
411 case DEATHRAY: // Try a desparation measure
413 if (ididit) hitme = TRUE;
415 case DEBUGCMD: // What do we want for debug???
420 case MAYDAY: // Call for help
422 if (ididit) hitme = TRUE;
425 alldone = 1; // quit the game
431 helpme(); // get help
434 commandhook(commands[i].name, FALSE);
436 if (alldone) break; // Game has ended
438 if (idebug) prout("2500");
442 if (alldone) break; // Events did us in
444 if (game.state.galaxy[quadx][quady] == 1000) { // Galaxy went Nova!
448 if (hitme && justin==0) {
451 if (game.state.galaxy[quadx][quady] == 1000) { // went NOVA!
464 int main(int argc, char **argv) {
465 int i, option, usecurses = TRUE;
467 while ((option = getopt(argc, argv, "t")) != -1) {
473 fprintf(stderr, "usage: sst [-t] [startcommand...].\n");
482 for (i = optind; i < argc; i++) {
483 strcat(line, argv[i]);
486 while (TRUE) { /* Play a game */
488 setup(line[0] == '\0');
498 if (tourn && alldone) {
499 proutn("Do you want your score recorded?");
505 proutn("Do you want to play again? ");
507 setwnd(FULLSCREEN_WINDOW);
512 prout("May the Great Bird of the Galaxy roost upon your home planet.");
518 /* return an enemy */
522 case IHR: s = "Romulan"; break;
523 case IHK: s = "Klingon"; break;
524 case IHC: s = "Commander"; break;
525 case IHS: s = "Super-commander"; break;
526 case IHSTAR: s = "Star"; break;
527 case IHP: s = "Planet"; break;
528 case IHB: s = "Starbase"; break;
529 case IHBLANK: s = "Black hole"; break;
530 case IHT: s = "Tholian"; break;
531 case IHWEB: s = "Tholian web"; break;
532 case IHQUEST: s = "Stranger"; break;
533 default: s = "Unknown??"; break;
538 char *cramlc(enum loctype key, int x, int y) {
541 if (key == quadrant) strcpy(buf, "Quadrant ");
542 else if (key == sector) strcpy(buf, "Sector ");
543 sprintf(buf+strlen(buf), "%d - %d", x, y);
547 void crmena(int i, int enemy, int key, int x, int y) {
548 if (i == 1) proutn("***");
551 proutn(cramlc(key, x, y));
557 case IHE: s = "Enterprise"; break;
558 case IHF: s = "Faerie Queene"; break;
559 default: s = "Ship???"; break;
565 prouts("******************************************************");
569 double expran(double avrage) {
570 return -avrage*log(1e-7 + Rand());
574 return rand()/(1.0 + (double)RAND_MAX);
577 void iran8(int *i, int *j) {
578 *i = Rand()*8.0 + 1.0;
579 *j = Rand()*8.0 + 1.0;
582 void iran10(int *i, int *j) {
583 *i = Rand()*10.0 + 1.0;
584 *j = Rand()*10.0 + 1.0;
593 /* return IHEOL next time */
606 // Read a line if nothing here
612 cgetline(line, sizeof(line));
614 if (curwnd==BOTTOM_WINDOW){
616 setwnd(LOWER_WINDOW);
621 // Skip leading white space
622 while (*linep == ' ') linep++;
628 if (isdigit(*linep) || *linep=='+' || *linep=='-' || *linep=='.') {
631 if (sscanf(linep, "%lf%n", &aaitem, &i) < 1) {
632 linep = line; // Invalid numbers are ignored
644 while (*linep && *linep!=' ') {
645 if ((cp - citem) < 9) *cp++ = tolower(*linep);
657 if (*citem == 'y') return TRUE;
658 if (*citem == 'n') return FALSE;
659 proutn("Please answer with \"Y\" or \"N\": ");
666 prout("Beg your pardon, Captain?");
670 /* New function -- compares s to scaned citem and returns true if it
671 matches to the length of s */
673 return strncasecmp(s, citem, max(1, strlen(citem))) == 0;
679 proutn("Reset levels? ");
681 if (energy < inenrg) energy = inenrg;
686 proutn("Reset damage? ");
689 for (i=0; i <= NDEVICES; i++) if (damage[i] > 0.0) damage[i] = 0.0;
692 proutn("Toggle idebug? ");
695 if (idebug) prout("Debug output ON");
696 else prout("Debug output OFF");
698 proutn("Cause selective damage? ");
701 for (i=1; i <= NDEVICES; i++) {
707 if (key == IHALPHA && isit("y")) {
709 if (i == DRADIO) stdamtim = game.state.date;
713 proutn("Examine/change events? ");
716 for (i = 1; i < NEVENTS; i++) {
718 if (future[i] == 1e30) continue;
720 case FSNOVA: proutn("Supernova "); break;
721 case FTBEAM: proutn("T Beam "); break;
722 case FSNAP: proutn("Snapshot "); break;
723 case FBATTAK: proutn("Base Attack "); break;
724 case FCDBAS: proutn("Base Destroy "); break;
725 case FSCMOVE: proutn("SC Move "); break;
726 case FSCDBAS: proutn("SC Base Destroy "); break;
728 proutn("%.2f", future[i]-game.state.date);
733 future[i] = game.state.date + aaitem;