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.
+
+ 8. Still more BSD-Trek: we now have a weighted damage table.
+ Also, the nav subsystem (enabling automatic course
+ setting) can be damaged separately from the main computer (which
+ handles weapons targeting, ETA calculation, and self-destruct).
*/
/* the input queue */
struct game game;
coord thing;
-int iqhere, iqengry;
+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
-bool randready; // Has the random-number generator initialized?
-FILE *logfp;
-
-char *device[NDEVICES] = {
- "S. R. Sensors",
- "L. R. Sensors",
- "Phasers",
- "Photon Tubes",
- "Life Support",
- "Warp Engines",
- "Impulse Engines",
- "Shields",
- "Subspace Radio",
- "Shuttle Craft",
- "Computer",
- "Transporter",
- "Shield Control",
- "Death Ray",
- "D. S. Probe"};
+FILE *logfp, *replayfp;
+
+char *systnames[NINHAB];
+char *device[NDEVICES];
static struct
{
{"QUIT", QUIT, 0},
#define HELP 36
{"HELP", HELP, 0},
+#define SEED 37
+ {"SEED", SEED, 0},
+#ifdef BSD_BUG_FOR_BUG
+#define VISUAL 38
+ {"VISUAL", VISUAL, 0},
+#endif
};
-#define NUMCOMMANDS sizeof(commands)/sizeof(commands[0])
+#define NUMCOMMANDS ARRAY_SIZE(commands)
#define ACCEPT(i) (!commands[i].option || (commands[i].option & game.options))
-static void listCommands(void) {
+static void listCommands(void)
+/* generate a list of legal commands */
+{
int i, k = 0;
- proutn("LEGAL COMMANDS ARE:");
+ proutn(_("LEGAL COMMANDS ARE:"));
for (i = 0; i < NUMCOMMANDS; i++) {
if (!ACCEPT(i))
continue;
skip(1);
}
-static void helpme(void)
+static void helpme(void)
+/* browse on-line help */
{
int i, j;
char cmdbuf[32], *cp;
for(;;) {
if (key == IHEOL) {
setwnd(prompt_window);
- proutn("Help on what command? ");
+ proutn(_("Help on what command? "));
key = scan();
}
setwnd(message_window);
- if (key == IHEOL) return;
+ 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;
+ if (i != NUMCOMMANDS)
+ break;
skip(1);
- prout("Valid commands:");
listCommands();
key = IHEOL;
chew();
if (fp == NULL)
fp = fopen(DOC_NAME, "r");
if (fp == NULL) {
- prout("Spock- \"Captain, that information is missing from the");
- prout(" computer. You need to find "DOC_NAME" and put it in the");
- prout(" current directory or to "SSTDOC".\"");
+ prout(_("Spock- \"Captain, that information is missing from the"));
+ proutn(_(" computer. You need to find "));
+ proutn(DOC_NAME);
+ prout(_(" and put it in the"));
+ proutn(_(" current directory or to "));
+ proutn(SSTDOC);
+ prout(".\"");
/*
* This used to continue: "You need to find SST.DOC and put
* it in the current directory."
}
for (;;) {
if (fgets(linebuf, sizeof(linebuf), fp) == NULL) {
- prout("Spock- \"Captain, there is no information on that command.\"");
+ prout(_("Spock- \"Captain, there is no information on that command.\""));
fclose(fp);
return;
}
}
skip(1);
- prout("Spock- \"Captain, I've found the following information:\"");
+ prout(_("Spock- \"Captain, I've found the following information:\""));
skip(1);
- while (fgets(linebuf, sizeof(linebuf),fp)) {
+ while (fgets(linebuf, sizeof(linebuf), fp)) {
+ char *eol;
if (strstr(linebuf, "******"))
break;
- proutn(linebuf);
+ if ((eol = strpbrk(linebuf, "\r\n")))
+ *eol = 0;
+ prout(linebuf);
}
fclose(fp);
}
-void enqueue(char *s)
+static void makemoves(void)
+/* command-interpretation loop */
{
- strcpy(line, s);
-}
-
-static void makemoves(void)
-{
- int i, v = 0;
+ int key, i, v = 0;
bool hitme;
clrscr();
setwnd(message_window);
drawmaps(1);
for(;;) { /* get a command */
hitme = false;
- game.justin = 0;
+ game.justin = false;
game.optime = 0.0;
i = -1;
chew();
clrscr();
proutn("COMMAND> ");
if (scan() == IHEOL) {
- makechart();
+ if (game.options & OPTION_CURSES)
+ makechart();
continue;
}
- game.ididit=0;
+ game.ididit = false;
clrscr();
setwnd(message_window);
clrscr();
commandhook(commands[i].name, true);
switch (v) { /* command switch */
case SRSCAN: // srscan
- srscan(SCAN_FULL);
+ srscan();
break;
case STATUS: // status
- srscan(SCAN_STATUS);
+ status(0);
break;
case REQUEST: // status request
- srscan(SCAN_REQUEST);
+ request();
break;
case LRSCAN: // lrscan
lrscan();
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);
+ doshield(false);
if (game.ididit) {
- hitme=true;
- game.shldchg = 0;
+ hitme = true;
+ game.shldchg = false;
}
break;
case DOCK: // dock
- dock(1);
- if (game.ididit) attack(0);
+ dock(true);
+ if (game.ididit)
+ attack(false);
break;
case DAMAGES: // damages
- dreprt();
+ damagereport();
break;
case CHART: // chart
- chart(0);
+ makechart();
break;
case IMPULSE: // impulse
- impuls();
+ impulse();
break;
case REST: // rest
wait();
- if (game.ididit) hitme = true;
+ if (game.ididit)
+ hitme = true;
break;
case WARP: // warp
- setwrp();
+ setwarp();
break;
case SCORE: // score
score();
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();
+ survey();
break;
case REPORT: // Game Report
report();
break;
case PROBE:
probe(); // Launch probe
- if (game.ididit) hitme = true;
+ if (game.ididit)
+ hitme = true;
break;
case ABANDON: // Abandon Ship
- abandn();
+ abandon();
break;
case DESTRUCT: // Self Destruct
- dstrct();
+ selfdestruct();
break;
case SAVE: // Save Game
freeze(false);
clrscr();
if (game.skill > SKILL_GOOD)
- prout("WARNING--Saved games produce no plaques!");
+ 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???
debugme();
break;
case MAYDAY: // Call for help
mayday();
- if (game.ididit) hitme = true;
+ if (game.ididit)
+ hitme = true;
break;
case QUIT:
- game.alldone = 1; // quit the game
+ game.alldone = true; // quit the game
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;
+#ifdef BSD_BUG_FOR_BUG
+ case VISUAL:
+ visual(); // perform visual scan
break;
+#endif
}
commandhook(commands[i].name, false);
for (;;) {
- if (game.alldone) break; // Game has ended
+ if (game.alldone)
+ break; // Game has ended
if (game.optime != 0.0) {
events();
- if (game.alldone) break; // Events did us in
+ if (game.alldone)
+ break; // Events did us in
}
if (game.state.galaxy[game.quadrant.x][game.quadrant.y].supernova) { // Galaxy went Nova!
- atover(0);
+ atover(false);
continue;
}
- if (hitme && game.justin==0) {
- attack(2);
- if (game.alldone) break;
+ if (hitme && !game.justin) {
+ attack(true);
+ if (game.alldone)
+ break;
if (game.state.galaxy[game.quadrant.x][game.quadrant.y].supernova) { // went NOVA!
- atover(0);
+ atover(false);
hitme = true;
continue;
}
}
break;
}
- if (game.alldone) break;
+ if (game.alldone)
+ break;
}
- if (idebug) prout("=== Ending");
+ if (idebug)
+ prout("=== Ending");
}
else
game.options |= OPTION_TTY;
- while ((option = getopt(argc, argv, "tx")) != -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;
exit(0);
}
}
+ /* where to save the input in case of bugs */
+ logfp = fopen("/usr/tmp/sst-input.log", "w");
+ if (logfp) {
+ setlinebuf(logfp);
+ fprintf(logfp, "seed %d\n", seed);
+ }
+ srand(seed);
- randomize();
iostart();
line[0] = '\0';
setup(line[0] == '\0');
if (game.alldone) {
score();
- game.alldone = 0;
+ game.alldone = false;
}
- else makemoves();
+ else
+ makemoves();
skip(1);
stars();
skip(1);
if (game.tourn && game.alldone) {
- proutn("Do you want your score recorded?");
- if (ja()) {
+ proutn(_("Do you want your score recorded?"));
+ if (ja() == true) {
chew2();
freeze(false);
}
}
- proutn("Do you want to play again? ");
- if (!ja()) break;
+ 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.");
+ prout(_("May the Great Bird of the Galaxy roost upon your home planet."));
return 0;
}
-void cramen(int i)
+void cramen(feature i)
+/* print the name of an enemy */
{
/* 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;
+ 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;
+ case IHW: s = _("Inhabited World"); break;
default: s = "Unknown??"; break;
}
proutn(s);
}
char *cramlc(enum loctype key, coord w)
+/* name a location */
{
static char buf[32];
buf[0] = '\0';
- if (key == quadrant) strcpy(buf, "Quadrant ");
- else if (key == sector) strcpy(buf, "Sector ");
+ if (key == quadrant)
+ strcpy(buf, _("Quadrant "));
+ else if (key == sector)
+ strcpy(buf, _("Sector "));
sprintf(buf+strlen(buf), "%d - %d", w.x, w.y);
return buf;
}
-void crmena(int i, int enemy, int key, coord w)
+void crmena(bool stars, feature enemy, enum loctype key, coord w)
+/* print an enemy and his location */
{
- if (i == 1) proutn("***");
+ if (stars)
+ proutn("***");
cramen(enemy);
- proutn(" at ");
+ proutn(_(" at "));
proutn(cramlc(key, w));
}
-void crmshp(void)
+void crmshp(void)
+/* print our ship name */
{
char *s;
switch (game.ship) {
- case IHE: s = "Enterprise"; break;
- case IHF: s = "Faerie Queene"; break;
+ case IHE: s = _("Enterprise"); break;
+ case IHF: s = _("Faerie Queene"); break;
default: s = "Ship???"; break;
}
proutn(s);
}
-void stars(void)
+void stars(void)
+/* print a line of stars */
{
prouts("******************************************************");
skip(1);
double Rand(void)
{
- if (!randready) {
- if (seed == 0)
- seed = (unsigned)time(NULL);
- if (idebug)
- fprintf(logfp, "seed %d\n", seed);
- srand(seed);
- randready = true;
- }
return rand()/(1.0 + (double)RAND_MAX);
}
-void iran(int size, int *i, int *j)
+coord randplace(int size)
+/* choose a random location */
{
- *i = Rand()*(size*1.0) + 1.0;
- *j = Rand()*(size*1.0) + 1.0;
+ coord w;
+ w.x = Rand()*(size*1.0) + 1.0;
+ w.y = Rand()*(size*1.0) + 1.0;
+ return w;
}
void chew(void)
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;
- }
+ i = 0;
+ // try a number
+ if (sscanf(linep, "%lf%n", &aaitem, &i) > 0) {
+ // skip to end
+ linep += i;
+ return IHREAL;
}
// Treat as alpha
cp = citem;
while (*linep && *linep!=' ') {
- if ((cp - citem) < 9) *cp++ = tolower(*linep);
+ if ((cp - citem) < 9)
+ *cp++ = tolower(*linep);
linep++;
}
*cp = 0;
return IHALPHA;
}
-bool ja(void)
+bool ja(void)
+/* yes-or-no confirmation */
{
chew();
for(;;) {
scan();
chew();
- if (*citem == 'y') return true;
- if (*citem == 'n') return false;
- proutn("Please answer with \"Y\" or \"N\": ");
+ if (*citem == 'y')
+ return true;
+ if (*citem == 'n')
+ return false;
+ proutn(_("Please answer with \"y\" or \"n\": "));
}
}
-void huh(void)
+void huh(void)
+/* complain about unparseable input */
{
chew();
skip(1);
- prout("Beg your pardon, Captain?");
+ prout(_("Beg your pardon, Captain?"));
}
-int isit(char *s)
+bool isit(char *s)
+/* compares s to citem and returns true if it matches to the length of 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;
-
}
-void debugme(void)
+void debugme(void)
+/* access to the internals for debugging */
{
proutn("Reset levels? ");
- if (ja() != 0) {
- if (game.energy < game.inenrg) game.energy = game.inenrg;
+ 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) {
+ proutn("Toggle debug flag? ");
+ if (ja() == true) {
idebug = !idebug;
- if (idebug) prout("Debug output ON");
- else prout("Debug output OFF");
+ 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 ");
}
}
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 (!is_scheduled(i)) continue;
switch (i) {
case FSNOVA: proutn("Supernova "); break;
case FTBEAM: proutn("T Beam "); break;
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", scheduled(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) {
- schedule(i, 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) {
+ if (ja() == true) {
game.state.galaxy[game.quadrant.x][game.quadrant.y].supernova = true;
- atover(1);
+ atover(true);
}
}