[open-adventure] 01/04: New upstream version 1.4+git20170917.0.d512384

Dr. Tobias Quathamer toddy at debian.org
Sat Sep 30 07:16:09 UTC 2017


This is an automated email from the git hooks/post-receive script.

toddy pushed a commit to branch master
in repository open-adventure.

commit 62a223679c3c661a056bf103df5961ebe7bf357c
Author: Dr. Tobias Quathamer <toddy at debian.org>
Date:   Sat Sep 30 09:08:04 2017 +0200

    New upstream version 1.4+git20170917.0.d512384
---
 NEWS                  |   2 +-
 actions.c             |  47 +++++++++---------
 advent.h              |  43 ++++++++++-------
 init.c                |   6 ---
 main.c                |  80 +++++++++++++++---------------
 misc.c                |  32 ++++++------
 saveresume.c          | 131 +++++++++++++++++++++++++++++++++++++++++++++++---
 tests/Makefile        |   1 -
 tests/illformed.chk   |   2 +-
 tests/resumefail2.chk |   2 +-
 10 files changed, 233 insertions(+), 113 deletions(-)

diff --git a/NEWS b/NEWS
index 487dd2d..28ba0f8 100644
--- a/NEWS
+++ b/NEWS
@@ -2,7 +2,7 @@
 
 1.4: 2017-08-07::
   Repair packaging error (omitted templates.)
-  Minor improvents in odd grammar cases.
+  Minor improvements in odd grammar cases.
 
 1.3: 2017-08-01::
   Split commands with objectless transitive verbs are handled correctly.
diff --git a/actions.c b/actions.c
index ec25552..059d92b 100644
--- a/actions.c
+++ b/actions.c
@@ -3,6 +3,7 @@
 #include <string.h>
 #include "advent.h"
 #include "dungeon.h"
+#include <inttypes.h>
 
 static int fill(verb_t, obj_t);
 
@@ -265,7 +266,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 +593,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);
@@ -1145,21 +1146,21 @@ static int say(command_t command)
 /* Say.  Echo WD2. Magic words override. */
 {
     if (command.word[1].type == MOTION &&
-       (command.word[1].id == XYZZY ||
-        command.word[1].id == PLUGH ||
-    	command.word[1].id == PLOVER)) {
-	    return GO_WORD2;
+        (command.word[1].id == XYZZY ||
+         command.word[1].id == PLUGH ||
+         command.word[1].id == PLOVER)) {
+        return GO_WORD2;
     }
     if (command.word[1].type == ACTION && command.word[1].id == PART)
         return reservoir();
-    
+
     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)) {
+         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);
@@ -1250,7 +1251,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;
@@ -1316,14 +1317,14 @@ int action(command_t command)
  *  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
@@ -1369,9 +1370,9 @@ int action(command_t command)
         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. */
+            /* 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) {
@@ -1508,7 +1509,7 @@ int action(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;
@@ -1560,11 +1561,11 @@ int action(command_t command)
             speak(actions[command.verb].message);
             return GO_CLEAROBJ;
         }
-	// LCOV_EXCL_START
-	// This case should never happen - here only as placeholder
+        // LCOV_EXCL_START
+        // This case should never happen - here only as placeholder
         case PART:
             return reservoir();
-	// LCOV_EXCL_STOP
+        // LCOV_EXCL_STOP
         case SEED:
             return seed(command.verb, command.word[1].raw);
         case WASTE:
diff --git a/advent.h b/advent.h
index 4491b42..e43459b 100644
--- a/advent.h
+++ b/advent.h
@@ -2,9 +2,16 @@
 #include <stdlib.h>
 #include <stdbool.h>
 #include <stdarg.h>
+#include <inttypes.h>
 
 #include "dungeon.h"
 
+/* LCG PRNG parameters tested against
+ * Knuth vol. 2. by the original authors */
+#define LCG_A 1093L
+#define LCG_C 221587L
+#define LCG_M 1048576L
+
 #define LINESIZE       1024
 #define TOKLEN         5          // № sigificant characters in a token */
 #define NDWARVES       6          // number of dwarves
@@ -112,7 +119,7 @@ typedef long loc_t;    // index into the locations array */
 typedef long turn_t;   // turn counter or threshold */
 
 struct game_t {
-    unsigned long lcg_a, lcg_c, lcg_m, lcg_x;
+    int32_t lcg_x;
     long abbnum;                 // How often to print long descriptions
     score_t bonus;               // What kind of finishing bonus we are getting
     loc_t chloc;                 // pirate chest location
@@ -122,6 +129,11 @@ struct game_t {
     bool clshnt;                 // has player read the clue in the endgame?
     bool closed;                 // whether we're all the way closed
     bool closng;                 // whether it's closing time yet
+    bool lmwarn;                 // has player been warned about lamp going dim?
+    bool novice;                 // asked for instructions at start-up?
+    bool panic;                  // has player found out he's trapped?
+    bool wzdark;                 // whether the loc he's leaving was dark
+    bool blooded;                // has player drunk of dragon's blood?
     long conds;                  // min value for cond[loc] if loc has any hints
     long detail;                 // level of detail in descriptions
 
@@ -134,38 +146,33 @@ struct game_t {
     long dflag;
 
     long dkill;                  // dwarves killed
-    long dtotal;                 // total dwarves (including pirate)
+    long dtotal;                 // total dwarves (including pirate) in loc
     long foobar;                 // progress in saying "FEE FIE FOE FOO".
     long holdng;                 // number of objects being carried
     long igo;                    // # uses of "go" instead of a direction
     long iwest;                  // # times he's said "west" instead of "w"
     long knfloc;                 // knife location; 0 if none, -1 after caveat
     turn_t limit;                // lifetime of lamp
-    bool lmwarn;                 // has player been warned about lamp going dim?
     loc_t loc;                   // where player is now
     loc_t newloc;                // where player is going
-    bool novice;                 // asked for instructions at start-up?
     turn_t numdie;               // number of times killed so far
     loc_t oldloc;                // where player was
-    loc_t oldlc2;                // where player was two moves ago 
+    loc_t oldlc2;                // where player was two moves ago
     obj_t oldobj;                // last object player handled
-    bool panic;                  // has player found out he's trapped?
     long saved;                  // point penalty for saves
     long tally;                  // count of treasures gained
     long thresh;                 // current threshold for endgame scoring tier
     turn_t trndex;               // FIXME: not used, remove on next format bump
     turn_t trnluz;               // # points lost so far due to turns used
     turn_t turns;                // counts commands given (ignores yes/no)
-    bool wzdark;                 // whether the loc he's leaving was dark
     char zzword[TOKLEN + 1];     // randomly generated magic word from bird
-    bool blooded;                // has player drunk of dragon's blood?
     long abbrev[NLOCATIONS + 1]; // has location been seen?
     long atloc[NLOCATIONS + 1];  // head of object linked list per location
     long dseen[NDWARVES + 1];    // true if dwarf has seen him
     loc_t dloc[NDWARVES + 1];    // location of dwarves, initially hard-wired in
     loc_t odloc[NDWARVES + 1];   // prior loc of each dwarf, initially garbage
     loc_t fixed[NOBJECTS + 1];   // fixed location of object (if  not IS_FREE)
-    long link[NOBJECTS * 2 + 1]; // object-list links
+    obj_t link[NOBJECTS * 2 + 1]; // object-list links
     loc_t place[NOBJECTS + 1];   // location of object
     long hinted[NHINTS];         // hinted[i] = true iff hint i has been used.
     long hintlc[NHINTS];         // hintlc[i] = how long at LOC with cond bit i
@@ -183,9 +190,9 @@ struct settings_t {
 };
 
 typedef struct {
-  char raw[LINESIZE];
-  vocab_t id;
-  word_type_t type;
+    char raw[LINESIZE];
+    vocab_t id;
+    word_type_t type;
 } command_word_t;
 
 typedef struct {
@@ -214,11 +221,11 @@ extern void drop(obj_t, loc_t);
 extern int atdwrf(loc_t);
 extern long setbit(int);
 extern bool tstbit(long, int);
-extern void set_seed(long);
-extern long randrange(long);
+extern void set_seed(int32_t);
+extern int32_t randrange(int32_t);
 extern long score(enum termination);
 extern void terminate(enum termination) __attribute__((noreturn));
-extern int savefile(FILE *, long);
+extern int savefile(FILE *, int32_t);
 extern int suspend(void);
 extern int resume(void);
 extern int restore(FILE *);
@@ -231,9 +238,9 @@ void bug(enum bugtype, const char *) __attribute__((__noreturn__));
 
 /* represent an empty command word */
 static const command_word_t empty_command_word = {
-  .raw = "",
-  .id = WORD_EMPTY,
-  .type = NO_WORD_TYPE,
+    .raw = "",
+    .id = WORD_EMPTY,
+    .type = NO_WORD_TYPE,
 };
 
 /* end */
diff --git a/init.c b/init.c
index be5c3fb..fbe4410 100644
--- a/init.c
+++ b/init.c
@@ -37,12 +37,6 @@ struct game_t game = {
     .loc     = LOC_START,
     .limit   = GAMELIMIT,
     .foobar  = WORD_EMPTY,
-
-    /* Initialize our LCG PRNG with parameters tested against
-     * Knuth vol. 2. by the original authors */
-    .lcg_a = 1093,
-    .lcg_c = 221587,
-    .lcg_m = 1048576,
 };
 
 long initialise(void)
diff --git a/main.c b/main.c
index 41bbe95..1b725c9 100644
--- a/main.c
+++ b/main.c
@@ -85,7 +85,6 @@ int main(int argc, char *argv[])
                 fprintf(stderr,
                         "advent: can't open save file %s for read\n",
                         optarg);
-            signal(SIGINT, sig_handler);
             break;
 #endif
         default:
@@ -461,6 +460,8 @@ static bool dwarfmove(void)
 static void croak(void)
 /*  Okay, he's dead.  Let's get on with it. */
 {
+    if (game.numdie < 0)
+        game.numdie = 0;
     const char* query = obituaries[game.numdie].query;
     const char* yes_response = obituaries[game.numdie].yes_response;
     ++game.numdie;
@@ -1050,43 +1051,43 @@ Lclearobj:
         if (game.knfloc > 0 && game.knfloc != game.loc)
             game.knfloc = 0;
 
-	/* Preserve state from last command for reuse when required */
-	command_t preserve = command;
+        /* Preserve state from last command for reuse when required */
+        command_t preserve = command;
 
-	// Get command input from user
+        // Get command input from user
         if (!get_command_input(&command))
             return false;
 
 #ifdef GDEBUG
-	/* Needs to stay synced with enum word_type_t */
-	const char *types[] = {"NO_WORD_TYPE", "MOTION", "OBJECT", "ACTION", "NUMERIC"};
-	/* needs to stay synced with enum speechpart */
-	const char *roles[] = {"unknown", "intransitive", "transitive"};
-	printf("Preserve: role = %s type1 = %s, id1 = %ld, type2 = %s, id2 = %ld\n",
-	       roles[preserve.part],
-	       types[preserve.word[0].type],
-	       preserve.word[0].id,
-	       types[preserve.word[1].type],
-	       preserve.word[1].id);
-	printf("Command: role = %s type1 = %s, id1 = %ld, type2 = %s, id2 = %ld\n",
-	       roles[command.part],
-	       types[command.word[0].type],
-	       command.word[0].id,
-	       types[command.word[1].type],
-	       command.word[1].id);
+        /* Needs to stay synced with enum word_type_t */
+        const char *types[] = {"NO_WORD_TYPE", "MOTION", "OBJECT", "ACTION", "NUMERIC"};
+        /* needs to stay synced with enum speechpart */
+        const char *roles[] = {"unknown", "intransitive", "transitive"};
+        printf("Preserve: role = %s type1 = %s, id1 = %ld, type2 = %s, id2 = %ld\n",
+               roles[preserve.part],
+               types[preserve.word[0].type],
+               preserve.word[0].id,
+               types[preserve.word[1].type],
+               preserve.word[1].id);
+        printf("Command: role = %s type1 = %s, id1 = %ld, type2 = %s, id2 = %ld\n",
+               roles[command.part],
+               types[command.word[0].type],
+               command.word[0].id,
+               types[command.word[1].type],
+               command.word[1].id);
 #endif
 
-	/* Handle of objectless action followed by actionless object */
-	if (preserve.word[0].type == ACTION && preserve.word[1].type == NO_WORD_TYPE && command.word[1].id == 0)
-	    command.verb = preserve.verb;
+        /* Handle of objectless action followed by actionless object */
+        if (preserve.word[0].type == ACTION && preserve.word[1].type == NO_WORD_TYPE && command.word[1].id == 0)
+            command.verb = preserve.verb;
 
 #ifdef BROKEN
-	/* Handling of actionless object followed by objectless action */
-	if (preserve.type1 == OBJECT && preserve.type2 == NO_WORD_TYPE && command.id2 == 0)
-	    command.obj = preserve.obj;
+        /* Handling of actionless object followed by objectless action */
+        if (preserve.type1 == OBJECT && preserve.type2 == NO_WORD_TYPE && command.id2 == 0)
+            command.obj = preserve.obj;
 #endif
 
-	++game.turns;
+        ++game.turns;
 
         if (closecheck()) {
             if (game.closed)
@@ -1122,8 +1123,8 @@ Lclearobj:
             }
             if ((command.word[0].id == WATER || command.word[0].id == OIL) && (command.word[1].id == PLANT || command.word[1].id == DOOR)) {
                 if (AT(command.word[1].id)) {
-		    command.word[1] = command.word[0];
-		    command.word[0].id = POUR;
+                    command.word[1] = command.word[0];
+                    command.word[0].id = POUR;
                     command.word[0].type = ACTION;
                     strncpy(command.word[0].raw, "pour", LINESIZE - 1);
                 }
@@ -1133,12 +1134,12 @@ Lclearobj:
                 command.word[0].type = ACTION;
             }
 
-	    /* From OV to VO form */
-	    if (command.word[0].type==OBJECT && command.word[1].type==ACTION) {
-		command_word_t stage = command.word[0];
-		command.word[0] = command.word[1];
-		command.word[1] = stage;
-	    }
+            /* From OV to VO form */
+            if (command.word[0].type == OBJECT && command.word[1].type == ACTION) {
+                command_word_t stage = command.word[0];
+                command.word[0] = command.word[1];
+                command.word[1] = stage;
+            }
         }
 
 Lookup:
@@ -1165,7 +1166,7 @@ Lookup:
             command.obj = command.word[0].id;
             break;
         case ACTION:
-            if(command.word[1].type == NUMERIC) 
+            if (command.word[1].type == NUMERIC)
                 command.part = transitive;
             else
                 command.part = intransitive;
@@ -1175,7 +1176,6 @@ Lookup:
         default: // LCOV_EXCL_LINE
             BUG(VOCABULARY_TYPE_N_OVER_1000_NOT_BETWEEN_0_AND_3); // LCOV_EXCL_LINE
         }
-
         switch (action(command)) {
         case GO_TERMINATE:
             return true;
@@ -1186,11 +1186,11 @@ Lookup:
             continue;	/* back to top of main interpreter loop */
         case GO_WORD2:
 #ifdef GDEBUG
-	    printf("Word shift\n");
+            printf("Word shift\n");
 #endif /* GDEBUG */
             /* Get second word for analysis. */
-  	    command.word[0] = command.word[1];
-	    command.word[1] = empty_command_word;
+            command.word[0] = command.word[1];
+            command.word[1] = empty_command_word;
             goto Lookup;
         case GO_UNKNOWN:
             /*  Random intransitive verbs come here.  Clear obj just in case
diff --git a/misc.c b/misc.c
index 5386ff7..80e4352 100644
--- a/misc.c
+++ b/misc.c
@@ -6,6 +6,7 @@
 #include <sys/time.h>
 #include <ctype.h>
 #include <editline/readline.h>
+#include <inttypes.h>
 
 #include "advent.h"
 #include "dungeon.h"
@@ -66,8 +67,8 @@ static void vspeak(const char* msg, bool blank, va_list ap)
             i++;
             // Integer specifier.
             if (msg[i] == 'd') {
-                long arg = va_arg(ap, long);
-                int ret = snprintf(renderp, size, "%ld", arg);
+                int32_t arg = va_arg(ap, int32_t);
+                int ret = snprintf(renderp, size, "%" PRId32, arg);
                 if (ret < size) {
                     renderp += ret;
                     size -= ret;
@@ -388,22 +389,21 @@ static int get_action_vocab_id(const char* word)
     return (WORD_NOT_FOUND);
 }
 
-static bool is_valid_int(const char *str) 
-/* Returns true if the string passed in is represents a valid integer, 
+static bool is_valid_int(const char *str)
+/* Returns true if the string passed in is represents a valid integer,
  * that could then be parsed by atoi() */
 {
     // Handle negative number
     if (*str == '-')
         ++str;
 
-    // Handle empty string or just "-". Should never reach this 
+    // Handle empty string or just "-". Should never reach this
     // point, because this is only used with transitive verbs.
     if (!*str)
         return false; // LCOV_EXCL_LINE
 
     // Check for non-digit chars in the rest of the stirng.
-    while (*str)
-    {
+    while (*str) {
         if (!isdigit(*str))
             return false;
         else
@@ -643,11 +643,13 @@ bool tstbit(long mask, int bit)
     return (mask & (1 << bit)) != 0;
 }
 
-void set_seed(long seedval)
+void set_seed(int32_t seedval)
 /* Set the LCG seed */
 {
-    game.lcg_x = (unsigned long) seedval % game.lcg_m;
-
+    game.lcg_x = seedval % LCG_M;
+    if (game.lcg_x < 0) {
+        game.lcg_x = LCG_M + game.lcg_x;
+    }
     // once seed is set, we need to generate the Z`ZZZ word
     for (int i = 0; i < 5; ++i) {
         game.zzword[i] = 'A' + randrange(26);
@@ -656,18 +658,18 @@ void set_seed(long seedval)
     game.zzword[5] = '\0';
 }
 
-static unsigned long get_next_lcg_value(void)
+static int32_t get_next_lcg_value(void)
 /* Return the LCG's current value, and then iterate it. */
 {
-    unsigned long old_x = game.lcg_x;
-    game.lcg_x = (game.lcg_a * game.lcg_x + game.lcg_c) % game.lcg_m;
+    int32_t old_x = game.lcg_x;
+    game.lcg_x = (LCG_A * game.lcg_x + LCG_C) % LCG_M;
     return old_x;
 }
 
-long randrange(long range)
+int32_t randrange(int32_t range)
 /* Return a random integer from [0, range). */
 {
-    return range * get_next_lcg_value() / game.lcg_m;
+    return range * get_next_lcg_value() / LCG_M;
 }
 
 // LCOV_EXCL_START
diff --git a/saveresume.c b/saveresume.c
index d854174..d494015 100644
--- a/saveresume.c
+++ b/saveresume.c
@@ -2,6 +2,7 @@
 #include <string.h>
 #include <editline/readline.h>
 #include <time.h>
+#include <inttypes.h>
 
 #include "advent.h"
 #include "dungeon.h"
@@ -11,7 +12,7 @@
  * see the history.adoc file in the source distribution for discussion.
  */
 
-#define VRSION	27	/* bump on save format change */
+#define VRSION	28	/* bump on save format change */
 
 /*
  * If you change the first three members, the resume function may not properly
@@ -20,16 +21,16 @@
  * when you do that.
  */
 struct save_t {
-    long savetime;
-    long mode;		/* not used, must be present for version detection */
-    long version;
+    int64_t savetime;
+    int32_t mode;		/* not used, must be present for version detection */
+    int32_t version;
     struct game_t game;
 };
 struct save_t save;
 
 #define IGNORE(r) do{if (r){}}while(0)
 
-int savefile(FILE *fp, long version)
+int savefile(FILE *fp, int32_t version)
 /* Save game to file. No input or output from user. */
 {
     save.savetime = time(NULL);
@@ -105,6 +106,8 @@ int resume(void)
     return restore(fp);
 }
 
+bool is_valid(struct game_t*);
+
 int restore(FILE* fp)
 {
     /*  Read and restore game state from file, assuming
@@ -118,10 +121,124 @@ int restore(FILE* fp)
     fclose(fp);
     if (save.version != VRSION) {
         rspeak(VERSION_SKEW, save.version / 10, MOD(save.version, 10), VRSION / 10, MOD(VRSION, 10));
-    } else {
-	game = save.game;
+    } else if (is_valid(&save.game)) {
+        game = save.game;
     }
     return GO_TOP;
 }
 
+bool is_valid(struct game_t* valgame)
+{
+    /*  Save files can be roughly grouped into three groups:
+     *  With valid, reaceable state, with valid, but unreachable
+     *  state and with invaild state. We check that state is
+     *  valid: no states are outside minimal or maximal value
+     */
+
+    /* Prevent division by zero */
+    if (valgame->abbnum == 0) {
+        return false;
+    }
+
+    /* Check for RNG overflow. Truncate */
+    if (valgame->lcg_x >= LCG_M) {
+        valgame->lcg_x %= LCG_M;
+    }
+
+    /* Check for RNG underflow. Transpose */
+    if (valgame->lcg_x < LCG_M) {
+        valgame->lcg_x = LCG_M + (valgame->lcg_x % LCG_M);
+    }
+
+    /*  Bounds check for locations */
+    if ( valgame->chloc  < -1 || valgame->chloc  > NLOCATIONS ||
+         valgame->chloc2 < -1 || valgame->chloc2 > NLOCATIONS ||
+         valgame->loc    <  0 || valgame->loc    > NLOCATIONS ||
+         valgame->newloc <  0 || valgame->newloc > NLOCATIONS ||
+         valgame->oldloc <  0 || valgame->oldloc > NLOCATIONS ||
+         valgame->oldlc2 <  0 || valgame->oldlc2 > NLOCATIONS) {
+        return false;
+    }
+    /*  Bounds check for location arrays */
+    for (int i = 0; i <= NDWARVES; i++) {
+        if (valgame->dloc[i]  < -1 || valgame->dloc[i]  > NLOCATIONS  ||
+            valgame->odloc[i] < -1 || valgame->odloc[i] > NLOCATIONS) {
+            return false;
+        }
+    }
+
+    for (int i = 0; i <= NOBJECTS; i++) {
+        if (valgame->place[i] < -1 || valgame->place[i] > NLOCATIONS  ||
+            valgame->fixed[i] < -1 || valgame->fixed[i] > NLOCATIONS) {
+            return false;
+        }
+    }
+
+    /*  Bounds check for dwarves */
+    if (valgame->dtotal < 0 || valgame->dtotal > NDWARVES ||
+        valgame->dkill < 0  || valgame->dkill  > NDWARVES) {
+        return false;
+    }
+
+    /*  Validate that we didn't die too many times in save */
+    if (valgame->numdie >= NDEATHS) {
+        return false;
+    }
+
+    /* Recalculate tally, throw the towel if in disagreement */
+    long temp_tally = 0;
+    for (int treasure = 1; treasure <= NOBJECTS; treasure++) {
+        if (objects[treasure].is_treasure) {
+            if (valgame->prop[treasure] == STATE_NOTFOUND) {
+                ++temp_tally;
+            }
+        }
+    }
+    if (temp_tally != valgame->tally) {
+        return false;
+    }
+
+    /* Check that properties of objects aren't beyond expected */
+    for (obj_t obj = 0; obj <= NOBJECTS; obj++) {
+        if (valgame->prop[obj] < STATE_NOTFOUND || valgame->prop[obj] > 1) {
+            switch (obj) {
+            case RUG:
+            case DRAGON:
+            case BIRD:
+            case BOTTLE:
+            case PLANT:
+            case PLANT2:
+            case TROLL:
+            case URN:
+            case EGGS:
+            case VASE:
+            case CHAIN:
+                if (valgame->prop[obj] == 2) // There are multiple different states, but it's convenient to clump them together
+                    continue;
+            /* FALLTHRU */
+            case BEAR:
+                if (valgame->prop[BEAR] == CONTENTED_BEAR || valgame->prop[BEAR] == BEAR_DEAD)
+                    continue;
+            /* FALLTHRU */
+            default:
+                return false;
+            }
+        }
+    }
+
+    /* Check that values in linked lists for objects in locations are inside bounds */
+    for (loc_t loc = LOC_NOWHERE; loc <= NLOCATIONS; loc++) {
+        if (valgame->atloc[loc] < NO_OBJECT || valgame->atloc[loc] > NOBJECTS * 2) {
+            return false;
+        }
+    }
+    for (obj_t obj = 0; obj <= NOBJECTS * 2; obj++ ) {
+        if (valgame->link[obj] < NO_OBJECT || valgame->link[obj] > NOBJECTS * 2) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
 /* end */
diff --git a/tests/Makefile b/tests/Makefile
index 4d7f215..fc4801f 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -25,7 +25,6 @@ check: savecheck regress
 	@-advent -l /dev/null <pitfall.log >/dev/null
 
 coverage: check
-	ls -lR $(PARDIR)
 	lcov -t "advent" -o $(PARDIR)/advent.info -c -d $(PARDIR) --gcov-tool=$(GCOV)
 	genhtml -o $(PARDIR)/coverage/ $(PARDIR)/advent.info
 	./coverage_dungeon.py
diff --git a/tests/illformed.chk b/tests/illformed.chk
index 20f18c9..3c763af 100644
--- a/tests/illformed.chk
+++ b/tests/illformed.chk
@@ -669,7 +669,7 @@ The grate is locked.
 
 > seed -123
 
-Seed set to 4294967173
+Seed set to -123
 
 You're outside grate.
 
diff --git a/tests/resumefail2.chk b/tests/resumefail2.chk
index cdda771..a34e001 100644
--- a/tests/resumefail2.chk
+++ b/tests/resumefail2.chk
@@ -11,7 +11,7 @@ down a gully.
 Can't open file y, try again.
 
 I'm sorry, but that Adventure was begun using Version -133.-7 of the
-save file format, and this program uses Version 2.7.  You must find an instance
+save file format, and this program uses Version 2.8.  You must find an instance
 using that other version in order to resume that Adventure.
 
 You're in front of building.

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-games/open-adventure.git



More information about the Pkg-games-commits mailing list