X-Git-Url: https://jxself.org/git/?p=open-adventure.git;a=blobdiff_plain;f=main.c;h=7a179212619ba34b306182894dde4205a0032cb9;hp=6eb783ac46a1b715a4bb17f293e6bf74bc41d150;hb=18a9be501ff8f0c57c5d540d0f5cd080c0438cd0;hpb=704b86afbbf1f60af53a3edd27dafc795674d694 diff --git a/main.c b/main.c index 6eb783a..7a17921 100644 --- a/main.c +++ b/main.c @@ -30,17 +30,17 @@ struct game_t game; long LNLENG, LNPOSN, PARMS[MAXPARMS + 1]; char rawbuf[LINESIZE], INLINE[LINESIZE + 1]; -long AMBER, AXE, BACK, BATTER, BEAR, BIRD, BLOOD, +long AMBER, AXE, BACK, BATTERY, BEAR, BIRD, BLOOD, BOTTLE, CAGE, CAVE, CAVITY, CHAIN, CHASM, CHEST, CLAM, COINS, DOOR, DPRSSN, DRAGON, DWARF, EGGS, - EMRALD, ENTER, ENTRNC, FIND, FISSUR, FOOD, + EMERALD, ENTER, ENTRNC, FIND, FISSURE, FOOD, GRATE, HINT, INVENT, JADE, KEYS, - KNIFE, LAMP, LOCK, LOOK, MAGZIN, + KNIFE, LAMP, LOCK, LOOK, MAGAZINE, MESSAG, MIRROR, NUGGET, NUL, OGRE, OIL, OYSTER, - PEARL, PILLOW, PLANT, PLANT2, PYRAM, RESER, ROD, ROD2, + PEARL, PILLOW, PLANT, PLANT2, PYRAMID, RESER, ROD, ROD2, RUBY, RUG, SAPPH, SAY, SIGN, SNAKE, - STEPS, STREAM, THROW, TRIDNT, TROLL, TROLL2, - URN, VASE, VEND, VOLCAN, WATER; + STEPS, STREAM, THROW, TRIDENT, TROLL, TROLL2, + URN, VASE, VEND, VOLCANO, WATER; long WD1, WD1X, WD2, WD2X; FILE *logfp = NULL, *rfp = NULL; @@ -66,7 +66,7 @@ static void sig_handler(int signo) * 15-treasure version (adventure) by Don Woods, April-June 1977 * 20-treasure version (rev 2) by Don Woods, August 1978 * Errata fixed: 78/12/25 - * Revived 2017 as Open Advebture. + * Revived 2017 as Open Adventure. */ static bool do_command(FILE *); @@ -77,7 +77,14 @@ int main(int argc, char *argv[]) /* Options. */ - while ((ch = getopt(argc, argv, "l:or:s")) != EOF) { +#ifndef ADVENT_NOSAVE + char* opts = "l:or:s"; + char* usage = "Usage: %s [-l logfilename] [-o] [-r restorefilename] [-s] \n"; +#else + char* opts = "l:os"; + char* usage = "Usage: %s [-l logfilename] [-o] [-s] \n"; +#endif + while ((ch = getopt(argc, argv, opts)) != EOF) { switch (ch) { case 'l': logfp = fopen(optarg, "w"); @@ -91,6 +98,7 @@ int main(int argc, char *argv[]) oldstyle = true; editline = prompt = false; break; +#ifndef ADVENT_NOSAVE case 'r': rfp = fopen(optarg, "r"); if (rfp == NULL) @@ -99,9 +107,25 @@ int main(int argc, char *argv[]) optarg); signal(SIGINT, sig_handler); break; +#endif case 's': editline = false; break; + default: + fprintf(stderr, + usage, argv[0]); + fprintf(stderr, + " where -l creates a log file of your game named as specified'\n"); + fprintf(stderr, + " -o 'oldstyle' (no prompt, no command editing, displays 'Initialising...')\n"); +#ifndef ADVENT_NOSAVE + fprintf(stderr, + " -r indicates restoring from specified saved game file\n"); +#endif + fprintf(stderr, + " -s indicates playing with command editing suppressed\n"); + exit(-1); + break; } } @@ -135,7 +159,7 @@ int main(int argc, char *argv[]) game.loc = LOC_START; game.limit = 330; if (!rfp) { - game.novice = YES(stdin, WELCOME_YOU, CAVE_NEARBY, NO_MESSAGE); + game.novice = YES(arbitrary_messages[WELCOME_YOU], arbitrary_messages[CAVE_NEARBY], arbitrary_messages[NO_MESSAGE]); if (game.novice)game.limit = 1000; } else { restore(rfp); @@ -174,7 +198,7 @@ static bool fallback_handler(char *buf) * all come back here eventually to finish the loop. Ignore * "HINTS" < 4 (special stuff, see database notes). */ -static void checkhints(FILE *cmdin) +static void checkhints(void) { if (COND[game.loc] >= game.conds) { for (int hint = 1; hint <= HNTMAX; hint++) { @@ -213,7 +237,7 @@ static void checkhints(FILE *cmdin) game.hintlc[hint] = 0; return; case 4: /* dark */ - if (game.prop[EMRALD] != -1 && game.prop[PYRAM] == -1) + if (game.prop[EMERALD] != -1 && game.prop[PYRAMID] == -1) break; game.hintlc[hint] = 0; return; @@ -245,17 +269,17 @@ static void checkhints(FILE *cmdin) game.hintlc[hint] = 0; return; default: - BUG(27); + BUG(HINT_NUMBER_EXCEEDS_GOTO_LIST); break; } /* Fall through to hint display */ game.hintlc[hint] = 0; - if (!YES(cmdin, HINTS[hint][3], NO_MESSAGE, OK_MAN)) + if (!YES(arbitrary_messages[HINTS[hint][3]], arbitrary_messages[NO_MESSAGE], arbitrary_messages[OK_MAN])) return; SETPRM(1, HINTS[hint][2], HINTS[hint][2]); RSPEAK(HINT_COST); - game.hinted[hint] = YES(cmdin, WANT_HINT, HINTS[hint][4], OK_MAN); + game.hinted[hint] = YES(arbitrary_messages[WANT_HINT], arbitrary_messages[HINTS[hint][4]], arbitrary_messages[OK_MAN]); if (game.hinted[hint] && game.limit > WARNTIME) game.limit += WARNTIME * HINTS[hint][2]; } @@ -281,7 +305,7 @@ static bool spotted_by_pirate(int i) for (int treasure = MINTRS; treasure <= MAXTRS; treasure++) { /* Pirate won't take pyramid from plover room or dark * room (too easy!). */ - if (treasure == PYRAM && (game.loc == PLAC[PYRAM] || game.loc == PLAC[EMRALD])) { + if (treasure == PYRAMID && (game.loc == PLAC[PYRAMID] || game.loc == PLAC[EMERALD])) { continue; } if (TOTING(treasure) || HERE(treasure)) @@ -313,7 +337,7 @@ static bool spotted_by_pirate(int i) if (robplayer) { RSPEAK(PIRATE_POUNCES); for (int treasure = MINTRS; treasure <= MAXTRS; treasure++) { - if (!(treasure == PYRAM && (game.loc == PLAC[PYRAM] || game.loc == PLAC[EMRALD]))) { + if (!(treasure == PYRAMID && (game.loc == PLAC[PYRAMID] || game.loc == PLAC[EMERALD]))) { if (AT(treasure) && game.fixed[treasure] == 0) CARRY(treasure, game.loc); if (TOTING(treasure)) @@ -438,7 +462,7 @@ static bool dwarfmove(void) if (game.dtotal == 0) return true; SETPRM(1, game.dtotal, 0); - RSPEAK(DWARF_PACK + 1 / game.dtotal); /* FIXME: Arithmetic on message number */ + RSPEAK(game.dtotal == 1 ? DWARF_SINGLE : DWARF_PACK); if (attack == 0) return true; if (game.dflag == 2)game.dflag = 3; @@ -457,7 +481,7 @@ static bool dwarfmove(void) /* "You're dead, Jim." * * If the current loc is zero, it means the clown got himself killed. - * We'll allow this maxdie times. MAXDIE is automatically set based + * We'll allow this maxdie times. maximum_deaths is automatically set based * on the number of snide messages available. Each death results in * a message (81, 83, etc.) which offers reincarnation; if accepted, * this results in message 82, 84, etc. The last time, if he wants @@ -474,18 +498,18 @@ static bool dwarfmove(void) * without the lamp!). game.oldloc is zapped so he can't just * "retreat". */ -static void croak(FILE *cmdin) +static void croak(void) /* Okay, he's dead. Let's get on with it. */ { + const char* query = obituaries[game.numdie].query; + const char* yes_response = obituaries[game.numdie].yes_response; ++game.numdie; if (game.closng) { /* He died during closing time. No resurrection. Tally up a * death and exit. */ RSPEAK(DEATH_CLOSING); terminate(endgame); - } - /* FIXME: Arithmetic on message numbers */ - else if (game.numdie == MAXDIE || !YES(cmdin, WATCH_IT + game.numdie * 2, WHICH_WAY + game.numdie * 2, OK_MAN)) + } else if (game.numdie == maximum_deaths || !YES(query, yes_response, arbitrary_messages[OK_MAN])) terminate(endgame); else { game.place[WATER] = game.place[OIL] = NOWHERE; @@ -511,12 +535,12 @@ static void croak(FILE *cmdin) * him, so we need game.oldlc2, which is the last place he was * safe.) */ -static bool playermove(FILE *cmdin, token_t verb, int motion) +static bool playermove(token_t verb, int motion) { int scratchloc, k2, kk = KEY[game.loc]; game.newloc = game.loc; if (kk == 0) - BUG(26); + BUG(LOCATION_HAS_NO_TRAVEL_ENTRIES); if (motion == NUL) return true; else if (motion == BACK) { @@ -592,7 +616,7 @@ static bool playermove(FILE *cmdin, token_t verb, int motion) if (motion == 29 || motion == 30)spk = BAD_DIRECTION; if (motion == 7 || motion == 36 || motion == 37)spk = UNSURE_FACING; if (motion == 11 || motion == 19)spk = NO_INOUT_HERE; - if (verb == FIND || verb == INVENT)spk = NEreplace; + if (verb == FIND || verb == INVENT)spk = NEARBY; if (motion == 62 || motion == 65)spk = NOTHING_HAPPENS; if (motion == 17)spk = WHICH_WAY; RSPEAK(spk); @@ -605,98 +629,104 @@ static bool playermove(FILE *cmdin, token_t verb, int motion) do { /* * (ESR) This special-travel loop may have to be repeated if it includes - * the plover passage. Same deal for any future cases wgerw we beed to + * the plover passage. Same deal for any future cases where we need to * block travel and then redo it once the blocking condition has been * removed. */ - for (;;) { - game.newloc = scratchloc / 1000; - motion = MOD(game.newloc, 100); - if (!SPECIAL(game.newloc)) { - if (game.newloc <= 100) { - if (game.newloc == 0 || PCT(game.newloc)) + for (;;) { /* L12 loop */ + for (;;) { + game.newloc = scratchloc / 1000; + motion = MOD(game.newloc, 100); + if (!SPECIAL(game.newloc)) { + if (game.newloc <= 100) { + if (game.newloc == 0 || PCT(game.newloc)) + break; + /* else fall through */ + } + if (TOTING(motion) || (game.newloc > 200 && AT(motion))) break; /* else fall through */ - } - if (TOTING(motion) || (game.newloc > 200 && AT(motion))) + } else if (game.prop[motion] != game.newloc / 100 - 3) break; - /* else fall through */ - } else if (game.prop[motion] != game.newloc / 100 - 3) - break; - do { - if (TRAVEL[kk] < 0)BUG(25); - ++kk; - game.newloc = labs(TRAVEL[kk]) / 1000; - } while - (game.newloc == scratchloc); - scratchloc = game.newloc; - } - - game.newloc = MOD(scratchloc, 1000); - if (!SPECIAL(game.newloc)) - return true; - if (game.newloc <= 500) { - game.newloc = game.newloc - SPECIALBASE; - switch (game.newloc) { - case 1: - /* Travel 301. Plover-alcove passage. Can carry only - * emerald. Note: travel table must include "useless" - * entries going through passage, which can never be used for - * actual motion, but can be spotted by "go back". */ - /* FIXME: Arithmetic on location numbers */ - game.newloc = 99 + 100 - game.loc; - if (game.holdng == 0 || (game.holdng == 1 && TOTING(EMRALD))) - return true; - game.newloc = game.loc; - RSPEAK(MUST_DROP); - return true; - case 2: - /* Travel 302. Plover transport. Drop the emerald (only use - * special travel if toting it), so he's forced to use the - * plover-passage to get it out. Having dropped it, go back and - * pretend he wasn't carrying it after all. */ - DROP(EMRALD, game.loc); do { - if (TRAVEL[kk] < 0)BUG(25); + if (TRAVEL[kk] < 0) + BUG(CONDITIONAL_TRAVEL_ENTRY_WITH_NO_ALTERATION); ++kk; game.newloc = labs(TRAVEL[kk]) / 1000; } while (game.newloc == scratchloc); - continue; /* back to top of do/while loop */ - case 3: - /* Travel 303. Troll bridge. Must be done only as special - * motion so that dwarves won't wander across and encounter - * the bear. (They won't follow the player there because - * that region is forbidden to the pirate.) If - * game.prop(TROLL)=1, he's crossed since paying, so step out - * and block him. (standard travel entries check for - * game.prop(TROLL)=0.) Special stuff for bear. */ - if (game.prop[TROLL] == 1) { - PSPEAK(TROLL, 1); - game.prop[TROLL] = 0; - MOVE(TROLL2, 0); - MOVE(TROLL2 + NOBJECTS, 0); - MOVE(TROLL, PLAC[TROLL]); - MOVE(TROLL + NOBJECTS, FIXD[TROLL]); - JUGGLE(CHASM); - game.newloc = game.loc; + scratchloc = game.newloc; + } + + game.newloc = MOD(scratchloc, 1000); + if (!SPECIAL(game.newloc)) + return true; + if (game.newloc <= 500) { + game.newloc -= SPECIALBASE; + switch (game.newloc) { + case 1: + /* Travel 301. Plover-alcove passage. Can carry only + * emerald. Note: travel table must include "useless" + * entries going through passage, which can never be used for + * actual motion, but can be spotted by "go back". */ + /* FIXME: Arithmetic on location numbers */ + game.newloc = 99 + 100 - game.loc; + if (game.holdng > 1 || (game.holdng == 1 && !TOTING(EMERALD))) { + game.newloc = game.loc; + RSPEAK(MUST_DROP); + } return true; - } else { - game.newloc = PLAC[TROLL] + FIXD[TROLL] - game.loc; - if (game.prop[TROLL] == 0)game.prop[TROLL] = 1; - if (!TOTING(BEAR)) return true; - RSPEAK(BRIDGE_COLLAPSE); - game.prop[CHASM] = 1; - game.prop[TROLL] = 2; - DROP(BEAR, game.newloc); - game.fixed[BEAR] = -1; - game.prop[BEAR] = 3; - game.oldlc2 = game.newloc; - croak(cmdin); - return false; + case 2: + /* Travel 302. Plover transport. Drop the emerald (only use + * special travel if toting it), so he's forced to use the + * plover-passage to get it out. Having dropped it, go back and + * pretend he wasn't carrying it after all. */ + DROP(EMERALD, game.loc); + do { + if (TRAVEL[kk] < 0) + BUG(CONDITIONAL_TRAVEL_ENTRY_WITH_NO_ALTERATION); + ++kk; + game.newloc = labs(TRAVEL[kk]) / 1000; + } while + (game.newloc == scratchloc); + scratchloc = game.newloc; + continue; /* goto L12 */ + case 3: + /* Travel 303. Troll bridge. Must be done only as special + * motion so that dwarves won't wander across and encounter + * the bear. (They won't follow the player there because + * that region is forbidden to the pirate.) If + * game.prop(TROLL)=1, he's crossed since paying, so step out + * and block him. (standard travel entries check for + * game.prop(TROLL)=0.) Special stuff for bear. */ + if (game.prop[TROLL] == 1) { + PSPEAK(TROLL, 1); + game.prop[TROLL] = 0; + MOVE(TROLL2, 0); + MOVE(TROLL2 + NOBJECTS, 0); + MOVE(TROLL, PLAC[TROLL]); + MOVE(TROLL + NOBJECTS, FIXD[TROLL]); + JUGGLE(CHASM); + game.newloc = game.loc; + return true; + } else { + game.newloc = PLAC[TROLL] + FIXD[TROLL] - game.loc; + if (game.prop[TROLL] == 0)game.prop[TROLL] = 1; + if (!TOTING(BEAR)) return true; + RSPEAK(BRIDGE_COLLAPSE); + game.prop[CHASM] = 1; + game.prop[TROLL] = 2; + DROP(BEAR, game.newloc); + game.fixed[BEAR] = -1; + game.prop[BEAR] = 3; + game.oldlc2 = game.newloc; + croak(); + return true; + } } + BUG(SPECIAL_TRAVEL_500_GT_L_GT_300_EXCEEDS_GOTO_LIST); } - BUG(20); + break; /* Leave L12 loop */ } } while (false); @@ -745,7 +775,7 @@ static bool closecheck(void) * have been activated, since we've found chest. */ if (game.clock1 == 0) { game.prop[GRATE] = 0; - game.prop[FISSUR] = 0; + game.prop[FISSURE] = 0; for (int i = 1; i <= NDWARVES; i++) { game.dseen[i] = false; game.dloc[i] = 0; @@ -832,12 +862,12 @@ static void lampcheck(void) * Second is for other cases of lamp dying. 12400 is when it * goes out. Even then, he can explore outside for a while * if desired. */ - if (game.limit <= WARNTIME && HERE(BATTER) && game.prop[BATTER] == 0 && HERE(LAMP)) { + if (game.limit <= WARNTIME && HERE(BATTERY) && game.prop[BATTERY] == 0 && HERE(LAMP)) { RSPEAK(REPLACE_BATTERIES); - game.prop[BATTER] = 1; - if (TOTING(BATTER)) - DROP(BATTER, game.loc); - game.limit = game.limit + 2500; + game.prop[BATTERY] = 1; + if (TOTING(BATTERY)) + DROP(BATTERY, game.loc); + game.limit += BATTERYLIFE; game.lmwarn = false; } else if (game.limit == 0) { game.limit = -1; @@ -848,8 +878,8 @@ static void lampcheck(void) if (!game.lmwarn && HERE(LAMP)) { game.lmwarn = true; int spk = GET_BATTERIES; - if (game.place[BATTER] == NOWHERE)spk = LAMP_DIM; - if (game.prop[BATTER] == 1)spk = MISSING_BATTERIES; + if (game.place[BATTERY] == NOWHERE)spk = LAMP_DIM; + if (game.prop[BATTERY] == 1)spk = MISSING_BATTERYIES; RSPEAK(spk); } } @@ -934,13 +964,13 @@ static bool do_command(FILE *cmdin) game.loc = game.newloc; if (!dwarfmove()) - croak(cmdin); + croak(); /* Describe the current location and (maybe) get next command. */ for (;;) { if (game.loc == 0) - croak(cmdin); + croak(); const char* msg = locations[game.loc].description.small; if (MOD(game.abbrev[game.loc], game.abbnum) == 0 || msg == 0) msg = locations[game.loc].description.big; @@ -950,20 +980,21 @@ static bool do_command(FILE *cmdin) if (game.wzdark && PCT(35)) { RSPEAK(PIT_FALL); game.oldlc2 = game.loc; - croak(cmdin); + croak(); continue; /* back to top of main interpreter loop */ } msg = arbitrary_messages[PITCH_DARK]; } if (TOTING(BEAR))RSPEAK(TAME_BEAR); - newspeak(msg); + speak(msg); if (FORCED(game.loc)) { - if (playermove(cmdin, verb, 1)) + if (playermove(verb, 1)) return true; else continue; /* back to top of main interpreter loop */ } - if (game.loc == 33 && PCT(25) && !game.closng)RSPEAK(SAYS_PLUGH); + if (game.loc == LOC_Y2 && PCT(25) && !game.closng) + RSPEAK(SAYS_PLUGH); listobjects(); @@ -973,7 +1004,7 @@ L2012: obj = 0; L2600: - checkhints(cmdin); + checkhints(); /* If closing time, check for any objects being toted with * game.prop < 0 and set the prop to -1-game.prop. This way @@ -1003,7 +1034,7 @@ L2607: game.foobar = (game.foobar > 0 ? -game.foobar : 0); ++game.turns; if (game.turns == game.thresh) { - newspeak(turn_threshold_messages[game.trndex]); + speak(turn_threshold_messages[game.trndex]); game.trnluz = game.trnluz + TRNVAL[game.trndex] / 100000; ++game.trndex; game.thresh = -1; @@ -1068,7 +1099,7 @@ Lookup: kmod = MOD(defn, 1000); switch (defn / 1000) { case 0: - if (playermove(cmdin, verb, kmod)) + if (playermove(verb, kmod)) return true; else continue; /* back to top of main interpreter loop */ @@ -1084,7 +1115,7 @@ Lookup: RSPEAK(kmod); goto L2012; default: - BUG(22); + BUG(VOCABULARY_TYPE_N_OVER_1000_NOT_BETWEEN_0_AND_3); } Laction: @@ -1092,7 +1123,7 @@ Laction: case GO_TERMINATE: return true; case GO_MOVE: - playermove(cmdin, verb, NUL); + playermove(verb, NUL); return true; case GO_TOP: continue; /* back to top of main interpreter loop */ @@ -1122,7 +1153,7 @@ Laction: RSPEAK(DWARVES_AWAKEN); terminate(endgame); default: - BUG(99); + BUG(ACTION_RETURNED_PHASE_CODE_BEYOND_END_OF_SWITCH); } } }