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;
109 {"REQUEST", REQUEST},
113 {"PHASERS", PHASERS},
115 {"TORPEDO", TORPEDO},
116 {"PHOTONS", TORPEDO},
120 {"SHIELDS", SHIELDS},
124 {"DAMAGES", DAMAGES},
128 {"IMPULSE", IMPULSE},
136 {"SENSORS", SENSORS},
140 {"TRANSPORT", TRANSPORT},
144 {"CRYSTALS", CRYSTALS},
146 {"SHUTTLE", SHUTTLE},
148 {"PLANETS", PLANETS},
152 {"COMPUTER", COMPUTER},
154 {"COMMANDS", COMMANDS},
163 {"ABANDON", ABANDON},
165 {"DESTRUCT", DESTRUCT},
167 {"DEATHRAY", DEATHRAY},
180 #define NUMCOMMANDS sizeof(commands)/sizeof(commands[0])
182 static void listCommands(int x) {
184 prout("LEGAL COMMANDS ARE:");
185 for (i = 0; i < NUMCOMMANDS; i++) {
186 proutn("%-12s ", commands[i].name);
193 static void helpme(void) {
195 char cmdbuf[32], *cp;
198 /* Give help on commands */
203 setwnd(BOTTOM_WINDOW);
204 proutn("Help on what command? ");
207 setwnd(LOWER_WINDOW);
208 if (key == IHEOL) return;
209 for (i = 0; i < NUMCOMMANDS; i++) {
210 if (strcasecmp(commands[i].name, citem)==0) {
211 i = commands[i].value;
215 if (i != NUMCOMMANDS) break;
217 prout("Valid commands:");
224 strcpy(cmdbuf, " ABBREV");
227 for (j = 0; commands[i].name[j]; j++)
228 cmdbuf[j] = toupper(commands[i].name[j]);
231 fp = fopen(SSTDOC, "r");
233 prout("Spock- \"Captain, that information is missing from the");
234 prout(" computer.\"");
236 * This used to continue: "You need to find SST.DOC and put
237 * it in the current directory."
242 if (fgets(linebuf, sizeof(linebuf), fp) == NULL) {
243 prout("Spock- \"Captain, there is no information on that command.\"");
247 if (linebuf[0] == '%' && linebuf[1] == '%'&& linebuf[2] == ' ') {
248 for (cp = linebuf+3; isspace(*cp); cp++)
250 linebuf[strlen(linebuf)-1] = '\0';
251 if (strcasecmp(cp, cmdbuf) == 0)
257 prout("Spock- \"Captain, I've found the following information:\"");
260 while (fgets(linebuf, sizeof(linebuf),fp)) {
261 if (strstr(linebuf, "******"))
268 void enqueue(char *s) {
272 static void makemoves(void) {
275 setwnd(LOWER_WINDOW);
276 while (TRUE) { /* command loop */
278 while (TRUE) { /* get a command */
284 setwnd(BOTTOM_WINDOW);
287 if (scan() == IHEOL) {
293 setwnd(LOWER_WINDOW);
295 for (i=0; i < ABANDON; i++)
296 if (isit(commands[i].name)) {
297 i = commands[i].value;
300 if (i < ABANDON) break;
301 for (; i < NUMCOMMANDS; i++)
302 if (strcasecmp(commands[i].name, citem) == 0) {
303 i = commands[i].value;
306 if (i < NUMCOMMANDS) break;
310 commandhook(commands[i].name, TRUE);
311 switch (i) { /* command switch */
312 case SRSCAN: // srscan
315 case STATUS: // status
318 case REQUEST: // status request
319 srscan(SCAN_REQUEST);
321 case LRSCAN: // lrscan
324 case PHASERS: // phasers
326 if (ididit) hitme = TRUE;
328 case TORPEDO: // photons
330 if (ididit) hitme = TRUE;
335 case SHIELDS: // shields
344 if (ididit) attack(0);
346 case DAMAGES: // damages
352 case IMPULSE: // impulse
357 if (ididit) hitme = TRUE;
365 case SENSORS: // sensors
370 if (ididit) hitme = TRUE;
372 case TRANSPORT: // transport "beam"
377 if (ididit) hitme = TRUE;
379 case CRYSTALS: // crystals
381 if (ididit) hitme = TRUE;
383 case SHUTTLE: // shuttle
385 if (ididit) hitme = TRUE;
387 case PLANETS: // Planet list
390 case REPORT: // Game Report
393 case COMPUTER: // use COMPUTER!
399 case EMEXIT: // Emergency exit
400 clrscr(); // Hide screen
401 freeze(TRUE); // forced save
402 exit(1); // And quick exit
405 probe(); // Launch probe
406 if (ididit) hitme = TRUE;
408 case ABANDON: // Abandon Ship
411 case DESTRUCT: // Self Destruct
414 case SAVE: // Save Game
418 prout("WARNING--Saved games produce no plaques!");
420 case DEATHRAY: // Try a desparation measure
422 if (ididit) hitme = TRUE;
424 case DEBUGCMD: // What do we want for debug???
429 case MAYDAY: // Call for help
431 if (ididit) hitme = TRUE;
434 alldone = 1; // quit the game
440 helpme(); // get help
443 commandhook(commands[i].name, FALSE);
445 if (alldone) break; // Game has ended
447 if (idebug) prout("2500");
451 if (alldone) break; // Events did us in
453 if (game.state.galaxy[quadx][quady] == 1000) { // Galaxy went Nova!
457 if (hitme && justin==0) {
460 if (game.state.galaxy[quadx][quady] == 1000) { // went NOVA!
473 int main(int argc, char **argv) {
474 int i, option, usecurses = TRUE;
476 while ((option = getopt(argc, argv, "t")) != -1) {
482 fprintf(stderr, "usage: sst [-t] [startcommand...].\n");
491 for (i = optind; i < argc; i++) {
492 strcat(line, argv[i]);
495 while (TRUE) { /* Play a game */
497 setup(line[0] == '\0');
507 if (tourn && alldone) {
508 proutn("Do you want your score recorded?");
514 proutn("Do you want to play again? ");
516 setwnd(FULLSCREEN_WINDOW);
521 prout("May the Great Bird of the Galaxy roost upon your home planet.");
527 /* return an enemy */
531 case IHR: s = "Romulan"; break;
532 case IHK: s = "Klingon"; break;
533 case IHC: s = "Commander"; break;
534 case IHS: s = "Super-commander"; break;
535 case IHSTAR: s = "Star"; break;
536 case IHP: s = "Planet"; break;
537 case IHB: s = "Starbase"; break;
538 case IHBLANK: s = "Black hole"; break;
539 case IHT: s = "Tholian"; break;
540 case IHWEB: s = "Tholian web"; break;
541 case IHQUEST: s = "Stranger"; break;
542 default: s = "Unknown??"; break;
547 char *cramlc(enum loctype key, int x, int y) {
550 if (key == quadrant) strcpy(buf, "Quadrant ");
551 else if (key == sector) strcpy(buf, "Sector ");
552 sprintf(buf+strlen(buf), "%d - %d", x, y);
556 void crmena(int i, int enemy, int key, int x, int y) {
557 if (i == 1) proutn("***");
560 proutn(cramlc(key, x, y));
566 case IHE: s = "Enterprise"; break;
567 case IHF: s = "Faerie Queene"; break;
568 default: s = "Ship???"; break;
574 prouts("******************************************************");
578 double expran(double avrage) {
579 return -avrage*log(1e-7 + Rand());
583 return rand()/(1.0 + (double)RAND_MAX);
586 void iran8(int *i, int *j) {
587 *i = Rand()*8.0 + 1.0;
588 *j = Rand()*8.0 + 1.0;
591 void iran10(int *i, int *j) {
592 *i = Rand()*10.0 + 1.0;
593 *j = Rand()*10.0 + 1.0;
602 /* return IHEOL next time */
615 // Read a line if nothing here
621 cgetline(line, sizeof(line));
623 if (curwnd==BOTTOM_WINDOW){
625 setwnd(LOWER_WINDOW);
630 // Skip leading white space
631 while (*linep == ' ') linep++;
637 if (isdigit(*linep) || *linep=='+' || *linep=='-' || *linep=='.') {
640 if (sscanf(linep, "%lf%n", &aaitem, &i) < 1) {
641 linep = line; // Invalid numbers are ignored
653 while (*linep && *linep!=' ') {
654 if ((cp - citem) < 9) *cp++ = tolower(*linep);
666 if (*citem == 'y') return TRUE;
667 if (*citem == 'n') return FALSE;
668 proutn("Please answer with \"Y\" or \"N\": ");
675 prout("Beg your pardon, Captain?");
679 /* New function -- compares s to scaned citem and returns true if it
680 matches to the length of s */
682 return strncasecmp(s, citem, max(1, strlen(citem))) == 0;
688 proutn("Reset levels? ");
690 if (energy < inenrg) energy = inenrg;
695 proutn("Reset damage? ");
698 for (i=0; i <= NDEVICES; i++) if (damage[i] > 0.0) damage[i] = 0.0;
701 proutn("Toggle idebug? ");
704 if (idebug) prout("Debug output ON");
705 else prout("Debug output OFF");
707 proutn("Cause selective damage? ");
710 for (i=1; i <= NDEVICES; i++) {
716 if (key == IHALPHA && isit("y")) {
718 if (i == DRADIO) stdamtim = game.state.date;
722 proutn("Examine/change events? ");
725 for (i = 1; i < NEVENTS; i++) {
727 if (future[i] == 1e30) continue;
729 case FSNOVA: proutn("Supernova "); break;
730 case FTBEAM: proutn("T Beam "); break;
731 case FSNAP: proutn("Snapshot "); break;
732 case FBATTAK: proutn("Base Attack "); break;
733 case FCDBAS: proutn("Base Destroy "); break;
734 case FSCMOVE: proutn("SC Move "); break;
735 case FSCDBAS: proutn("SC Base Destroy "); break;
737 proutn("%.2f", future[i]-game.state.date);
742 future[i] = game.state.date + aaitem;