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 Mainly, I translated this C code out of FORTRAN into C -- created #defines
91 for a lot of magic numbers.
93 1. "sos" and "call" becomes "mayday", "freeze" and "save" are both good.
95 2. Status report now indicates when dilithium crystals are on board.
97 3. Can now report starbases left in scrscan.
101 /* the input queue */
102 static char line[128], *linep = line;
103 static int usecurses = TRUE;
116 {"REQUEST", REQUEST},
120 {"PHASERS", PHASERS},
122 {"TORPEDO", TORPEDO},
123 {"PHOTONS", TORPEDO},
127 {"SHIELDS", SHIELDS},
131 {"DAMAGES", DAMAGES},
135 {"IMPULSE", IMPULSE},
143 {"SENSORS", SENSORS},
147 {"TRANSPORT", TRANSPORT},
151 {"CRYSTALS", CRYSTALS},
153 {"SHUTTLE", SHUTTLE},
155 {"PLANETS", PLANETS},
159 {"COMPUTER", COMPUTER},
161 {"COMMANDS", COMMANDS},
170 {"ABANDON", ABANDON},
172 {"DESTRUCT", DESTRUCT},
174 {"DEATHRAY", DEATHRAY},
187 #define NUMCOMMANDS sizeof(commands)/sizeof(commands[0])
189 #define MIN_CURSES_COMMAND PHASERS /* might change someday */
191 static void listCommands(int usecurses) {
193 proutn("LEGAL COMMANDS ARE:");
194 for (i = usecurses ? MIN_CURSES_COMMAND : 0; i < NUMCOMMANDS; i++) {
197 proutn("%-12s ", commands[i].name);
203 static void helpme(void) {
205 char cmdbuf[32], *cp;
208 /* Give help on commands */
213 setwnd(prompt_window);
214 proutn("Help on what command? ");
217 setwnd(message_window);
218 if (key == IHEOL) return;
219 for (i = 0; i < NUMCOMMANDS; i++) {
220 if (strcasecmp(commands[i].name, citem)==0) {
221 i = commands[i].value;
225 if (i != NUMCOMMANDS) break;
227 prout("Valid commands:");
228 listCommands(usecurses);
234 strcpy(cmdbuf, " ABBREV");
237 for (j = 0; commands[i].name[j]; j++)
238 cmdbuf[j] = toupper(commands[i].name[j]);
241 fp = fopen(SSTDOC, "r");
243 prout("Spock- \"Captain, that information is missing from the");
244 prout(" computer.\"");
246 * This used to continue: "You need to find SST.DOC and put
247 * it in the current directory."
252 if (fgets(linebuf, sizeof(linebuf), fp) == NULL) {
253 prout("Spock- \"Captain, there is no information on that command.\"");
257 if (linebuf[0] == '%' && linebuf[1] == '%'&& linebuf[2] == ' ') {
258 for (cp = linebuf+3; isspace(*cp); cp++)
260 linebuf[strlen(linebuf)-1] = '\0';
261 if (strcasecmp(cp, cmdbuf) == 0)
267 prout("Spock- \"Captain, I've found the following information:\"");
270 while (fgets(linebuf, sizeof(linebuf),fp)) {
271 if (strstr(linebuf, "******"))
278 void enqueue(char *s) {
282 static void makemoves(void) {
285 setwnd(message_window);
286 while (TRUE) { /* command loop */
288 while (TRUE) { /* get a command */
294 setwnd(prompt_window);
297 if (scan() == IHEOL) {
303 setwnd(message_window);
305 for (i=0; i < ABANDON; i++)
306 if (isit(commands[i].name)) {
307 i = commands[i].value;
310 if (i < ABANDON) break;
311 for (; i < NUMCOMMANDS; i++)
312 if (strcasecmp(commands[i].name, citem) == 0) {
313 i = commands[i].value;
316 if (i < NUMCOMMANDS) break;
317 listCommands(usecurses);
319 commandhook(commands[i].name, TRUE);
320 switch (i) { /* command switch */
321 case SRSCAN: // srscan
324 case STATUS: // status
327 case REQUEST: // status request
328 srscan(SCAN_REQUEST);
330 case LRSCAN: // lrscan
333 case PHASERS: // phasers
335 if (ididit) hitme = TRUE;
337 case TORPEDO: // photons
339 if (ididit) hitme = TRUE;
344 case SHIELDS: // shields
353 if (ididit) attack(0);
355 case DAMAGES: // damages
361 case IMPULSE: // impulse
366 if (ididit) hitme = TRUE;
374 case SENSORS: // sensors
379 if (ididit) hitme = TRUE;
381 case TRANSPORT: // transport "beam"
386 if (ididit) hitme = TRUE;
388 case CRYSTALS: // crystals
390 if (ididit) hitme = TRUE;
392 case SHUTTLE: // shuttle
394 if (ididit) hitme = TRUE;
396 case PLANETS: // Planet list
399 case REPORT: // Game Report
402 case COMPUTER: // use COMPUTER!
406 listCommands(usecurses);
408 case EMEXIT: // Emergency exit
409 clrscr(); // Hide screen
410 freeze(TRUE); // forced save
411 exit(1); // And quick exit
414 probe(); // Launch probe
415 if (ididit) hitme = TRUE;
417 case ABANDON: // Abandon Ship
420 case DESTRUCT: // Self Destruct
423 case SAVE: // Save Game
426 if (skill > SKILL_GOOD)
427 prout("WARNING--Saved games produce no plaques!");
429 case DEATHRAY: // Try a desparation measure
431 if (ididit) hitme = TRUE;
433 case DEBUGCMD: // What do we want for debug???
438 case MAYDAY: // Call for help
440 if (ididit) hitme = TRUE;
443 alldone = 1; // quit the game
449 helpme(); // get help
452 commandhook(commands[i].name, FALSE);
454 if (alldone) break; // Game has ended
456 if (idebug) prout("2500");
460 if (alldone) break; // Events did us in
462 if (game.state.galaxy[quadx][quady] == SUPERNOVA_PLACE) { // Galaxy went Nova!
466 if (hitme && justin==0) {
469 if (game.state.galaxy[quadx][quady] == SUPERNOVA_PLACE) { // went NOVA!
482 int main(int argc, char **argv) {
485 while ((option = getopt(argc, argv, "t")) != -1) {
491 fprintf(stderr, "usage: sst [-t] [startcommand...].\n");
500 for (i = optind; i < argc; i++) {
501 strcat(line, argv[i]);
504 while (TRUE) { /* Play a game */
505 setwnd(fullscreen_window);
508 setup(line[0] == '\0');
518 if (tourn && alldone) {
519 proutn("Do you want your score recorded?");
525 proutn("Do you want to play again? ");
529 prout("May the Great Bird of the Galaxy roost upon your home planet.");
535 /* return an enemy */
539 case IHR: s = "Romulan"; break;
540 case IHK: s = "Klingon"; break;
541 case IHC: s = "Commander"; break;
542 case IHS: s = "Super-commander"; break;
543 case IHSTAR: s = "Star"; break;
544 case IHP: s = "Planet"; break;
545 case IHB: s = "Starbase"; break;
546 case IHBLANK: s = "Black hole"; break;
547 case IHT: s = "Tholian"; break;
548 case IHWEB: s = "Tholian web"; break;
549 case IHQUEST: s = "Stranger"; break;
550 default: s = "Unknown??"; break;
555 char *cramlc(enum loctype key, int x, int y) {
558 if (key == quadrant) strcpy(buf, "Quadrant ");
559 else if (key == sector) strcpy(buf, "Sector ");
560 sprintf(buf+strlen(buf), "%d - %d", x, y);
564 void crmena(int i, int enemy, int key, int x, int y) {
565 if (i == 1) proutn("***");
568 proutn(cramlc(key, x, y));
574 case IHE: s = "Enterprise"; break;
575 case IHF: s = "Faerie Queene"; break;
576 default: s = "Ship???"; break;
582 prouts("******************************************************");
586 double expran(double avrage) {
587 return -avrage*log(1e-7 + Rand());
591 return rand()/(1.0 + (double)RAND_MAX);
594 void iran(int size, int *i, int *j) {
595 *i = Rand()*(size*1.0) + 1.0;
596 *j = Rand()*(size*1.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;