Compare commits
25 commits
Author | SHA1 | Date | |
---|---|---|---|
|
7d848c89e1 | ||
|
7bbf994fce | ||
|
3e989aec53 | ||
|
9df69fe034 | ||
|
a2bb39dc7e | ||
|
5c90880f0a | ||
|
92451f1fff | ||
|
96ad6c6245 | ||
|
40742e112b | ||
|
a4fd14caf7 | ||
|
9a6e4406f5 | ||
|
08f0351817 | ||
|
0157e58668 | ||
|
354e56a69b | ||
|
9c3f4b0c90 | ||
|
20fd7c589f | ||
|
8c553af53e | ||
|
f1cb740c41 | ||
|
cf4adf8d02 | ||
|
acdfa96315 | ||
|
3d6c689ffa | ||
|
8dcc6e6641 | ||
|
e17ff128da | ||
|
cb293f4aa4 | ||
|
124e7768b4 |
13 changed files with 130 additions and 129 deletions
|
@ -23,3 +23,5 @@ 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
|
||||
|
|
7
Makefile
7
Makefile
|
@ -67,14 +67,17 @@ cheat: $(CHEAT_OBJS) dungeon.o
|
|||
|
||||
CSUPPRESSIONS = --suppress=missingIncludeSystem --suppress=invalidscanf
|
||||
cppcheck:
|
||||
@-cppcheck -I. --quiet --template gcc -UPROP_SET_SEEN --enable=all $(CSUPPRESSIONS) *.[ch]
|
||||
@-cppcheck -I. --quiet --template gcc -UOBJECT_SET_SEEN --enable=all $(CSUPPRESSIONS) *.[ch]
|
||||
|
||||
pylint:
|
||||
@-pylint --score=n *.py */*.py
|
||||
|
||||
check: advent cheat pylint cppcheck
|
||||
check: advent cheat pylint cppcheck spellcheck
|
||||
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
|
||||
|
|
|
@ -2,6 +2,9 @@
|
|||
// 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.
|
||||
|
||||
|
|
31
actions.c
31
actions.c
|
@ -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 (PROP_IS_NOTFOUND(ROD2) || !game.closed) {
|
||||
if (OBJECT_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:
|
||||
/* Next guard tests whether plant is tiny or stashed */
|
||||
rspeak(game.objects[PLANT].prop <= PLANT_THIRSTY
|
||||
rspeak((game.objects[PLANT].prop == PLANT_THIRSTY ||
|
||||
OBJECT_IS_STASHED(PLANT))
|
||||
? 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 &&
|
||||
!PROP_IS_STASHED(BIRD)) {
|
||||
!OBJECT_IS_STASHED(BIRD)) {
|
||||
if (game.objects[BIRD].prop == BIRD_FOREST_UNCAGED) {
|
||||
DESTROY(BIRD);
|
||||
rspeak(BIRD_CRAP);
|
||||
|
@ -406,8 +406,7 @@ static phase_codes_t vcarry(verb_t verb, obj_t obj) {
|
|||
game.objects[BIRD].prop = BIRD_CAGED;
|
||||
}
|
||||
if ((obj == BIRD || obj == CAGE) &&
|
||||
(game.objects[BIRD].prop == BIRD_CAGED ||
|
||||
PROP_STASHED(BIRD) == BIRD_CAGED)) {
|
||||
OBJECT_STATE_EQUALS(BIRD, BIRD_CAGED)) {
|
||||
/* expression maps BIRD to CAGE and CAGE to BIRD */
|
||||
carry(BIRD + CAGE - obj, game.loc);
|
||||
}
|
||||
|
@ -418,8 +417,8 @@ static phase_codes_t vcarry(verb_t verb, obj_t obj) {
|
|||
game.objects[LIQUID()].place = CARRIED;
|
||||
}
|
||||
|
||||
if (GSTONE(obj) && !PROP_IS_FOUND(obj)) {
|
||||
PROP_SET_FOUND(obj);
|
||||
if (GSTONE(obj) && !OBJECT_IS_FOUND(obj)) {
|
||||
OBJECT_SET_FOUND(obj);
|
||||
game.objects[CAVITY].prop = CAVITY_EMPTY;
|
||||
}
|
||||
rspeak(OK_MAN);
|
||||
|
@ -677,7 +676,7 @@ static phase_codes_t extinguish(verb_t verb, obj_t obj) {
|
|||
break;
|
||||
case LAMP:
|
||||
state_change(LAMP, LAMP_DARK);
|
||||
rspeak(DARK(game.loc) ? PITCH_DARK : NO_MESSAGE);
|
||||
rspeak(IS_DARK_HERE() ? PITCH_DARK : NO_MESSAGE);
|
||||
break;
|
||||
case DRAGON:
|
||||
case VOLCANO:
|
||||
|
@ -971,7 +970,7 @@ static phase_codes_t listen(void) {
|
|||
}
|
||||
for (obj_t i = 1; i <= NOBJECTS; i++) {
|
||||
if (!HERE(i) || objects[i].sounds[0] == NULL ||
|
||||
PROP_IS_STASHED_OR_UNSEEN(i)) {
|
||||
OBJECT_IS_STASHED(i) || OBJECT_IS_NOTFOUND(i)) {
|
||||
continue;
|
||||
}
|
||||
int mi = game.objects[i].prop;
|
||||
|
@ -1151,17 +1150,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 &&
|
||||
!PROP_IS_STASHED(i)) {
|
||||
!OBJECT_IS_STASHED(i)) {
|
||||
command.obj = command.obj * NOBJECTS + i;
|
||||
}
|
||||
}
|
||||
if (command.obj > NOBJECTS || command.obj == NO_OBJECT ||
|
||||
DARK(game.loc)) {
|
||||
IS_DARK_HERE()) {
|
||||
return GO_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
if (DARK(game.loc)) {
|
||||
if (IS_DARK_HERE()) {
|
||||
sspeak(NO_SEE, command.word[0].raw);
|
||||
} else if (command.obj == OYSTER) {
|
||||
if (!TOTING(OYSTER) || !game.closed) {
|
||||
|
@ -1175,7 +1174,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 ||
|
||||
PROP_IS_NOTFOUND(command.obj)) {
|
||||
OBJECT_IS_NOTFOUND(command.obj)) {
|
||||
speak(actions[command.verb].message);
|
||||
} else {
|
||||
pspeak(command.obj, study, true,
|
||||
|
@ -1351,9 +1350,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 && PROP_IS_NOTFOUND(JADE)) {
|
||||
game.loc == game.objects[STEPS].place && OBJECT_IS_NOTFOUND(JADE)) {
|
||||
drop(JADE, game.loc);
|
||||
PROP_SET_FOUND(JADE);
|
||||
OBJECT_SET_FOUND(JADE);
|
||||
--game.tally;
|
||||
rspeak(NECKLACE_FLY);
|
||||
return GO_CLEAROBJ;
|
||||
|
|
|
@ -3,6 +3,9 @@
|
|||
// 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
|
||||
|
||||
|
|
98
advent.h
98
advent.h
|
@ -47,7 +47,6 @@
|
|||
#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
|
||||
|
@ -61,71 +60,49 @@
|
|||
* STATE_NOTFOUND is only set on treasures. Non-treasures start the
|
||||
* game in STATE_FOUND.
|
||||
*
|
||||
* PROP_STASHED is supposed to map a state property value to a
|
||||
* PROP_STASHIFY 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.
|
||||
*/
|
||||
#define PROP_STASHIFY(n) (-1 - (n))
|
||||
#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 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.
|
||||
* All tests of the prop member are done with either these macros or ==.
|
||||
*/
|
||||
#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 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 PROMPT "> "
|
||||
|
||||
/*
|
||||
* DESTROY(N) = Get rid of an item by putting it in LOC_NOWHERE
|
||||
* MOD(N,M) = Arithmetic modulus
|
||||
* TOTING(OBJ) = true if the OBJ is being carried
|
||||
* AT(OBJ) = true if on either side of two-placed object
|
||||
* 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)
|
||||
* 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)
|
||||
* 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
|
||||
* 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
|
||||
* DESTROY(N) = Get rid of an item by putting it in LOC_NOWHERE
|
||||
* MOD(N,M) = Arithmetic modulus
|
||||
* TOTING(OBJ) = true if the OBJ is being carried
|
||||
* AT(OBJ) = true if on either side of two-placed object
|
||||
* 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)
|
||||
* 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
|
||||
* 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
|
||||
* 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
|
||||
*/
|
||||
#define DESTROY(N) move(N, LOC_NOWHERE)
|
||||
#define MOD(N, M) ((N) % (M))
|
||||
|
@ -143,15 +120,15 @@
|
|||
(CNDBIT((LOC), COND_FLUID) ? CNDBIT((LOC), COND_OILY) ? OIL : WATER \
|
||||
: NO_OBJECT)
|
||||
#define FORCED(LOC) CNDBIT(LOC, COND_FORCED)
|
||||
#define DARK(DUMMY) \
|
||||
#define IS_DARK_HERE() \
|
||||
(!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 OUTSID(LOC) (CNDBIT(LOC, COND_ABOVE) || FOREST(LOC))
|
||||
#define INSIDE(LOC) (!OUTSID(LOC) || LOC == LOC_BUILDING)
|
||||
#define OUTSIDE(LOC) (CNDBIT(LOC, COND_ABOVE) || FOREST(LOC))
|
||||
#define INSIDE(LOC) (!OUTSIDE(LOC) || LOC == LOC_BUILDING)
|
||||
#define INDEEP(LOC) CNDBIT((LOC), COND_DEEP)
|
||||
#define BUG(x) bug(x, #x)
|
||||
|
||||
|
@ -257,11 +234,8 @@ 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 {
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
# 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
|
||||
|
@ -10,7 +14,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 be
|
||||
# attribute, if false, means that single-letter synonyms should not be
|
||||
# accepted in oldstyle mode; it defaults to true.
|
||||
#
|
||||
# actions: Action words, grouped into synonyms, and their corresponding
|
||||
|
@ -3432,7 +3436,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 pencilled on one
|
||||
I'm afraid the magazine is written in dwarvish. But penciled on one
|
||||
cover you see, "Please leave the magazines at the construction site."
|
||||
- DWARF:
|
||||
words: ['dwarf', 'dwarv']
|
||||
|
@ -3940,11 +3944,13 @@ 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?
|
||||
|
@ -4226,7 +4232,7 @@ actions: !!omap
|
|||
message: |-
|
||||
There is a puff of orange smoke; within it, fiery runes spell out:
|
||||
|
||||
\tOpen Adventure %V - http://www.catb.org/esr/open-adventure/
|
||||
Open Adventure %V - http://www.catb.org/esr/open-adventure/
|
||||
words: ['versi']
|
||||
noaction: true
|
||||
|
||||
|
|
17
init.c
17
init.c
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Initialisation
|
||||
*
|
||||
* SPDX-FileCopyrightText: (C) 1977, 2005 by Will Crowther and Don Woodsm
|
||||
* SPDX-FileCopyrightText: (C) 1977, 2005 by Will Crowther and Don Woods
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
|
@ -76,13 +76,18 @@ 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. */
|
||||
for (int treasure = 1; treasure <= NOBJECTS; treasure++) {
|
||||
if (objects[treasure].is_treasure) {
|
||||
* 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) {
|
||||
++game.tally;
|
||||
if (objects[treasure].inventory != 0) {
|
||||
PROP_SET_NOT_FOUND(treasure);
|
||||
if (objects[object].inventory != NULL) {
|
||||
OBJECT_SET_NOT_FOUND(object);
|
||||
}
|
||||
} else {
|
||||
OBJECT_SET_FOUND(object);
|
||||
}
|
||||
}
|
||||
game.conds = setbit(COND_HBASE);
|
||||
|
|
48
main.c
48
main.c
|
@ -81,7 +81,7 @@ char *myreadline(const char *prompt) {
|
|||
}
|
||||
}
|
||||
|
||||
if (isatty(fileno(settings.scriptfp))) {
|
||||
if (isatty(fileno(settings.scriptfp)) && !settings.oldstyle) {
|
||||
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 (!PROP_IS_NOTFOUND(EMERALD) &&
|
||||
PROP_IS_NOTFOUND(PYRAMID)) {
|
||||
if (!OBJECT_IS_NOTFOUND(EMERALD) &&
|
||||
OBJECT_IS_NOTFOUND(PYRAMID)) {
|
||||
break;
|
||||
}
|
||||
game.hints[hint].lc = 0;
|
||||
|
@ -188,7 +188,8 @@ static void checkhints(void) {
|
|||
return;
|
||||
case 9: /* jade */
|
||||
if (game.tally == 1 &&
|
||||
PROP_IS_STASHED_OR_UNSEEN(JADE)) {
|
||||
(OBJECT_IS_STASHED(JADE) ||
|
||||
OBJECT_IS_NOTFOUND(JADE))) {
|
||||
break;
|
||||
}
|
||||
game.hints[hint].lc = 0;
|
||||
|
@ -231,8 +232,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
|
||||
* PROP_IS_FOUND(CHEST) == true. */
|
||||
if (game.loc == game.chloc || !PROP_IS_NOTFOUND(CHEST)) {
|
||||
* OBJECT_IS_FOUND(CHEST) == true. */
|
||||
if (game.loc == game.chloc || !OBJECT_IS_NOTFOUND(CHEST)) {
|
||||
return true;
|
||||
}
|
||||
int snarfed = 0;
|
||||
|
@ -533,7 +534,7 @@ static void describe_location(void) {
|
|||
msg = locations[game.loc].description.big;
|
||||
}
|
||||
|
||||
if (!FORCED(game.loc) && DARK(game.loc)) {
|
||||
if (!FORCED(game.loc) && IS_DARK_HERE()) {
|
||||
msg = arbitrary_messages[PITCH_DARK];
|
||||
}
|
||||
|
||||
|
@ -639,7 +640,7 @@ static void playermove(int motion) {
|
|||
} else if (motion == CAVE) {
|
||||
/* Cave. Different messages depending on whether above ground.
|
||||
*/
|
||||
rspeak((OUTSID(game.loc) && game.loc != LOC_GRATE)
|
||||
rspeak((OUTSIDE(game.loc) && game.loc != LOC_GRATE)
|
||||
? FOLLOW_STREAM
|
||||
: NEED_DETAIL);
|
||||
return;
|
||||
|
@ -1046,7 +1047,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 (!DARK(game.loc)) {
|
||||
if (!IS_DARK_HERE()) {
|
||||
++game.locs[game.loc].abbrev;
|
||||
for (int i = game.locs[game.loc].atloc; i != 0;
|
||||
i = game.link[i]) {
|
||||
|
@ -1061,11 +1062,11 @@ static void listobjects(void) {
|
|||
* running this code only on objects with the treasure
|
||||
* property set. Nope. There is mystery here.
|
||||
*/
|
||||
if (PROP_IS_STASHED_OR_UNSEEN(obj)) {
|
||||
if (OBJECT_IS_STASHED(i) || OBJECT_IS_NOTFOUND(obj)) {
|
||||
if (game.closed) {
|
||||
continue;
|
||||
}
|
||||
PROP_SET_FOUND(obj);
|
||||
OBJECT_SET_FOUND(obj);
|
||||
if (obj == RUG) {
|
||||
game.objects[RUG].prop = RUG_DRAGON;
|
||||
}
|
||||
|
@ -1192,7 +1193,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 (OUTSID(game.newloc) && game.newloc != 0 && game.closng) {
|
||||
if (OUTSIDE(game.newloc) && game.newloc != 0 && game.closng) {
|
||||
rspeak(EXIT_CLOSED);
|
||||
game.newloc = game.loc;
|
||||
if (!game.panic) {
|
||||
|
@ -1228,7 +1229,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) && DARK(game.loc) && game.wzdark &&
|
||||
if (!FORCED(game.loc) && IS_DARK_HERE() && game.wzdark &&
|
||||
PCT(PIT_KILL_PROB)) {
|
||||
rspeak(PIT_FALL);
|
||||
game.oldlc2 = game.loc;
|
||||
|
@ -1266,26 +1267,27 @@ 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 ((PROP_IS_NOTFOUND(OYSTER) ||
|
||||
PROP_IS_STASHED(OYSTER)) &&
|
||||
if ((OBJECT_IS_NOTFOUND(OYSTER) ||
|
||||
OBJECT_IS_STASHED(OYSTER)) &&
|
||||
TOTING(OYSTER)) {
|
||||
pspeak(OYSTER, look, true, 1);
|
||||
}
|
||||
for (size_t i = 1; i <= NOBJECTS; i++) {
|
||||
if (TOTING(i) && (PROP_IS_NOTFOUND(i) ||
|
||||
PROP_IS_STASHED(i))) {
|
||||
game.objects[i].prop =
|
||||
PROP_STASHED(i);
|
||||
if (TOTING(i) &&
|
||||
(OBJECT_IS_NOTFOUND(i) ||
|
||||
OBJECT_IS_STASHED(i))) {
|
||||
OBJECT_STASHIFY(
|
||||
i, game.objects[i].prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Check to see if the room is dark. */
|
||||
game.wzdark = DARK(game.loc);
|
||||
|
||||
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? */
|
||||
* Possibly this should fire if the knife is here but
|
||||
* the room is dark? */
|
||||
if (game.knfloc > LOC_NOWHERE &&
|
||||
game.knfloc != game.loc) {
|
||||
game.knfloc = LOC_NOWHERE;
|
||||
|
|
25
misc.c
25
misc.c
|
@ -12,6 +12,7 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
@ -495,8 +496,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. but we shortstop this more simply by making each
|
||||
* raw-input buffer as int as the entire input buffer. */
|
||||
* overflow. We shortstop this more simply by making each
|
||||
* raw-input buffer as long 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
|
||||
|
@ -512,10 +513,14 @@ 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[TOKLEN + TOKLEN] =
|
||||
cmd->word[1].raw[TOKLEN + TOKLEN] = '\0';
|
||||
cmd->word[0].raw[TRUNCLEN] = cmd->word[1].raw[TRUNCLEN] = '\0';
|
||||
for (size_t i = 0; i < strlen(cmd->word[0].raw); i++) {
|
||||
cmd->word[0].raw[i] = toupper(cmd->word[0].raw[i]);
|
||||
}
|
||||
|
@ -617,14 +622,12 @@ 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 it returns a value used to set
|
||||
* up the negated game.prop values for the repository objects. */
|
||||
/* put() is the same as move(), except the object is stashed and
|
||||
* can no longer be picked up. */
|
||||
move(object, where);
|
||||
/* (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);
|
||||
OBJECT_STASHIFY(object, pval);
|
||||
#ifdef OBJECT_SET_SEEN
|
||||
OBJECT_SET_SEEN(object);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -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 longstannding minor bug in the
|
||||
handling of incorrect magic-word sequebcesm,
|
||||
Sarson nudged us into fixing a longstanding minor bug in the
|
||||
handling of incorrect magic-word sequences,
|
||||
|
||||
== Nomenclature ==
|
||||
|
||||
|
@ -75,7 +75,8 @@ 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".
|
||||
"eying" for "eyeing", "thresholds" for "threshholds", "pencilled"
|
||||
for "penciled".
|
||||
|
||||
* Under odd circumstances (dropping rug or vase outdoors) the game could
|
||||
formerly say "floor" when it should say "ground" (or "dirt", or
|
||||
|
|
|
@ -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 (PROP_IS_NOTFOUND2(valgame, treasure)) {
|
||||
if (OBJECT_IS_NOTFOUND2(valgame, treasure)) {
|
||||
++temp_tally;
|
||||
}
|
||||
}
|
||||
|
|
4
score.c
4
score.c
|
@ -49,11 +49,11 @@ int score(enum termination mode) {
|
|||
if (i > CHEST) {
|
||||
k = 16;
|
||||
}
|
||||
if (!PROP_IS_STASHED(i) && !PROP_IS_NOTFOUND(i)) {
|
||||
if (!OBJECT_IS_STASHED(i) && !OBJECT_IS_NOTFOUND(i)) {
|
||||
score += 2;
|
||||
}
|
||||
if (game.objects[i].place == LOC_BUILDING &&
|
||||
PROP_IS_FOUND(i)) {
|
||||
OBJECT_IS_FOUND(i)) {
|
||||
score += k - 2;
|
||||
}
|
||||
mxscor += k;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue