Compare commits

..

No commits in common. "master" and "1.18" have entirely different histories.
master ... 1.18

16 changed files with 135 additions and 588 deletions

View file

@ -23,5 +23,3 @@ You can also use pip to install PyYAML: `pip3 install PyYAML`.
5. Run `./advent` to play.
6. If you want to buld the documentation you will need asciidoctor.
7. Running the regression tests requires batchspell

View file

@ -12,7 +12,7 @@ VERS=$(shell sed -n <NEWS.adoc '/^[0-9]/s/:.*//p' | head -1)
.PHONY: check coverage
CC?=gcc
CCFLAGS+=-std=c99 -Wall -Wextra -D_DEFAULT_SOURCE -DVERSION=\"$(VERS)\" -O2 -D_FORTIFY_SOURCE=2 -fstack-protector-all $(CFLAGS) -g $(EXTRA)
CCFLAGS+=-std=c99 -D_DEFAULT_SOURCE -DVERSION=\"$(VERS)\" -O2 -D_FORTIFY_SOURCE=2 -fstack-protector-all $(CFLAGS) -g $(EXTRA)
LIBS=$(shell pkg-config --libs libedit)
INC+=$(shell pkg-config --cflags libedit)
@ -67,17 +67,14 @@ cheat: $(CHEAT_OBJS) dungeon.o
CSUPPRESSIONS = --suppress=missingIncludeSystem --suppress=invalidscanf
cppcheck:
@-cppcheck -I. --quiet --template gcc -UOBJECT_SET_SEEN --enable=all $(CSUPPRESSIONS) *.[ch]
@-cppcheck -I. --quiet --template gcc -UPROP_SET_SEEN --enable=all $(CSUPPRESSIONS) *.[ch]
pylint:
@-pylint --score=n *.py */*.py
check: advent cheat pylint cppcheck spellcheck
check: advent cheat pylint cppcheck
cd tests; $(MAKE) --quiet
spellcheck:
@batchspell adventure.yaml advent.adoc
reflow:
@clang-format --style="{IndentWidth: 8, UseTab: ForIndentation}" -i $$(find . -name "*.[ch]")
@black --quiet *.py

View file

@ -2,12 +2,6 @@
// SPDX-FileCopyrightText: (C) Eric S. Raymond <esr@thyrsus.com>
// SPDX-License-Identifier: CC-BY-4.0
1.20: 2024-09-23::
Make oldstyle correctly suppress line editing.
1.19: 2024-06-27::
Ensore that the KNIVES_VANISH message can't issue twice.
1.18: 2024-02-15::
Bring the manual page fully up to date.

View file

@ -246,7 +246,7 @@ static phase_codes_t bigwords(vocab_t id) {
static void blast(void) {
/* Blast. No effect unless you've got dynamite, which is a neat trick!
*/
if (OBJECT_IS_NOTFOUND(ROD2) || !game.closed) {
if (PROP_IS_NOTFOUND(ROD2) || !game.closed) {
rspeak(REQUIRES_DYNAMITE);
} else {
if (HERE(ROD2)) {
@ -329,8 +329,8 @@ static phase_codes_t vcarry(verb_t verb, obj_t obj) {
if (game.objects[obj].fixed != IS_FREE) {
switch (obj) {
case PLANT:
rspeak((game.objects[PLANT].prop == PLANT_THIRSTY ||
OBJECT_IS_STASHED(PLANT))
/* Next guard tests whether plant is tiny or stashed */
rspeak(game.objects[PLANT].prop <= PLANT_THIRSTY
? DEEP_ROOTS
: YOU_JOKING);
break;
@ -389,7 +389,7 @@ static phase_codes_t vcarry(verb_t verb, obj_t obj) {
}
if (obj == BIRD && game.objects[BIRD].prop != BIRD_CAGED &&
!OBJECT_IS_STASHED(BIRD)) {
!PROP_IS_STASHED(BIRD)) {
if (game.objects[BIRD].prop == BIRD_FOREST_UNCAGED) {
DESTROY(BIRD);
rspeak(BIRD_CRAP);
@ -406,7 +406,8 @@ static phase_codes_t vcarry(verb_t verb, obj_t obj) {
game.objects[BIRD].prop = BIRD_CAGED;
}
if ((obj == BIRD || obj == CAGE) &&
OBJECT_STATE_EQUALS(BIRD, BIRD_CAGED)) {
(game.objects[BIRD].prop == BIRD_CAGED ||
PROP_STASHED(BIRD) == BIRD_CAGED)) {
/* expression maps BIRD to CAGE and CAGE to BIRD */
carry(BIRD + CAGE - obj, game.loc);
}
@ -417,8 +418,8 @@ static phase_codes_t vcarry(verb_t verb, obj_t obj) {
game.objects[LIQUID()].place = CARRIED;
}
if (GSTONE(obj) && !OBJECT_IS_FOUND(obj)) {
OBJECT_SET_FOUND(obj);
if (GSTONE(obj) && !PROP_IS_FOUND(obj)) {
PROP_SET_FOUND(obj);
game.objects[CAVITY].prop = CAVITY_EMPTY;
}
rspeak(OK_MAN);
@ -676,7 +677,7 @@ static phase_codes_t extinguish(verb_t verb, obj_t obj) {
break;
case LAMP:
state_change(LAMP, LAMP_DARK);
rspeak(IS_DARK_HERE() ? PITCH_DARK : NO_MESSAGE);
rspeak(DARK(game.loc) ? PITCH_DARK : NO_MESSAGE);
break;
case DRAGON:
case VOLCANO:
@ -970,7 +971,7 @@ static phase_codes_t listen(void) {
}
for (obj_t i = 1; i <= NOBJECTS; i++) {
if (!HERE(i) || objects[i].sounds[0] == NULL ||
OBJECT_IS_STASHED(i) || OBJECT_IS_NOTFOUND(i)) {
PROP_IS_STASHED_OR_UNSEEN(i)) {
continue;
}
int mi = game.objects[i].prop;
@ -1150,17 +1151,17 @@ static phase_codes_t read(command_t command)
command.obj = NO_OBJECT;
for (int i = 1; i <= NOBJECTS; i++) {
if (HERE(i) && objects[i].texts[0] != NULL &&
!OBJECT_IS_STASHED(i)) {
!PROP_IS_STASHED(i)) {
command.obj = command.obj * NOBJECTS + i;
}
}
if (command.obj > NOBJECTS || command.obj == NO_OBJECT ||
IS_DARK_HERE()) {
DARK(game.loc)) {
return GO_UNKNOWN;
}
}
if (IS_DARK_HERE()) {
if (DARK(game.loc)) {
sspeak(NO_SEE, command.word[0].raw);
} else if (command.obj == OYSTER) {
if (!TOTING(OYSTER) || !game.closed) {
@ -1174,7 +1175,7 @@ static phase_codes_t read(command_t command)
1); // Not really a sound, but oh well.
}
} else if (objects[command.obj].texts[0] == NULL ||
OBJECT_IS_NOTFOUND(command.obj)) {
PROP_IS_NOTFOUND(command.obj)) {
speak(actions[command.verb].message);
} else {
pspeak(command.obj, study, true,
@ -1350,9 +1351,9 @@ static phase_codes_t wave(verb_t verb, obj_t obj) {
}
if (game.objects[BIRD].prop == BIRD_UNCAGED &&
game.loc == game.objects[STEPS].place && OBJECT_IS_NOTFOUND(JADE)) {
game.loc == game.objects[STEPS].place && PROP_IS_NOTFOUND(JADE)) {
drop(JADE, game.loc);
OBJECT_SET_FOUND(JADE);
PROP_SET_FOUND(JADE);
--game.tally;
rspeak(NECKLACE_FLY);
return GO_CLEAROBJ;

View file

@ -3,9 +3,6 @@
// SPDX-FileCopyrightText: (C) Eric S. Raymond <esr@thyrsus.com>
// SPDX-License-Identifier: CC-BY-4.0
// batchspell: add advent logfile savefile roleplaying Gillogly PDP Ctrl-D
// batchspell: add EOF autosave endianness wumpus zork nethack
== NAME ==
advent - Colossal Cave Adventure
@ -65,7 +62,7 @@ argument of '-' is taken as a directive to read from standard input.
The binary save file format is fragile, dependent on your machine's
endianness, and unlikely to survive through version bumps. There are
version and endianness checks when attempting to restore from a save.
version and emdianness checks when attempting to restore from a save.
The input parser was the first attempt *ever* at natural-language
parsing in a game and has some known deficiencies. While later text

View file

@ -47,6 +47,7 @@
#define IS_FIXED -1
#define IS_FREE 0
#ifndef FOUNDBOOL
/* (ESR) It is fitting that translation of the original ADVENT should
* have left us a maze of twisty little conditionals that resists all
* understanding. Setting and use of what is now the per-object state
@ -60,27 +61,50 @@
* STATE_NOTFOUND is only set on treasures. Non-treasures start the
* game in STATE_FOUND.
*
* PROP_STASHIFY is supposed to map a state property value to a
* PROP_STASHED is supposed to map a state property value to a
* negative range, where the object cannot be picked up but the value
* can be recovered later. Various objects get this property when
* the cave starts to close. Only seems to be significant for the bird
* and readable objects, notably the clam/oyster - but the code around
* those tests is difficult to read.
*
* All tests of the prop member are done with either these macros or ==.
* those test is difficult to read.
*/
#define OBJECT_IS_NOTFOUND(obj) (game.objects[obj].prop == STATE_NOTFOUND)
#define OBJECT_IS_FOUND(obj) (game.objects[obj].prop == STATE_FOUND)
#define OBJECT_SET_FOUND(obj) (game.objects[obj].prop = STATE_FOUND)
#define OBJECT_SET_NOT_FOUND(obj) (game.objects[obj].prop = STATE_NOTFOUND)
#define OBJECT_IS_NOTFOUND2(g, o) (g.objects[o].prop == STATE_NOTFOUND)
#define PROP_IS_INVALID(val) (val < -MAX_STATE - 1 || val > MAX_STATE)
#define PROP_STASHIFY(n) (-1 - (n))
#define OBJECT_STASHIFY(obj, pval) game.objects[obj].prop = PROP_STASHIFY(pval)
#define OBJECT_IS_STASHED(obj) (game.objects[obj].prop < STATE_NOTFOUND)
#define OBJECT_STATE_EQUALS(obj, pval) \
((game.objects[obj].prop == pval) || \
(game.objects[obj].prop == PROP_STASHIFY(pval)))
#define PROP_IS_STASHED(obj) (game.objects[obj].prop < STATE_NOTFOUND)
#define PROP_IS_NOTFOUND(obj) (game.objects[obj].prop == STATE_NOTFOUND)
#define PROP_IS_FOUND(obj) (game.objects[obj].prop == STATE_FOUND)
#define PROP_IS_STASHED_OR_UNSEEN(obj) (game.objects[obj].prop < 0)
#define PROP_SET_FOUND(obj) (game.objects[obj].prop = STATE_FOUND)
#define PROP_SET_NOT_FOUND(obj) (game.objects[obj].prop = STATE_NOTFOUND)
#define PROP_IS_NOTFOUND2(g, o) (g.objects[o].prop == STATE_NOTFOUND)
#define PROP_IS_INVALID(val) (val < -MAX_STATE - 1 || val > MAX_STATE)
#else
/* (ESR) Only the boldest of adventurers will explore here. This
* alternate set of definitions for the macros above was an attempt to
* break from out of the state encoding a per-object "found" member
* telling whether or not the player has seen the object.
*
* What's broken when you try to use thus is
* PROP_IS_STASHED_OR_UNSEEN. The symptom is game.tally getting
* decremented on non-treasures.
*/
#define PROP_STASHIFY(n) (-(n))
#define PROP_IS_STASHED(obj) (game.objects[obj].prop < 0)
#define PROP_IS_NOTFOUND(obj) (!game.objects[obj].found)
#define PROP_IS_FOUND(obj) \
(game.objects[obj].found && game.objects[obj].prop == 0)
#define PROP_IS_STASHED_OR_UNSEEN(obj) \
(!game.objects[obj].found || game.objects[obj].prop < 0)
#define PROP_SET_FOUND(obj) \
do { \
game.objects[obj].found = true; \
game.objects[obj].prop = STATE_FOUND; \
} while (0)
#define PROP_SET_NOT_FOUND(obj) game.objects[obj].found = false
#define PROP_IS_NOTFOUND2(g, o) (!g.objects[o].found)
#define PROP_IS_INVALID(val) (val < -MAX_STATE || val > MAX_STATE)
#define PROP_SET_SEEN(obj) game.objects[object].found = true
#endif
#define PROP_STASHED(obj) PROP_STASHIFY(game.objects[obj].prop)
#define PROMPT "> "
@ -94,15 +118,14 @@
* LIQUID() = object number of liquid in bottle
* LIQLOC(LOC) = object number of liquid (if any) at LOC
* FORCED(LOC) = true if LOC moves without asking for input (COND=2)
* IS_DARK_HERE() = true if location "LOC" is dark
* DARK(LOC) = true if location "LOC" is dark
* PCT(N) = true N% of the time (N integer from 0 to 100)
* GSTONE(OBJ) = true if OBJ is a gemstone
* FOREST(LOC) = true if LOC is part of the forest
* OUTSIDE(LOC) = true if location not in the cave
* OUTSID(LOC) = true if location not in the cave
* INSIDE(LOC) = true if location is in the cave or the building at the
* beginning of the game
* INDEEP(LOC) = true if location is in the Hall of Mists or deeper
* BUG(X) = report bug and exit
* beginning of the game INDEEP(LOC) = true if location is in the Hall of Mists
* or deeper BUG(X) = report bug and exit
*/
#define DESTROY(N) move(N, LOC_NOWHERE)
#define MOD(N, M) ((N) % (M))
@ -120,15 +143,15 @@
(CNDBIT((LOC), COND_FLUID) ? CNDBIT((LOC), COND_OILY) ? OIL : WATER \
: NO_OBJECT)
#define FORCED(LOC) CNDBIT(LOC, COND_FORCED)
#define IS_DARK_HERE() \
#define DARK(DUMMY) \
(!CNDBIT(game.loc, COND_LIT) && \
(game.objects[LAMP].prop == LAMP_DARK || !HERE(LAMP)))
#define PCT(N) (randrange(100) < (N))
#define GSTONE(OBJ) \
((OBJ) == EMERALD || (OBJ) == RUBY || (OBJ) == AMBER || (OBJ) == SAPPH)
#define FOREST(LOC) CNDBIT(LOC, COND_FOREST)
#define OUTSIDE(LOC) (CNDBIT(LOC, COND_ABOVE) || FOREST(LOC))
#define INSIDE(LOC) (!OUTSIDE(LOC) || LOC == LOC_BUILDING)
#define OUTSID(LOC) (CNDBIT(LOC, COND_ABOVE) || FOREST(LOC))
#define INSIDE(LOC) (!OUTSID(LOC) || LOC == LOC_BUILDING)
#define INDEEP(LOC) CNDBIT((LOC), COND_DEEP)
#define BUG(x) bug(x, #x)
@ -234,8 +257,11 @@ struct game_t {
loc_t oldloc; // prior loc of each dwarf, initially garbage
} dwarves[NDWARVES + 1];
struct {
#ifdef FOUNDBOOL
bool32_t found; // has the location of this object been found?
#endif
loc_t fixed; // fixed location of object (if not IS_FREE)
int32_t prop; // object state
int32_t prop; // object state */
loc_t place; // location of object
} objects[NOBJECTS + 1];
struct {

View file

@ -1,10 +1,6 @@
# SPDX-FileCopyrightText: (C) Eric S. Raymond <esr@thyrsus.com>
# SPDX-License-Identifier: BSD-2-Clause
#
# batchspell: add XYZZY Twopit Bedquilt ne se sw nw dwarves dwarvish gouts
# batchspell: add Crowther add axe pinin Har har meself Hmmm Adventuredom
# batchspell: add Tsk gameplay bugfixes
#
# This YAML file gets processed into a collection of data structures and
# variable initializers describing Colossal Cave. It replaces an ad-hoc
# text database shipped with Adventure versions up to 2.5. The format
@ -14,7 +10,7 @@
# We define a bunch of YAML structures:
#
# motions: Motion words, grouped into synonyms. The 'oldstyle'
# attribute, if false, means that single-letter synonyms should not be
# attribute, if false, means that single-letter synonyms should be
# accepted in oldstyle mode; it defaults to true.
#
# actions: Action words, grouped into synonyms, and their corresponding
@ -3436,7 +3432,7 @@ objects: !!omap
- 'There are a few recent issues of "Spelunker Today" magazine here.'
texts:
- |-
I'm afraid the magazine is written in dwarvish. But penciled on one
I'm afraid the magazine is written in dwarvish. But pencilled on one
cover you see, "Please leave the magazines at the construction site."
- DWARF:
words: ['dwarf', 'dwarv']
@ -3944,13 +3940,11 @@ obituaries:
Oh dear, you seem to have gotten yourself killed. I might be able to
help you out, but I've never really done this before. Do you want me
to try to reincarnate you?
# batchspell: add wr
yes_response: |-
All right. But don't blame me if something goes wr......
--- POOF!! ---
You are engulfed in a cloud of orange smoke. Coughing and gasping,
you emerge from the smoke and find....
# batchspell: remove wr
- query: |-
You clumsy oaf, you've done it again! I don't know how long I can
keep this up. Do you want me to try reincarnating you again?
@ -4232,7 +4226,7 @@ actions: !!omap
message: |-
There is a puff of orange smoke; within it, fiery runes spell out:
Open Adventure %V - http://www.catb.org/esr/open-adventure/
\tOpen Adventure %V - http://www.catb.org/esr/open-adventure/
words: ['versi']
noaction: true

17
init.c
View file

@ -1,7 +1,7 @@
/*
* Initialisation
*
* SPDX-FileCopyrightText: (C) 1977, 2005 by Will Crowther and Don Woods
* SPDX-FileCopyrightText: (C) 1977, 2005 by Will Crowther and Don Woodsm
* SPDX-License-Identifier: BSD-2-Clause
*/
@ -76,18 +76,13 @@ int initialise(void) {
/* Treasure props are initially STATE_NOTFOUND, and are set to
* STATE_FOUND the first time they are described. game.tally
* keeps track of how many are not yet found, so we know when to
* close the cave.
* (ESR) Non-treasures are set to STATE_FOUND explicitly so we
* don't rely on the value of uninitialized storage. This is to
* make translation to future languages easier. */
for (int object = 1; object <= NOBJECTS; object++) {
if (objects[object].is_treasure) {
* close the cave. */
for (int treasure = 1; treasure <= NOBJECTS; treasure++) {
if (objects[treasure].is_treasure) {
++game.tally;
if (objects[object].inventory != NULL) {
OBJECT_SET_NOT_FOUND(object);
if (objects[treasure].inventory != 0) {
PROP_SET_NOT_FOUND(treasure);
}
} else {
OBJECT_SET_FOUND(object);
}
}
game.conds = setbit(COND_HBASE);

52
main.c
View file

@ -81,7 +81,7 @@ char *myreadline(const char *prompt) {
}
}
if (isatty(fileno(settings.scriptfp)) && !settings.oldstyle) {
if (isatty(fileno(settings.scriptfp))) {
free(buf); // LCOV_EXCL_LINE
return readline(prompt); // LCOV_EXCL_LINE
} else {
@ -152,8 +152,8 @@ static void checkhints(void) {
game.hints[hint].lc = 0;
return;
case 4: /* dark */
if (!OBJECT_IS_NOTFOUND(EMERALD) &&
OBJECT_IS_NOTFOUND(PYRAMID)) {
if (!PROP_IS_NOTFOUND(EMERALD) &&
PROP_IS_NOTFOUND(PYRAMID)) {
break;
}
game.hints[hint].lc = 0;
@ -188,8 +188,7 @@ static void checkhints(void) {
return;
case 9: /* jade */
if (game.tally == 1 &&
(OBJECT_IS_STASHED(JADE) ||
OBJECT_IS_NOTFOUND(JADE))) {
PROP_IS_STASHED_OR_UNSEEN(JADE)) {
break;
}
game.hints[hint].lc = 0;
@ -232,8 +231,8 @@ static bool spotted_by_pirate(int i) {
* tally=1 for an unseen chest, let the pirate be spotted. Note
* that game.objexts,place[CHEST] = LOC_NOWHERE might mean that he's
* thrown it to the troll, but in that case he's seen the chest
* OBJECT_IS_FOUND(CHEST) == true. */
if (game.loc == game.chloc || !OBJECT_IS_NOTFOUND(CHEST)) {
* PROP_IS_FOUND(CHEST) == true. */
if (game.loc == game.chloc || !PROP_IS_NOTFOUND(CHEST)) {
return true;
}
int snarfed = 0;
@ -534,7 +533,7 @@ static void describe_location(void) {
msg = locations[game.loc].description.big;
}
if (!FORCED(game.loc) && IS_DARK_HERE()) {
if (!FORCED(game.loc) && DARK(game.loc)) {
msg = arbitrary_messages[PITCH_DARK];
}
@ -640,7 +639,7 @@ static void playermove(int motion) {
} else if (motion == CAVE) {
/* Cave. Different messages depending on whether above ground.
*/
rspeak((OUTSIDE(game.loc) && game.loc != LOC_GRATE)
rspeak((OUTSID(game.loc) && game.loc != LOC_GRATE)
? FOLLOW_STREAM
: NEED_DETAIL);
return;
@ -1047,7 +1046,7 @@ static void listobjects(void) {
* Similarly for chain; game.prop is initially CHAINING_BEAR (locked to
* bear). These hacks are because game.prop=0 is needed to
* get full score. */
if (!IS_DARK_HERE()) {
if (!DARK(game.loc)) {
++game.locs[game.loc].abbrev;
for (int i = game.locs[game.loc].atloc; i != 0;
i = game.link[i]) {
@ -1062,11 +1061,11 @@ static void listobjects(void) {
* running this code only on objects with the treasure
* property set. Nope. There is mystery here.
*/
if (OBJECT_IS_STASHED(i) || OBJECT_IS_NOTFOUND(obj)) {
if (PROP_IS_STASHED_OR_UNSEEN(obj)) {
if (game.closed) {
continue;
}
OBJECT_SET_FOUND(obj);
PROP_SET_FOUND(obj);
if (obj == RUG) {
game.objects[RUG].prop = RUG_DRAGON;
}
@ -1193,7 +1192,7 @@ static bool preprocess_command(command_t *command) {
static bool do_move(void) {
/* Actually execute the move to the new location and dwarf movement */
/* Can't leave cave once it's closing (except by main office). */
if (OUTSIDE(game.newloc) && game.newloc != 0 && game.closng) {
if (OUTSID(game.newloc) && game.newloc != 0 && game.closng) {
rspeak(EXIT_CLOSED);
game.newloc = game.loc;
if (!game.panic) {
@ -1229,7 +1228,7 @@ static bool do_move(void) {
/* The easiest way to get killed is to fall into a pit in
* pitch darkness. */
if (!FORCED(game.loc) && IS_DARK_HERE() && game.wzdark &&
if (!FORCED(game.loc) && DARK(game.loc) && game.wzdark &&
PCT(PIT_KILL_PROB)) {
rspeak(PIT_FALL);
game.oldlc2 = game.loc;
@ -1267,28 +1266,25 @@ static bool do_command(void) {
* way objects won't be described until they've
* been picked up and put down separate from
* their respective piles. */
if ((OBJECT_IS_NOTFOUND(OYSTER) ||
OBJECT_IS_STASHED(OYSTER)) &&
if ((PROP_IS_NOTFOUND(OYSTER) ||
PROP_IS_STASHED(OYSTER)) &&
TOTING(OYSTER)) {
pspeak(OYSTER, look, true, 1);
}
for (size_t i = 1; i <= NOBJECTS; i++) {
if (TOTING(i) &&
(OBJECT_IS_NOTFOUND(i) ||
OBJECT_IS_STASHED(i))) {
OBJECT_STASHIFY(
i, game.objects[i].prop);
if (TOTING(i) && (PROP_IS_NOTFOUND(i) ||
PROP_IS_STASHED(i))) {
game.objects[i].prop =
PROP_STASHED(i);
}
}
}
/* Check to see if the room is dark. */
game.wzdark = IS_DARK_HERE();
/* If the knife is not here it permanently disappears.
* Possibly this should fire if the knife is here but
* the room is dark? */
if (game.knfloc > LOC_NOWHERE &&
/* Check to see if the room is dark. If the knife is
* here, and it's dark, the knife permanently disappears
*/
game.wzdark = DARK(game.loc);
if (game.knfloc != LOC_NOWHERE &&
game.knfloc != game.loc) {
game.knfloc = LOC_NOWHERE;
}

25
misc.c
View file

@ -12,7 +12,6 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <sys/time.h>
#include <unistd.h>
@ -496,8 +495,8 @@ static void tokenize(char *raw, command_t *cmd) {
memset(&cmd->word[1].raw, '\0', sizeof(cmd->word[1].raw));
/* Bound prefix on the %s would be needed to prevent buffer
* overflow. We shortstop this more simply by making each
* raw-input buffer as long as the entire input buffer. */
* overflow. but we shortstop this more simply by making each
* raw-input buffer as int as the entire input buffer. */
sscanf(raw, "%s%s", cmd->word[0].raw, cmd->word[1].raw);
/* (ESR) In oldstyle mode, simulate the uppercasing and truncating
@ -513,14 +512,10 @@ static void tokenize(char *raw, command_t *cmd) {
* in their tools. On the other, not simulating this misbehavior
* goes against the goal of making oldstyle as accurate as
* possible an emulation of the original UI.
*
* The definition of TRUNCLEN is dubious. It accurately reflects the
* FORTRAN, but it's possible that was a bug and the proper definition
* is (TOKLEN).
*/
#define TRUNCLEN (TOKLEN + TOKLEN)
if (settings.oldstyle) {
cmd->word[0].raw[TRUNCLEN] = cmd->word[1].raw[TRUNCLEN] = '\0';
cmd->word[0].raw[TOKLEN + TOKLEN] =
cmd->word[1].raw[TOKLEN + TOKLEN] = '\0';
for (size_t i = 0; i < strlen(cmd->word[0].raw); i++) {
cmd->word[0].raw[i] = toupper(cmd->word[0].raw[i]);
}
@ -622,12 +617,14 @@ void move(obj_t object, loc_t where) {
}
void put(obj_t object, loc_t where, int pval) {
/* put() is the same as move(), except the object is stashed and
* can no longer be picked up. */
/* put() is the same as move(), except it returns a value used to set
* up the negated game.prop values for the repository objects. */
move(object, where);
OBJECT_STASHIFY(object, pval);
#ifdef OBJECT_SET_SEEN
OBJECT_SET_SEEN(object);
/* (ESR) Read this in combination with the macro defintions in advebt.h.
*/
game.objects[object].prop = PROP_STASHIFY(pval);
#ifdef PROP_SET_SEEN
PROP_SET_SEEN(object);
#endif
}

View file

@ -16,8 +16,8 @@ of Peje Nilsson in restructuring some particularly grotty gotos is
gratefully acknowledged. Petr Voropaev contributed fuzz testing and
code cleanups. Aaron Traas did a lot of painstaking work to improve
test coverage, and factored out the last handful of gotos. Ryan
Sarson nudged us into fixing a longstanding minor bug in the
handling of incorrect magic-word sequences,
Sarson nudged us into fixing a longstannding minor bug in the
handling of incorrect magic-word sequebcesm,
== Nomenclature ==
@ -75,15 +75,10 @@ Bug fixes:
* A few minor typos have been corrected: absence of capitalization on
"Swiss" and "Persian", inconsistent spelling of "imbedded" vs. "embedded",
"eying" for "eyeing", "thresholds" for "threshholds", "pencilled"
for "penciled".
"eying" for "eyeing", "thresholds" for "threshholds".
* Under odd circumstances (dropping rug or vase outdoors) the game could
formerly say "floor" when it should say "ground" (or "dirt", or
something).
* The "knives vanish" message could formerly be emitted when "I see no
knife here." would be appropriate.
formerly say "floor" when it should say "ground" (or "dirt", or something).
Enhancements:

View file

@ -230,7 +230,7 @@ bool is_valid(struct game_t valgame) {
int temp_tally = 0;
for (int treasure = 1; treasure <= NOBJECTS; treasure++) {
if (objects[treasure].is_treasure) {
if (OBJECT_IS_NOTFOUND2(valgame, treasure)) {
if (PROP_IS_NOTFOUND2(valgame, treasure)) {
++temp_tally;
}
}

View file

@ -49,11 +49,11 @@ int score(enum termination mode) {
if (i > CHEST) {
k = 16;
}
if (!OBJECT_IS_STASHED(i) && !OBJECT_IS_NOTFOUND(i)) {
if (!PROP_IS_STASHED(i) && !PROP_IS_NOTFOUND(i)) {
score += 2;
}
if (game.objects[i].place == LOC_BUILDING &&
OBJECT_IS_FOUND(i)) {
PROP_IS_FOUND(i)) {
score += k - 2;
}
mxscor += k;

View file

@ -170,7 +170,7 @@ oldcompare:
echo 1..$(words $(shell ls *.log))) | $(TAPFILTER)
@rm *.ochk *-new advent430 adventure.data
# List all NOCOMPARE tests.
# List all NOMPARE tests.
residuals:
@grep -n NOCOMPARE *.log

View file

@ -1,386 +0,0 @@
Welcome to Adventure!! Would you like instructions?
> no
You are standing at the end of a road before a small brick building.
Around you is a forest. A small stream flows out of the building and
down a gully.
> seed 1640849217
Seed set to 1640849217
You're in front of building.
> e
You are inside a building, a well house for a large spring.
There are some keys on the ground here.
There is a shiny brass lamp nearby.
There is food here.
There is a bottle of water here.
> get lamp
OK
> xyzzy
>>Foof!<<
It is now pitch dark. If you proceed you will likely fall into a pit.
> get rod
OK
> on
Your lamp is now on.
You are in a debris room filled with stuff washed in from the surface.
A low wide passage with cobbles becomes plugged with mud and debris
here, but an awkward canyon leads upward and west. In the mud someone
has scrawled, "MAGIC WORD XYZZY".
> w
You are in an awkward sloping east/west canyon.
> w
You are in a splendid chamber thirty feet high. The walls are frozen
rivers of orange stone. An awkward canyon and a good passage exit
from east and west sides of the chamber.
A cheerful little bird is sitting here singing.
> w
At your feet is a small pit breathing traces of white mist. An east
passage ends here except for a small crack leading on.
Rough stone steps lead down the pit.
> d
You are at one end of a vast hall stretching forward out of sight to
the west. There are openings to either side. Nearby, a wide stone
staircase leads downward. The hall is filled with wisps of white mist
swaying to and fro almost as if alive. A cold wind blows up the
staircase. There is a passage at the top of a dome behind you.
Rough stone steps lead up the dome.
> w
You are on the east bank of a fissure slicing clear across the hall.
The mist is quite thick here, and the fissure is too wide to jump.
> wave rod
A crystal bridge now spans the fissure.
> w
You are on the west side of the fissure in the Hall of Mists.
There are diamonds here!
A crystal bridge spans the fissure.
> e
You're on east bank of fissure.
A crystal bridge spans the fissure.
> w
You're on west bank of fissure.
There are diamonds here!
A crystal bridge spans the fissure.
> e
You're on east bank of fissure.
A crystal bridge spans the fissure.
> w
You're on west bank of fissure.
There are diamonds here!
A crystal bridge spans the fissure.
> e
You're on east bank of fissure.
A crystal bridge spans the fissure.
> w
You're on west bank of fissure.
There are diamonds here!
A crystal bridge spans the fissure.
> e
You're on east bank of fissure.
A crystal bridge spans the fissure.
> w
You're on west bank of fissure.
There are diamonds here!
A crystal bridge spans the fissure.
> e
You are on the east bank of a fissure slicing clear across the hall.
The mist is quite thick here, and the fissure is too wide to jump.
A crystal bridge spans the fissure.
> w
You are on the west side of the fissure in the Hall of Mists.
There are diamonds here!
A crystal bridge spans the fissure.
> e
You're on east bank of fissure.
A crystal bridge spans the fissure.
> w
You're on west bank of fissure.
There are diamonds here!
A crystal bridge spans the fissure.
> e
You're on east bank of fissure.
A crystal bridge spans the fissure.
> w
You're on west bank of fissure.
There are diamonds here!
A crystal bridge spans the fissure.
> e
You're on east bank of fissure.
A crystal bridge spans the fissure.
> w
You're on west bank of fissure.
There are diamonds here!
A crystal bridge spans the fissure.
> e
You're on east bank of fissure.
A crystal bridge spans the fissure.
> w
You're on west bank of fissure.
There are diamonds here!
A crystal bridge spans the fissure.
> e
You are on the east bank of a fissure slicing clear across the hall.
The mist is quite thick here, and the fissure is too wide to jump.
A crystal bridge spans the fissure.
> w
You are on the west side of the fissure in the Hall of Mists.
There are diamonds here!
A crystal bridge spans the fissure.
> e
You're on east bank of fissure.
A crystal bridge spans the fissure.
> w
You're on west bank of fissure.
There are diamonds here!
A crystal bridge spans the fissure.
> e
You're on east bank of fissure.
A crystal bridge spans the fissure.
> w
You're on west bank of fissure.
There are diamonds here!
A crystal bridge spans the fissure.
> e
You're on east bank of fissure.
A crystal bridge spans the fissure.
> w
You're on west bank of fissure.
There are diamonds here!
A crystal bridge spans the fissure.
> e
You're on east bank of fissure.
A crystal bridge spans the fissure.
> w
You're on west bank of fissure.
There are diamonds here!
A crystal bridge spans the fissure.
> e
You are on the east bank of a fissure slicing clear across the hall.
The mist is quite thick here, and the fissure is too wide to jump.
A crystal bridge spans the fissure.
> w
You are on the west side of the fissure in the Hall of Mists.
There are diamonds here!
A crystal bridge spans the fissure.
> e
You're on east bank of fissure.
A crystal bridge spans the fissure.
> w
You're on west bank of fissure.
There are diamonds here!
A crystal bridge spans the fissure.
> e
A little dwarf just walked around a corner, saw you, threw a little
axe at you which missed, cursed, and ran away.
You're on east bank of fissure.
There is a little axe here.
A crystal bridge spans the fissure.
> w
There is a threatening little dwarf in the room with you!
One sharp nasty knife is thrown at you!
It misses!
You're on west bank of fissure.
There are diamonds here!
A crystal bridge spans the fissure.
> get knife
The dwarves' knives vanish as they strike the walls of the cave.
> look
Sorry, but I am not allowed to give more detail. I will repeat the
long description of your location.
There is a threatening little dwarf in the room with you!
One sharp nasty knife is thrown at you!
It misses!
You are on the west side of the fissure in the Hall of Mists.
There are diamonds here!
A crystal bridge spans the fissure.
> get knife
I see no knife here.
> quit
Do you really want to quit now?
> yes
OK
You scored 59 out of a possible 430, using 50 turns.
Your score qualifies you as a novice class adventurer.
To achieve the next higher rating, you need 62 more points.

View file

@ -1,57 +0,0 @@
## Test whether KNIVES_VANISH can be issued twice
# SPDX-FileCopyrightText: Copyright Eric S. Raymond <esr@thyrsus.com>
# SPDX-License-Identifier: BSD-2-Clause
#NOCOMPARE avoide spuriuous failure on second "get knife"
no
seed 1640849217
e
get lamp
xyzzy
get rod
on
w
w
w
d
w
wave rod
w
e
w
e
w
e
w
e
w
e
w
e
w
e
w
e
w
e
w
e
w
e
w
e
w
e
w
e
w
e
w
e
w
e
w
get knife
look
get knife
quit
yes