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.
94 3. Can now report vbases left in scrscan.
99 static char line[128], *linep = line;
100 static int usecurses = TRUE;
113 {"REQUEST", REQUEST},
117 {"PHASERS", PHASERS},
119 {"TORPEDO", TORPEDO},
120 {"PHOTONS", TORPEDO},
124 {"SHIELDS", SHIELDS},
128 {"DAMAGES", DAMAGES},
132 {"IMPULSE", IMPULSE},
140 {"SENSORS", SENSORS},
144 {"TRANSPORT", TRANSPORT},
148 {"CRYSTALS", CRYSTALS},
150 {"SHUTTLE", SHUTTLE},
152 {"PLANETS", PLANETS},
156 {"COMPUTER", COMPUTER},
158 {"COMMANDS", COMMANDS},
167 {"ABANDON", ABANDON},
169 {"DESTRUCT", DESTRUCT},
171 {"DEATHRAY", DEATHRAY},
184 #define NUMCOMMANDS sizeof(commands)/sizeof(commands[0])
186 #define MIN_CURSES_COMMAND PHASERS /* might change someday */
188 static void listCommands(int usecurses) {
190 proutn("LEGAL COMMANDS ARE:");
191 for (i = usecurses ? MIN_CURSES_COMMAND : 0; i < NUMCOMMANDS; i++) {
194 proutn("%-12s ", commands[i].name);
200 static void helpme(void) {
202 char cmdbuf[32], *cp;
205 /* Give help on commands */
210 setwnd(prompt_window);
211 proutn("Help on what command? ");
214 setwnd(message_window);
215 if (key == IHEOL) return;
216 for (i = 0; i < NUMCOMMANDS; i++) {
217 if (strcasecmp(commands[i].name, citem)==0) {
218 i = commands[i].value;
222 if (i != NUMCOMMANDS) break;
224 prout("Valid commands:");
225 listCommands(usecurses);
231 strcpy(cmdbuf, " ABBREV");
234 for (j = 0; commands[i].name[j]; j++)
235 cmdbuf[j] = toupper(commands[i].name[j]);
238 fp = fopen(SSTDOC, "r");
240 prout("Spock- \"Captain, that information is missing from the");
241 prout(" computer.\"");
243 * This used to continue: "You need to find SST.DOC and put
244 * it in the current directory."
249 if (fgets(linebuf, sizeof(linebuf), fp) == NULL) {
250 prout("Spock- \"Captain, there is no information on that command.\"");
254 if (linebuf[0] == '%' && linebuf[1] == '%'&& linebuf[2] == ' ') {
255 for (cp = linebuf+3; isspace(*cp); cp++)
257 linebuf[strlen(linebuf)-1] = '\0';
258 if (strcasecmp(cp, cmdbuf) == 0)
264 prout("Spock- \"Captain, I've found the following information:\"");
267 while (fgets(linebuf, sizeof(linebuf),fp)) {
268 if (strstr(linebuf, "******"))
275 void enqueue(char *s) {
279 static void makemoves(void) {
282 setwnd(message_window);
283 while (TRUE) { /* command loop */
285 while (TRUE) { /* get a command */
291 setwnd(prompt_window);
294 if (scan() == IHEOL) {
300 setwnd(message_window);
302 for (i=0; i < ABANDON; i++)
303 if (isit(commands[i].name)) {
304 i = commands[i].value;
307 if (i < ABANDON) break;
308 for (; i < NUMCOMMANDS; i++)
309 if (strcasecmp(commands[i].name, citem) == 0) {
310 i = commands[i].value;
313 if (i < NUMCOMMANDS) break;
314 listCommands(usecurses);
316 commandhook(commands[i].name, TRUE);
317 switch (i) { /* command switch */
318 case SRSCAN: // srscan
321 case STATUS: // status
324 case REQUEST: // status request
325 srscan(SCAN_REQUEST);
327 case LRSCAN: // lrscan
330 case PHASERS: // phasers
332 if (ididit) hitme = TRUE;
334 case TORPEDO: // photons
336 if (ididit) hitme = TRUE;
341 case SHIELDS: // shields
350 if (ididit) attack(0);
352 case DAMAGES: // damages
358 case IMPULSE: // impulse
363 if (ididit) hitme = TRUE;
371 case SENSORS: // sensors
376 if (ididit) hitme = TRUE;
378 case TRANSPORT: // transport "beam"
383 if (ididit) hitme = TRUE;
385 case CRYSTALS: // crystals
387 if (ididit) hitme = TRUE;
389 case SHUTTLE: // shuttle
391 if (ididit) hitme = TRUE;
393 case PLANETS: // Planet list
396 case REPORT: // Game Report
399 case COMPUTER: // use COMPUTER!
403 listCommands(usecurses);
405 case EMEXIT: // Emergency exit
406 clrscr(); // Hide screen
407 freeze(TRUE); // forced save
408 exit(1); // And quick exit
411 probe(); // Launch probe
412 if (ididit) hitme = TRUE;
414 case ABANDON: // Abandon Ship
417 case DESTRUCT: // Self Destruct
420 case SAVE: // Save Game
424 prout("WARNING--Saved games produce no plaques!");
426 case DEATHRAY: // Try a desparation measure
428 if (ididit) hitme = TRUE;
430 case DEBUGCMD: // What do we want for debug???
435 case MAYDAY: // Call for help
437 if (ididit) hitme = TRUE;
440 alldone = 1; // quit the game
446 helpme(); // get help
449 commandhook(commands[i].name, FALSE);
451 if (alldone) break; // Game has ended
453 if (idebug) prout("2500");
457 if (alldone) break; // Events did us in
459 if (game.state.galaxy[quadx][quady] == SUPERNOVA_PLACE) { // Galaxy went Nova!
463 if (hitme && justin==0) {
466 if (game.state.galaxy[quadx][quady] == SUPERNOVA_PLACE) { // went NOVA!
479 int main(int argc, char **argv) {
482 while ((option = getopt(argc, argv, "t")) != -1) {
488 fprintf(stderr, "usage: sst [-t] [startcommand...].\n");
497 for (i = optind; i < argc; i++) {
498 strcat(line, argv[i]);
501 while (TRUE) { /* Play a game */
502 setwnd(fullscreen_window);
505 setup(line[0] == '\0');
515 if (tourn && alldone) {
516 proutn("Do you want your score recorded?");
522 proutn("Do you want to play again? ");
526 prout("May the Great Bird of the Galaxy roost upon your home planet.");
532 /* return an enemy */
536 case IHR: s = "Romulan"; break;
537 case IHK: s = "Klingon"; break;
538 case IHC: s = "Commander"; break;
539 case IHS: s = "Super-commander"; break;
540 case IHSTAR: s = "Star"; break;
541 case IHP: s = "Planet"; break;
542 case IHB: s = "Starbase"; break;
543 case IHBLANK: s = "Black hole"; break;
544 case IHT: s = "Tholian"; break;
545 case IHWEB: s = "Tholian web"; break;
546 case IHQUEST: s = "Stranger"; break;
547 default: s = "Unknown??"; break;
552 char *cramlc(enum loctype key, int x, int y) {
555 if (key == quadrant) strcpy(buf, "Quadrant ");
556 else if (key == sector) strcpy(buf, "Sector ");
557 sprintf(buf+strlen(buf), "%d - %d", x, y);
561 void crmena(int i, int enemy, int key, int x, int y) {
562 if (i == 1) proutn("***");
565 proutn(cramlc(key, x, y));
571 case IHE: s = "Enterprise"; break;
572 case IHF: s = "Faerie Queene"; break;
573 default: s = "Ship???"; break;
579 prouts("******************************************************");
583 double expran(double avrage) {
584 return -avrage*log(1e-7 + Rand());
588 return rand()/(1.0 + (double)RAND_MAX);
591 void iran8(int *i, int *j) {
592 *i = Rand()*8.0 + 1.0;
593 *j = Rand()*8.0 + 1.0;
596 void iran10(int *i, int *j) {
597 *i = Rand()*10.0 + 1.0;
598 *j = Rand()*10.0 + 1.0;
607 /* return IHEOL next time */
620 // Read a line if nothing here
626 cgetline(line, sizeof(line));
628 if (curwnd==prompt_window){
630 setwnd(message_window);
635 // Skip leading white space
636 while (*linep == ' ') linep++;
642 if (isdigit(*linep) || *linep=='+' || *linep=='-' || *linep=='.') {
645 if (sscanf(linep, "%lf%n", &aaitem, &i) < 1) {
646 linep = line; // Invalid numbers are ignored
658 while (*linep && *linep!=' ') {
659 if ((cp - citem) < 9) *cp++ = tolower(*linep);
671 if (*citem == 'y') return TRUE;
672 if (*citem == 'n') return FALSE;
673 proutn("Please answer with \"Y\" or \"N\": ");
680 prout("Beg your pardon, Captain?");
684 /* New function -- compares s to scaned citem and returns true if it
685 matches to the length of s */
687 return strncasecmp(s, citem, max(1, strlen(citem))) == 0;
693 proutn("Reset levels? ");
695 if (energy < inenrg) energy = inenrg;
700 proutn("Reset damage? ");
703 for (i=0; i <= NDEVICES; i++) if (damage[i] > 0.0) damage[i] = 0.0;
706 proutn("Toggle idebug? ");
709 if (idebug) prout("Debug output ON");
710 else prout("Debug output OFF");
712 proutn("Cause selective damage? ");
715 for (i=1; i <= NDEVICES; i++) {
721 if (key == IHALPHA && isit("y")) {
723 if (i == DRADIO) stdamtim = game.state.date;
727 proutn("Examine/change events? ");
730 for (i = 1; i < NEVENTS; i++) {
732 if (future[i] == 1e30) continue;
734 case FSNOVA: proutn("Supernova "); break;
735 case FTBEAM: proutn("T Beam "); break;
736 case FSNAP: proutn("Snapshot "); break;
737 case FBATTAK: proutn("Base Attack "); break;
738 case FCDBAS: proutn("Base Destroy "); break;
739 case FSCMOVE: proutn("SC Move "); break;
740 case FSCDBAS: proutn("SC Base Destroy "); break;
742 proutn("%.2f", future[i]-game.state.date);
747 future[i] = game.state.date + aaitem;