Jettison MAKEWD(), GETTXT(), vocab(), GETIN(), and the old db compiler.
[open-adventure.git] / main.c
diff --git a/main.c b/main.c
index 3d3a8fb705851a3ac0b54efb9edfea7f1087631e..c5dc311d0e7cf7a6b4e32107ec482a3d57afdc4e 100644 (file)
--- a/main.c
+++ b/main.c
@@ -20,8 +20,8 @@
 #include <getopt.h>
 #include <signal.h>
 #include <time.h>
+#include <string.h>
 #include "advent.h"
-#include "database.h"
 #include "linenoise/linenoise.h"
 #include "newdb.h"
 
@@ -37,6 +37,8 @@ bool oldstyle = false;
 bool editline = true;
 bool prompt = true;
 
+// LCOV_EXCL_START
+// exclude from coverage analysis because it requires interactivity to test
 static void sig_handler(int signo)
 {
     if (signo == SIGINT) {
@@ -45,6 +47,7 @@ static void sig_handler(int signo)
     }
     exit(0);
 }
+// LCOV_EXCL_STOP
 
 /*
  * MAIN PROGRAM
@@ -58,7 +61,7 @@ static void sig_handler(int signo)
  *          Revived 2017 as Open Adventure.
  */
 
-static bool do_command(FILE *);
+static bool do_command(void);
 
 int main(int argc, char *argv[])
 {
@@ -133,7 +136,7 @@ int main(int argc, char *argv[])
     initialise();
 
     /*  Start-up, dwarf stuff */
-    game.zzword = rndvoc(3, 0);
+    make_zzword(game.zzword);
     game.newloc = LOC_START;
     game.loc = LOC_START;
     game.limit = GAMELIMIT;
@@ -150,7 +153,7 @@ int main(int argc, char *argv[])
 
     /* interpret commands until EOF or interrupt */
     for (;;) {
-        if (!do_command(stdin))
+        if (!do_command())
             break;
     }
     /* show score and exit */
@@ -167,7 +170,7 @@ static bool fallback_handler(char *buf)
         // autogenerated, so don't charge user time for it.
         --game.turns;
         // here we reconfigure any global game state that uses random numbers
-        game.zzword = rndvoc(3, 0);
+       make_zzword(game.zzword);
         return true;
     }
     return false;
@@ -247,7 +250,7 @@ static void checkhints(void)
                     game.hintlc[hint] = 0;
                     return;
                 default:
-                    BUG(HINT_NUMBER_EXCEEDS_GOTO_LIST);
+                    BUG(HINT_NUMBER_EXCEEDS_GOTO_LIST); // LCOV_EXCL_LINE
                     break;
                 }
 
@@ -521,7 +524,7 @@ static bool playermove(token_t verb, int motion)
     int scratchloc, k2, kk = tkey[game.loc];
     game.newloc = game.loc;
     if (kk == 0)
-        BUG(LOCATION_HAS_NO_TRAVEL_ENTRIES);
+        BUG(LOCATION_HAS_NO_TRAVEL_ENTRIES); // LCOV_EXCL_LINE
     if (motion == NUL)
         return true;
     else if (motion == BACK) {
@@ -598,7 +601,7 @@ static bool playermove(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 = NEARBY;
+            if (verb == FIND || verb == INVENTORY)spk = NEARBY;
             if (motion == 62 || motion == 65)spk = NOTHING_HAPPENS;
             if (motion == 17)spk = WHICH_WAY;
             rspeak(spk);
@@ -610,42 +613,39 @@ static bool playermove(token_t verb, int motion)
     /* (ESR) We've found a destination that goes with the motion verb.
      * Next we need to check any conditional(s) on this destination, and
      * possibly on following entries. */
-    scratchloc = T_HIGH(travel[kk]);
-
     do {
-        /*
-         * (ESR) This conditional-skip loop may have to be repeated if
-         * it includes 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 (;;) { /* 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))
+                long cond = T_CONDITION(travel[kk]);
+                long arg = MOD(cond, 100);
+                if (!SPECIAL(cond)) {
+                   /* YAML N and [pct N] conditionals */
+                    if (cond <= 100) {
+                        if (cond == 0 || PCT(cond))
                             break;
                         /* else fall through */
                     }
-                   /* handles the YAML "with" clause */
-                    if (TOTING(motion) || (game.newloc > 200 && AT(motion)))
+                   /* YAML [with OBJ] clause */
+                    if (TOTING(arg) || (cond > 200 && AT(arg)))
                         break;
-                    /* else fall through */
-                } else if (game.prop[motion] != game.newloc / 100 - 3)
+                    /* else fall through to check [not OBJ STATE] */
+                } else if (game.prop[arg] != cond / 100 - 3)
                     break;
-                do {
-                    if (travel[kk].stop)
-                        BUG(CONDITIONAL_TRAVEL_ENTRY_WITH_NO_ALTERATION);
-                    ++kk;
-                    game.newloc = T_HIGH(travel[kk]);
+
+               /* We arrive here on conditional failure.
+                * Skip to next non-matching destination */
+               long k2 = kk;
+               do {
+                    if (travel[k2].stop)
+                        BUG(CONDITIONAL_TRAVEL_ENTRY_WITH_NO_ALTERATION); // LCOV_EXCL_LINE
+                    ++k2;
                 } while
-                (game.newloc == scratchloc);
-                scratchloc = game.newloc;
+                   (T_HIGH(travel[kk]) == T_HIGH(travel[k2]));
+               kk = k2;
             }
 
-            game.newloc = MOD(scratchloc, 1000);
+           /* Found an eligible rule, now execute it */
+            game.newloc = T_DESTINATION(travel[kk]);
             if (!SPECIAL(game.newloc))
                 return true;
 
@@ -676,14 +676,14 @@ static bool playermove(token_t verb, int motion)
                      * to get it out.  Having dropped it, go back and
                      * pretend he wasn't carrying it after all. */
                     drop(EMERALD, game.loc);
+                   k2 = kk;
                     do {
-                        if (travel[kk].stop)
-                            BUG(CONDITIONAL_TRAVEL_ENTRY_WITH_NO_ALTERATION);
-                        ++kk;
-                        game.newloc = T_HIGH(travel[kk]);
+                        if (travel[k2].stop)
+                            BUG(CONDITIONAL_TRAVEL_ENTRY_WITH_NO_ALTERATION); // LCOV_EXCL_LINE
+                        ++k2;
                     } while
-                    (game.newloc == scratchloc);
-                    scratchloc = game.newloc;
+                       (T_HIGH(travel[kk]) == T_HIGH(travel[k2]));
+                    kk = k2;
                     continue; /* goto L12 */
                 case 3:
                     /* Travel 303.  Troll bridge.  Must be done only
@@ -714,13 +714,13 @@ static bool playermove(token_t verb, int motion)
                         game.prop[TROLL] = 2;
                         drop(BEAR, game.newloc);
                         game.fixed[BEAR] = -1;
-                        game.prop[BEAR] = 3;
+                        game.prop[BEAR] = BEAR_DEAD;
                         game.oldlc2 = game.newloc;
                         croak();
                         return true;
                     }
                default:
-                   BUG(SPECIAL_TRAVEL_500_GT_L_GT_300_EXCEEDS_GOTO_LIST);
+                   BUG(SPECIAL_TRAVEL_500_GT_L_GT_300_EXCEEDS_GOTO_LIST); // LCOV_EXCL_LINE
                 }
             }
             break; /* Leave L12 loop */
@@ -777,7 +777,8 @@ static bool closecheck(void)
         move(TROLL2, objects[TROLL].plac);
         move(TROLL2 + NOBJECTS, objects[TROLL].fixd);
         juggle(CHASM);
-        if (game.prop[BEAR] != 3)DESTROY(BEAR);
+        if (game.prop[BEAR] != BEAR_DEAD)
+           DESTROY(BEAR);
         game.prop[CHAIN] = 0;
         game.fixed[CHAIN] = 0;
         game.prop[AXE] = 0;
@@ -922,7 +923,7 @@ static void listobjects(void)
     }
 }
 
-static bool do_command(FILE *cmdin)
+static bool do_command()
 /* Get and execute a command */
 {
     long V1, V2;
@@ -1015,8 +1016,25 @@ L2600:
             game.knfloc = 0;
 
         /* This is where we get a new command from the user */
-        if (!GETIN(cmdin, &command.wd1, &command.wd1x, &command.wd2, &command.wd2x))
-            return false;
+       char* input;
+       for (;;) {
+         input = get_input();
+         if (input == NULL)
+           return(false);
+         if (word_count(input) > 2)
+         {
+           rspeak(TWO_WORDS);
+           continue;
+         }
+         if (strcmp(input, "") != 0)
+           break;
+       }
+       long tokens[4];
+       tokenize(input, tokens);
+       command.wd1 = tokens[0];
+        command.wd1x = tokens[1];
+        command.wd2 = tokens[2];
+        command.wd2x = tokens[3];
 
         /*  Every input, check "game.foobar" flag.  If zero, nothing's
          *  going on.  If pos, make neg.  If neg, he skipped a word,
@@ -1048,8 +1066,12 @@ L2607:
         } else
             lampcheck();
 
-        V1 = vocab(command.wd1, -1);
-        V2 = vocab(command.wd2, -1);
+       char word1[6];
+       char word2[6];
+       packed_to_token(command.wd1, word1);
+       packed_to_token(command.wd2, word2);
+       V1 = get_vocab_id(word1);
+       V2 = get_vocab_id(word2);
         if (V1 == ENTER && (V2 == STREAM || V2 == 1000 + WATER)) {
             if (LIQLOC(game.loc) == WATER) {
                 rspeak(FEET_WET);
@@ -1067,26 +1089,27 @@ L2607:
             if (!((V1 != 1000 + WATER && V1 != 1000 + OIL) ||
                   (V2 != 1000 + PLANT && V2 != 1000 + DOOR))) {
                 if (AT(V2 - 1000))
-                    command.wd2 = MAKEWD(WORD_POUR);
+                   command.wd2 = token_to_packed("POUR");
             }
             if (V1 == 1000 + CAGE && V2 == 1000 + BIRD && HERE(CAGE) && HERE(BIRD))
-                command.wd1 = MAKEWD(WORD_CATCH);
+               command.wd1 = token_to_packed("CATCH");
         }
 L2620:
-        if (wordeq(command.wd1, MAKEWD(WORD_WEST))) {
+        if (wordeq(command.wd1, token_to_packed("WEST"))) {
             ++game.iwest;
             if (game.iwest == 10)
                 rspeak(W_IS_WEST);
         }
-        if (wordeq(command.wd1, MAKEWD(WORD_GO)) && !wordempty(command.wd2)) {
+        if (wordeq(command.wd1, token_to_packed("GO")) && !wordempty(command.wd2)) {
             if (++igo == 10)
                 rspeak(GO_UNNEEDED);
         }
 Lookup:
-        defn = vocab(command.wd1, -1);
+       packed_to_token(command.wd1, word1);
+       defn = get_vocab_id(word1);
         if (defn == -1) {
             /* Gee, I don't understand. */
-            if (fallback_handler(rawbuf))
+            if (fallback_handler(input))
                 continue;
             rspeak(DONT_KNOW, command.wd1, command.wd1x);
             goto L2600;
@@ -1107,14 +1130,14 @@ Lookup:
             command.verb = kmod;
             break;
         case 3:
-            rspeak(kmod);
+            rspeak(specials[kmod].message);
             goto L2012;
         default:
-            BUG(VOCABULARY_TYPE_N_OVER_1000_NOT_BETWEEN_0_AND_3);
+            BUG(VOCABULARY_TYPE_N_OVER_1000_NOT_BETWEEN_0_AND_3); // LCOV_EXCL_LINE
         }
 
 Laction:
-        switch (action(cmdin, &command)) {
+        switch (action(&command)) {
         case GO_TERMINATE:
             return true;
         case GO_MOVE:
@@ -1147,8 +1170,9 @@ Laction:
             rspeak(DWARVES_AWAKEN);
             terminate(endgame);
         default:
-            BUG(ACTION_RETURNED_PHASE_CODE_BEYOND_END_OF_SWITCH);
+            BUG(ACTION_RETURNED_PHASE_CODE_BEYOND_END_OF_SWITCH); // LCOV_EXCL_LINE
         }
+       linenoiseFree(input);
     }
 }