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:
54 1. The Space Thingy can be shoved, if you it ram, and can fire back if
57 2. The Tholian can be hit with phasers
59 3. When you are docked, base covers you with an almost invincible shields
60 (a commander can still ram you, or a Romulan can destroy the base,
61 or a SCom can even succeed with direct attack IIRC, but this rarely
64 4. SCom can't escape from you if no more enemies remain (without this,
65 chasing SCom can take an eternity).
67 5. Probe target you enter is now the destination quadrant. Before I don't
68 remember what it was, but it was something I had difficulty using)
70 6. Secret password is now autogenerated.
72 7. "Plaque" is adjusted for A4 paper :-)
74 8. Phasers now tells you how much energy needed, but only if the computer
77 9. Planets are auto-scanned when you enter the quadrant.
79 10. Mining or using crystals in presense of enemy now yields an attack.
80 There are other minor adjustments to what yields an attack
83 11. Ramming a black hole is no longer instant death. There is a
84 chance you might get timewarped instead.
86 12. "freeze" command reverts to "save", most people will understand this
89 13. Screen-oriented interface, with sensor scans always up.
91 Eric Raymond's changes:
93 1. "sos" and "call" becomes "mayday", "freeze" and "save" are both good.
109 {"PHASERS", PHASERS},
111 {"TORPEDO", TORPEDO},
112 {"PHOTONS", TORPEDO},
116 {"SHIELDS", SHIELDS},
120 {"DAMAGES", DAMAGES},
124 {"IMPULSE", IMPULSE},
132 {"SENSORS", SENSORS},
136 {"TRANSPORT", TRANSPORT},
140 {"CRYSTALS", CRYSTALS},
142 {"SHUTTLE", SHUTTLE},
144 {"PLANETS", PLANETS},
148 {"COMPUTER", COMPUTER},
150 {"COMMANDS", COMMANDS},
159 {"ABANDON", ABANDON},
161 {"DESTRUCT", DESTRUCT},
163 {"DEATHRAY", DEATHRAY},
176 #define NUMCOMMANDS sizeof(commands)/sizeof(commands[0])
178 static void listCommands(int x) {
180 prout("LEGAL COMMANDS ARE:");
181 for (i = 0; i < NUMCOMMANDS; i++) {
182 proutn("%-12s ", commands[i].name);
189 static void helpme(void) {
191 char cmdbuf[32], *cp;
194 /* Give help on commands */
199 setwnd(BOTTOM_WINDOW);
200 proutn("Help on what command? ");
203 setwnd(LOWER_WINDOW);
204 if (key == IHEOL) return;
205 for (i = 0; i < NUMCOMMANDS; i++) {
206 if (strcasecmp(commands[i].name, citem)==0) {
207 i = commands[i].value;
211 if (i != NUMCOMMANDS) break;
213 prout("Valid commands:");
220 strcpy(cmdbuf, " ABBREV");
223 for (j = 0; commands[i].name[j]; j++)
224 cmdbuf[j] = toupper(commands[i].name[j]);
227 fp = fopen(SSTDOC, "r");
229 prout("Spock- \"Captain, that information is missing from the");
230 prout(" computer.\"");
232 * This used to continue: "You need to find SST.DOC and put
233 * it in the current directory."
238 if (fgets(linebuf, sizeof(linebuf), fp) == NULL) {
239 prout("Spock- \"Captain, there is no information on that command.\"");
243 if (linebuf[0] == '%' && linebuf[1] == '%'&& linebuf[2] == ' ') {
244 for (cp = linebuf+3; isspace(*cp); cp++)
246 linebuf[strlen(linebuf)-1] = '\0';
247 if (strcasecmp(cp, cmdbuf) == 0)
253 prout("Spock- \"Captain, I've found the following information:\"");
256 while (fgets(linebuf, sizeof(linebuf),fp)) {
257 if (strstr(linebuf, "******"))
264 static void makemoves(void) {
267 setwnd(LOWER_WINDOW);
268 while (TRUE) { /* command loop */
270 while (TRUE) { /* get a command */
276 setwnd(BOTTOM_WINDOW);
279 if (scan() == IHEOL) {
285 setwnd(LOWER_WINDOW);
287 for (i=0; i < ABANDON; i++)
288 if (isit(commands[i].name)) {
289 i = commands[i].value;
292 if (i < ABANDON) break;
293 for (; i < NUMCOMMANDS; i++)
294 if (strcasecmp(commands[i].name, citem) == 0) {
295 i = commands[i].value;
298 if (i < NUMCOMMANDS) break;
302 commandhook(commands[i].name, TRUE);
303 switch (i) { /* command switch */
304 case SRSCAN: // srscan
307 case LRSCAN: // lrscan
310 case PHASERS: // phasers
312 if (ididit) hitme = TRUE;
314 case TORPEDO: // photons
316 if (ididit) hitme = TRUE;
321 case SHIELDS: // shields
330 if (ididit) attack(0);
332 case DAMAGES: // damages
338 case IMPULSE: // impulse
343 if (ididit) hitme = TRUE;
351 case SENSORS: // sensors
356 if (ididit) hitme = TRUE;
358 case TRANSPORT: // transport "beam"
363 if (ididit) hitme = TRUE;
365 case CRYSTALS: // crystals
367 if (ididit) hitme = TRUE;
369 case SHUTTLE: // shuttle
371 if (ididit) hitme = TRUE;
373 case PLANETS: // Planet list
376 case REPORT: // Game Report
379 case COMPUTER: // use COMPUTER!
385 case EMEXIT: // Emergency exit
386 clrscr(); // Hide screen
387 freeze(TRUE); // forced save
388 exit(1); // And quick exit
391 probe(); // Launch probe
392 if (ididit) hitme = TRUE;
394 case ABANDON: // Abandon Ship
397 case DESTRUCT: // Self Destruct
400 case SAVE: // Save Game
404 prout("WARNING--Saved games produce no plaques!");
406 case DEATHRAY: // Try a desparation measure
408 if (ididit) hitme = TRUE;
410 case DEBUGCMD: // What do we want for debug???
415 case MAYDAY: // Call for help
417 if (ididit) hitme = TRUE;
420 alldone = 1; // quit the game
426 helpme(); // get help
429 commandhook(commands[i].name, FALSE);
431 if (alldone) break; // Game has ended
433 if (idebug) prout("2500");
437 if (alldone) break; // Events did us in
439 if (game.state.galaxy[quadx][quady] == 1000) { // Galaxy went Nova!
443 if (hitme && justin==0) {
446 if (game.state.galaxy[quadx][quady] == 1000) { // went NOVA!
459 int main(int argc, char **argv) {
460 int i, option, usecurses = TRUE;
462 while ((option = getopt(argc, argv, "t")) != -1) {
468 fprintf(stderr, "usage: sst [-t] [startcommand...].\n");
477 for (i = optind; i < argc; i++) {
478 strcat(line, argv[i]);
481 while (TRUE) { /* Play a game */
483 setup(line[0] == '\0');
493 if (tourn && alldone) {
494 proutn("Do you want your score recorded?");
500 proutn("Do you want to play again? ");
502 setwnd(FULLSCREEN_WINDOW);
507 prout("May the Great Bird of the Galaxy roost upon your home planet.");
513 /* return an enemy */
517 case IHR: s = "Romulan"; break;
518 case IHK: s = "Klingon"; break;
519 case IHC: s = "Commander"; break;
520 case IHS: s = "Super-commander"; break;
521 case IHSTAR: s = "Star"; break;
522 case IHP: s = "Planet"; break;
523 case IHB: s = "Starbase"; break;
524 case IHBLANK: s = "Black hole"; break;
525 case IHT: s = "Tholian"; break;
526 case IHWEB: s = "Tholian web"; break;
527 case IHQUEST: s = "Stranger"; break;
528 default: s = "Unknown??"; break;
533 char *cramlc(enum loctype key, int x, int y) {
536 if (key == quadrant) strcpy(buf, "Quadrant ");
537 else if (key == sector) strcpy(buf, "Sector ");
538 sprintf(buf+strlen(buf), "%d - %d", x, y);
542 void crmena(int i, int enemy, int key, int x, int y) {
543 if (i == 1) proutn("***");
546 proutn(cramlc(key, x, y));
552 case IHE: s = "Enterprise"; break;
553 case IHF: s = "Faerie Queene"; break;
554 default: s = "Ship???"; break;
560 prouts("******************************************************");
564 double expran(double avrage) {
565 return -avrage*log(1e-7 + Rand());
569 return rand()/(1.0 + (double)RAND_MAX);
572 void iran8(int *i, int *j) {
573 *i = Rand()*8.0 + 1.0;
574 *j = Rand()*8.0 + 1.0;
577 void iran10(int *i, int *j) {
578 *i = Rand()*10.0 + 1.0;
579 *j = Rand()*10.0 + 1.0;
588 /* return IHEOL next time */
601 // Read a line if nothing here
607 cgetline(line, sizeof(line));
609 if (curwnd==BOTTOM_WINDOW){
611 setwnd(LOWER_WINDOW);
616 // Skip leading white space
617 while (*linep == ' ') linep++;
623 if (isdigit(*linep) || *linep=='+' || *linep=='-' || *linep=='.') {
626 if (sscanf(linep, "%lf%n", &aaitem, &i) < 1) {
627 linep = line; // Invalid numbers are ignored
639 while (*linep && *linep!=' ') {
640 if ((cp - citem) < 9) *cp++ = tolower(*linep);
652 if (*citem == 'y') return TRUE;
653 if (*citem == 'n') return FALSE;
654 proutn("Please answer with \"Y\" or \"N\": ");
661 prout("Beg your pardon, Captain?");
665 /* New function -- compares s to scaned citem and returns true if it
666 matches to the length of s */
668 return strncasecmp(s, citem, max(1, strlen(citem))) == 0;
674 proutn("Reset levels? ");
676 if (energy < inenrg) energy = inenrg;
681 proutn("Reset damage? ");
684 for (i=0; i <= NDEVICES; i++) if (damage[i] > 0.0) damage[i] = 0.0;
687 proutn("Toggle idebug? ");
690 if (idebug) prout("Debug output ON");
691 else prout("Debug output OFF");
693 proutn("Cause selective damage? ");
696 for (i=1; i <= NDEVICES; i++) {
702 if (key == IHALPHA && isit("y")) {
704 if (i == DRADIO) stdamtim = game.state.date;
708 proutn("Examine/change events? ");
711 for (i = 1; i < NEVENTS; i++) {
713 if (future[i] == 1e30) continue;
715 case FSNOVA: proutn("Supernova "); break;
716 case FTBEAM: proutn("T Beam "); break;
717 case FSNAP: proutn("Snapshot "); break;
718 case FBATTAK: proutn("Base Attack "); break;
719 case FCDBAS: proutn("Base Destroy "); break;
720 case FSCMOVE: proutn("SC Move "); break;
721 case FSCDBAS: proutn("SC Base Destroy "); break;
723 proutn("%.2f", future[i]-game.state.date);
728 future[i] = game.state.date + aaitem;