Create regression test for issue #36.
[open-adventure.git] / actions.c
index 375e6337b24385bb0ac9c311b705a7112f6aba52..ceb728a0d86c6ae0f706ce2ca9179c790f4a0f58 100644 (file)
--- a/actions.c
+++ b/actions.c
@@ -1,12 +1,21 @@
+/*
+ * Actions for the duneon-running code.
+ *
+ * Copyright (c) 1977, 2005 by Will Crowther and Don Woods
+ * Copyright (c) 2017 by Eric S. Raymond
+ * SPDX-License-Identifier: BSD-2-clause
+ */
+
 #include <stdlib.h>
 #include <stdbool.h>
 #include <string.h>
 #include "advent.h"
 #include "dungeon.h"
+#include <inttypes.h>
 
 static int fill(verb_t, obj_t);
 
-static int attack(struct command_t command)
+static int attack(command_t command)
 /*  Attack.  Assume target if unambiguous.  "Throw" also links here.
  *  Attackable objects fall into two categories: enemies (snake,
  *  dwarf, etc.)  and others (bird, clam, machine).  Ambiguous if 2
@@ -265,7 +274,7 @@ static int vbreak(verb_t verb, obj_t obj)
             game.fixed[VASE] = IS_FIXED;
             break;
         }
-       /* FALLTHRU */
+    /* FALLTHRU */
     default:
         speak(actions[verb].message);
     }
@@ -592,7 +601,7 @@ static int eat(verb_t verb, obj_t obj)
     case INTRANSITIVE:
         if (!HERE(FOOD))
             return GO_UNKNOWN;
-       /* FALLTHRU */
+    /* FALLTHRU */
     case FOOD:
         DESTROY(FOOD);
         rspeak(THANKS_DELICIOUS);
@@ -1076,7 +1085,7 @@ static int quit(void)
     return GO_CLEAROBJ;
 }
 
-static int read(struct command_t command)
+static int read(command_t command)
 /*  Read.  Print stuff based on objtxt.  Oyster (?) is special case. */
 {
     if (command.obj == INTRANSITIVE) {
@@ -1092,7 +1101,7 @@ static int read(struct command_t command)
     }
 
     if (DARK(game.loc)) {
-        sspeak(NO_SEE, command.raw1);
+        sspeak(NO_SEE, command.word[0].raw);
     } else if (command.obj == OYSTER && !game.clshnt && game.closed) {
         game.clshnt = yes(arbitrary_messages[CLUE_QUERY], arbitrary_messages[WAYOUT_CLUE], arbitrary_messages[OK_MAN]);
     } else if (objects[command.obj].texts[0] == NULL ||
@@ -1141,28 +1150,28 @@ static int rub(verb_t verb, obj_t obj)
     return GO_CLEAROBJ;
 }
 
-static int say(struct command_t command)
+static int say(command_t command)
 /* Say.  Echo WD2. Magic words override. */
 {
-    if (command.type2 == MOTION &&
-       (command.id2 == XYZZY ||
-        command.id2 == PLUGH ||
-       command.id2 == PLOVER)) {
-           return GO_WORD2;
+    if (command.word[1].type == MOTION &&
+        (command.word[1].id == XYZZY ||
+         command.word[1].id == PLUGH ||
+         command.word[1].id == PLOVER)) {
+        return GO_WORD2;
     }
-    if (command.type2 == ACTION && command.id2 == PART)
+    if (command.word[1].type == ACTION && command.word[1].id == PART)
         return reservoir();
-    
-    if (command.type2 == ACTION &&
-        (command.id2 == FEE ||
-        command.id2 == FIE ||
-        command.id2 == FOE ||
-        command.id2 == FOO ||
-        command.id2 == FUM ||
-        command.id2 == PART)) {
-        return bigwords(command.id2);
-    }
-    sspeak(OKEY_DOKEY, command.raw2);
+
+    if (command.word[1].type == ACTION &&
+        (command.word[1].id == FEE ||
+         command.word[1].id == FIE ||
+         command.word[1].id == FOE ||
+         command.word[1].id == FOO ||
+         command.word[1].id == FUM ||
+         command.word[1].id == PART)) {
+        return bigwords(command.word[1].id);
+    }
+    sspeak(OKEY_DOKEY, command.word[1].raw);
     return GO_CLEAROBJ;
 }
 
@@ -1173,7 +1182,7 @@ static int throw_support(vocab_t spk)
     return GO_MOVE;
 }
 
-static int throw (struct command_t command)
+static int throw (command_t command)
 /*  Throw.  Same as discard unless axe.  Then same as attack except
  *  ignore bird, and if dwarf is present then one might be killed.
  *  (Only way to do so!)  Axe also special for dragon, bear, and
@@ -1250,7 +1259,7 @@ static int wake(verb_t verb, obj_t obj)
 static int seed(verb_t verb, const char *arg)
 /* Set seed */
 {
-    int seed = atoi(arg);
+    int32_t seed = strtol(arg, NULL, 10);
     speak(actions[verb].message, seed);
     set_seed(seed);
     --game.turns;
@@ -1311,19 +1320,19 @@ static int wave(verb_t verb, obj_t obj)
     }
 }
 
-int action(struct command_t command)
+int action(command_t command)
 /*  Analyse a verb.  Remember what it was, go back for object if second word
  *  unless verb is "say", which snarfs arbitrary second word.
  */
 {
-    /* Previously, actions that result in a message, but don't do anything 
-     * further were called "specials". Now they're handled here as normal 
+    /* Previously, actions that result in a message, but don't do anything
+     * further were called "specials". Now they're handled here as normal
      * actions. If noaction is true, then we spit out the message and return */
     if (actions[command.verb].noaction) {
         speak(actions[command.verb].message);
         return GO_CLEAROBJ;
     }
-    
+
     if (command.part == unknown) {
         /*  Analyse an object word.  See if the thing is here, whether
          *  we've got a verb yet, and so on.  Object must be here
@@ -1353,28 +1362,26 @@ int action(struct command_t command)
             command.obj = ROD2;
             /* FALL THROUGH */;
         } else if ((command.verb == FIND ||
-                    command.verb == INVENTORY) && (command.id2 == WORD_EMPTY || command.id2 == WORD_NOT_FOUND))
+                    command.verb == INVENTORY) && (command.word[1].id == WORD_EMPTY || command.word[1].id == WORD_NOT_FOUND))
             /* FALL THROUGH */;
         else {
-            sspeak(NO_SEE, command.raw1);
+            sspeak(NO_SEE, command.word[0].raw);
             return GO_CLEAROBJ;
         }
 
-        if (command.id2 != WORD_EMPTY && command.id2 != WORD_NOT_FOUND)
-            return GO_WORD2;
         if (command.verb != 0)
             command.part = transitive;
     }
 
     switch (command.part) {
     case intransitive:
-        if (command.raw2[0] != '\0' && command.verb != SAY)
+        if (command.word[1].raw[0] != '\0' && command.verb != SAY)
             return GO_WORD2;
         if (command.verb == SAY)
-           /* KEYS is not special, anything not NO_OBJECT or INTRANSITIVE
-            * will do here. We're preventing interpretation as an intransitive
-            * verb when the word is unknown. */
-            command.obj = command.raw2[0] != '\0' ? KEYS : NO_OBJECT;
+            /* KEYS is not special, anything not NO_OBJECT or INTRANSITIVE
+             * will do here. We're preventing interpretation as an intransitive
+             * verb when the word is unknown. */
+            command.obj = command.word[1].raw[0] != '\0' ? KEYS : NO_OBJECT;
         if (command.obj == NO_OBJECT ||
             command.obj == INTRANSITIVE) {
             /*  Analyse an intransitive verb (ie, no object given yet). */
@@ -1439,7 +1446,7 @@ int action(struct command_t command)
             case FOE:
             case FOO:
             case FUM:
-                return bigwords(command.id1);
+                return bigwords(command.word[0].id);
             case BRIEF:
                 return brief();
             case READ:
@@ -1510,7 +1517,7 @@ int action(struct command_t command)
         case RUB:
             return rub(command.verb, command.obj);
         case THROW:
-            return throw(command);
+            return throw (command);
         case QUIT: {
             speak(actions[command.verb].message);
             return GO_CLEAROBJ;
@@ -1562,18 +1569,21 @@ int action(struct command_t command)
             speak(actions[command.verb].message);
             return GO_CLEAROBJ;
         }
+        // LCOV_EXCL_START
+        // This case should never happen - here only as placeholder
         case PART:
             return reservoir();
+        // LCOV_EXCL_STOP
         case SEED:
-            return seed(command.verb, command.raw2);
+            return seed(command.verb, command.word[1].raw);
         case WASTE:
-            return waste(command.verb, (turn_t)atol(command.raw2));
+            return waste(command.verb, (turn_t)atol(command.word[1].raw));
         default: // LCOV_EXCL_LINE
             BUG(TRANSITIVE_ACTION_VERB_EXCEEDS_GOTO_LIST); // LCOV_EXCL_LINE
         }
     case unknown:
         /* Unknown verb, couldn't deduce object - might need hint */
-        sspeak(WHAT_DO, command.raw1);
+        sspeak(WHAT_DO, command.word[0].raw);
         return GO_CHECKHINT;
     default: // LCOV_EXCL_LINE
         BUG(SPEECHPART_NOT_TRANSITIVE_OR_INTRANSITIVE_OR_UNKNOWN); // LCOV_EXCL_LINE