X-Git-Url: https://jxself.org/git/?p=super-star-trek.git;a=blobdiff_plain;f=src%2Fsst.c;h=16199e6df68ccb8acd5fd54b1fcf2ab7e4b7f966;hp=4288bbbd8651e7e4c2ecfbb81c421108e4700a82;hb=ad1478c7cc24b761592a1e355015b44b243aeeda;hpb=52265793501a00845a0d6108d1af6e50e3ece379 diff --git a/src/sst.c b/src/sst.c index 4288bbb..16199e6 100644 --- a/src/sst.c +++ b/src/sst.c @@ -155,20 +155,34 @@ for a lot of magic numbers and refactored the heck out of it. 5. Half the quadrants now have inhabited planets, from which one cannot mine dilithium (there will still be the same additional number - of dilithium-bearing planets). Right now this is just color, but - eventually we'll fold in BSD-Trek-like logic for Klingons to attack - and enslave inhabited worlds. + of dilithium-bearing planets). Torpedoing an inhabited world is *bad*. + There is BSD-Trek-like logic for Klingons to attack and enslave + inhabited worlds, producing more ships (only is skill is 'good' or + better). (Controlled by OPTION_WORLDS and turned off if game + type is "plain" or "almy".) + + 6. User input is now logged so we can do regression testing. + + 7. More BSD-Trek features: You can now lose if your entire crew + dies in battle. When abandoning ship in a game with inhabited + worlds enabled, they must have one in the quadrant to beam down + to; otherwise they die in space and this counts heavily against + your score. Docking at a starbase replenishes your crew. */ /* the input queue */ static char line[128], *linep = line; struct game game; -int thingx, thingy, iqhere, iqengry; -int iscore, iskill; // Common PLAQ +coord thing; +bool iqhere, iqengry; +int iscore, iskill; // Common PLAQ double aaitem; double perdate; char citem[10]; +int seed; // the random-number seed +bool idebug; // debug mode +FILE *logfp, *replayfp; char *device[NDEVICES] = { "S. R. Sensors", @@ -208,67 +222,69 @@ commands[] = { #define TORPEDO 5 {"TORPEDO", TORPEDO, 0}, {"PHOTONS", TORPEDO, 0}, -#define MOVE 6 +#define MOVE 7 {"MOVE", MOVE, 0}, -#define SHIELDS 7 +#define SHIELDS 8 {"SHIELDS", SHIELDS, 0}, -#define DOCK 8 +#define DOCK 9 {"DOCK", DOCK, 0}, -#define DAMAGES 9 +#define DAMAGES 10 {"DAMAGES", DAMAGES, 0}, -#define CHART 10 +#define CHART 11 {"CHART", CHART, 0}, -#define IMPULSE 11 +#define IMPULSE 12 {"IMPULSE", IMPULSE, 0}, -#define REST 12 +#define REST 13 {"REST", REST, 0}, -#define WARP 13 +#define WARP 14 {"WARP", WARP, 0}, -#define SCORE 14 +#define SCORE 15 {"SCORE", SCORE, 0}, -#define SENSORS 15 +#define SENSORS 16 {"SENSORS", SENSORS, OPTION_PLANETS}, -#define ORBIT 16 +#define ORBIT 17 {"ORBIT", ORBIT, OPTION_PLANETS}, -#define TRANSPORT 17 +#define TRANSPORT 18 {"TRANSPORT", TRANSPORT, OPTION_PLANETS}, -#define MINE 18 +#define MINE 19 {"MINE", MINE, OPTION_PLANETS}, -#define CRYSTALS 19 +#define CRYSTALS 20 {"CRYSTALS", CRYSTALS, OPTION_PLANETS}, -#define SHUTTLE 20 +#define SHUTTLE 21 {"SHUTTLE", SHUTTLE, OPTION_PLANETS}, -#define PLANETS 21 +#define PLANETS 22 {"PLANETS", PLANETS, OPTION_PLANETS}, -#define REPORT 22 +#define REPORT 23 {"REPORT", REPORT, 0}, -#define COMPUTER 23 +#define COMPUTER 24 {"COMPUTER", COMPUTER, 0}, -#define COMMANDS 24 +#define COMMANDS 25 {"COMMANDS", COMMANDS, 0}, -#define EMEXIT 25 +#define EMEXIT 26 {"EMEXIT", EMEXIT, 0}, -#define PROBE 26 +#define PROBE 27 {"PROBE", PROBE, OPTION_PROBE}, -#define SAVE 27 +#define SAVE 28 {"SAVE", SAVE, 0}, {"FREEZE", SAVE, 0}, -#define ABANDON 28 +#define ABANDON 30 {"ABANDON", ABANDON, 0}, -#define DESTRUCT 29 +#define DESTRUCT 31 {"DESTRUCT", DESTRUCT, 0}, -#define DEATHRAY 30 +#define DEATHRAY 32 {"DEATHRAY", DEATHRAY, 0}, -#define DEBUGCMD 31 +#define DEBUGCMD 33 {"DEBUG", DEBUGCMD, 0}, -#define MAYDAY 32 +#define MAYDAY 34 {"MAYDAY", MAYDAY, 0}, //{"SOS", MAYDAY, 0}, //{"CALL", MAYDAY, 0}, -#define QUIT 33 +#define QUIT 35 {"QUIT", QUIT, 0}, -#define HELP 34 +#define HELP 36 {"HELP", HELP, 0}, +#define SEED 37 + {"SEED", SEED, 0}, }; #define NUMCOMMANDS sizeof(commands)/sizeof(commands[0]) @@ -297,7 +313,7 @@ static void helpme(void) /* Give help on commands */ int key; key = scan(); - while (TRUE) { + for(;;) { if (key == IHEOL) { setwnd(prompt_window); proutn("Help on what command? "); @@ -374,13 +390,14 @@ void enqueue(char *s) static void makemoves(void) { - int i, v = 0, hitme; + int key, i, v = 0; + bool hitme; clrscr(); setwnd(message_window); - while (TRUE) { /* command loop */ + for(;;) { /* command loop */ drawmaps(1); - while (TRUE) { /* get a command */ - hitme = FALSE; + for(;;) { /* get a command */ + hitme = false; game.justin = 0; game.optime = 0.0; i = -1; @@ -392,7 +409,7 @@ static void makemoves(void) makechart(); continue; } - game.ididit=0; + game.ididit = false; clrscr(); setwnd(message_window); clrscr(); @@ -412,7 +429,7 @@ static void makemoves(void) break; listCommands(); } - commandhook(commands[i].name, TRUE); + commandhook(commands[i].name, true); switch (v) { /* command switch */ case SRSCAN: // srscan srscan(SCAN_FULL); @@ -428,19 +445,19 @@ static void makemoves(void) break; case PHASERS: // phasers phasers(); - if (game.ididit) hitme = TRUE; + if (game.ididit) hitme = true; break; case TORPEDO: // photons photon(); - if (game.ididit) hitme = TRUE; + if (game.ididit) hitme = true; break; case MOVE: // move - warp(1); + warp(false); break; case SHIELDS: // shields doshield(1); if (game.ididit) { - hitme=TRUE; + hitme=true; game.shldchg = 0; } break; @@ -452,14 +469,14 @@ static void makemoves(void) dreprt(); break; case CHART: // chart - chart(0); + chart(false); break; case IMPULSE: // impulse impuls(); break; case REST: // rest wait(); - if (game.ididit) hitme = TRUE; + if (game.ididit) hitme = true; break; case WARP: // warp setwrp(); @@ -472,22 +489,22 @@ static void makemoves(void) break; case ORBIT: // orbit orbit(); - if (game.ididit) hitme = TRUE; + if (game.ididit) hitme = true; break; case TRANSPORT: // transport "beam" beam(); break; case MINE: // mine mine(); - if (game.ididit) hitme = TRUE; + if (game.ididit) hitme = true; break; case CRYSTALS: // crystals usecrystals(); - if (game.ididit) hitme = TRUE; + if (game.ididit) hitme = true; break; case SHUTTLE: // shuttle shuttle(); - if (game.ididit) hitme = TRUE; + if (game.ididit) hitme = true; break; case PLANETS: // Planet list preport(); @@ -503,68 +520,65 @@ static void makemoves(void) break; case EMEXIT: // Emergency exit clrscr(); // Hide screen - freeze(TRUE); // forced save + freeze(true); // forced save exit(1); // And quick exit break; case PROBE: probe(); // Launch probe - if (game.ididit) hitme = TRUE; + if (game.ididit) hitme = true; break; case ABANDON: // Abandon Ship abandn(); break; case DESTRUCT: // Self Destruct - dstrct(); + selfdestruct(); break; case SAVE: // Save Game - freeze(FALSE); + freeze(false); clrscr(); if (game.skill > SKILL_GOOD) prout("WARNING--Saved games produce no plaques!"); break; case DEATHRAY: // Try a desparation measure deathray(); - if (game.ididit) hitme = TRUE; + if (game.ididit) hitme = true; break; case DEBUGCMD: // What do we want for debug??? -#ifdef DEBUG debugme(); -#endif break; case MAYDAY: // Call for help - help(); - if (game.ididit) hitme = TRUE; + mayday(); + if (game.ididit) hitme = true; break; case QUIT: game.alldone = 1; // quit the game -#ifdef DEBUG - if (game.idebug) score(); -#endif break; case HELP: - helpme(); // get help + helpme(); // get help + break; + case SEED: // set random-number seed + key = scan(); + if (key == IHREAL) + seed = (int)aaitem; break; } - commandhook(commands[i].name, FALSE); + commandhook(commands[i].name, false); for (;;) { if (game.alldone) break; // Game has ended -#ifdef DEBUG - if (game.idebug) prout("2500"); -#endif if (game.optime != 0.0) { events(); if (game.alldone) break; // Events did us in } - if (game.state.galaxy[game.quadx][game.quady].supernova) { // Galaxy went Nova! - atover(0); + if (game.state.galaxy[game.quadrant.x][game.quadrant.y].supernova) { // Galaxy went Nova! + atover(false); continue; } - if (hitme && game.justin==0) { + if (hitme && !game.justin) { attack(2); if (game.alldone) break; - if (game.state.galaxy[game.quadx][game.quady].supernova) { // went NOVA! - atover(0); - hitme = TRUE; + if (game.state.galaxy[game.quadrant.x][game.quadrant.y].supernova) { // went NOVA! + atover(false); + hitme = true; continue; } } @@ -572,6 +586,7 @@ static void makemoves(void) } if (game.alldone) break; } + if (idebug) prout("=== Ending"); } @@ -585,19 +600,39 @@ int main(int argc, char **argv) else game.options |= OPTION_TTY; - while ((option = getopt(argc, argv, "t")) != -1) { + seed = (int)time(NULL); + while ((option = getopt(argc, argv, "r:tx")) != -1) { switch (option) { + case 'r': + replayfp = fopen(optarg, "r"); + if (replayfp == NULL) { + fprintf(stderr, "sst: can't open replay file %s\n", optarg); + exit(1); + } + if (fscanf(replayfp, "seed %d\n", &seed) != 1) { + fprintf(stderr, "sst: replay file %s is ill-formed\n", optarg); + exit(1); + } + /* FALL THROUGH */ case 't': game.options |= OPTION_TTY; game.options &=~ OPTION_CURSES; break; + case 'x': + idebug = true; + break; default: - fprintf(stderr, "usage: sst [-t] [startcommand...].\n"); + fprintf(stderr, "usage: sst [-t] [-x] [startcommand...].\n"); exit(0); } } + /* where to save the input in case of bugs */ + logfp = fopen("sst-input.log", "w"); + setlinebuf(logfp); + fprintf(logfp, "seed %d\n", seed); + srand(seed); - randomize(); + srand(seed); iostart(); line[0] = '\0'; @@ -605,11 +640,8 @@ int main(int argc, char **argv) strcat(line, argv[i]); strcat(line, " "); } - while (TRUE) { /* Play a game */ + for(;;) { /* Play a game */ setwnd(fullscreen_window); -#ifdef DEBUG - prout("INITIAL OPTIONS: %0lx", game.options); -#endif /* DEBUG */ clrscr(); prelim(); setup(line[0] == '\0'); @@ -624,9 +656,9 @@ int main(int argc, char **argv) if (game.tourn && game.alldone) { proutn("Do you want your score recorded?"); - if (ja()) { + if (ja() == true) { chew2(); - freeze(FALSE); + freeze(false); } } proutn("Do you want to play again? "); @@ -660,22 +692,22 @@ void cramen(int i) proutn(s); } -char *cramlc(enum loctype key, int x, int y) +char *cramlc(enum loctype key, coord w) { 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); + sprintf(buf+strlen(buf), "%d - %d", w.x, w.y); return buf; } -void crmena(int i, int enemy, int key, int x, int y) +void crmena(bool stars, int enemy, enum loctype key, coord w) { - if (i == 1) proutn("***"); + if (stars) proutn("***"); cramen(enemy); proutn(" at "); - proutn(cramlc(key, x, y)); + proutn(cramlc(key, w)); } void crmshp(void) @@ -700,8 +732,9 @@ double expran(double avrage) return -avrage*log(1e-7 + Rand()); } -double Rand(void) { - return rand()/(1.0 + (double)RAND_MAX); +double Rand(void) +{ + return rand()/(1.0 + (double)RAND_MAX); } void iran(int size, int *i, int *j) @@ -778,14 +811,14 @@ int scan(void) return IHALPHA; } -int ja(void) +bool ja(void) { chew(); - while (TRUE) { + for(;;) { scan(); chew(); - if (*citem == 'y') return TRUE; - if (*citem == 'n') return FALSE; + if (*citem == 'y') return true; + if (*citem == 'n') return false; proutn("Please answer with \"Y\" or \"N\": "); } } @@ -806,31 +839,30 @@ int isit(char *s) } -#ifdef DEBUG void debugme(void) { proutn("Reset levels? "); - if (ja() != 0) { - if (energy < game.inenrg) energy = game.inenrg; - shield = game.inshld; - torps = game.intorps; + if (ja() == true) { + if (game.energy < game.inenrg) game.energy = game.inenrg; + game.shield = game.inshld; + game.torps = game.intorps; game.lsupres = game.inlsr; } proutn("Reset damage? "); - if (ja() != 0) { + if (ja() == true) { int i; for (i=0; i < NDEVICES; i++) if (game.damage[i] > 0.0) game.damage[i] = 0.0; } - proutn("Toggle game.idebug? "); - if (ja() != 0) { - game.idebug = !game.idebug; - if (game.idebug) prout("Debug output ON"); + proutn("Toggle debug flag? "); + if (ja() == true) { + idebug = !idebug; + if (idebug) prout("Debug output ON"); else prout("Debug output OFF"); } proutn("Cause selective damage? "); - if (ja() != 0) { + if (ja() == true) { int i, key; for (i=0; i < NDEVICES; i++) { proutn("Kill "); @@ -844,11 +876,12 @@ void debugme(void) } } proutn("Examine/change events? "); - if (ja() != 0) { + if (ja() == true) { + event *ev; + coord w; 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; @@ -857,21 +890,56 @@ void debugme(void) case FCDBAS: proutn("Base Destroy "); break; case FSCMOVE: proutn("SC Move "); break; case FSCDBAS: proutn("SC Base Destroy "); break; + case FDSPROB: proutn("Probe Move "); break; + case FDISTR: proutn("Distress Call "); break; + case FENSLV: proutn("Enlavement "); break; + case FREPRO: proutn("Klingon Build "); break; } - proutn("%.2f", game.future[i]-game.state.date); + if (is_scheduled(i)) { + proutn("%.2f", scheduled(i)-game.state.date); + if (i == FENSLV || i == FREPRO) { + ev = findevent(i); + proutn(" in %d-%d", ev->quadrant.x,ev->quadrant.y); + } + } else + proutn("never"); + proutn("? "); chew(); - proutn(" ?"); key = scan(); - if (key == IHREAL) { - game.future[i] = game.state.date + aaitem; + if (key == 'n') { + unschedule(i); + chew(); + } else if (key == IHREAL) { + ev = schedule(i, aaitem); + if (i == FENSLV || i == FREPRO) { + chew(); + proutn("In quadrant- "); + key = scan(); + /* IHEOL says to leave coordinates as they are */ + if (key != IHEOL) { + if (key != IHREAL) { + prout("Event %d canceled, no x coordinate.", i); + unschedule(i); + continue; + } + w.x = (int)aaitem; + key = scan(); + if (key != IHREAL) { + prout("Event %d canceled, no y coordinate.", i); + unschedule(i); + continue; + } + w.y = (int)aaitem; + ev->quadrant = w; + } + } } } chew(); } proutn("Induce supernova here? "); - if (ja() != 0) { - game.state.galaxy[game.quadx][game.quady].supernova = TRUE; - atover(1); + if (ja() == true) { + game.state.galaxy[game.quadrant.x][game.quadrant.y].supernova = true; + atover(true); } } -#endif