Compare commits
No commits in common. "master" and "1.18" have entirely different histories.
16 changed files with 135 additions and 588 deletions
|
@ -23,5 +23,3 @@ You can also use pip to install PyYAML: `pip3 install PyYAML`.
|
||||||
5. Run `./advent` to play.
|
5. Run `./advent` to play.
|
||||||
|
|
||||||
6. If you want to buld the documentation you will need asciidoctor.
|
6. If you want to buld the documentation you will need asciidoctor.
|
||||||
|
|
||||||
7. Running the regression tests requires batchspell
|
|
||||||
|
|
9
Makefile
9
Makefile
|
@ -12,7 +12,7 @@ VERS=$(shell sed -n <NEWS.adoc '/^[0-9]/s/:.*//p' | head -1)
|
||||||
.PHONY: check coverage
|
.PHONY: check coverage
|
||||||
|
|
||||||
CC?=gcc
|
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)
|
LIBS=$(shell pkg-config --libs libedit)
|
||||||
INC+=$(shell pkg-config --cflags libedit)
|
INC+=$(shell pkg-config --cflags libedit)
|
||||||
|
|
||||||
|
@ -67,17 +67,14 @@ cheat: $(CHEAT_OBJS) dungeon.o
|
||||||
|
|
||||||
CSUPPRESSIONS = --suppress=missingIncludeSystem --suppress=invalidscanf
|
CSUPPRESSIONS = --suppress=missingIncludeSystem --suppress=invalidscanf
|
||||||
cppcheck:
|
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:
|
||||||
@-pylint --score=n *.py */*.py
|
@-pylint --score=n *.py */*.py
|
||||||
|
|
||||||
check: advent cheat pylint cppcheck spellcheck
|
check: advent cheat pylint cppcheck
|
||||||
cd tests; $(MAKE) --quiet
|
cd tests; $(MAKE) --quiet
|
||||||
|
|
||||||
spellcheck:
|
|
||||||
@batchspell adventure.yaml advent.adoc
|
|
||||||
|
|
||||||
reflow:
|
reflow:
|
||||||
@clang-format --style="{IndentWidth: 8, UseTab: ForIndentation}" -i $$(find . -name "*.[ch]")
|
@clang-format --style="{IndentWidth: 8, UseTab: ForIndentation}" -i $$(find . -name "*.[ch]")
|
||||||
@black --quiet *.py
|
@black --quiet *.py
|
||||||
|
|
|
@ -2,12 +2,6 @@
|
||||||
// SPDX-FileCopyrightText: (C) Eric S. Raymond <esr@thyrsus.com>
|
// SPDX-FileCopyrightText: (C) Eric S. Raymond <esr@thyrsus.com>
|
||||||
// SPDX-License-Identifier: CC-BY-4.0
|
// 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::
|
1.18: 2024-02-15::
|
||||||
Bring the manual page fully up to date.
|
Bring the manual page fully up to date.
|
||||||
|
|
||||||
|
|
31
actions.c
31
actions.c
|
@ -246,7 +246,7 @@ static phase_codes_t bigwords(vocab_t id) {
|
||||||
static void blast(void) {
|
static void blast(void) {
|
||||||
/* Blast. No effect unless you've got dynamite, which is a neat trick!
|
/* 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);
|
rspeak(REQUIRES_DYNAMITE);
|
||||||
} else {
|
} else {
|
||||||
if (HERE(ROD2)) {
|
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) {
|
if (game.objects[obj].fixed != IS_FREE) {
|
||||||
switch (obj) {
|
switch (obj) {
|
||||||
case PLANT:
|
case PLANT:
|
||||||
rspeak((game.objects[PLANT].prop == PLANT_THIRSTY ||
|
/* Next guard tests whether plant is tiny or stashed */
|
||||||
OBJECT_IS_STASHED(PLANT))
|
rspeak(game.objects[PLANT].prop <= PLANT_THIRSTY
|
||||||
? DEEP_ROOTS
|
? DEEP_ROOTS
|
||||||
: YOU_JOKING);
|
: YOU_JOKING);
|
||||||
break;
|
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 &&
|
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) {
|
if (game.objects[BIRD].prop == BIRD_FOREST_UNCAGED) {
|
||||||
DESTROY(BIRD);
|
DESTROY(BIRD);
|
||||||
rspeak(BIRD_CRAP);
|
rspeak(BIRD_CRAP);
|
||||||
|
@ -406,7 +406,8 @@ static phase_codes_t vcarry(verb_t verb, obj_t obj) {
|
||||||
game.objects[BIRD].prop = BIRD_CAGED;
|
game.objects[BIRD].prop = BIRD_CAGED;
|
||||||
}
|
}
|
||||||
if ((obj == BIRD || obj == CAGE) &&
|
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 */
|
/* expression maps BIRD to CAGE and CAGE to BIRD */
|
||||||
carry(BIRD + CAGE - obj, game.loc);
|
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;
|
game.objects[LIQUID()].place = CARRIED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GSTONE(obj) && !OBJECT_IS_FOUND(obj)) {
|
if (GSTONE(obj) && !PROP_IS_FOUND(obj)) {
|
||||||
OBJECT_SET_FOUND(obj);
|
PROP_SET_FOUND(obj);
|
||||||
game.objects[CAVITY].prop = CAVITY_EMPTY;
|
game.objects[CAVITY].prop = CAVITY_EMPTY;
|
||||||
}
|
}
|
||||||
rspeak(OK_MAN);
|
rspeak(OK_MAN);
|
||||||
|
@ -676,7 +677,7 @@ static phase_codes_t extinguish(verb_t verb, obj_t obj) {
|
||||||
break;
|
break;
|
||||||
case LAMP:
|
case LAMP:
|
||||||
state_change(LAMP, LAMP_DARK);
|
state_change(LAMP, LAMP_DARK);
|
||||||
rspeak(IS_DARK_HERE() ? PITCH_DARK : NO_MESSAGE);
|
rspeak(DARK(game.loc) ? PITCH_DARK : NO_MESSAGE);
|
||||||
break;
|
break;
|
||||||
case DRAGON:
|
case DRAGON:
|
||||||
case VOLCANO:
|
case VOLCANO:
|
||||||
|
@ -970,7 +971,7 @@ static phase_codes_t listen(void) {
|
||||||
}
|
}
|
||||||
for (obj_t i = 1; i <= NOBJECTS; i++) {
|
for (obj_t i = 1; i <= NOBJECTS; i++) {
|
||||||
if (!HERE(i) || objects[i].sounds[0] == NULL ||
|
if (!HERE(i) || objects[i].sounds[0] == NULL ||
|
||||||
OBJECT_IS_STASHED(i) || OBJECT_IS_NOTFOUND(i)) {
|
PROP_IS_STASHED_OR_UNSEEN(i)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
int mi = game.objects[i].prop;
|
int mi = game.objects[i].prop;
|
||||||
|
@ -1150,17 +1151,17 @@ static phase_codes_t read(command_t command)
|
||||||
command.obj = NO_OBJECT;
|
command.obj = NO_OBJECT;
|
||||||
for (int i = 1; i <= NOBJECTS; i++) {
|
for (int i = 1; i <= NOBJECTS; i++) {
|
||||||
if (HERE(i) && objects[i].texts[0] != NULL &&
|
if (HERE(i) && objects[i].texts[0] != NULL &&
|
||||||
!OBJECT_IS_STASHED(i)) {
|
!PROP_IS_STASHED(i)) {
|
||||||
command.obj = command.obj * NOBJECTS + i;
|
command.obj = command.obj * NOBJECTS + i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (command.obj > NOBJECTS || command.obj == NO_OBJECT ||
|
if (command.obj > NOBJECTS || command.obj == NO_OBJECT ||
|
||||||
IS_DARK_HERE()) {
|
DARK(game.loc)) {
|
||||||
return GO_UNKNOWN;
|
return GO_UNKNOWN;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IS_DARK_HERE()) {
|
if (DARK(game.loc)) {
|
||||||
sspeak(NO_SEE, command.word[0].raw);
|
sspeak(NO_SEE, command.word[0].raw);
|
||||||
} else if (command.obj == OYSTER) {
|
} else if (command.obj == OYSTER) {
|
||||||
if (!TOTING(OYSTER) || !game.closed) {
|
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.
|
1); // Not really a sound, but oh well.
|
||||||
}
|
}
|
||||||
} else if (objects[command.obj].texts[0] == NULL ||
|
} else if (objects[command.obj].texts[0] == NULL ||
|
||||||
OBJECT_IS_NOTFOUND(command.obj)) {
|
PROP_IS_NOTFOUND(command.obj)) {
|
||||||
speak(actions[command.verb].message);
|
speak(actions[command.verb].message);
|
||||||
} else {
|
} else {
|
||||||
pspeak(command.obj, study, true,
|
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 &&
|
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);
|
drop(JADE, game.loc);
|
||||||
OBJECT_SET_FOUND(JADE);
|
PROP_SET_FOUND(JADE);
|
||||||
--game.tally;
|
--game.tally;
|
||||||
rspeak(NECKLACE_FLY);
|
rspeak(NECKLACE_FLY);
|
||||||
return GO_CLEAROBJ;
|
return GO_CLEAROBJ;
|
||||||
|
|
|
@ -3,9 +3,6 @@
|
||||||
// SPDX-FileCopyrightText: (C) Eric S. Raymond <esr@thyrsus.com>
|
// SPDX-FileCopyrightText: (C) Eric S. Raymond <esr@thyrsus.com>
|
||||||
// SPDX-License-Identifier: CC-BY-4.0
|
// 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 ==
|
== NAME ==
|
||||||
advent - Colossal Cave Adventure
|
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
|
The binary save file format is fragile, dependent on your machine's
|
||||||
endianness, and unlikely to survive through version bumps. There are
|
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
|
The input parser was the first attempt *ever* at natural-language
|
||||||
parsing in a game and has some known deficiencies. While later text
|
parsing in a game and has some known deficiencies. While later text
|
||||||
|
|
100
advent.h
100
advent.h
|
@ -47,6 +47,7 @@
|
||||||
#define IS_FIXED -1
|
#define IS_FIXED -1
|
||||||
#define IS_FREE 0
|
#define IS_FREE 0
|
||||||
|
|
||||||
|
#ifndef FOUNDBOOL
|
||||||
/* (ESR) It is fitting that translation of the original ADVENT should
|
/* (ESR) It is fitting that translation of the original ADVENT should
|
||||||
* have left us a maze of twisty little conditionals that resists all
|
* have left us a maze of twisty little conditionals that resists all
|
||||||
* understanding. Setting and use of what is now the per-object state
|
* understanding. Setting and use of what is now the per-object state
|
||||||
|
@ -60,49 +61,71 @@
|
||||||
* STATE_NOTFOUND is only set on treasures. Non-treasures start the
|
* STATE_NOTFOUND is only set on treasures. Non-treasures start the
|
||||||
* game in STATE_FOUND.
|
* 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
|
* negative range, where the object cannot be picked up but the value
|
||||||
* can be recovered later. Various objects get this property when
|
* can be recovered later. Various objects get this property when
|
||||||
* the cave starts to close. Only seems to be significant for the bird
|
* the cave starts to close. Only seems to be significant for the bird
|
||||||
* and readable objects, notably the clam/oyster - but the code around
|
* and readable objects, notably the clam/oyster - but the code around
|
||||||
* those tests is difficult to read.
|
* those test is difficult to read.
|
||||||
*
|
|
||||||
* All tests of the prop member are done with either these macros or ==.
|
|
||||||
*/
|
*/
|
||||||
#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 PROP_STASHIFY(n) (-1 - (n))
|
||||||
#define OBJECT_STASHIFY(obj, pval) game.objects[obj].prop = PROP_STASHIFY(pval)
|
#define PROP_IS_STASHED(obj) (game.objects[obj].prop < STATE_NOTFOUND)
|
||||||
#define OBJECT_IS_STASHED(obj) (game.objects[obj].prop < STATE_NOTFOUND)
|
#define PROP_IS_NOTFOUND(obj) (game.objects[obj].prop == STATE_NOTFOUND)
|
||||||
#define OBJECT_STATE_EQUALS(obj, pval) \
|
#define PROP_IS_FOUND(obj) (game.objects[obj].prop == STATE_FOUND)
|
||||||
((game.objects[obj].prop == pval) || \
|
#define PROP_IS_STASHED_OR_UNSEEN(obj) (game.objects[obj].prop < 0)
|
||||||
(game.objects[obj].prop == PROP_STASHIFY(pval)))
|
#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 "> "
|
#define PROMPT "> "
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* DESTROY(N) = Get rid of an item by putting it in LOC_NOWHERE
|
* DESTROY(N) = Get rid of an item by putting it in LOC_NOWHERE
|
||||||
* MOD(N,M) = Arithmetic modulus
|
* MOD(N,M) = Arithmetic modulus
|
||||||
* TOTING(OBJ) = true if the OBJ is being carried
|
* TOTING(OBJ) = true if the OBJ is being carried
|
||||||
* AT(OBJ) = true if on either side of two-placed object
|
* AT(OBJ) = true if on either side of two-placed object
|
||||||
* HERE(OBJ) = true if the OBJ is at "LOC" (or is being carried)
|
* HERE(OBJ) = true if the OBJ is at "LOC" (or is being carried)
|
||||||
* CNDBIT(L,N) = true if COND(L) has bit n set (bit 0 is units bit)
|
* CNDBIT(L,N) = true if COND(L) has bit n set (bit 0 is units bit)
|
||||||
* LIQUID() = object number of liquid in bottle
|
* LIQUID() = object number of liquid in bottle
|
||||||
* LIQLOC(LOC) = object number of liquid (if any) at LOC
|
* LIQLOC(LOC) = object number of liquid (if any) at LOC
|
||||||
* FORCED(LOC) = true if LOC moves without asking for input (COND=2)
|
* 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)
|
* PCT(N) = true N% of the time (N integer from 0 to 100)
|
||||||
* GSTONE(OBJ) = true if OBJ is a gemstone
|
* GSTONE(OBJ) = true if OBJ is a gemstone
|
||||||
* FOREST(LOC) = true if LOC is part of the forest
|
* 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
|
* INSIDE(LOC) = true if location is in the cave or the building at the
|
||||||
* beginning of the game
|
* beginning of the game INDEEP(LOC) = true if location is in the Hall of Mists
|
||||||
* INDEEP(LOC) = true if location is in the Hall of Mists or deeper
|
* or deeper BUG(X) = report bug and exit
|
||||||
* BUG(X) = report bug and exit
|
|
||||||
*/
|
*/
|
||||||
#define DESTROY(N) move(N, LOC_NOWHERE)
|
#define DESTROY(N) move(N, LOC_NOWHERE)
|
||||||
#define MOD(N, M) ((N) % (M))
|
#define MOD(N, M) ((N) % (M))
|
||||||
|
@ -120,15 +143,15 @@
|
||||||
(CNDBIT((LOC), COND_FLUID) ? CNDBIT((LOC), COND_OILY) ? OIL : WATER \
|
(CNDBIT((LOC), COND_FLUID) ? CNDBIT((LOC), COND_OILY) ? OIL : WATER \
|
||||||
: NO_OBJECT)
|
: NO_OBJECT)
|
||||||
#define FORCED(LOC) CNDBIT(LOC, COND_FORCED)
|
#define FORCED(LOC) CNDBIT(LOC, COND_FORCED)
|
||||||
#define IS_DARK_HERE() \
|
#define DARK(DUMMY) \
|
||||||
(!CNDBIT(game.loc, COND_LIT) && \
|
(!CNDBIT(game.loc, COND_LIT) && \
|
||||||
(game.objects[LAMP].prop == LAMP_DARK || !HERE(LAMP)))
|
(game.objects[LAMP].prop == LAMP_DARK || !HERE(LAMP)))
|
||||||
#define PCT(N) (randrange(100) < (N))
|
#define PCT(N) (randrange(100) < (N))
|
||||||
#define GSTONE(OBJ) \
|
#define GSTONE(OBJ) \
|
||||||
((OBJ) == EMERALD || (OBJ) == RUBY || (OBJ) == AMBER || (OBJ) == SAPPH)
|
((OBJ) == EMERALD || (OBJ) == RUBY || (OBJ) == AMBER || (OBJ) == SAPPH)
|
||||||
#define FOREST(LOC) CNDBIT(LOC, COND_FOREST)
|
#define FOREST(LOC) CNDBIT(LOC, COND_FOREST)
|
||||||
#define OUTSIDE(LOC) (CNDBIT(LOC, COND_ABOVE) || FOREST(LOC))
|
#define OUTSID(LOC) (CNDBIT(LOC, COND_ABOVE) || FOREST(LOC))
|
||||||
#define INSIDE(LOC) (!OUTSIDE(LOC) || LOC == LOC_BUILDING)
|
#define INSIDE(LOC) (!OUTSID(LOC) || LOC == LOC_BUILDING)
|
||||||
#define INDEEP(LOC) CNDBIT((LOC), COND_DEEP)
|
#define INDEEP(LOC) CNDBIT((LOC), COND_DEEP)
|
||||||
#define BUG(x) bug(x, #x)
|
#define BUG(x) bug(x, #x)
|
||||||
|
|
||||||
|
@ -234,8 +257,11 @@ struct game_t {
|
||||||
loc_t oldloc; // prior loc of each dwarf, initially garbage
|
loc_t oldloc; // prior loc of each dwarf, initially garbage
|
||||||
} dwarves[NDWARVES + 1];
|
} dwarves[NDWARVES + 1];
|
||||||
struct {
|
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)
|
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
|
loc_t place; // location of object
|
||||||
} objects[NOBJECTS + 1];
|
} objects[NOBJECTS + 1];
|
||||||
struct {
|
struct {
|
||||||
|
|
|
@ -1,10 +1,6 @@
|
||||||
# SPDX-FileCopyrightText: (C) Eric S. Raymond <esr@thyrsus.com>
|
# SPDX-FileCopyrightText: (C) Eric S. Raymond <esr@thyrsus.com>
|
||||||
# SPDX-License-Identifier: BSD-2-Clause
|
# 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
|
# This YAML file gets processed into a collection of data structures and
|
||||||
# variable initializers describing Colossal Cave. It replaces an ad-hoc
|
# variable initializers describing Colossal Cave. It replaces an ad-hoc
|
||||||
# text database shipped with Adventure versions up to 2.5. The format
|
# text database shipped with Adventure versions up to 2.5. The format
|
||||||
|
@ -14,7 +10,7 @@
|
||||||
# We define a bunch of YAML structures:
|
# We define a bunch of YAML structures:
|
||||||
#
|
#
|
||||||
# motions: Motion words, grouped into synonyms. The 'oldstyle'
|
# 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.
|
# accepted in oldstyle mode; it defaults to true.
|
||||||
#
|
#
|
||||||
# actions: Action words, grouped into synonyms, and their corresponding
|
# 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.'
|
- 'There are a few recent issues of "Spelunker Today" magazine here.'
|
||||||
texts:
|
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."
|
cover you see, "Please leave the magazines at the construction site."
|
||||||
- DWARF:
|
- DWARF:
|
||||||
words: ['dwarf', 'dwarv']
|
words: ['dwarf', 'dwarv']
|
||||||
|
@ -3944,13 +3940,11 @@ obituaries:
|
||||||
Oh dear, you seem to have gotten yourself killed. I might be able to
|
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
|
help you out, but I've never really done this before. Do you want me
|
||||||
to try to reincarnate you?
|
to try to reincarnate you?
|
||||||
# batchspell: add wr
|
|
||||||
yes_response: |-
|
yes_response: |-
|
||||||
All right. But don't blame me if something goes wr......
|
All right. But don't blame me if something goes wr......
|
||||||
--- POOF!! ---
|
--- POOF!! ---
|
||||||
You are engulfed in a cloud of orange smoke. Coughing and gasping,
|
You are engulfed in a cloud of orange smoke. Coughing and gasping,
|
||||||
you emerge from the smoke and find....
|
you emerge from the smoke and find....
|
||||||
# batchspell: remove wr
|
|
||||||
- query: |-
|
- query: |-
|
||||||
You clumsy oaf, you've done it again! I don't know how long I can
|
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?
|
keep this up. Do you want me to try reincarnating you again?
|
||||||
|
@ -4232,7 +4226,7 @@ actions: !!omap
|
||||||
message: |-
|
message: |-
|
||||||
There is a puff of orange smoke; within it, fiery runes spell out:
|
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']
|
words: ['versi']
|
||||||
noaction: true
|
noaction: true
|
||||||
|
|
||||||
|
|
17
init.c
17
init.c
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* Initialisation
|
* 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
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -76,18 +76,13 @@ int initialise(void) {
|
||||||
/* Treasure props are initially STATE_NOTFOUND, and are set to
|
/* Treasure props are initially STATE_NOTFOUND, and are set to
|
||||||
* STATE_FOUND the first time they are described. game.tally
|
* STATE_FOUND the first time they are described. game.tally
|
||||||
* keeps track of how many are not yet found, so we know when to
|
* keeps track of how many are not yet found, so we know when to
|
||||||
* close the cave.
|
* close the cave. */
|
||||||
* (ESR) Non-treasures are set to STATE_FOUND explicitly so we
|
for (int treasure = 1; treasure <= NOBJECTS; treasure++) {
|
||||||
* don't rely on the value of uninitialized storage. This is to
|
if (objects[treasure].is_treasure) {
|
||||||
* make translation to future languages easier. */
|
|
||||||
for (int object = 1; object <= NOBJECTS; object++) {
|
|
||||||
if (objects[object].is_treasure) {
|
|
||||||
++game.tally;
|
++game.tally;
|
||||||
if (objects[object].inventory != NULL) {
|
if (objects[treasure].inventory != 0) {
|
||||||
OBJECT_SET_NOT_FOUND(object);
|
PROP_SET_NOT_FOUND(treasure);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
OBJECT_SET_FOUND(object);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
game.conds = setbit(COND_HBASE);
|
game.conds = setbit(COND_HBASE);
|
||||||
|
|
52
main.c
52
main.c
|
@ -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
|
free(buf); // LCOV_EXCL_LINE
|
||||||
return readline(prompt); // LCOV_EXCL_LINE
|
return readline(prompt); // LCOV_EXCL_LINE
|
||||||
} else {
|
} else {
|
||||||
|
@ -152,8 +152,8 @@ static void checkhints(void) {
|
||||||
game.hints[hint].lc = 0;
|
game.hints[hint].lc = 0;
|
||||||
return;
|
return;
|
||||||
case 4: /* dark */
|
case 4: /* dark */
|
||||||
if (!OBJECT_IS_NOTFOUND(EMERALD) &&
|
if (!PROP_IS_NOTFOUND(EMERALD) &&
|
||||||
OBJECT_IS_NOTFOUND(PYRAMID)) {
|
PROP_IS_NOTFOUND(PYRAMID)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
game.hints[hint].lc = 0;
|
game.hints[hint].lc = 0;
|
||||||
|
@ -188,8 +188,7 @@ static void checkhints(void) {
|
||||||
return;
|
return;
|
||||||
case 9: /* jade */
|
case 9: /* jade */
|
||||||
if (game.tally == 1 &&
|
if (game.tally == 1 &&
|
||||||
(OBJECT_IS_STASHED(JADE) ||
|
PROP_IS_STASHED_OR_UNSEEN(JADE)) {
|
||||||
OBJECT_IS_NOTFOUND(JADE))) {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
game.hints[hint].lc = 0;
|
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
|
* tally=1 for an unseen chest, let the pirate be spotted. Note
|
||||||
* that game.objexts,place[CHEST] = LOC_NOWHERE might mean that he's
|
* 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
|
* thrown it to the troll, but in that case he's seen the chest
|
||||||
* OBJECT_IS_FOUND(CHEST) == true. */
|
* PROP_IS_FOUND(CHEST) == true. */
|
||||||
if (game.loc == game.chloc || !OBJECT_IS_NOTFOUND(CHEST)) {
|
if (game.loc == game.chloc || !PROP_IS_NOTFOUND(CHEST)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
int snarfed = 0;
|
int snarfed = 0;
|
||||||
|
@ -534,7 +533,7 @@ static void describe_location(void) {
|
||||||
msg = locations[game.loc].description.big;
|
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];
|
msg = arbitrary_messages[PITCH_DARK];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -640,7 +639,7 @@ static void playermove(int motion) {
|
||||||
} else if (motion == CAVE) {
|
} else if (motion == CAVE) {
|
||||||
/* Cave. Different messages depending on whether above ground.
|
/* 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
|
? FOLLOW_STREAM
|
||||||
: NEED_DETAIL);
|
: NEED_DETAIL);
|
||||||
return;
|
return;
|
||||||
|
@ -1047,7 +1046,7 @@ static void listobjects(void) {
|
||||||
* Similarly for chain; game.prop is initially CHAINING_BEAR (locked to
|
* Similarly for chain; game.prop is initially CHAINING_BEAR (locked to
|
||||||
* bear). These hacks are because game.prop=0 is needed to
|
* bear). These hacks are because game.prop=0 is needed to
|
||||||
* get full score. */
|
* get full score. */
|
||||||
if (!IS_DARK_HERE()) {
|
if (!DARK(game.loc)) {
|
||||||
++game.locs[game.loc].abbrev;
|
++game.locs[game.loc].abbrev;
|
||||||
for (int i = game.locs[game.loc].atloc; i != 0;
|
for (int i = game.locs[game.loc].atloc; i != 0;
|
||||||
i = game.link[i]) {
|
i = game.link[i]) {
|
||||||
|
@ -1062,11 +1061,11 @@ static void listobjects(void) {
|
||||||
* running this code only on objects with the treasure
|
* running this code only on objects with the treasure
|
||||||
* property set. Nope. There is mystery here.
|
* 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) {
|
if (game.closed) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
OBJECT_SET_FOUND(obj);
|
PROP_SET_FOUND(obj);
|
||||||
if (obj == RUG) {
|
if (obj == RUG) {
|
||||||
game.objects[RUG].prop = RUG_DRAGON;
|
game.objects[RUG].prop = RUG_DRAGON;
|
||||||
}
|
}
|
||||||
|
@ -1193,7 +1192,7 @@ static bool preprocess_command(command_t *command) {
|
||||||
static bool do_move(void) {
|
static bool do_move(void) {
|
||||||
/* Actually execute the move to the new location and dwarf movement */
|
/* Actually execute the move to the new location and dwarf movement */
|
||||||
/* Can't leave cave once it's closing (except by main office). */
|
/* 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);
|
rspeak(EXIT_CLOSED);
|
||||||
game.newloc = game.loc;
|
game.newloc = game.loc;
|
||||||
if (!game.panic) {
|
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
|
/* The easiest way to get killed is to fall into a pit in
|
||||||
* pitch darkness. */
|
* pitch darkness. */
|
||||||
if (!FORCED(game.loc) && IS_DARK_HERE() && game.wzdark &&
|
if (!FORCED(game.loc) && DARK(game.loc) && game.wzdark &&
|
||||||
PCT(PIT_KILL_PROB)) {
|
PCT(PIT_KILL_PROB)) {
|
||||||
rspeak(PIT_FALL);
|
rspeak(PIT_FALL);
|
||||||
game.oldlc2 = game.loc;
|
game.oldlc2 = game.loc;
|
||||||
|
@ -1267,28 +1266,25 @@ static bool do_command(void) {
|
||||||
* way objects won't be described until they've
|
* way objects won't be described until they've
|
||||||
* been picked up and put down separate from
|
* been picked up and put down separate from
|
||||||
* their respective piles. */
|
* their respective piles. */
|
||||||
if ((OBJECT_IS_NOTFOUND(OYSTER) ||
|
if ((PROP_IS_NOTFOUND(OYSTER) ||
|
||||||
OBJECT_IS_STASHED(OYSTER)) &&
|
PROP_IS_STASHED(OYSTER)) &&
|
||||||
TOTING(OYSTER)) {
|
TOTING(OYSTER)) {
|
||||||
pspeak(OYSTER, look, true, 1);
|
pspeak(OYSTER, look, true, 1);
|
||||||
}
|
}
|
||||||
for (size_t i = 1; i <= NOBJECTS; i++) {
|
for (size_t i = 1; i <= NOBJECTS; i++) {
|
||||||
if (TOTING(i) &&
|
if (TOTING(i) && (PROP_IS_NOTFOUND(i) ||
|
||||||
(OBJECT_IS_NOTFOUND(i) ||
|
PROP_IS_STASHED(i))) {
|
||||||
OBJECT_IS_STASHED(i))) {
|
game.objects[i].prop =
|
||||||
OBJECT_STASHIFY(
|
PROP_STASHED(i);
|
||||||
i, game.objects[i].prop);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check to see if the room is dark. */
|
/* Check to see if the room is dark. If the knife is
|
||||||
game.wzdark = IS_DARK_HERE();
|
* here, and it's dark, the knife permanently disappears
|
||||||
|
*/
|
||||||
/* If the knife is not here it permanently disappears.
|
game.wzdark = DARK(game.loc);
|
||||||
* Possibly this should fire if the knife is here but
|
if (game.knfloc != LOC_NOWHERE &&
|
||||||
* the room is dark? */
|
|
||||||
if (game.knfloc > LOC_NOWHERE &&
|
|
||||||
game.knfloc != game.loc) {
|
game.knfloc != game.loc) {
|
||||||
game.knfloc = LOC_NOWHERE;
|
game.knfloc = LOC_NOWHERE;
|
||||||
}
|
}
|
||||||
|
|
25
misc.c
25
misc.c
|
@ -12,7 +12,6 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <strings.h>
|
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <unistd.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));
|
memset(&cmd->word[1].raw, '\0', sizeof(cmd->word[1].raw));
|
||||||
|
|
||||||
/* Bound prefix on the %s would be needed to prevent buffer
|
/* Bound prefix on the %s would be needed to prevent buffer
|
||||||
* overflow. We shortstop this more simply by making each
|
* overflow. but we shortstop this more simply by making each
|
||||||
* raw-input buffer as long as the entire input buffer. */
|
* raw-input buffer as int as the entire input buffer. */
|
||||||
sscanf(raw, "%s%s", cmd->word[0].raw, cmd->word[1].raw);
|
sscanf(raw, "%s%s", cmd->word[0].raw, cmd->word[1].raw);
|
||||||
|
|
||||||
/* (ESR) In oldstyle mode, simulate the uppercasing and truncating
|
/* (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
|
* in their tools. On the other, not simulating this misbehavior
|
||||||
* goes against the goal of making oldstyle as accurate as
|
* goes against the goal of making oldstyle as accurate as
|
||||||
* possible an emulation of the original UI.
|
* 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) {
|
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++) {
|
for (size_t i = 0; i < strlen(cmd->word[0].raw); i++) {
|
||||||
cmd->word[0].raw[i] = toupper(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) {
|
void put(obj_t object, loc_t where, int pval) {
|
||||||
/* put() is the same as move(), except the object is stashed and
|
/* put() is the same as move(), except it returns a value used to set
|
||||||
* can no longer be picked up. */
|
* up the negated game.prop values for the repository objects. */
|
||||||
move(object, where);
|
move(object, where);
|
||||||
OBJECT_STASHIFY(object, pval);
|
/* (ESR) Read this in combination with the macro defintions in advebt.h.
|
||||||
#ifdef OBJECT_SET_SEEN
|
*/
|
||||||
OBJECT_SET_SEEN(object);
|
game.objects[object].prop = PROP_STASHIFY(pval);
|
||||||
|
#ifdef PROP_SET_SEEN
|
||||||
|
PROP_SET_SEEN(object);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
13
notes.adoc
13
notes.adoc
|
@ -16,8 +16,8 @@ of Peje Nilsson in restructuring some particularly grotty gotos is
|
||||||
gratefully acknowledged. Petr Voropaev contributed fuzz testing and
|
gratefully acknowledged. Petr Voropaev contributed fuzz testing and
|
||||||
code cleanups. Aaron Traas did a lot of painstaking work to improve
|
code cleanups. Aaron Traas did a lot of painstaking work to improve
|
||||||
test coverage, and factored out the last handful of gotos. Ryan
|
test coverage, and factored out the last handful of gotos. Ryan
|
||||||
Sarson nudged us into fixing a longstanding minor bug in the
|
Sarson nudged us into fixing a longstannding minor bug in the
|
||||||
handling of incorrect magic-word sequences,
|
handling of incorrect magic-word sequebcesm,
|
||||||
|
|
||||||
== Nomenclature ==
|
== Nomenclature ==
|
||||||
|
|
||||||
|
@ -75,15 +75,10 @@ Bug fixes:
|
||||||
|
|
||||||
* A few minor typos have been corrected: absence of capitalization on
|
* A few minor typos have been corrected: absence of capitalization on
|
||||||
"Swiss" and "Persian", inconsistent spelling of "imbedded" vs. "embedded",
|
"Swiss" and "Persian", inconsistent spelling of "imbedded" vs. "embedded",
|
||||||
"eying" for "eyeing", "thresholds" for "threshholds", "pencilled"
|
"eying" for "eyeing", "thresholds" for "threshholds".
|
||||||
for "penciled".
|
|
||||||
|
|
||||||
* Under odd circumstances (dropping rug or vase outdoors) the game could
|
* Under odd circumstances (dropping rug or vase outdoors) the game could
|
||||||
formerly say "floor" when it should say "ground" (or "dirt", or
|
formerly say "floor" when it should say "ground" (or "dirt", or something).
|
||||||
something).
|
|
||||||
|
|
||||||
* The "knives vanish" message could formerly be emitted when "I see no
|
|
||||||
knife here." would be appropriate.
|
|
||||||
|
|
||||||
Enhancements:
|
Enhancements:
|
||||||
|
|
||||||
|
|
|
@ -230,7 +230,7 @@ bool is_valid(struct game_t valgame) {
|
||||||
int temp_tally = 0;
|
int temp_tally = 0;
|
||||||
for (int treasure = 1; treasure <= NOBJECTS; treasure++) {
|
for (int treasure = 1; treasure <= NOBJECTS; treasure++) {
|
||||||
if (objects[treasure].is_treasure) {
|
if (objects[treasure].is_treasure) {
|
||||||
if (OBJECT_IS_NOTFOUND2(valgame, treasure)) {
|
if (PROP_IS_NOTFOUND2(valgame, treasure)) {
|
||||||
++temp_tally;
|
++temp_tally;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
4
score.c
4
score.c
|
@ -49,11 +49,11 @@ int score(enum termination mode) {
|
||||||
if (i > CHEST) {
|
if (i > CHEST) {
|
||||||
k = 16;
|
k = 16;
|
||||||
}
|
}
|
||||||
if (!OBJECT_IS_STASHED(i) && !OBJECT_IS_NOTFOUND(i)) {
|
if (!PROP_IS_STASHED(i) && !PROP_IS_NOTFOUND(i)) {
|
||||||
score += 2;
|
score += 2;
|
||||||
}
|
}
|
||||||
if (game.objects[i].place == LOC_BUILDING &&
|
if (game.objects[i].place == LOC_BUILDING &&
|
||||||
OBJECT_IS_FOUND(i)) {
|
PROP_IS_FOUND(i)) {
|
||||||
score += k - 2;
|
score += k - 2;
|
||||||
}
|
}
|
||||||
mxscor += k;
|
mxscor += k;
|
||||||
|
|
|
@ -170,7 +170,7 @@ oldcompare:
|
||||||
echo 1..$(words $(shell ls *.log))) | $(TAPFILTER)
|
echo 1..$(words $(shell ls *.log))) | $(TAPFILTER)
|
||||||
@rm *.ochk *-new advent430 adventure.data
|
@rm *.ochk *-new advent430 adventure.data
|
||||||
|
|
||||||
# List all NOCOMPARE tests.
|
# List all NOMPARE tests.
|
||||||
residuals:
|
residuals:
|
||||||
@grep -n NOCOMPARE *.log
|
@grep -n NOCOMPARE *.log
|
||||||
|
|
||||||
|
|
386
tests/knife.chk
386
tests/knife.chk
|
@ -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.
|
|
|
@ -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
|
|
Loading…
Add table
Add a link
Reference in a new issue