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 <[email protected]> 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 _______________________________________________ Pkg-games-commits mailing list [email protected] http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/pkg-games-commits

