-#define INCLUDED // Define externs here\r
-#include "sst.h"\r
-#include <ctype.h>\r
-#include <stdarg.h>\r
-#ifdef MSDOS\r
-#include <dos.h>\r
-#endif\r
-#include <time.h>\r
- \r
-int getch(void);\r
-\r
-static char line[128], *linep = line;\r
-static int linecount; /* for paging */\r
-\r
-static void clearscreen(void);\r
-\r
-/* Compared to original version, I've changed the "help" command to\r
- "call" and the "terminate" command to "quit" to better match\r
- user expectations. The DECUS version apparently made those changes\r
- as well as changing "freeze" to "save". However I like "freeze".\r
-\r
- When I got a later version of Super Star Trek that I was converting\r
- from, I added the emexit command.\r
-\r
- That later version also mentions srscan and lrscan working when\r
- docked (using the starbase's scanners), so I made some changes here\r
- to do this (and indicating that fact to the player), and then realized\r
- the base would have a subspace radio as well -- doing a Chart when docked\r
- updates the star chart, and all radio reports will be heard. The Dock\r
- command will also give a report if a base is under attack.\r
-\r
- Movecom no longer reports movement if sensors are damaged so you wouldn't\r
- otherwise know it.\r
-\r
- Also added:\r
-\r
- 1. Better base positioning at startup\r
-\r
- 2. deathray improvement (but keeping original failure alternatives)\r
-\r
- 3. Tholian Web\r
-\r
- 4. Enemies can ram the Enterprise. Regular Klingons and Romulans can\r
- move in Expert and Emeritus games. This code could use improvement.\r
-\r
- 5. The deep space probe looks interesting! DECUS version\r
-\r
- 6. Perhaps cloaking to be added later? BSD version\r
-\r
-\r
- */\r
-\r
-\r
-static char *commands[] = {\r
- "srscan",\r
- "lrscan",\r
- "phasers",\r
- "photons",\r
- "move",\r
- "shields",\r
- "dock",\r
- "damages",\r
- "chart",\r
- "impulse",\r
- "rest",\r
- "warp",\r
- "status",\r
- "sensors",\r
- "orbit",\r
- "transport",\r
- "mine",\r
- "crystals",\r
- "shuttle",\r
- "planets",\r
- "request",\r
- "report",\r
- "computer",\r
- "commands",\r
- "emexit",\r
- "probe",\r
- "abandon",\r
- "destruct",\r
- "freeze",\r
- "deathray",\r
- "debug",\r
- "call",\r
- "quit",\r
- "help"\r
-};\r
-#define NUMCOMMANDS sizeof(commands)/sizeof(commands[0])\r
-\r
-static void listCommands(int x) {\r
- prout(" SRSCAN MOVE PHASERS CALL\n"\r
- " STATUS IMPULSE PHOTONS ABANDON\n"\r
- " LRSCAN WARP SHIELDS DESTRUCT\n"\r
- " CHART REST DOCK QUIT\n"\r
- " DAMAGES REPORT SENSORS ORBIT\n"\r
- " TRANSPORT MINE CRYSTALS SHUTTLE\n"\r
- " PLANETS REQUEST DEATHRAY FREEZE\n"\r
- " COMPUTER EMEXIT PROBE COMMANDS");\r
- if (x) prout(" HELP");\r
-}\r
-\r
-static void helpme(void) {\r
- int i, j;\r
- char cmdbuf[32];\r
- char linebuf[132];\r
- FILE *fp;\r
- /* Give help on commands */\r
- int key;\r
- key = scan();\r
- while (TRUE) {\r
- if (key == IHEOL) {\r
- proutn("Help on what command?");\r
- key = scan();\r
- }\r
- if (key == IHEOL) return;\r
- for (i = 0; i < NUMCOMMANDS; i++) {\r
- if (strcmp(commands[i], citem)==0) break;\r
- }\r
- if (i != NUMCOMMANDS) break;\r
- skip(1);\r
- prout("Valid commands:");\r
- listCommands(FALSE);\r
- key = IHEOL;\r
- chew();\r
- skip(1);\r
- }\r
- if (i == 23) {\r
- strcpy(cmdbuf, " ABBREV");\r
- }\r
- else {\r
- strcpy(cmdbuf, " Mnemonic: ");\r
- j = 0;\r
- while ((cmdbuf[j+13] = toupper(commands[i][j])) != 0) j++;\r
- }\r
- fp = fopen("sst.doc", "r");\r
- if (fp == NULL) {\r
- prout("Spock- \"Captain, that information is missing from the");\r
- prout(" computer. You need to find SST.DOC and put it in the");\r
- prout(" current directory.\"");\r
- return;\r
- }\r
- i = strlen(cmdbuf);\r
- do {\r
- if (fgets(linebuf, 132, fp) == NULL) {\r
- prout("Spock- \"Captain, there is no information on that command.\"");\r
- fclose(fp);\r
- return;\r
- }\r
- } while (strncmp(linebuf, cmdbuf, i) != 0);\r
-\r
- skip(1);\r
- prout("Spock- \"Captain, I've found the following information:\"");\r
- skip(1);\r
-\r
- do {\r
- if (linebuf[0]!=12) { // ignore page break lines \r
- linebuf[strlen(linebuf)-1] = '\0'; // No \n at end\r
- prout(linebuf);\r
- }\r
- fgets(linebuf,132,fp);\r
- } while (strstr(linebuf, "******")==NULL);\r
- fclose(fp);\r
-}\r
-\r
-static void makemoves(void) {\r
- int i, hitme;\r
- char ch;\r
- while (TRUE) { /* command loop */\r
- hitme = FALSE;\r
- justin = 0;\r
- Time = 0.0;\r
- i = -1;\r
- while (TRUE) { /* get a command */\r
- chew();\r
- skip(1);\r
- proutn("COMMAND> ");\r
- if (scan() == IHEOL) continue;\r
- for (i=0; i < 26; i++)\r
- if (isit(commands[i]))\r
- break;\r
- if (i < 26) break;\r
- for (; i < NUMCOMMANDS; i++)\r
- if (strcmp(commands[i], citem) == 0) break;\r
- if (i < NUMCOMMANDS) break;\r
-\r
- if (skill <= 2) {\r
- prout("UNRECOGNIZED COMMAND. LEGAL COMMANDS ARE:");\r
- listCommands(TRUE);\r
- }\r
- else prout("UNRECOGNIZED COMMAND.");\r
- }\r
- switch (i) { /* command switch */\r
- case 0: // srscan\r
- srscan(1);\r
- break;\r
- case 1: // lrscan\r
- lrscan();\r
- break;\r
- case 2: // phasers\r
- phasers();\r
- if (ididit) hitme = TRUE;\r
- break;\r
- case 3: // photons\r
- photon();\r
- if (ididit) hitme = TRUE;\r
- break;\r
- case 4: // move\r
- warp(1);\r
- break;\r
- case 5: // shields\r
- doshield(1);\r
- if (ididit) {\r
- attack(2);\r
- shldchg = 0;\r
- }\r
- break;\r
- case 6: // dock\r
- dock();\r
- break;\r
- case 7: // damages\r
- dreprt();\r
- break;\r
- case 8: // chart\r
- chart(0);\r
- break;\r
- case 9: // impulse\r
- impuls();\r
- break;\r
- case 10: // rest\r
- wait();\r
- if (ididit) hitme = TRUE;\r
- break;\r
- case 11: // warp\r
- setwrp();\r
- break;\r
- case 12: // status\r
- srscan(3);\r
- break;\r
- case 13: // sensors\r
- sensor();\r
- break;\r
- case 14: // orbit\r
- orbit();\r
- if (ididit) hitme = TRUE;\r
- break;\r
- case 15: // transport "beam"\r
- beam();\r
- break;\r
- case 16: // mine\r
- mine();\r
- if (ididit) hitme = TRUE;\r
- break;\r
- case 17: // crystals\r
- usecrystals();\r
- break;\r
- case 18: // shuttle\r
- shuttle();\r
- if (ididit) hitme = TRUE;\r
- break;\r
- case 19: // Planet list\r
- preport();\r
- break;\r
- case 20: // Status information\r
- srscan(2);\r
- break;\r
- case 21: // Game Report \r
- report(0);\r
- break;\r
- case 22: // use COMPUTER!\r
- eta();\r
- break;\r
- case 23:\r
- listCommands(TRUE);\r
- break;\r
- case 24: // Emergency exit\r
- clearscreen(); // Hide screen\r
- freeze(TRUE); // forced save\r
- exit(1); // And quick exit\r
- break;\r
- case 25:\r
- probe(); // Launch probe\r
- break;\r
- case 26: // Abandon Ship\r
- abandn();\r
- break;\r
- case 27: // Self Destruct\r
- dstrct();\r
- break;\r
- case 28: // Save Game\r
- freeze(FALSE);\r
- if (skill > 3)\r
- prout("WARNING--Frozen games produce no plaques!");\r
- break;\r
- case 29: // Try a desparation measure\r
- deathray();\r
- if (ididit) hitme = TRUE;\r
- break;\r
- case 30: // What do we want for debug???\r
-#ifdef DEBUG\r
- debugme();\r
-#endif\r
- break;\r
- case 31: // Call for help\r
- help();\r
- break;\r
- case 32:\r
- alldone = 1; // quit the game\r
-#ifdef DEBUG\r
- if (idebug) score();\r
-#endif\r
- break;\r
- case 33:\r
- helpme(); // get help\r
- break;\r
- }\r
- for (;;) {\r
- if (alldone) break; // Game has ended\r
-#ifdef DEBUG\r
- if (idebug) prout("2500");\r
-#endif\r
- if (Time != 0.0) {\r
- events();\r
- if (alldone) break; // Events did us in\r
- }\r
- if (game.state.galaxy[quadx][quady] == 1000) { // Galaxy went Nova!\r
- atover(0);\r
- continue;\r
- }\r
- if (nenhere == 0) movetho();\r
- if (hitme && justin==0) {\r
- attack(2);\r
- if (alldone) break;\r
- if (game.state.galaxy[quadx][quady] == 1000) { // went NOVA! \r
- atover(0);\r
- hitme = TRUE;\r
- continue;\r
- }\r
- }\r
- break;\r
- }\r
- if (alldone) break;\r
- }\r
-}\r
-\r
-\r
-int main(int argc, char **argv) {\r
- int i;\r
- int hitme;\r
- char ch;\r
- prelim();\r
-\r
- if (argc > 1) {\r
- fromcommandline = 1;\r
- line[0] = '\0';\r
- while (--argc > 0) {\r
- strcat(line, *(++argv));\r
- strcat(line, " ");\r
- }\r
- }\r
- else fromcommandline = 0;\r
-\r
-\r
- while (TRUE) { /* Play a game */\r
- setup();\r
- if (alldone) {\r
- score();\r
- alldone = 0;\r
- }\r
- else makemoves();\r
- skip(2);\r
- stars();\r
- skip(1);\r
-\r
- if (tourn && alldone) {\r
- proutn("Do you want your score recorded?");\r
- if (ja()) {\r
- chew2();\r
- freeze(FALSE);\r
- }\r
- }\r
- proutn("Do you want to play again?");\r
- if (!ja()) break;\r
- }\r
- skip(1);\r
- prout("May the Great Bird of the Galaxy roost upon your home planet.");\r
-}\r
-\r
-\r
-void cramen(int i) {\r
- /* return an enemy */\r
- char *s;\r
- \r
- switch (i) {\r
- case IHR: s = "Romulan"; break;\r
- case IHK: s = "Klingon"; break;\r
- case IHC: s = "Commander"; break;\r
- case IHS: s = "Super-commander"; break;\r
- case IHSTAR: s = "Star"; break;\r
- case IHP: s = "Planet"; break;\r
- case IHB: s = "Starbase"; break;\r
- case IHBLANK: s = "Black hole"; break;\r
- case IHT: s = "Tholian"; break;\r
- case IHWEB: s = "Tholian web"; break;\r
- default: s = "Unknown??"; break;\r
- }\r
- proutn(s);\r
-}\r
-\r
-void cramlc(int key, int x, int y) {\r
- if (key == 1) proutn(" Quadrant");\r
- else if (key == 2) proutn(" Sector");\r
- proutn(" %d - %d", x, y);\r
-}\r
-\r
-void crmena(int i, int enemy, int key, int x, int y) {\r
- if (i == 1) proutn("***");\r
- cramen(enemy);\r
- proutn(" at");\r
- cramlc(key, x, y);\r
-}\r
-\r
-void crmshp(void) {\r
- char *s;\r
- switch (ship) {\r
- case IHE: s = "Enterprise"; break;\r
- case IHF: s = "Faerie Queene"; break;\r
- default: s = "Ship???"; break;\r
- }\r
- proutn(s);\r
-}\r
-\r
-void stars(void) {\r
- prouts("******************************************************");\r
- skip(1);\r
-}\r
-\r
-double expran(double avrage) {\r
- return -avrage*log(1e-7 + Rand());\r
-}\r
-\r
-double Rand(void) {\r
- return rand()/(1.0 + (double)RAND_MAX);\r
-}\r
-\r
-void iran8(int *i, int *j) {\r
- *i = Rand()*8.0 + 1.0;\r
- *j = Rand()*8.0 + 1.0;\r
-}\r
-\r
-void iran10(int *i, int *j) {\r
- *i = Rand()*10.0 + 1.0;\r
- *j = Rand()*10.0 + 1.0;\r
-}\r
-\r
-void chew(void) {\r
- linecount = 0;\r
- linep = line;\r
- *linep = 0;\r
-}\r
-\r
-void chew2(void) {\r
- /* return IHEOL next time */\r
- linecount = 0;\r
- linep = line+1;\r
- *linep = 0;\r
-}\r
-\r
-int scan(void) {\r
- int i;\r
- char *cp;\r
-\r
- linecount = 0;\r
-\r
- // Init result\r
- aaitem = 0.0;\r
- *citem = 0;\r
-\r
- // Read a line if nothing here\r
- if (*linep == 0) {\r
- if (linep != line) {\r
- chew();\r
- return IHEOL;\r
- }\r
- fgets(line, sizeof(line), stdin);\r
- line[strlen(line)-1] = '\0';\r
- linep = line;\r
- }\r
- // Skip leading white space\r
- while (*linep == ' ') linep++;\r
- // Nothing left\r
- if (*linep == 0) {\r
- chew();\r
- return IHEOL;\r
- }\r
- if (isdigit(*linep) || *linep=='+' || *linep=='-' || *linep=='.') {\r
- // treat as a number\r
- if (sscanf(linep, "%lf%n", &aaitem, &i) < 1) {\r
- linep = line; // Invalid numbers are ignored\r
- *linep = 0;\r
- return IHEOL;\r
- }\r
- else {\r
- // skip to end\r
- linep += i;\r
- return IHREAL;\r
- }\r
- }\r
- // Treat as alpha\r
- cp = citem;\r
- while (*linep && *linep!=' ') {\r
- if ((cp - citem) < 9) *cp++ = tolower(*linep);\r
- linep++;\r
- }\r
- *cp = 0;\r
- return IHALPHA;\r
-}\r
-\r
-int ja(void) {\r
- chew();\r
- while (TRUE) {\r
- scan();\r
- chew();\r
- if (*citem == 'y') return TRUE;\r
- if (*citem == 'n') return FALSE;\r
- proutn("Please answer with \"Y\" or \"N\":");\r
- }\r
-}\r
-\r
-void cramf(double x, int w, int d) {\r
- char buf[64];\r
- sprintf(buf, "%*.*f", w, d, x);\r
- proutn(buf);\r
-}\r
-\r
-double square(double i) { return i*i; }\r
- \r
-static void clearscreen(void) {\r
- /* Somehow we need to clear the screen */\r
-#ifdef __BORLANDC__\r
- extern void clrscr(void);\r
- clrscr();\r
-#else\r
- proutn("\033[2J"); /* Hope for an ANSI display */\r
-#endif\r
-}\r
-\r
-/* We will pull these out in case we want to do something special later */\r
-\r
-void pause(int i) {\r
- putchar('\n');\r
- if (i==1) {\r
- if (skill > 2)\r
- prout("[ANOUNCEMENT ARRIVING...]");\r
- else\r
- prout("[IMPORTANT ANNOUNCEMENT ARRIVING -- HIT SPACE BAR TO CONTINUE]");\r
- getch();\r
- }\r
- else {\r
- if (skill > 2)\r
- proutn("[CONTINUE?]");\r
- else\r
- proutn("[HIT SPACE BAR TO CONTINUE]");\r
- getch();\r
- proutn("\r \r");\r
- }\r
- if (i != 0) {\r
- clearscreen();\r
- }\r
- linecount = 0;\r
-}\r
-\r
-\r
-void skip(int i) {\r
- while (i-- > 0) {\r
- linecount++;\r
- if (linecount >= 23)\r
- pause(0);\r
- else\r
- putchar('\n');\r
- }\r
-}\r
-\r
-\r
-void proutn(char *fmt, ...) {\r
- va_list ap;\r
- va_start(ap, fmt);\r
- vprintf(fmt, ap);\r
- va_end(ap);\r
-}\r
-\r
-void prout(char *fmt, ...) {\r
- va_list ap;\r
- va_start(ap, fmt);\r
- vprintf(fmt, ap);\r
- va_end(ap);\r
- skip(1);\r
-}\r
-\r
-void prouts(char *fmt, ...) {\r
- clock_t endTime;\r
- char *s, buf[BUFSIZ];\r
- /* print slowly! */\r
- va_list ap;\r
- va_start(ap, fmt);\r
- vsprintf(buf, fmt, ap);\r
- va_end(ap);\r
- skip(1);\r
- for (s = buf; *s; s++) {\r
- endTime = clock() + CLOCKS_PER_SEC*0.05;\r
- while (clock() < endTime) ;\r
- putchar(*s);\r
- fflush(stdout);\r
- }\r
-}\r
-\r
-void huh(void) {\r
- chew();\r
- skip(1);\r
- prout("Beg your pardon, Captain?");\r
-}\r
-\r
-int isit(char *s) {\r
- /* New function -- compares s to scaned citem and returns true if it\r
- matches to the length of s */\r
-\r
- return strncmp(s, citem, max(1, strlen(citem))) == 0;\r
-\r
-}\r
-\r
-#ifdef DEBUG\r
-void debugme(void) {\r
- proutn("Reset levels? ");\r
- if (ja() != 0) {\r
- if (energy < inenrg) energy = inenrg;\r
- shield = inshld;\r
- torps = intorps;\r
- lsupres = inlsr;\r
- }\r
- proutn("Reset damage? ");\r
- if (ja() != 0) {\r
- int i;\r
- for (i=0; i <= NDEVICES; i++) if (damage[i] > 0.0) damage[i] = 0.0;\r
- stdamtim = 1e30;\r
- }\r
- proutn("Toggle idebug? ");\r
- if (ja() != 0) {\r
- idebug = !idebug;\r
- if (idebug) prout("Debug output ON");\r
- else prout("Debug output OFF");\r
- }\r
- proutn("Cause selective damage? ");\r
- if (ja() != 0) {\r
- int i, key;\r
- for (i=1; i <= NDEVICES; i++) {\r
- proutn("Kill ");\r
- proutn(device[i]);\r
- proutn("? ");\r
- chew();\r
- key = scan();\r
- if (key == IHALPHA && isit("y")) {\r
- damage[i] = 10.0;\r
- if (i == DRADIO) stdamtim = game.state.date;\r
- }\r
- }\r
- }\r
- proutn("Examine/change events? ");\r
- if (ja() != 0) {\r
- int i;\r
- for (i = 1; i < NEVENTS; i++) {\r
- int key;\r
- if (future[i] == 1e30) continue;\r
- switch (i) {\r
- case FSNOVA: proutn("Supernova "); break;\r
- case FTBEAM: proutn("T Beam "); break;\r
- case FSNAP: proutn("Snapshot "); break;\r
- case FBATTAK: proutn("Base Attack "); break;\r
- case FCDBAS: proutn("Base Destroy "); break;\r
- case FSCMOVE: proutn("SC Move "); break;\r
- case FSCDBAS: proutn("SC Base Destroy "); break;\r
- }\r
- cramf(future[i]-game.state.date, 8, 2);\r
- chew();\r
- proutn(" ?");\r
- key = scan();\r
- if (key == IHREAL) {\r
- future[i] = game.state.date + aaitem;\r
- }\r
- }\r
- chew();\r
- }\r
-}\r
- \r
-\r
-#endif\r
+#define INCLUDED // Define externs here
+#include <ctype.h>
+#include <getopt.h>
+#include <time.h>
+#include "sstlinux.h"
+#include "sst.h"
+
+#ifndef SSTDOC
+#define SSTDOC "sst.doc"
+#endif
+
+/*
+
+Dave Matuszek says:
+
+ SRSCAN, MOVE, PHASERS, CALL, STATUS, IMPULSE, PHOTONS, ABANDON,
+ LRSCAN, WARP, SHIELDS, DESTRUCT, CHART, REST, DOCK, QUIT, and DAMAGE
+ were in the original non-"super" version.
+
+ Tholians weren't in the original. Dave is dubious about their merits.
+
+ Planets and dilithium crystals weren't in the original. Dave is OK
+ with this idea. He says the bit about the Galileo getting
+ turned into a McDonald's is "consistant with our original vision".
+
+ Dave also says the Space Thingy should not be preserved across saved
+ games, so you can't prove to others that you've seen it. He says it
+ shouldn't fire back, either. It should do nothing except scream and
+ disappear when hit by photon torpedos. It's OK that it may move
+ when attacked, but it didn't in the original.
+
+ The Faerie Queen, black holes, and time warping were in the original.
+
+Here are Tom Almy's changes:
+
+ Compared to original version, I've changed the "help" command to
+ "call" and the "terminate" command to "quit" to better match
+ user expectations. The DECUS version apparently made those changes
+ as well as changing "freeze" to "save". However I like "freeze".
+
+ When I got a later version of Super Star Trek that I was converting
+ from, I added the emexit command.
+
+ That later version also mentions srscan and lrscan working when
+ docked (using the starbase's scanners), so I made some changes here
+ to do this (and indicating that fact to the player), and then realized
+ the base would have a subspace radio as well -- doing a Chart when docked
+ updates the star chart, and all radio reports will be heard. The Dock
+ command will also give a report if a base is under attack.
+
+ Movecom no longer reports movement if sensors are damaged so you wouldn't
+ otherwise know it.
+
+ Also added:
+
+ 1. Better base positioning at startup
+
+ 2. Deathray improvement (but keeping original failure alternatives)
+
+ 3. Tholian Web.
+
+ 4. Enemies can ram the Enterprise. Regular Klingons and Romulans can
+ move in Expert and Emeritus games. This code could use improvement.
+
+ 5. The deep space probe looks interesting! DECUS version
+
+ 6. Perhaps cloaking to be added later? BSD version
+
+Here are Stas Sergeev's changes:
+
+ 1. The Space Thingy can be shoved, if you ram it, and can fire back if
+ fired upon.
+
+ 2. The Tholian can be hit with phasers
+
+ 3. When you are docked, base covers you with an almost invincible shields
+ (a commander can still ram you, or a Romulan can destroy the base,
+ or a SCom can even succeed with direct attack IIRC, but this rarely
+ happens).
+
+ 4. SCom can't escape from you if no more enemies remain (without this,
+ chasing SCom can take an eternity).
+
+ 5. Probe target you enter is now the destination quadrant. Before I don't
+ remember what it was, but it was something I had difficulty using)
+
+ 6. Secret password is now autogenerated.
+
+ 7. "Plaque" is adjusted for A4 paper :-)
+
+ 8. Phasers now tells you how much energy needed, but only if the computer
+ is alive.
+
+ 9. Planets are auto-scanned when you enter the quadrant.
+
+ 10. Mining or using crystals in presense of enemy now yields an attack.
+ There are other minor adjustments to what yields an attack
+ and what does not.
+
+ 11. Ramming a black hole is no longer instant death. There is a
+ chance you might get timewarped instead.
+
+ 12. "freeze" command reverts to "save", most people will understand this
+ better anyway.
+
+ 13. Screen-oriented interface, with sensor scans always up.
+
+Eric Raymond's changes:
+
+ Mainly, I translated this C code out of FORTRAN into C -- created #defines
+ for a lot of magic numbers and refactored the heck out of it.
+
+ 1. "sos" and "call" becomes "mayday", "freeze" and "save" are both good.
+
+ 2. Status report now indicates when dilithium crystals are on board.
+
+ 3. Per Dave Matuszek's remarks, Thingy state is not saved across games.
+ */
+
+/* the input queue */
+static char line[128], *linep = line;
+
+static struct
+{
+ char *name;
+ int value;
+ unsigned long option;
+}
+commands[] = {
+#define SRSCAN 0
+ {"SRSCAN", SRSCAN, OPTION_TTY},
+#define STATUS 1
+ {"STATUS", STATUS, OPTION_TTY},
+#define REQUEST 2
+ {"REQUEST", REQUEST, OPTION_TTY},
+#define LRSCAN 3
+ {"LRSCAN", LRSCAN, OPTION_TTY},
+#define PHASERS 4
+ {"PHASERS", PHASERS, 0},
+#define TORPEDO 5
+ {"TORPEDO", TORPEDO, 0},
+ {"PHOTONS", TORPEDO, 0},
+#define MOVE 6
+ {"MOVE", MOVE, 0},
+#define SHIELDS 7
+ {"SHIELDS", SHIELDS, 0},
+#define DOCK 8
+ {"DOCK", DOCK, 0},
+#define DAMAGES 9
+ {"DAMAGES", DAMAGES, 0},
+#define CHART 10
+ {"CHART", CHART, 0},
+#define IMPULSE 11
+ {"IMPULSE", IMPULSE, 0},
+#define REST 12
+ {"REST", REST, 0},
+#define WARP 13
+ {"WARP", WARP, 0},
+#define SCORE 14
+ {"SCORE", SCORE, 0},
+#define SENSORS 15
+ {"SENSORS", SENSORS, OPTION_PLANETS},
+#define ORBIT 16
+ {"ORBIT", ORBIT, OPTION_PLANETS},
+#define TRANSPORT 17
+ {"TRANSPORT", TRANSPORT, OPTION_PLANETS},
+#define MINE 18
+ {"MINE", MINE, OPTION_PLANETS},
+#define CRYSTALS 19
+ {"CRYSTALS", CRYSTALS, OPTION_PLANETS},
+#define SHUTTLE 20
+ {"SHUTTLE", SHUTTLE, OPTION_PLANETS},
+#define PLANETS 21
+ {"PLANETS", PLANETS, OPTION_PLANETS},
+#define REPORT 22
+ {"REPORT", REPORT, 0},
+#define COMPUTER 23
+ {"COMPUTER", COMPUTER, 0},
+#define COMMANDS 24
+ {"COMMANDS", COMMANDS, 0},
+#define EMEXIT 25
+ {"EMEXIT", EMEXIT, 0},
+#define PROBE 26
+ {"PROBE", PROBE, OPTION_PROBE},
+#define SAVE 27
+ {"SAVE", SAVE, 0},
+ {"FREEZE", SAVE, 0},
+#define ABANDON 28
+ {"ABANDON", ABANDON, 0},
+#define DESTRUCT 29
+ {"DESTRUCT", DESTRUCT, 0},
+#define DEATHRAY 30
+ {"DEATHRAY", DEATHRAY, 0},
+#define DEBUGCMD 31
+ {"DEBUG", DEBUGCMD, 0},
+#define MAYDAY 32
+ {"MAYDAY", MAYDAY, 0},
+ {"SOS", MAYDAY, 0},
+ {"CALL", MAYDAY, 0},
+#define QUIT 33
+ {"QUIT", QUIT, 0},
+#define HELP 34
+ {"HELP", HELP, 0},
+};
+
+#define NUMCOMMANDS sizeof(commands)/sizeof(commands[0])
+
+static void listCommands(void) {
+ int i, k = 0;
+ proutn("LEGAL COMMANDS ARE:");
+ for (i = 0; i < NUMCOMMANDS; i++) {
+ if (commands[i].option && !(commands[i].option & game.options))
+ continue;
+ if (k % 5 == 0)
+ skip(1);
+ proutn("%-12s ", commands[i].name);
+ k++;
+ }
+ skip(1);
+}
+
+static void helpme(void)
+{
+ int i, j;
+ char cmdbuf[32], *cp;
+ char linebuf[132];
+ FILE *fp;
+ /* Give help on commands */
+ int key;
+ key = scan();
+ while (TRUE) {
+ if (key == IHEOL) {
+ setwnd(prompt_window);
+ proutn("Help on what command? ");
+ key = scan();
+ }
+ setwnd(message_window);
+ if (key == IHEOL) return;
+ for (i = 0; i < NUMCOMMANDS; i++) {
+ if (strcasecmp(commands[i].name, citem)==0) {
+ i = commands[i].value;
+ break;
+ }
+ }
+ if (i != NUMCOMMANDS) break;
+ skip(1);
+ prout("Valid commands:");
+ listCommands();
+ key = IHEOL;
+ chew();
+ skip(1);
+ }
+ if (i == COMMANDS) {
+ strcpy(cmdbuf, " ABBREV");
+ }
+ else {
+ for (j = 0; commands[i].name[j]; j++)
+ cmdbuf[j] = toupper(commands[i].name[j]);
+ cmdbuf[j] = '\0';
+ }
+ fp = fopen(SSTDOC, "r");
+ if (fp == NULL) {
+ prout("Spock- \"Captain, that information is missing from the");
+ prout(" computer.\"");
+ /*
+ * This used to continue: "You need to find SST.DOC and put
+ * it in the current directory."
+ */
+ return;
+ }
+ for (;;) {
+ if (fgets(linebuf, sizeof(linebuf), fp) == NULL) {
+ prout("Spock- \"Captain, there is no information on that command.\"");
+ fclose(fp);
+ return;
+ }
+ if (linebuf[0] == '%' && linebuf[1] == '%'&& linebuf[2] == ' ') {
+ for (cp = linebuf+3; isspace(*cp); cp++)
+ continue;
+ linebuf[strlen(linebuf)-1] = '\0';
+ if (strcasecmp(cp, cmdbuf) == 0)
+ break;
+ }
+ }
+
+ skip(1);
+ prout("Spock- \"Captain, I've found the following information:\"");
+ skip(1);
+
+ while (fgets(linebuf, sizeof(linebuf),fp)) {
+ if (strstr(linebuf, "******"))
+ break;
+ proutn(linebuf);
+ }
+ fclose(fp);
+}
+
+void enqueue(char *s)
+{
+ strcpy(line, s);
+}
+
+static void makemoves(void)
+{
+ int i, v = 0, hitme;
+ clrscr();
+ setwnd(message_window);
+ while (TRUE) { /* command loop */
+ drawmaps(1);
+ while (TRUE) { /* get a command */
+ hitme = FALSE;
+ justin = 0;
+ Time = 0.0;
+ i = -1;
+ chew();
+ setwnd(prompt_window);
+ clrscr();
+ proutn("COMMAND> ");
+ if (scan() == IHEOL) {
+ makechart();
+ continue;
+ }
+ ididit=0;
+ clrscr();
+ setwnd(message_window);
+ clrscr();
+ for (i=0; i < ABANDON; i++)
+ if (isit(commands[i].name)) {
+ v = commands[i].value;
+ break;
+ }
+ if (i < ABANDON && (!commands[i].option || (commands[i].option & game.options)))
+ break;
+ for (; i < NUMCOMMANDS; i++)
+ if (strcasecmp(commands[i].name, citem) == 0) {
+ v = commands[i].value;
+ break;
+ }
+ if (i < NUMCOMMANDS && (!commands[i].option || (commands[i].option & game.options)))
+ break;
+ listCommands();
+ }
+ commandhook(commands[i].name, TRUE);
+ switch (v) { /* command switch */
+ case SRSCAN: // srscan
+ srscan(SCAN_FULL);
+ break;
+ case STATUS: // status
+ srscan(SCAN_STATUS);
+ break;
+ case REQUEST: // status request
+ srscan(SCAN_REQUEST);
+ break;
+ case LRSCAN: // lrscan
+ lrscan();
+ break;
+ case PHASERS: // phasers
+ phasers();
+ if (ididit) hitme = TRUE;
+ break;
+ case TORPEDO: // photons
+ photon();
+ if (ididit) hitme = TRUE;
+ break;
+ case MOVE: // move
+ warp(1);
+ break;
+ case SHIELDS: // shields
+ doshield(1);
+ if (ididit) {
+ hitme=TRUE;
+ shldchg = 0;
+ }
+ break;
+ case DOCK: // dock
+ dock(1);
+ if (ididit) attack(0);
+ break;
+ case DAMAGES: // damages
+ dreprt();
+ break;
+ case CHART: // chart
+ chart(0);
+ break;
+ case IMPULSE: // impulse
+ impuls();
+ break;
+ case REST: // rest
+ wait();
+ if (ididit) hitme = TRUE;
+ break;
+ case WARP: // warp
+ setwrp();
+ break;
+ case SCORE: // score
+ score();
+ break;
+ case SENSORS: // sensors
+ sensor(TRUE);
+ break;
+ case ORBIT: // orbit
+ orbit();
+ if (ididit) hitme = TRUE;
+ break;
+ case TRANSPORT: // transport "beam"
+ beam();
+ break;
+ case MINE: // mine
+ mine();
+ if (ididit) hitme = TRUE;
+ break;
+ case CRYSTALS: // crystals
+ usecrystals();
+ if (ididit) hitme = TRUE;
+ break;
+ case SHUTTLE: // shuttle
+ shuttle();
+ if (ididit) hitme = TRUE;
+ break;
+ case PLANETS: // Planet list
+ preport();
+ break;
+ case REPORT: // Game Report
+ report();
+ break;
+ case COMPUTER: // use COMPUTER!
+ eta();
+ break;
+ case COMMANDS:
+ listCommands();
+ break;
+ case EMEXIT: // Emergency exit
+ clrscr(); // Hide screen
+ freeze(TRUE); // forced save
+ exit(1); // And quick exit
+ break;
+ case PROBE:
+ probe(); // Launch probe
+ if (ididit) hitme = TRUE;
+ break;
+ case ABANDON: // Abandon Ship
+ abandn();
+ break;
+ case DESTRUCT: // Self Destruct
+ dstrct();
+ break;
+ case SAVE: // Save Game
+ freeze(FALSE);
+ clrscr();
+ if (skill > SKILL_GOOD)
+ prout("WARNING--Saved games produce no plaques!");
+ break;
+ case DEATHRAY: // Try a desparation measure
+ deathray();
+ if (ididit) hitme = TRUE;
+ break;
+ case DEBUGCMD: // What do we want for debug???
+#ifdef DEBUG
+ debugme();
+#endif
+ break;
+ case MAYDAY: // Call for help
+ help();
+ if (ididit) hitme = TRUE;
+ break;
+ case QUIT:
+ alldone = 1; // quit the game
+#ifdef DEBUG
+ if (idebug) score();
+#endif
+ break;
+ case HELP:
+ helpme(); // get help
+ break;
+ }
+ commandhook(commands[i].name, FALSE);
+ for (;;) {
+ if (alldone) break; // Game has ended
+#ifdef DEBUG
+ if (idebug) prout("2500");
+#endif
+ if (Time != 0.0) {
+ events();
+ if (alldone) break; // Events did us in
+ }
+ if (game.state.galaxy[quadx][quady].supernova) { // Galaxy went Nova!
+ atover(0);
+ continue;
+ }
+ if (hitme && justin==0) {
+ attack(2);
+ if (alldone) break;
+ if (game.state.galaxy[quadx][quady].supernova) { // went NOVA!
+ atover(0);
+ hitme = TRUE;
+ continue;
+ }
+ }
+ break;
+ }
+ if (alldone) break;
+ }
+}
+
+
+int main(int argc, char **argv)
+{
+ int i, option;
+
+ game.options = OPTION_ALL &~ OPTION_IOMODES;
+ if (getenv("TERM"))
+ game.options |= OPTION_CURSES;
+ else
+ game.options |= OPTION_TTY;
+
+ while ((option = getopt(argc, argv, "t")) != -1) {
+ switch (option) {
+ case 't':
+ game.options |= OPTION_TTY;
+ game.options &=~ OPTION_CURSES;
+ break;
+ default:
+ fprintf(stderr, "usage: sst [-t] [startcommand...].\n");
+ exit(0);
+ }
+ }
+
+ randomize();
+ iostart();
+
+ line[0] = '\0';
+ for (i = optind; i < argc; i++) {
+ strcat(line, argv[i]);
+ strcat(line, " ");
+ }
+ while (TRUE) { /* Play a game */
+ setwnd(fullscreen_window);
+#ifdef DEBUG
+ prout("INITIAL OPTIONS: %0lx\n", game.options);
+#endif /* DEBUG */
+ clrscr();
+ prelim();
+ setup(line[0] == '\0');
+ if (alldone) {
+ score();
+ alldone = 0;
+ }
+ else makemoves();
+ skip(1);
+ stars();
+ skip(1);
+
+ if (tourn && alldone) {
+ proutn("Do you want your score recorded?");
+ if (ja()) {
+ chew2();
+ freeze(FALSE);
+ }
+ }
+ proutn("Do you want to play again? ");
+ if (!ja()) break;
+ }
+ skip(1);
+ prout("May the Great Bird of the Galaxy roost upon your home planet.");
+ return 0;
+}
+
+
+void cramen(int i)
+{
+ /* return an enemy */
+ char *s;
+
+ switch (i) {
+ case IHR: s = "Romulan"; break;
+ case IHK: s = "Klingon"; break;
+ case IHC: s = "Commander"; break;
+ case IHS: s = "Super-commander"; break;
+ case IHSTAR: s = "Star"; break;
+ case IHP: s = "Planet"; break;
+ case IHB: s = "Starbase"; break;
+ case IHBLANK: s = "Black hole"; break;
+ case IHT: s = "Tholian"; break;
+ case IHWEB: s = "Tholian web"; break;
+ case IHQUEST: s = "Stranger"; break;
+ default: s = "Unknown??"; break;
+ }
+ proutn(s);
+}
+
+char *cramlc(enum loctype key, int x, int y)
+{
+ static char buf[32];
+ buf[0] = '\0';
+ if (key == quadrant) strcpy(buf, "Quadrant ");
+ else if (key == sector) strcpy(buf, "Sector ");
+ sprintf(buf+strlen(buf), "%d - %d", x, y);
+ return buf;
+}
+
+void crmena(int i, int enemy, int key, int x, int y)
+{
+ if (i == 1) proutn("***");
+ cramen(enemy);
+ proutn(" at ");
+ proutn(cramlc(key, x, y));
+}
+
+void crmshp(void)
+{
+ char *s;
+ switch (ship) {
+ case IHE: s = "Enterprise"; break;
+ case IHF: s = "Faerie Queene"; break;
+ default: s = "Ship???"; break;
+ }
+ proutn(s);
+}
+
+void stars(void)
+{
+ prouts("******************************************************");
+ skip(1);
+}
+
+double expran(double avrage)
+{
+ return -avrage*log(1e-7 + Rand());
+}
+
+double Rand(void) {
+ return rand()/(1.0 + (double)RAND_MAX);
+}
+
+void iran(int size, int *i, int *j)
+{
+ *i = Rand()*(size*1.0) + 1.0;
+ *j = Rand()*(size*1.0) + 1.0;
+}
+
+void chew(void)
+{
+ linep = line;
+ *linep = 0;
+}
+
+void chew2(void)
+{
+ /* return IHEOL next time */
+ linep = line+1;
+ *linep = 0;
+}
+
+int scan(void)
+{
+ int i;
+ char *cp;
+
+ // Init result
+ aaitem = 0.0;
+ *citem = 0;
+
+ // Read a line if nothing here
+ if (*linep == 0) {
+ if (linep != line) {
+ chew();
+ return IHEOL;
+ }
+ cgetline(line, sizeof(line));
+ fflush(stdin);
+ if (curwnd==prompt_window){
+ clrscr();
+ setwnd(message_window);
+ clrscr();
+ }
+ linep = line;
+ }
+ // Skip leading white space
+ while (*linep == ' ') linep++;
+ // Nothing left
+ if (*linep == 0) {
+ chew();
+ return IHEOL;
+ }
+ if (isdigit(*linep) || *linep=='+' || *linep=='-' || *linep=='.') {
+ // treat as a number
+ i = 0;
+ if (sscanf(linep, "%lf%n", &aaitem, &i) < 1) {
+ linep = line; // Invalid numbers are ignored
+ *linep = 0;
+ return IHEOL;
+ }
+ else {
+ // skip to end
+ linep += i;
+ return IHREAL;
+ }
+ }
+ // Treat as alpha
+ cp = citem;
+ while (*linep && *linep!=' ') {
+ if ((cp - citem) < 9) *cp++ = tolower(*linep);
+ linep++;
+ }
+ *cp = 0;
+ return IHALPHA;
+}
+
+int ja(void)
+{
+ chew();
+ while (TRUE) {
+ scan();
+ chew();
+ if (*citem == 'y') return TRUE;
+ if (*citem == 'n') return FALSE;
+ proutn("Please answer with \"Y\" or \"N\": ");
+ }
+}
+
+void huh(void)
+{
+ chew();
+ skip(1);
+ prout("Beg your pardon, Captain?");
+}
+
+int isit(char *s)
+{
+ /* New function -- compares s to scanned citem and returns true if it
+ matches to the length of s */
+
+ return strncasecmp(s, citem, max(1, strlen(citem))) == 0;
+
+}
+
+#ifdef DEBUG
+void debugme(void)
+{
+ proutn("Reset levels? ");
+ if (ja() != 0) {
+ if (energy < inenrg) energy = inenrg;
+ shield = inshld;
+ torps = intorps;
+ lsupres = inlsr;
+ }
+ proutn("Reset damage? ");
+ if (ja() != 0) {
+ int i;
+ for (i=0; i < NDEVICES; i++)
+ if (game.damage[i] > 0.0)
+ game.damage[i] = 0.0;
+ stdamtim = 1e30;
+ }
+ proutn("Toggle idebug? ");
+ if (ja() != 0) {
+ idebug = !idebug;
+ if (idebug) prout("Debug output ON");
+ else prout("Debug output OFF");
+ }
+ proutn("Cause selective damage? ");
+ if (ja() != 0) {
+ int i, key;
+ for (i=0; i < NDEVICES; i++) {
+ proutn("Kill ");
+ proutn(device[i]);
+ proutn("? ");
+ chew();
+ key = scan();
+ if (key == IHALPHA && isit("y")) {
+ game.damage[i] = 10.0;
+ if (i == DRADIO) stdamtim = game.state.date;
+ }
+ }
+ }
+ proutn("Examine/change events? ");
+ if (ja() != 0) {
+ int i;
+ for (i = 1; i < NEVENTS; i++) {
+ int key;
+ if (game.future[i] == 1e30) continue;
+ switch (i) {
+ case FSNOVA: proutn("Supernova "); break;
+ case FTBEAM: proutn("T Beam "); break;
+ case FSNAP: proutn("Snapshot "); break;
+ case FBATTAK: proutn("Base Attack "); break;
+ case FCDBAS: proutn("Base Destroy "); break;
+ case FSCMOVE: proutn("SC Move "); break;
+ case FSCDBAS: proutn("SC Base Destroy "); break;
+ }
+ proutn("%.2f", game.future[i]-game.state.date);
+ chew();
+ proutn(" ?");
+ key = scan();
+ if (key == IHREAL) {
+ game.future[i] = game.state.date + aaitem;
+ }
+ }
+ chew();
+ }
+}
+#endif