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 void drawmaps(short l) {
268 /* hook to be called after moving to redraw maps */
270 _setcursortype(_NOCURSOR);
272 if (l!=2) setwnd(LEFTUPPER_WINDOW);
277 setwnd(SRSCAN_WINDOW);
280 setwnd(LRSCAN_WINDOW);
284 _setcursortype(_NORMALCURSOR);
289 static void makemoves(void) {
292 setwnd(LOWER_WINDOW);
293 while (TRUE) { /* command loop */
295 while (TRUE) { /* get a command */
301 setwnd(BOTTOM_WINDOW);
304 if (scan() == IHEOL) {
306 _setcursortype(_NOCURSOR);
307 setwnd(LOWER_WINDOW);
310 _setcursortype(_NORMALCURSOR);
316 setwnd(LOWER_WINDOW);
318 for (i=0; i < ABANDON; i++)
319 if (isit(commands[i].name)) {
320 i = commands[i].value;
323 if (i < ABANDON) break;
324 for (; i < NUMCOMMANDS; i++)
325 if (strcasecmp(commands[i].name, citem) == 0) {
326 i = commands[i].value;
329 if (i < NUMCOMMANDS) break;
333 commandhook(commands[i].name, TRUE);
334 switch (i) { /* command switch */
336 case SRSCAN: // srscan
339 case LRSCAN: // lrscan
343 case PHASERS: // phasers
345 if (ididit) hitme = TRUE;
347 case TORPEDO: // photons
349 if (ididit) hitme = TRUE;
354 case SHIELDS: // shields
363 if (ididit) attack(0);
365 case DAMAGES: // damages
371 case IMPULSE: // impulse
376 if (ididit) hitme = TRUE;
385 case SENSORS: // sensors
391 if (ididit) hitme = TRUE;
393 case TRANSPORT: // transport "beam"
398 if (ididit) hitme = TRUE;
400 case CRYSTALS: // crystals
402 if (ididit) hitme = TRUE;
404 case SHUTTLE: // shuttle
406 if (ididit) hitme = TRUE;
408 case PLANETS: // Planet list
411 case REPORT: // Game Report
414 case COMPUTER: // use COMPUTER!
420 case EMEXIT: // Emergency exit
421 clrscr(); // Hide screen
422 freeze(TRUE); // forced save
423 exit(1); // And quick exit
426 probe(); // Launch probe
427 if (ididit) hitme = TRUE;
429 case ABANDON: // Abandon Ship
432 case DESTRUCT: // Self Destruct
435 case SAVE: // Save Game
439 prout("WARNING--Saved games produce no plaques!");
441 case DEATHRAY: // Try a desparation measure
443 if (ididit) hitme = TRUE;
445 case DEBUGCMD: // What do we want for debug???
450 case MAYDAY: // Call for help
452 if (ididit) hitme = TRUE;
455 alldone = 1; // quit the game
461 helpme(); // get help
464 commandhook(commands[i].name, FALSE);
466 if (alldone) break; // Game has ended
468 if (idebug) prout("2500");
472 if (alldone) break; // Events did us in
474 if (game.state.galaxy[quadx][quady] == 1000) { // Galaxy went Nova!
478 if (hitme && justin==0) {
481 if (game.state.galaxy[quadx][quady] == 1000) { // went NOVA!
494 int main(int argc, char **argv) {
495 int i, option, usecurses = TRUE;
497 while ((option = getopt(argc, argv, "t")) != -1) {
503 fprintf(stderr, "usage: sst [-t] [startcommand...].\n");
514 setwnd(FULLSCREEN_WINDOW);
517 for (i = optind; i < argc; i++) {
518 strcat(line, argv[i]);
521 while (TRUE) { /* Play a game */
523 setup(line[0] == '\0');
533 if (tourn && alldone) {
534 proutn("Do you want your score recorded?");
540 proutn("Do you want to play again? ");
542 setwnd(FULLSCREEN_WINDOW);
549 prout("May the Great Bird of the Galaxy roost upon your home planet.");
555 /* return an enemy */
559 case IHR: s = "Romulan"; break;
560 case IHK: s = "Klingon"; break;
561 case IHC: s = "Commander"; break;
562 case IHS: s = "Super-commander"; break;
563 case IHSTAR: s = "Star"; break;
564 case IHP: s = "Planet"; break;
565 case IHB: s = "Starbase"; break;
566 case IHBLANK: s = "Black hole"; break;
567 case IHT: s = "Tholian"; break;
568 case IHWEB: s = "Tholian web"; break;
569 case IHQUEST: s = "Stranger"; break;
570 default: s = "Unknown??"; break;
575 char *cramlc(enum loctype key, int x, int y) {
578 if (key == quadrant) strcpy(buf, "Quadrant ");
579 else if (key == sector) strcpy(buf, "Sector ");
580 sprintf(buf+strlen(buf), "%d - %d", x, y);
584 void crmena(int i, int enemy, int key, int x, int y) {
585 if (i == 1) proutn("***");
588 proutn(cramlc(key, x, y));
594 case IHE: s = "Enterprise"; break;
595 case IHF: s = "Faerie Queene"; break;
596 default: s = "Ship???"; break;
602 prouts("******************************************************");
606 double expran(double avrage) {
607 return -avrage*log(1e-7 + Rand());
611 return rand()/(1.0 + (double)RAND_MAX);
614 void iran8(int *i, int *j) {
615 *i = Rand()*8.0 + 1.0;
616 *j = Rand()*8.0 + 1.0;
619 void iran10(int *i, int *j) {
620 *i = Rand()*10.0 + 1.0;
621 *j = Rand()*10.0 + 1.0;
630 /* return IHEOL next time */
643 // Read a line if nothing here
649 cgetline(line, sizeof(line));
652 if (curwnd==BOTTOM_WINDOW){
654 setwnd(LOWER_WINDOW);
660 // Skip leading white space
661 while (*linep == ' ') linep++;
667 if (isdigit(*linep) || *linep=='+' || *linep=='-' || *linep=='.') {
670 if (sscanf(linep, "%lf%n", &aaitem, &i) < 1) {
671 linep = line; // Invalid numbers are ignored
683 while (*linep && *linep!=' ') {
684 if ((cp - citem) < 9) *cp++ = tolower(*linep);
696 if (*citem == 'y') return TRUE;
697 if (*citem == 'n') return FALSE;
698 proutn("Please answer with \"Y\" or \"N\": ");
705 prout("Beg your pardon, Captain?");
709 /* New function -- compares s to scaned citem and returns true if it
710 matches to the length of s */
712 return strncasecmp(s, citem, max(1, strlen(citem))) == 0;
718 proutn("Reset levels? ");
720 if (energy < inenrg) energy = inenrg;
725 proutn("Reset damage? ");
728 for (i=0; i <= NDEVICES; i++) if (damage[i] > 0.0) damage[i] = 0.0;
731 proutn("Toggle idebug? ");
734 if (idebug) prout("Debug output ON");
735 else prout("Debug output OFF");
737 proutn("Cause selective damage? ");
740 for (i=1; i <= NDEVICES; i++) {
746 if (key == IHALPHA && isit("y")) {
748 if (i == DRADIO) stdamtim = game.state.date;
752 proutn("Examine/change events? ");
755 for (i = 1; i < NEVENTS; i++) {
757 if (future[i] == 1e30) continue;
759 case FSNOVA: proutn("Supernova "); break;
760 case FTBEAM: proutn("T Beam "); break;
761 case FSNAP: proutn("Snapshot "); break;
762 case FBATTAK: proutn("Base Attack "); break;
763 case FCDBAS: proutn("Base Destroy "); break;
764 case FSCMOVE: proutn("SC Move "); break;
765 case FSCDBAS: proutn("SC Base Destroy "); break;
767 proutn("%.2f", future[i]-game.state.date);
772 future[i] = game.state.date + aaitem;