1 #define INCLUDED // Define externs here
9 #define SSTDOC "sst.doc"
14 Here are Tom Almy's changes:
16 Compared to original version, I've changed the "help" command to
17 "call" and the "terminate" command to "quit" to better match
18 user expectations. The DECUS version apparently made those changes
19 as well as changing "freeze" to "save". However I like "freeze".
21 When I got a later version of Super Star Trek that I was converting
22 from, I added the emexit command.
24 That later version also mentions srscan and lrscan working when
25 docked (using the starbase's scanners), so I made some changes here
26 to do this (and indicating that fact to the player), and then realized
27 the base would have a subspace radio as well -- doing a Chart when docked
28 updates the star chart, and all radio reports will be heard. The Dock
29 command will also give a report if a base is under attack.
31 Movecom no longer reports movement if sensors are damaged so you wouldn't
36 1. Better base positioning at startup
38 2. Deathray improvement (but keeping original failure alternatives)
42 4. Enemies can ram the Enterprise. Regular Klingons and Romulans can
43 move in Expert and Emeritus games. This code could use improvement.
45 5. The deep space probe looks interesting! DECUS version
47 6. Perhaps cloaking to be added later? BSD version
49 Here are Stas Sergeev's changes:
51 1. The Space Thingy can be shoved, if you it ram, and can fire back if
54 2. The Tholian can be hit with phasers
56 3. When you are docked, base covers you with an almost invincible shields
57 (a commander can still ram you, or a Romulan can destroy the base,
58 or a SCom can even succeed with direct attack IIRC, but this rarely
61 4. SCom can't escape from you if no more enemies remain (without this,
62 chasing SCom can take an eternity).
64 5. Probe target you enter is now the destination quadrant. Before I don't
65 remember what it was, but it was something I had difficulty using)
67 6. Secret password is now autogenerated.
69 7. "Plaque" is adjusted for A4 paper :-)
71 8. Phasers now tells you how much energy needed, but only if the computer
74 9. Planets are auto-scanned when you enter the quadrant.
76 10. Mining or using crystals in presense of enemy now yields an attack.
77 There are other minor adjustments to what yields an attack
80 11. Ramming a black hole is no longer instant death. There is a
81 chance you might get timewarped instead.
83 12. "freeze" command reverts to "save", most people will understand this
86 13. Screen-oriented interface, with sensor scans always up.
88 Eric Raymond's changes:
90 1. "sos" and "call" becomes "mayday", "freeze" and "save" are both good.
92 2. Status report now indicates when dilithium crystals are on board.
97 static char line[128], *linep = line;
98 static usecurses = TRUE;
111 {"REQUEST", REQUEST},
115 {"PHASERS", PHASERS},
117 {"TORPEDO", TORPEDO},
118 {"PHOTONS", TORPEDO},
122 {"SHIELDS", SHIELDS},
126 {"DAMAGES", DAMAGES},
130 {"IMPULSE", IMPULSE},
138 {"SENSORS", SENSORS},
142 {"TRANSPORT", TRANSPORT},
146 {"CRYSTALS", CRYSTALS},
148 {"SHUTTLE", SHUTTLE},
150 {"PLANETS", PLANETS},
154 {"COMPUTER", COMPUTER},
156 {"COMMANDS", COMMANDS},
165 {"ABANDON", ABANDON},
167 {"DESTRUCT", DESTRUCT},
169 {"DEATHRAY", DEATHRAY},
182 #define NUMCOMMANDS sizeof(commands)/sizeof(commands[0])
184 #define MIN_CURSES_COMMAND PHASERS /* might change someday */
186 static void listCommands(int usecurses) {
188 proutn("LEGAL COMMANDS ARE:");
189 for (i = usecurses ? MIN_CURSES_COMMAND : 0; i < NUMCOMMANDS; i++) {
192 proutn("%-12s ", commands[i].name);
198 static void helpme(void) {
200 char cmdbuf[32], *cp;
203 /* Give help on commands */
208 setwnd(prompt_window);
209 proutn("Help on what command? ");
212 setwnd(message_window);
213 if (key == IHEOL) return;
214 for (i = 0; i < NUMCOMMANDS; i++) {
215 if (strcasecmp(commands[i].name, citem)==0) {
216 i = commands[i].value;
220 if (i != NUMCOMMANDS) break;
222 prout("Valid commands:");
223 listCommands(usecurses);
229 strcpy(cmdbuf, " ABBREV");
232 for (j = 0; commands[i].name[j]; j++)
233 cmdbuf[j] = toupper(commands[i].name[j]);
236 fp = fopen(SSTDOC, "r");
238 prout("Spock- \"Captain, that information is missing from the");
239 prout(" computer.\"");
241 * This used to continue: "You need to find SST.DOC and put
242 * it in the current directory."
247 if (fgets(linebuf, sizeof(linebuf), fp) == NULL) {
248 prout("Spock- \"Captain, there is no information on that command.\"");
252 if (linebuf[0] == '%' && linebuf[1] == '%'&& linebuf[2] == ' ') {
253 for (cp = linebuf+3; isspace(*cp); cp++)
255 linebuf[strlen(linebuf)-1] = '\0';
256 if (strcasecmp(cp, cmdbuf) == 0)
262 prout("Spock- \"Captain, I've found the following information:\"");
265 while (fgets(linebuf, sizeof(linebuf),fp)) {
266 if (strstr(linebuf, "******"))
273 void enqueue(char *s) {
277 static void makemoves(void) {
280 setwnd(message_window);
281 while (TRUE) { /* command loop */
283 while (TRUE) { /* get a command */
289 setwnd(prompt_window);
292 if (scan() == IHEOL) {
298 setwnd(message_window);
300 for (i=0; i < ABANDON; i++)
301 if (isit(commands[i].name)) {
302 i = commands[i].value;
305 if (i < ABANDON) break;
306 for (; i < NUMCOMMANDS; i++)
307 if (strcasecmp(commands[i].name, citem) == 0) {
308 i = commands[i].value;
311 if (i < NUMCOMMANDS) break;
312 listCommands(usecurses);
314 commandhook(commands[i].name, TRUE);
315 switch (i) { /* command switch */
316 case SRSCAN: // srscan
319 case STATUS: // status
322 case REQUEST: // status request
323 srscan(SCAN_REQUEST);
325 case LRSCAN: // lrscan
328 case PHASERS: // phasers
330 if (ididit) hitme = TRUE;
332 case TORPEDO: // photons
334 if (ididit) hitme = TRUE;
339 case SHIELDS: // shields
348 if (ididit) attack(0);
350 case DAMAGES: // damages
356 case IMPULSE: // impulse
361 if (ididit) hitme = TRUE;
369 case SENSORS: // sensors
374 if (ididit) hitme = TRUE;
376 case TRANSPORT: // transport "beam"
381 if (ididit) hitme = TRUE;
383 case CRYSTALS: // crystals
385 if (ididit) hitme = TRUE;
387 case SHUTTLE: // shuttle
389 if (ididit) hitme = TRUE;
391 case PLANETS: // Planet list
394 case REPORT: // Game Report
397 case COMPUTER: // use COMPUTER!
401 listCommands(usecurses);
403 case EMEXIT: // Emergency exit
404 clrscr(); // Hide screen
405 freeze(TRUE); // forced save
406 exit(1); // And quick exit
409 probe(); // Launch probe
410 if (ididit) hitme = TRUE;
412 case ABANDON: // Abandon Ship
415 case DESTRUCT: // Self Destruct
418 case SAVE: // Save Game
422 prout("WARNING--Saved games produce no plaques!");
424 case DEATHRAY: // Try a desparation measure
426 if (ididit) hitme = TRUE;
428 case DEBUGCMD: // What do we want for debug???
433 case MAYDAY: // Call for help
435 if (ididit) hitme = TRUE;
438 alldone = 1; // quit the game
444 helpme(); // get help
447 commandhook(commands[i].name, FALSE);
449 if (alldone) break; // Game has ended
451 if (idebug) prout("2500");
455 if (alldone) break; // Events did us in
457 if (game.state.galaxy[quadx][quady] == 1000) { // Galaxy went Nova!
461 if (hitme && justin==0) {
464 if (game.state.galaxy[quadx][quady] == 1000) { // went NOVA!
477 int main(int argc, char **argv) {
480 while ((option = getopt(argc, argv, "t")) != -1) {
486 fprintf(stderr, "usage: sst [-t] [startcommand...].\n");
495 for (i = optind; i < argc; i++) {
496 strcat(line, argv[i]);
499 while (TRUE) { /* Play a game */
500 setwnd(fullscreen_window);
503 setup(line[0] == '\0');
513 if (tourn && alldone) {
514 proutn("Do you want your score recorded?");
520 proutn("Do you want to play again? ");
524 prout("May the Great Bird of the Galaxy roost upon your home planet.");
530 /* return an enemy */
534 case IHR: s = "Romulan"; break;
535 case IHK: s = "Klingon"; break;
536 case IHC: s = "Commander"; break;
537 case IHS: s = "Super-commander"; break;
538 case IHSTAR: s = "Star"; break;
539 case IHP: s = "Planet"; break;
540 case IHB: s = "Starbase"; break;
541 case IHBLANK: s = "Black hole"; break;
542 case IHT: s = "Tholian"; break;
543 case IHWEB: s = "Tholian web"; break;
544 case IHQUEST: s = "Stranger"; break;
545 default: s = "Unknown??"; break;
550 char *cramlc(enum loctype key, int x, int y) {
553 if (key == quadrant) strcpy(buf, "Quadrant ");
554 else if (key == sector) strcpy(buf, "Sector ");
555 sprintf(buf+strlen(buf), "%d - %d", x, y);
559 void crmena(int i, int enemy, int key, int x, int y) {
560 if (i == 1) proutn("***");
563 proutn(cramlc(key, x, y));
569 case IHE: s = "Enterprise"; break;
570 case IHF: s = "Faerie Queene"; break;
571 default: s = "Ship???"; break;
577 prouts("******************************************************");
581 double expran(double avrage) {
582 return -avrage*log(1e-7 + Rand());
586 return rand()/(1.0 + (double)RAND_MAX);
589 void iran8(int *i, int *j) {
590 *i = Rand()*8.0 + 1.0;
591 *j = Rand()*8.0 + 1.0;
594 void iran10(int *i, int *j) {
595 *i = Rand()*10.0 + 1.0;
596 *j = Rand()*10.0 + 1.0;
605 /* return IHEOL next time */
618 // Read a line if nothing here
624 cgetline(line, sizeof(line));
626 if (curwnd==prompt_window){
628 setwnd(message_window);
633 // Skip leading white space
634 while (*linep == ' ') linep++;
640 if (isdigit(*linep) || *linep=='+' || *linep=='-' || *linep=='.') {
643 if (sscanf(linep, "%lf%n", &aaitem, &i) < 1) {
644 linep = line; // Invalid numbers are ignored
656 while (*linep && *linep!=' ') {
657 if ((cp - citem) < 9) *cp++ = tolower(*linep);
669 if (*citem == 'y') return TRUE;
670 if (*citem == 'n') return FALSE;
671 proutn("Please answer with \"Y\" or \"N\": ");
678 prout("Beg your pardon, Captain?");
682 /* New function -- compares s to scaned citem and returns true if it
683 matches to the length of s */
685 return strncasecmp(s, citem, max(1, strlen(citem))) == 0;
691 proutn("Reset levels? ");
693 if (energy < inenrg) energy = inenrg;
698 proutn("Reset damage? ");
701 for (i=0; i <= NDEVICES; i++) if (damage[i] > 0.0) damage[i] = 0.0;
704 proutn("Toggle idebug? ");
707 if (idebug) prout("Debug output ON");
708 else prout("Debug output OFF");
710 proutn("Cause selective damage? ");
713 for (i=1; i <= NDEVICES; i++) {
719 if (key == IHALPHA && isit("y")) {
721 if (i == DRADIO) stdamtim = game.state.date;
725 proutn("Examine/change events? ");
728 for (i = 1; i < NEVENTS; i++) {
730 if (future[i] == 1e30) continue;
732 case FSNOVA: proutn("Supernova "); break;
733 case FTBEAM: proutn("T Beam "); break;
734 case FSNAP: proutn("Snapshot "); break;
735 case FBATTAK: proutn("Base Attack "); break;
736 case FCDBAS: proutn("Base Destroy "); break;
737 case FSCMOVE: proutn("SC Move "); break;
738 case FSCDBAS: proutn("SC Base Destroy "); break;
740 proutn("%.2f", future[i]-game.state.date);
745 future[i] = game.state.date + aaitem;