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},
150 {"REQUEST", REQUEST},
155 {"COMPUTER", COMPUTER},
157 {"COMMANDS", COMMANDS},
166 {"ABANDON", ABANDON},
168 {"DESTRUCT", DESTRUCT},
170 {"DEATHRAY", DEATHRAY},
184 wnd wnds[6]={{1,1,80,25},{1,1,25,12},{26,2,80,12},{65,1,80,10},{1,13,80,23},{1,24,80,25}};
188 #define NUMCOMMANDS sizeof(commands)/sizeof(commands[0])
190 static void listCommands(int x) {
192 prout("LEGAL COMMANDS ARE:");
193 for (i = 0; i < NUMCOMMANDS; i++) {
194 proutn("%-12s ", commands[i].name);
201 static void helpme(void) {
203 char cmdbuf[32], *cp;
206 /* Give help on commands */
214 proutn("Help on what command? ");
220 if (key == IHEOL) return;
221 for (i = 0; i < NUMCOMMANDS; i++) {
222 if (strcasecmp(commands[i].name, citem)==0) {
223 i = commands[i].value;
227 if (i != NUMCOMMANDS) break;
229 prout("Valid commands:");
236 strcpy(cmdbuf, " ABBREV");
239 for (j = 0; commands[i].name[j]; j++)
240 cmdbuf[j] = toupper(commands[i].name[j]);
243 fp = fopen(SSTDOC, "r");
245 prout("Spock- \"Captain, that information is missing from the");
246 prout(" computer.\"");
248 * This used to continue: "You need to find SST.DOC and put
249 * it in the current directory."
254 if (fgets(linebuf, sizeof(linebuf), fp) == NULL) {
255 prout("Spock- \"Captain, there is no information on that command.\"");
259 if (linebuf[0] == '%' && linebuf[1] == '%'&& linebuf[2] == ' ') {
260 for (cp = linebuf+3; isspace(*cp); cp++)
262 linebuf[strlen(linebuf)-1] = '\0';
263 if (strcasecmp(cp, cmdbuf) == 0)
269 prout("Spock- \"Captain, I've found the following information:\"");
272 while (fgets(linebuf, sizeof(linebuf),fp)) {
273 if (strstr(linebuf, "******"))
280 void drawmaps(short l) {
281 /* hook to be called after moving to redraw maps */
283 _setcursortype(_NOCURSOR);
297 _setcursortype(_NORMALCURSOR);
302 static void makemoves(void) {
308 while (TRUE) { /* command loop */
310 while (TRUE) { /* get a command */
321 if (scan() == IHEOL) {
323 _setcursortype(_NOCURSOR);
327 _setcursortype(_NORMALCURSOR);
337 for (i=0; i < ABANDON; i++)
338 if (isit(commands[i].name)) {
339 i = commands[i].value;
342 if (i < ABANDON) break;
343 for (; i < NUMCOMMANDS; i++)
344 if (strcasecmp(commands[i].name, citem) == 0) {
345 i = commands[i].value;
348 if (i < NUMCOMMANDS) break;
352 commandhook(commands[i].name, TRUE);
353 switch (i) { /* command switch */
355 case SRSCAN: // srscan
358 case LRSCAN: // lrscan
362 case PHASERS: // phasers
364 if (ididit) hitme = TRUE;
366 case TORPEDO: // photons
368 if (ididit) hitme = TRUE;
373 case SHIELDS: // shields
382 if (ididit) attack(0);
384 case DAMAGES: // damages
390 case IMPULSE: // impulse
395 if (ididit) hitme = TRUE;
404 case SENSORS: // sensors
410 if (ididit) hitme = TRUE;
412 case TRANSPORT: // transport "beam"
417 if (ididit) hitme = TRUE;
419 case CRYSTALS: // crystals
421 if (ididit) hitme = TRUE;
423 case SHUTTLE: // shuttle
425 if (ididit) hitme = TRUE;
427 case PLANETS: // Planet list
430 case REPORT: // Game Report
433 case COMPUTER: // use COMPUTER!
439 case EMEXIT: // Emergency exit
440 clrscr(); // Hide screen
441 freeze(TRUE); // forced save
442 exit(1); // And quick exit
445 probe(); // Launch probe
446 if (ididit) hitme = TRUE;
448 case ABANDON: // Abandon Ship
451 case DESTRUCT: // Self Destruct
454 case SAVE: // Save Game
460 prout("WARNING--Saved games produce no plaques!");
462 case DEATHRAY: // Try a desparation measure
464 if (ididit) hitme = TRUE;
466 case DEBUGCMD: // What do we want for debug???
471 case MAYDAY: // Call for help
473 if (ididit) hitme = TRUE;
476 alldone = 1; // quit the game
482 helpme(); // get help
485 commandhook(commands[i].name, FALSE);
487 if (alldone) break; // Game has ended
489 if (idebug) prout("2500");
493 if (alldone) break; // Events did us in
495 if (game.state.galaxy[quadx][quady] == 1000) { // Galaxy went Nova!
499 if (hitme && justin==0) {
502 if (game.state.galaxy[quadx][quady] == 1000) { // went NOVA!
515 int main(int argc, char **argv) {
516 int i, option, usecurses = TRUE;
518 while ((option = getopt(argc, argv, "t")) != -1) {
524 fprintf(stderr, "usage: sst [-t] [startcommand...].\n");
538 for (i = optind; i < argc; i++) {
539 strcat(line, argv[i]);
542 while (TRUE) { /* Play a game */
544 setup(line[0] == '\0');
554 if (tourn && alldone) {
555 proutn("Do you want your score recorded?");
561 proutn("Do you want to play again? ");
572 prout("May the Great Bird of the Galaxy roost upon your home planet.");
578 /* return an enemy */
582 case IHR: s = "Romulan"; break;
583 case IHK: s = "Klingon"; break;
584 case IHC: s = "Commander"; break;
585 case IHS: s = "Super-commander"; break;
586 case IHSTAR: s = "Star"; break;
587 case IHP: s = "Planet"; break;
588 case IHB: s = "Starbase"; break;
589 case IHBLANK: s = "Black hole"; break;
590 case IHT: s = "Tholian"; break;
591 case IHWEB: s = "Tholian web"; break;
592 case IHQUEST: s = "Stranger"; break;
593 default: s = "Unknown??"; break;
598 char *cramlc(enum loctype key, int x, int y) {
601 if (key == quadrant) strcpy(buf, "Quadrant ");
602 else if (key == sector) strcpy(buf, "Sector ");
603 sprintf(buf+strlen(buf), "%d - %d", x, y);
607 void crmena(int i, int enemy, int key, int x, int y) {
608 if (i == 1) proutn("***");
611 proutn(cramlc(key, x, y));
617 case IHE: s = "Enterprise"; break;
618 case IHF: s = "Faerie Queene"; break;
619 default: s = "Ship???"; break;
625 prouts("******************************************************");
629 double expran(double avrage) {
630 return -avrage*log(1e-7 + Rand());
634 return rand()/(1.0 + (double)RAND_MAX);
637 void iran8(int *i, int *j) {
638 *i = Rand()*8.0 + 1.0;
639 *j = Rand()*8.0 + 1.0;
642 void iran10(int *i, int *j) {
643 *i = Rand()*10.0 + 1.0;
644 *j = Rand()*10.0 + 1.0;
653 /* return IHEOL next time */
666 // Read a line if nothing here
672 getline(line, sizeof(line));
683 // Skip leading white space
684 while (*linep == ' ') linep++;
690 if (isdigit(*linep) || *linep=='+' || *linep=='-' || *linep=='.') {
693 if (sscanf(linep, "%lf%n", &aaitem, &i) < 1) {
694 linep = line; // Invalid numbers are ignored
706 while (*linep && *linep!=' ') {
707 if ((cp - citem) < 9) *cp++ = tolower(*linep);
719 if (*citem == 'y') return TRUE;
720 if (*citem == 'n') return FALSE;
721 proutn("Please answer with \"Y\" or \"N\": ");
728 prout("Beg your pardon, Captain?");
732 /* New function -- compares s to scaned citem and returns true if it
733 matches to the length of s */
735 return strncasecmp(s, citem, max(1, strlen(citem))) == 0;
741 proutn("Reset levels? ");
743 if (energy < inenrg) energy = inenrg;
748 proutn("Reset damage? ");
751 for (i=0; i <= NDEVICES; i++) if (damage[i] > 0.0) damage[i] = 0.0;
754 proutn("Toggle idebug? ");
757 if (idebug) prout("Debug output ON");
758 else prout("Debug output OFF");
760 proutn("Cause selective damage? ");
763 for (i=1; i <= NDEVICES; i++) {
769 if (key == IHALPHA && isit("y")) {
771 if (i == DRADIO) stdamtim = game.state.date;
775 proutn("Examine/change events? ");
778 for (i = 1; i < NEVENTS; i++) {
780 if (future[i] == 1e30) continue;
782 case FSNOVA: proutn("Supernova "); break;
783 case FTBEAM: proutn("T Beam "); break;
784 case FSNAP: proutn("Snapshot "); break;
785 case FBATTAK: proutn("Base Attack "); break;
786 case FCDBAS: proutn("Base Destroy "); break;
787 case FSCMOVE: proutn("SC Move "); break;
788 case FSCDBAS: proutn("SC Base Destroy "); break;
790 proutn("%.2f", future[i]-game.state.date);
795 future[i] = game.state.date + aaitem;