Improve test coverage.
[open-adventure.git] / main.c
diff --git a/main.c b/main.c
index 405d9d37fe18280d0efdd996affd6ede7c672442..c18803605493f35f506df5262185652e47fbaa9c 100644 (file)
--- 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 *);
@@ -102,6 +102,19 @@ int main(int argc, char *argv[])
         case 's':
             editline = false;
             break;
+        default:
+            fprintf(stderr,
+                    "Usage: %s [-l logfilename] [-o] [-r restorefilename] [-s] \n", 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");
+            fprintf(stderr,
+                    "        -r indicates restoring from specified saved game file\n");
+            fprintf(stderr,
+                    "        -s indicates playing with command editing suppressed\n");
+            exit(-1);
+            break;
         }
     }
 
@@ -135,7 +148,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);
@@ -150,7 +163,7 @@ int main(int argc, char *argv[])
             break;
     }
     /* show score and exit */
-    score(quitgame);
+    terminate(quitgame);
 }
 
 static bool fallback_handler(char *buf)
@@ -174,7 +187,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 +226,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 +258,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 +294,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 +326,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))
@@ -457,7 +470,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,20 +487,20 @@ 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);
-        score(endgame);
-
+        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))
-        score(endgame);
+    else if (game.numdie == maximum_deaths || !YES(query, yes_response, arbitrary_messages[OK_MAN]))
+        terminate(endgame);
     else {
         game.place[WATER] = game.place[OIL] = NOWHERE;
         if (TOTING(LAMP))
@@ -512,12 +525,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) {
@@ -624,8 +637,10 @@ static bool playermove(FILE *cmdin, token_t verb, int motion)
                 /* else fall through */
             } else if (game.prop[motion] != game.newloc / 100 - 3)
                 break;
+L12:
             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
@@ -646,24 +661,18 @@ static bool playermove(FILE *cmdin, token_t verb, int motion)
                  *  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);
+                if (game.holdng > 1 || (game.holdng == 1 && !TOTING(EMERALD))) {
+                    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);
-                    ++kk;
-                    game.newloc = labs(TRAVEL[kk]) / 1000;
-                } while
-                (game.newloc == scratchloc);
-                continue;      /* back to top of do/while loop */
+                DROP(EMERALD, game.loc);
+                goto L12;
             case 3:
                 /*  Travel 303.  Troll bridge.  Must be done only as special
                  *  motion so that dwarves won't wander across and encounter
@@ -693,11 +702,10 @@ static bool playermove(FILE *cmdin, token_t verb, int motion)
                     game.fixed[BEAR] = -1;
                     game.prop[BEAR] = 3;
                     game.oldlc2 = game.newloc;
-                    croak(cmdin);
-                    return false;
+                    croak();
                 }
             }
-            BUG(20);
+            BUG(SPECIAL_TRAVEL_500_GT_L_GT_300_EXCEEDS_GOTO_LIST);
         }
     } while
     (false);
@@ -746,7 +754,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;
@@ -833,11 +841,11 @@ 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.prop[BATTERY] = 1;
+        if (TOTING(BATTERY))
+            DROP(BATTERY, game.loc);
         game.limit = game.limit + 2500;
         game.lmwarn = false;
     } else if (game.limit == 0) {
@@ -849,8 +857,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);
         }
     }
@@ -915,7 +923,7 @@ static bool do_command(FILE *cmdin)
     if (OUTSID(game.newloc) && game.newloc != 0 && game.closng) {
         RSPEAK(EXIT_CLOSED);
         game.newloc = game.loc;
-        if (!game.panic)game.clock2 = 15;
+        if (!game.panic)game.clock2 = PANICTIME;
         game.panic = true;
     }
 
@@ -935,13 +943,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;
@@ -951,15 +959,15 @@ 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 */
@@ -974,7 +982,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
@@ -1004,7 +1012,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;
@@ -1069,7 +1077,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 */
@@ -1085,7 +1093,7 @@ Lookup:
             RSPEAK(kmod);
             goto L2012;
         default:
-            BUG(22);
+            BUG(VOCABULARY_TYPE_N_OVER_1000_NOT_BETWEEN_0_AND_3);
         }
 
 Laction:
@@ -1093,7 +1101,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 */
@@ -1121,10 +1129,9 @@ Laction:
         case GO_DWARFWAKE:
             /*  Oh dear, he's disturbed the dwarves. */
             RSPEAK(DWARVES_AWAKEN);
-            score(endgame);
-            return true;
+            terminate(endgame);
         default:
-            BUG(99);
+            BUG(ACTION_RETURNED_PHASE_CODE_BEYOND_END_OF_SWITCH);
         }
     }
 }