X-Git-Url: https://jxself.org/git/?p=super-star-trek.git;a=blobdiff_plain;f=sst.c;h=1d4ca2feb1d55d33a9e89a00d7a43326c0828f26;hp=3567c2551b8aa14c25d622fdcc77a5de6d3097b4;hb=f1af4f83e663d93c704ce0ada75ea4aa9ae3c65b;hpb=1072751ee59a11b65fe84d0314fee4bbcf14990e diff --git a/sst.c b/sst.c index 3567c25..1d4ca2f 100644 --- a/sst.c +++ b/sst.c @@ -1,700 +1,806 @@ -#define INCLUDED // Define externs here -#include -#include -#include "sst.h" - -#ifndef SSTDOC -#define SSTDOC "sst.doc" -#endif - -static char line[128], *linep = line; - -/* - -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 (controlled by the proprocessor symbol -SERGEEV, not yet completely merged): - - 1. The Space Thingy can be shoved, if you it ram, and can fire back if - fired upon. - - 1 The Tholian can be hit with phasers - - 2. 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). - - 3. SCom can't escape from you if no more enemies remain (without this, - chasing SCom can take an eternity). - - 4. 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) - - 5. Secret password is now autogenerated. - - 6. "Plaque" is adjusted for A4 paper:) - - 7. Phasers now tells you how much energy needed, but only if the computer - is alive. - - 8. Planets are auto-scanned when you enter the quadrant. - - 9. 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. - - 10. Ramming a black hole is no longer instant death. There is a - chance you might get timewarped instead. - - */ - -static char *commands[] = { - "srscan", - "lrscan", - "phasers", - "photons", - "move", - "shields", - "dock", - "damages", - "chart", - "impulse", - "rest", - "warp", - "status", - "sensors", - "orbit", - "transport", - "mine", - "crystals", - "shuttle", - "planets", - "request", - "report", - "computer", - "commands", - "emexit", - "probe", - "abandon", - "destruct", - "freeze", - "deathray", - "debug", - "call", - "quit", - "help" -}; -#define NUMCOMMANDS sizeof(commands)/sizeof(commands[0]) - -static void listCommands(int x) { - prout(" SRSCAN MOVE PHASERS CALL\n" - " STATUS IMPULSE PHOTONS ABANDON\n" - " LRSCAN WARP SHIELDS DESTRUCT\n" - " CHART REST DOCK QUIT\n" - " DAMAGES REPORT SENSORS ORBIT\n" - " TRANSPORT MINE CRYSTALS SHUTTLE\n" - " PLANETS REQUEST DEATHRAY FREEZE\n" - " COMPUTER EMEXIT PROBE COMMANDS"); - if (x) prout(" HELP"); -} - -#ifdef SERGEEV -void setwnd(short wndnum){ - int cury; - cury=wherey()+wnds[curwnd].wndtop-wnds[wndnum].wndtop; - if ((curwnd==0)&&(wndnum!=0)) clrscr(); - window(wnds[wndnum].wndleft, wnds[wndnum].wndtop, wnds[wndnum].wndright, wnds[wndnum].wndbottom); - if ((curwnd==wndnum)&&(cury>wnds[wndnum].wndbottom-wnds[wndnum].wndtop+1)){ - gotoxy(wnds[wndnum].wndright-wnds[wndnum].wndleft+1,wnds[wndnum].wndbottom-wnds[wndnum].wndtop+1); - skip(1); - } - curwnd=wndnum; - gotoxy(1,cury); -} -#endif /* SERGEEV */ - -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) { -#ifdef SERGEEV - setwnd(5); -#endif /* SERGEEV */ - proutn("Help on what command? "); - key = scan(); - } -#ifdef SERGEEV - setwnd(4); -#endif /* SERGEEV */ - if (key == IHEOL) return; - for (i = 0; i < NUMCOMMANDS; i++) { - if (strcmp(commands[i], citem)==0) break; - } - if (i != NUMCOMMANDS) break; - skip(1); - prout("Valid commands:"); - listCommands(FALSE); - key = IHEOL; - chew(); - skip(1); - } - if (i == 23) { - strcpy(cmdbuf, " ABBREV"); - } - else { - for (j = 0; commands[i][j]; j++) - cmdbuf[j] = toupper(commands[i][j]); - cmdbuf[j] = '\0'; - } - fp = fopen(SSTDOC, "r"); - if (fp == NULL) { - prout("Spock- \"Captain, that information is missing from the"); - prout(" computer. You need to find SST.DOC and put it in the"); - prout(" 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 (strcmp(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; - proutc(linebuf); - } - fclose(fp); -} - -#ifdef SERGEEV -void drawmaps(short l){ - _setcursortype(_NOCURSOR); - if (l==1) sensor(); - if (l!=2) setwnd(1); - gotoxy(1,1); - strcpy(line,"s"); - srscan(1); - if (l!=2){ - setwnd(2); - clrscr(); - srscan(2); - setwnd(3); - clrscr(); - strcpy(line,"l"); - lrscan(); - _setcursortype(_NORMALCURSOR); - } -} -#endif /* SERGEEV */ - -static void makemoves(void) { - int i, hitme; - while (TRUE) { /* command loop */ - hitme = FALSE; - justin = 0; - Time = 0.0; - i = -1; - while (TRUE) { /* get a command */ - chew(); - skip(1); - proutn("COMMAND> "); - if (scan() == IHEOL) continue; - for (i=0; i < 26; i++) - if (isit(commands[i])) - break; - if (i < 26) break; - for (; i < NUMCOMMANDS; i++) - if (strcmp(commands[i], citem) == 0) break; - if (i < NUMCOMMANDS) break; - - if (skill <= 2) { - prout("UNRECOGNIZED COMMAND. LEGAL COMMANDS ARE:"); - listCommands(TRUE); - } - else prout("UNRECOGNIZED COMMAND."); - } - commandhook(commands[i], TRUE); - switch (i) { /* command switch */ - case 0: // srscan - srscan(1); - break; - case 1: // lrscan - lrscan(); - break; - case 2: // phasers - phasers(); - if (ididit) hitme = TRUE; - break; - case 3: // photons - photon(); - if (ididit) hitme = TRUE; - break; - case 4: // move - warp(1); - break; - case 5: // shields - doshield(1); - if (ididit) { - attack(2); - shldchg = 0; - } - break; - case 6: // dock - dock(1); - if (ididit) attack(0); - break; - case 7: // damages - dreprt(); - break; - case 8: // chart - chart(0); - break; - case 9: // impulse - impuls(); - break; - case 10: // rest - wait(); - if (ididit) hitme = TRUE; - break; - case 11: // warp - setwrp(); - break; - case 12: // status - srscan(3); - break; - case 13: // sensors - sensor(); - break; - case 14: // orbit - orbit(); - if (ididit) hitme = TRUE; - break; - case 15: // transport "beam" - beam(); - break; - case 16: // mine - mine(); - if (ididit) hitme = TRUE; - break; - case 17: // crystals - usecrystals(); - break; - case 18: // shuttle - shuttle(); - if (ididit) hitme = TRUE; - break; - case 19: // Planet list - preport(); - break; - case 20: // Status information - srscan(2); - break; - case 21: // Game Report - report(0); - break; - case 22: // use COMPUTER! - eta(); - break; - case 23: - listCommands(TRUE); - break; - case 24: // Emergency exit - clearscreen(); // Hide screen - freeze(TRUE); // forced save - exit(1); // And quick exit - break; - case 25: - probe(); // Launch probe - break; - case 26: // Abandon Ship - abandn(); - break; - case 27: // Self Destruct - dstrct(); - break; - case 28: // Save Game - freeze(FALSE); - if (skill > 3) - prout("WARNING--Frozen games produce no plaques!"); - break; - case 29: // Try a desparation measure - deathray(); - if (ididit) hitme = TRUE; - break; - case 30: // What do we want for debug??? -#ifdef DEBUG - debugme(); -#endif - break; - case 31: // Call for help - help(); - break; - case 32: - alldone = 1; // quit the game -#ifdef DEBUG - if (idebug) score(); -#endif - break; - case 33: - helpme(); // get help - break; - } - commandhook(commands[i], 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] == 1000) { // Galaxy went Nova! - atover(0); - continue; - } - if (nenhere == 0) movetho(); - if (hitme && justin==0) { - attack(2); - if (alldone) break; - if (game.state.galaxy[quadx][quady] == 1000) { // went NOVA! - atover(0); - hitme = TRUE; - continue; - } - } - break; - } - if (alldone) break; - } -} - - -int main(int argc, char **argv) { - int i, option, usecurses = TRUE; - while ((option = getopt(argc, argv, "t")) != -1) { - switch (option) { - case 't': - usecurses = FALSE; - break; - default: - fprintf(stderr, "usage: sst [-t] [startcommand...].\n"); - exit(0); - } - } - - iostart(usecurses); - prelim(); - line[0] = '\0'; - for (i = optind; i < argc; i++) { - strcat(line, argv[i]); - strcat(line, " "); - } - while (TRUE) { /* Play a game */ - setup(line[0] == '\0'); - if (alldone) { - score(); - alldone = 0; - } - else makemoves(); - skip(2); - 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; -#ifdef SERGEEV - setwnd(0); - clrscr(); -#endif /* SERGEEV */ - } - skip(1); -#ifndef SERGEEV - ioend(); -#endif /* SERGEEV */ - puts("May the Great Bird of the Galaxy roost upon your home planet."); - exit(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 iran8(int *i, int *j) { - *i = Rand()*8.0 + 1.0; - *j = Rand()*8.0 + 1.0; -} - -void iran10(int *i, int *j) { - *i = Rand()*10.0 + 1.0; - *j = Rand()*10.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; - } - getline(line, sizeof(line)); - 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 scaned citem and returns true if it - matches to the length of s */ - - return strncmp(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 (damage[i] > 0.0) 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=1; i <= NDEVICES; i++) { - proutn("Kill "); - proutn(device[i]); - proutn("? "); - chew(); - key = scan(); - if (key == IHALPHA && isit("y")) { - 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 (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", future[i]-game.state.date); - chew(); - proutn(" ?"); - key = scan(); - if (key == IHREAL) { - future[i] = game.state.date + aaitem; - } - } - chew(); - } -} - - -#endif +#define INCLUDED // Define externs here +#include +#include +#include +#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]) +#define ACCEPT(i) (!commands[i].option || (commands[i].option & game.options)) + +static void listCommands(void) { + int i, k = 0; + proutn("LEGAL COMMANDS ARE:"); + for (i = 0; i < NUMCOMMANDS; i++) { + if (!ACCEPT(i)) + 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 (ACCEPT(i) && 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 (ACCEPT(i) && 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 (ACCEPT(i) && 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(); + 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 | OPTION_SHOWME); + if (getenv("TERM")) + game.options |= OPTION_CURSES | OPTION_SHOWME; + 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", 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; + } + 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; + } + } + } + proutn("Examine/change events? "); + if (ja() != 0) { + int i; + for (i = 1; i < NEVENTS; i++) { + int key; + if (game.future[i] == FOREVER) 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(); + } + proutn("Induce supernova here? "); + if (ja() != 0) { + game.state.galaxy[quadx][quady].supernova = TRUE; + atover(1); + } +} +#endif