1TBS reflow with clang-format.

This commit is contained in:
Eric S. Raymond 2024-01-27 06:17:02 -05:00
parent c11938aed5
commit be429016af
9 changed files with 4137 additions and 3936 deletions

View file

@ -68,6 +68,9 @@ cheat: $(CHEAT_OBJS) dungeon.o
check: advent cheat
cd tests; $(MAKE) --quiet
reflow:
@clang-format --style="{IndentWidth: 8, UseTab: ForIndentation}" -i $$(find . -name "*.[ch]")
# Requires gcov, lcov, libasan6, and libubsan1
# The last two are Ubuntu names, might vary on other distributions.
# After this, run your browser on coverage/open-adventure/index.html

314
actions.c
View file

@ -5,10 +5,10 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <inttypes.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include "advent.h"
@ -59,8 +59,8 @@ static phase_codes_t attack(command_t command) {
obj = VEND;
++changes;
}
/* Clam and oyster both treated as clam for intransitive case;
* no harm done. */
/* Clam and oyster both treated as clam for intransitive
* case; no harm done. */
if (HERE(CLAM) || HERE(OYSTER)) {
obj = CLAM;
++changes;
@ -80,8 +80,9 @@ static phase_codes_t attack(command_t command) {
return GO_CLEAROBJ;
}
if (obj == VEND) {
state_change(VEND,
game.objects[VEND].prop == VEND_BLOCKS ? VEND_UNBLOCKS : VEND_BLOCKS);
state_change(VEND, game.objects[VEND].prop == VEND_BLOCKS
? VEND_UNBLOCKS
: VEND_BLOCKS);
return GO_CLEAROBJ;
}
@ -115,10 +116,10 @@ static phase_codes_t attack(command_t command) {
}
state_change(DRAGON, DRAGON_DEAD);
game.objects[RUG].prop = RUG_FLOOR;
/* Hardcoding LOC_SECRET5 as the dragon's death location is ugly.
* The way it was computed before was worse; it depended on the
* two dragon locations being LOC_SECRET4 and LOC_SECRET6 and
* LOC_SECRET5 being right between them.
/* Hardcoding LOC_SECRET5 as the dragon's death location is
* ugly. The way it was computed before was worse; it depended
* on the two dragon locations being LOC_SECRET4 and LOC_SECRET6
* and LOC_SECRET5 being right between them.
*/
move(DRAGON + NOBJECTS, IS_FIXED);
move(RUG + NOBJECTS, IS_FREE);
@ -149,9 +150,7 @@ static phase_codes_t attack(command_t command) {
game.dwarves[i].seen = false;
}
}
rspeak((dwarves > 1) ?
OGRE_PANIC1 :
OGRE_PANIC2);
rspeak((dwarves > 1) ? OGRE_PANIC1 : OGRE_PANIC2);
return GO_CLEAROBJ;
}
@ -185,21 +184,21 @@ static phase_codes_t attack(command_t command) {
}
static phase_codes_t bigwords(vocab_t id) {
/* Only called on FEE FIE FOE FOO (AND FUM). Advance to next state if given
* in proper order. Look up foo in special section of vocab to determine which
* word we've got. Last word zips the eggs back to the giant room (unless
* already there). */
/* Only called on FEE FIE FOE FOO (AND FUM). Advance to next state if
* given in proper order. Look up foo in special section of vocab to
* determine which word we've got. Last word zips the eggs back to the
* giant room (unless already there). */
int foobar = abs(game.foobar);
/* Only FEE can start a magic-word sequence. */
if ((foobar == WORD_EMPTY) && (id == FIE || id == FOE || id == FOO || id == FUM)) {
if ((foobar == WORD_EMPTY) &&
(id == FIE || id == FOE || id == FOO || id == FUM)) {
rspeak(NOTHING_HAPPENS);
return GO_CLEAROBJ;
}
if ((foobar == WORD_EMPTY && id == FEE) ||
(foobar == FEE && id == FIE) ||
(foobar == FIE && id == FOE) ||
(foobar == FEE && id == FIE) || (foobar == FIE && id == FOE) ||
(foobar == FOE && id == FOO)) {
game.foobar = id;
if (id != FOO) {
@ -212,10 +211,11 @@ static phase_codes_t bigwords(vocab_t id) {
rspeak(NOTHING_HAPPENS);
return GO_CLEAROBJ;
} else {
/* Bring back troll if we steal the eggs back from him before
* crossing. */
if (game.objects[EGGS].place == LOC_NOWHERE && game.objects[TROLL].place == LOC_NOWHERE
&& game.objects[TROLL].prop == TROLL_UNPAID)
/* Bring back troll if we steal the eggs back from him
* before crossing. */
if (game.objects[EGGS].place == LOC_NOWHERE &&
game.objects[TROLL].place == LOC_NOWHERE &&
game.objects[TROLL].prop == TROLL_UNPAID)
game.objects[TROLL].prop = TROLL_PAIDONCE;
if (HERE(EGGS)) {
pspeak(EGGS, look, true, EGGS_VANISHED);
@ -241,7 +241,8 @@ 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! */
/* Blast. No effect unless you've got dynamite, which is a neat trick!
*/
if (PROP_IS_NOTFOUND(ROD2) || !game.closed)
rspeak(REQUIRES_DYNAMITE);
else {
@ -260,7 +261,8 @@ static void blast(void) {
}
static phase_codes_t vbreak(verb_t verb, obj_t obj) {
/* Break. Only works for mirror in repository and, of course, the vase. */
/* Break. Only works for mirror in repository and, of course, the
* vase. */
switch (obj) {
case MIRROR:
if (game.closed) {
@ -286,7 +288,8 @@ static phase_codes_t vbreak(verb_t verb, obj_t obj) {
}
static phase_codes_t brief(void) {
/* Brief. Intransitive only. Suppress full descriptions after first time. */
/* Brief. Intransitive only. Suppress full descriptions after first
* time. */
game.abbnum = 10000;
game.detail = 3;
rspeak(BRIEF_CONFIRM);
@ -294,11 +297,12 @@ static phase_codes_t brief(void) {
}
static phase_codes_t vcarry(verb_t verb, obj_t obj) {
/* Carry an object. Special cases for bird and cage (if bird in cage, can't
* take one without the other). Liquids also special, since they depend on
* status of bottle. Also various side effects, etc. */
/* Carry an object. Special cases for bird and cage (if bird in cage,
* can't take one without the other). Liquids also special, since they
* depend on status of bottle. Also various side effects, etc. */
if (obj == INTRANSITIVE) {
/* Carry, no object given yet. OK if only one object present. */
/* Carry, no object given yet. OK if only one object present.
*/
if (game.locs[game.loc].atloc == NO_OBJECT ||
game.link[game.locs[game.loc].atloc] != 0 ||
atdwrf(game.loc) > 0) {
@ -322,16 +326,24 @@ static phase_codes_t vcarry(verb_t verb, obj_t obj) {
switch (obj) {
case PLANT:
/* Next guard tests whether plant is tiny or stashed */
rspeak(game.objects[PLANT].prop <= PLANT_THIRSTY ? DEEP_ROOTS : YOU_JOKING);
rspeak(game.objects[PLANT].prop <= PLANT_THIRSTY
? DEEP_ROOTS
: YOU_JOKING);
break;
case BEAR:
rspeak( game.objects[BEAR].prop == SITTING_BEAR ? BEAR_CHAINED : YOU_JOKING);
rspeak(game.objects[BEAR].prop == SITTING_BEAR
? BEAR_CHAINED
: YOU_JOKING);
break;
case CHAIN:
rspeak( game.objects[BEAR].prop != UNTAMED_BEAR ? STILL_LOCKED : YOU_JOKING);
rspeak(game.objects[BEAR].prop != UNTAMED_BEAR
? STILL_LOCKED
: YOU_JOKING);
break;
case RUG:
rspeak(game.objects[RUG].prop == RUG_HOVER ? RUG_HOVERS : YOU_JOKING);
rspeak(game.objects[RUG].prop == RUG_HOVER
? RUG_HOVERS
: YOU_JOKING);
break;
case URN:
rspeak(URN_NOBUDGE);
@ -370,10 +382,10 @@ static phase_codes_t vcarry(verb_t verb, obj_t obj) {
if (game.holdng >= INVLIMIT) {
rspeak(CARRY_LIMIT);
return GO_CLEAROBJ;
}
if (obj == BIRD && game.objects[BIRD].prop != BIRD_CAGED && !PROP_IS_STASHED(BIRD)) {
if (obj == BIRD && game.objects[BIRD].prop != BIRD_CAGED &&
!PROP_IS_STASHED(BIRD)) {
if (game.objects[BIRD].prop == BIRD_FOREST_UNCAGED) {
DESTROY(BIRD);
rspeak(BIRD_CRAP);
@ -390,7 +402,8 @@ 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)) {
(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);
}
@ -428,9 +441,9 @@ static int chain(verb_t verb) {
switch (game.objects[BEAR].prop) {
// LCOV_EXCL_START
case BEAR_DEAD:
/* Can't be reached until the bear can die in some way other
* than a bridge collapse. Leave in in case this changes, but
* exclude from coverage testing. */
/* Can't be reached until the bear can die in some way
* other than a bridge collapse. Leave in in case this
* changes, but exclude from coverage testing. */
game.objects[BEAR].fixed = IS_FIXED;
break;
// LCOV_EXCL_STOP
@ -461,9 +474,9 @@ static int chain(verb_t verb) {
}
static phase_codes_t discard(verb_t verb, obj_t obj) {
/* Discard object. "Throw" also comes here for most objects. Special cases for
* bird (might attack snake or dragon) and cage (might contain bird) and vase.
* Drop coins at vending machine for extra batteries. */
/* Discard object. "Throw" also comes here for most objects. Special
* cases for bird (might attack snake or dragon) and cage (might contain
* bird) and vase. Drop coins at vending machine for extra batteries. */
if (obj == ROD && !TOTING(ROD) && TOTING(ROD2)) {
obj = ROD2;
}
@ -473,11 +486,13 @@ static phase_codes_t discard(verb_t verb, obj_t obj) {
return GO_CLEAROBJ;
}
if (GSTONE(obj) && AT(CAVITY) && game.objects[CAVITY].prop != CAVITY_FULL) {
if (GSTONE(obj) && AT(CAVITY) &&
game.objects[CAVITY].prop != CAVITY_FULL) {
rspeak(GEM_FITS);
game.objects[obj].prop = STATE_IN_CAVITY;
game.objects[CAVITY].prop = CAVITY_FULL;
if (HERE(RUG) && ((obj == EMERALD && game.objects[RUG].prop != RUG_HOVER) ||
if (HERE(RUG) &&
((obj == EMERALD && game.objects[RUG].prop != RUG_HOVER) ||
(obj == RUBY && game.objects[RUG].prop == RUG_HOVER))) {
if (obj == RUBY) {
rspeak(RUG_SETTLES);
@ -487,7 +502,9 @@ static phase_codes_t discard(verb_t verb, obj_t obj) {
rspeak(RUG_RISES);
}
if (!TOTING(RUG) || obj == RUBY) {
int k = (game.objects[RUG].prop == RUG_HOVER) ? RUG_FLOOR : RUG_HOVER;
int k = (game.objects[RUG].prop == RUG_HOVER)
? RUG_FLOOR
: RUG_HOVER;
game.objects[RUG].prop = k;
if (k == RUG_HOVER) {
k = objects[SAPPH].plac;
@ -526,9 +543,8 @@ static phase_codes_t discard(verb_t verb, obj_t obj) {
if (obj == VASE) {
if (game.loc != objects[PILLOW].plac) {
state_change(VASE, AT(PILLOW)
? VASE_WHOLE
: VASE_DROPPED);
state_change(VASE,
AT(PILLOW) ? VASE_WHOLE : VASE_DROPPED);
if (game.objects[VASE].prop != VASE_WHOLE) {
game.objects[VASE].fixed = IS_FIXED;
}
@ -559,7 +575,8 @@ static phase_codes_t discard(verb_t verb, obj_t obj) {
rspeak(OK_MAN);
}
game.objects[BIRD].prop = FOREST(game.loc) ? BIRD_FOREST_UNCAGED : BIRD_UNCAGED;
game.objects[BIRD].prop =
FOREST(game.loc) ? BIRD_FOREST_UNCAGED : BIRD_UNCAGED;
drop(obj, game.loc);
return GO_CLEAROBJ;
}
@ -570,8 +587,9 @@ static phase_codes_t discard(verb_t verb, obj_t obj) {
}
static phase_codes_t drink(verb_t verb, obj_t obj) {
/* Drink. If no object, assume water and look for it here. If water is in
* the bottle, drink that, else must be at a water loc, so drink stream. */
/* Drink. If no object, assume water and look for it here. If water
* is in the bottle, drink that, else must be at a water loc, so drink
* stream. */
if (obj == INTRANSITIVE && LIQLOC(game.loc) != WATER &&
(LIQUID() != WATER || !HERE(BOTTLE))) {
return GO_UNKNOWN;
@ -599,8 +617,9 @@ static phase_codes_t drink(verb_t verb, obj_t obj) {
}
static phase_codes_t eat(verb_t verb, obj_t obj) {
/* Eat. Intransitive: assume food if present, else ask what. Transitive: food
* ok, some things lose appetite, rest are ridiculous. */
/* Eat. Intransitive: assume food if present, else ask what.
* Transitive: food ok, some things lose appetite, rest are ridiculous.
*/
switch (obj) {
case INTRANSITIVE:
if (!HERE(FOOD))
@ -651,9 +670,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(DARK(game.loc) ? PITCH_DARK : NO_MESSAGE);
break;
case DRAGON:
case VOLCANO:
@ -666,8 +683,8 @@ static phase_codes_t extinguish(verb_t verb, obj_t obj) {
}
static phase_codes_t feed(verb_t verb, obj_t obj) {
/* Feed. If bird, no seed. Snake, dragon, troll: quip. If dwarf, make him
* mad. Bear, special. */
/* Feed. If bird, no seed. Snake, dragon, troll: quip. If dwarf,
* make him mad. Bear, special. */
switch (obj) {
case BIRD:
rspeak(BIRD_PINING);
@ -796,9 +813,8 @@ phase_codes_t fill(verb_t verb, obj_t obj) {
return GO_CLEAROBJ;
}
state_change(BOTTLE, (LIQLOC(game.loc) == OIL)
? OIL_BOTTLE
: WATER_BOTTLE);
state_change(BOTTLE,
(LIQLOC(game.loc) == OIL) ? OIL_BOTTLE : WATER_BOTTLE);
if (TOTING(BOTTLE)) {
game.objects[LIQUID()].place = CARRIED;
}
@ -806,7 +822,8 @@ phase_codes_t fill(verb_t verb, obj_t obj) {
}
static phase_codes_t find(verb_t verb, obj_t obj) {
/* Find. Might be carrying it, or it might be here. Else give caveat. */
/* Find. Might be carrying it, or it might be here. Else give caveat.
*/
if (TOTING(obj)) {
rspeak(ALREADY_CARRYING);
return GO_CLEAROBJ;
@ -823,7 +840,6 @@ static phase_codes_t find(verb_t verb, obj_t obj) {
return GO_CLEAROBJ;
}
speak(actions[verb].message);
return GO_CLEAROBJ;
}
@ -871,7 +887,8 @@ static phase_codes_t fly(verb_t verb, obj_t obj) {
}
static phase_codes_t inven(void) {
/* Inventory. If object, treat same as find. Else report on current burden. */
/* Inventory. If object, treat same as find. Else report on current
* burden. */
bool empty = true;
for (obj_t i = 1; i <= NOBJECTS; i++) {
if (i == BEAR || !TOTING(i))
@ -893,7 +910,8 @@ static phase_codes_t light(verb_t verb, obj_t obj) {
/* Light. Applicable only to lamp and urn. */
if (obj == INTRANSITIVE) {
int selects = 0;
if (HERE(LAMP) && game.objects[LAMP].prop == LAMP_DARK && game.limit >= 0) {
if (HERE(LAMP) && game.objects[LAMP].prop == LAMP_DARK &&
game.limit >= 0) {
obj = LAMP;
selects++;
}
@ -907,9 +925,9 @@ static phase_codes_t light(verb_t verb, obj_t obj) {
switch (obj) {
case URN:
state_change(URN, game.objects[URN].prop == URN_EMPTY ?
URN_EMPTY :
URN_LIT);
state_change(URN, game.objects[URN].prop == URN_EMPTY
? URN_EMPTY
: URN_LIT);
break;
case LAMP:
if (game.limit < 0) {
@ -928,7 +946,8 @@ static phase_codes_t light(verb_t verb, obj_t obj) {
}
static phase_codes_t listen(void) {
/* Listen. Intransitive only. Print stuff based on object sound properties. */
/* Listen. Intransitive only. Print stuff based on object sound
* properties. */
bool soundlatch = false;
vocab_t sound = locations[game.loc].sound;
if (sound != SILENT) {
@ -939,7 +958,8 @@ static phase_codes_t listen(void) {
soundlatch = true;
}
for (obj_t i = 1; i <= NOBJECTS; i++) {
if (!HERE(i) || objects[i].sounds[0] == NULL || PROP_IS_STASHED_OR_UNSEEN(i)) {
if (!HERE(i) || objects[i].sounds[0] == NULL ||
PROP_IS_STASHED_OR_UNSEEN(i)) {
continue;
}
int mi = game.objects[i].prop;
@ -1008,9 +1028,9 @@ static phase_codes_t lock(verb_t verb, obj_t obj) {
}
game.panic = true;
} else {
state_change(GRATE, (verb == LOCK) ?
GRATE_CLOSED :
GRATE_OPEN);
state_change(GRATE, (verb == LOCK)
? GRATE_CLOSED
: GRATE_OPEN);
}
} else {
rspeak(NO_KEYS);
@ -1042,7 +1062,8 @@ static phase_codes_t lock(verb_t verb, obj_t obj) {
}
break;
case DOOR:
rspeak((game.objects[DOOR].prop == DOOR_UNRUSTED) ? OK_MAN : RUSTY_DOOR);
rspeak((game.objects[DOOR].prop == DOOR_UNRUSTED) ? OK_MAN
: RUSTY_DOOR);
break;
case CAGE:
rspeak(NO_LOCK);
@ -1087,7 +1108,8 @@ static phase_codes_t pour(verb_t verb, obj_t obj) {
if (!AT(DOOR)) {
if (obj == WATER) {
/* cycle through the three plant states */
state_change(PLANT, MOD(game.objects[PLANT].prop + 1, 3));
state_change(PLANT,
MOD(game.objects[PLANT].prop + 1, 3));
game.objects[PLANT2].prop = game.objects[PLANT].prop;
return GO_MOVE;
} else {
@ -1095,16 +1117,16 @@ static phase_codes_t pour(verb_t verb, obj_t obj) {
return GO_CLEAROBJ;
}
} else {
state_change(DOOR, (obj == OIL) ?
DOOR_UNRUSTED :
DOOR_RUSTED);
state_change(DOOR, (obj == OIL) ? DOOR_UNRUSTED : DOOR_RUSTED);
return GO_CLEAROBJ;
}
}
static phase_codes_t quit(void) {
/* Quit. Intransitive only. Verify intent and exit if that's what he wants. */
if (yes_or_no(arbitrary_messages[REALLY_QUIT], arbitrary_messages[OK_MAN], arbitrary_messages[OK_MAN])) {
/* Quit. Intransitive only. Verify intent and exit if that's what he
* wants. */
if (yes_or_no(arbitrary_messages[REALLY_QUIT],
arbitrary_messages[OK_MAN], arbitrary_messages[OK_MAN])) {
terminate(quitgame);
}
return GO_CLEAROBJ;
@ -1116,11 +1138,13 @@ static phase_codes_t read(command_t command)
if (command.obj == INTRANSITIVE) {
command.obj = NO_OBJECT;
for (int i = 1; i <= NOBJECTS; i++) {
if (HERE(i) && objects[i].texts[0] != NULL && !PROP_IS_STASHED(i)) {
if (HERE(i) && objects[i].texts[0] != NULL &&
!PROP_IS_STASHED(i)) {
command.obj = command.obj * NOBJECTS + i;
}
}
if (command.obj > NOBJECTS || command.obj == NO_OBJECT || DARK(game.loc)) {
if (command.obj > NOBJECTS || command.obj == NO_OBJECT ||
DARK(game.loc)) {
return GO_UNKNOWN;
}
}
@ -1131,14 +1155,19 @@ static phase_codes_t read(command_t command)
if (!TOTING(OYSTER) || !game.closed) {
rspeak(DONT_UNDERSTAND);
} else if (!game.clshnt) {
game.clshnt = yes_or_no(arbitrary_messages[CLUE_QUERY], arbitrary_messages[WAYOUT_CLUE], arbitrary_messages[OK_MAN]);
game.clshnt = yes_or_no(arbitrary_messages[CLUE_QUERY],
arbitrary_messages[WAYOUT_CLUE],
arbitrary_messages[OK_MAN]);
} else {
pspeak(OYSTER, hear, true, 1); // Not really a sound, but oh well.
pspeak(OYSTER, hear, true,
1); // Not really a sound, but oh well.
}
} else if (objects[command.obj].texts[0] == NULL || PROP_IS_NOTFOUND(command.obj)) {
} else if (objects[command.obj].texts[0] == NULL ||
PROP_IS_NOTFOUND(command.obj)) {
speak(actions[command.verb].message);
} else {
pspeak(command.obj, study, true, game.objects[command.obj].prop);
pspeak(command.obj, study, true,
game.objects[command.obj].prop);
}
return GO_CLEAROBJ;
}
@ -1149,8 +1178,9 @@ static phase_codes_t reservoir(void) {
rspeak(NOTHING_HAPPENS);
return GO_CLEAROBJ;
} else {
state_change(RESER,
game.objects[RESER].prop == WATERS_PARTED ? WATERS_UNPARTED : WATERS_PARTED);
state_change(RESER, game.objects[RESER].prop == WATERS_PARTED
? WATERS_UNPARTED
: WATERS_PARTED);
if (AT(RESER))
return GO_CLEAROBJ;
else {
@ -1182,8 +1212,7 @@ static phase_codes_t rub(verb_t verb, obj_t obj) {
static phase_codes_t say(command_t command) {
/* Say. Echo WD2. Magic words override. */
if (command.word[1].type == MOTION &&
(command.word[1].id == XYZZY ||
command.word[1].id == PLUGH ||
(command.word[1].id == XYZZY || command.word[1].id == PLUGH ||
command.word[1].id == PLOVER)) {
return GO_WORD2;
}
@ -1192,20 +1221,16 @@ static phase_codes_t say(command_t command) {
}
if (command.word[1].type == ACTION &&
(command.word[1].id == FEE ||
command.word[1].id == FIE ||
command.word[1].id == FOE ||
command.word[1].id == FOO ||
command.word[1].id == FUM ||
command.word[1].id == PART)) {
(command.word[1].id == FEE || command.word[1].id == FIE ||
command.word[1].id == FOE || command.word[1].id == FOO ||
command.word[1].id == FUM || command.word[1].id == PART)) {
return bigwords(command.word[1].id);
}
sspeak(OKEY_DOKEY, command.word[1].raw);
return GO_CLEAROBJ;
}
static phase_codes_t throw_support(vocab_t spk)
{
static phase_codes_t throw_support(vocab_t spk) {
rspeak(spk);
drop(AXE, game.loc);
return GO_MOVE;
@ -1240,7 +1265,8 @@ static phase_codes_t throwit(command_t command) {
return (discard(command.verb, command.obj));
} else {
if (atdwrf(game.loc) <= 0) {
if (AT(DRAGON) && game.objects[DRAGON].prop == DRAGON_BARS)
if (AT(DRAGON) &&
game.objects[DRAGON].prop == DRAGON_BARS)
return throw_support(DRAGON_SCALES);
if (AT(TROLL)) {
return throw_support(TROLL_RETURNS);
@ -1248,8 +1274,10 @@ static phase_codes_t throwit(command_t command) {
if (AT(OGRE)) {
return throw_support(OGRE_DODGE);
}
if (HERE(BEAR) && game.objects[BEAR].prop == UNTAMED_BEAR) {
/* This'll teach him to throw the axe at the bear! */
if (HERE(BEAR) &&
game.objects[BEAR].prop == UNTAMED_BEAR) {
/* This'll teach him to throw the axe at the
* bear! */
drop(AXE, game.loc);
game.objects[AXE].fixed = IS_FIXED;
juggle(BEAR);
@ -1266,9 +1294,8 @@ static phase_codes_t throwit(command_t command) {
int i = atdwrf(game.loc);
game.dwarves[i].seen = false;
game.dwarves[i].loc = LOC_NOWHERE;
return throw_support((++game.dkill == 1) ?
DWARF_SMOKE :
KILLED_DWARF);
return throw_support(
(++game.dkill == 1) ? DWARF_SMOKE : KILLED_DWARF);
}
}
}
@ -1302,16 +1329,16 @@ static phase_codes_t waste(verb_t verb, turn_t turns) {
static phase_codes_t wave(verb_t verb, obj_t obj) {
/* Wave. No effect unless waving rod at fissure or at bird. */
if (obj != ROD || !TOTING(obj) || (!HERE(BIRD) && (game.closng || !AT(FISSURE)))) {
speak(((!TOTING(obj)) && (obj != ROD ||
!TOTING(ROD2))) ?
arbitrary_messages[ARENT_CARRYING] :
actions[verb].message);
if (obj != ROD || !TOTING(obj) ||
(!HERE(BIRD) && (game.closng || !AT(FISSURE)))) {
speak(((!TOTING(obj)) && (obj != ROD || !TOTING(ROD2)))
? arbitrary_messages[ARENT_CARRYING]
: actions[verb].message);
return GO_CLEAROBJ;
}
if (game.objects[BIRD].prop == BIRD_UNCAGED && game.loc == game.objects[STEPS].place
&& PROP_IS_NOTFOUND(JADE)) {
if (game.objects[BIRD].prop == BIRD_UNCAGED &&
game.loc == game.objects[STEPS].place && PROP_IS_NOTFOUND(JADE)) {
drop(JADE, game.loc);
PROP_SET_FOUND(JADE);
--game.tally;
@ -1319,35 +1346,37 @@ static phase_codes_t wave(verb_t verb, obj_t obj) {
return GO_CLEAROBJ;
} else {
if (game.closed) {
rspeak((game.objects[BIRD].prop == BIRD_CAGED) ?
CAGE_FLY :
FREE_FLY);
rspeak((game.objects[BIRD].prop == BIRD_CAGED)
? CAGE_FLY
: FREE_FLY);
return GO_DWARFWAKE;
}
if (game.closng || !AT(FISSURE)) {
rspeak((game.objects[BIRD].prop == BIRD_CAGED) ?
CAGE_FLY :
FREE_FLY);
rspeak((game.objects[BIRD].prop == BIRD_CAGED)
? CAGE_FLY
: FREE_FLY);
return GO_CLEAROBJ;
}
if (HERE(BIRD))
rspeak((game.objects[BIRD].prop == BIRD_CAGED) ?
CAGE_FLY :
FREE_FLY);
rspeak((game.objects[BIRD].prop == BIRD_CAGED)
? CAGE_FLY
: FREE_FLY);
state_change(FISSURE,
game.objects[FISSURE].prop == BRIDGED ? UNBRIDGED : BRIDGED);
state_change(FISSURE, game.objects[FISSURE].prop == BRIDGED
? UNBRIDGED
: BRIDGED);
return GO_CLEAROBJ;
}
}
phase_codes_t action(command_t command) {
/* Analyse a verb. Remember what it was, go back for object if second word
* unless verb is "say", which snarfs arbitrary second word.
/* Analyse a verb. Remember what it was, go back for object if second
* word unless verb is "say", which snarfs arbitrary second word.
*/
/* Previously, actions that result in a message, but don't do anything
* further were called "specials". Now they're handled here as normal
* actions. If noaction is true, then we spit out the message and return */
* actions. If noaction is true, then we spit out the message and return
*/
if (actions[command.verb].noaction) {
speak(actions[command.verb].message);
return GO_CLEAROBJ;
@ -1365,13 +1394,16 @@ phase_codes_t action(command_t command) {
/* FALL THROUGH */;
} else if (command.obj == DWARF && atdwrf(game.loc) > 0) {
/* FALL THROUGH */;
} else if (!game.closed && ((LIQUID() == command.obj && HERE(BOTTLE)) ||
} else if (!game.closed &&
((LIQUID() == command.obj && HERE(BOTTLE)) ||
command.obj == LIQLOC(game.loc))) {
/* FALL THROUGH */;
} else if (command.obj == OIL && HERE(URN) && game.objects[URN].prop != URN_EMPTY) {
} else if (command.obj == OIL && HERE(URN) &&
game.objects[URN].prop != URN_EMPTY) {
command.obj = URN;
/* FALL THROUGH */;
} else if (command.obj == PLANT && AT(PLANT2) && game.objects[PLANT2].prop != PLANT_THIRSTY) {
} else if (command.obj == PLANT && AT(PLANT2) &&
game.objects[PLANT2].prop != PLANT_THIRSTY) {
command.obj = PLANT2;
/* FALL THROUGH */;
} else if (command.obj == KNIFE && game.knfloc == game.loc) {
@ -1382,7 +1414,9 @@ phase_codes_t action(command_t command) {
command.obj = ROD2;
/* FALL THROUGH */;
} else if ((command.verb == FIND ||
command.verb == INVENTORY) && (command.word[1].id == WORD_EMPTY || command.word[1].id == WORD_NOT_FOUND)) {
command.verb == INVENTORY) &&
(command.word[1].id == WORD_EMPTY ||
command.word[1].id == WORD_NOT_FOUND)) {
/* FALL THROUGH */;
} else {
sspeak(NO_SEE, command.word[0].raw);
@ -1400,13 +1434,16 @@ phase_codes_t action(command_t command) {
return GO_WORD2;
}
if (command.verb == SAY) {
/* KEYS is not special, anything not NO_OBJECT or INTRANSITIVE
* will do here. We're preventing interpretation as an intransitive
* verb when the word is unknown. */
command.obj = command.word[1].raw[0] != '\0' ? KEYS : NO_OBJECT;
/* KEYS is not special, anything not NO_OBJECT or
* INTRANSITIVE will do here. We're preventing
* interpretation as an intransitive verb when the word
* is unknown. */
command.obj =
command.word[1].raw[0] != '\0' ? KEYS : NO_OBJECT;
}
if (command.obj == NO_OBJECT || command.obj == INTRANSITIVE) {
/* Analyse an intransitive verb (ie, no object given yet). */
/* Analyse an intransitive verb (ie, no object given
* yet). */
switch (command.verb) {
case CARRY:
return vcarry(command.verb, INTRANSITIVE);
@ -1592,7 +1629,8 @@ phase_codes_t action(command_t command) {
case SEED:
return seed(command.verb, command.word[1].raw);
case WASTE:
return waste(command.verb, (turn_t)atol(command.word[1].raw));
return waste(command.verb,
(turn_t)atol(command.word[1].raw));
default: // LCOV_EXCL_LINE
BUG(TRANSITIVE_ACTION_VERB_EXCEEDS_GOTO_LIST); // LCOV_EXCL_LINE
}

View file

@ -4,11 +4,11 @@
* SPDX-FileCopyrightText: (C) 1977, 2005 by Will Crowther and Don Woods
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <inttypes.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdarg.h>
#include <inttypes.h>
#include "dungeon.h"
@ -30,7 +30,8 @@
#define FLASHTIME 50 // turns from first warning till blinding flash
#define PANICTIME 15 // time left after closing
#define BATTERYLIFE 2500 // turn limit increment from batteries
#define WORD_NOT_FOUND -1 // "Word not found" flag value for the vocab hash functions.
#define WORD_NOT_FOUND \
-1 // "Word not found" flag value for the vocab hash functions.
#define WORD_EMPTY 0 // "Word empty" flag value for the vocab hash functions
#define PIT_KILL_PROB 35 // Percentage probability of dying from fall in pit.
#define CARRIED -1 // Player is toting it
@ -89,9 +90,15 @@
#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_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)
@ -116,22 +123,32 @@
* 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
* 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))
#define TOTING(OBJ) (game.objects[OBJ].place == CARRIED)
#define AT(OBJ) (game.objects[OBJ].place == game.loc || game.objects[OBJ].fixed == game.loc)
#define AT(OBJ) \
(game.objects[OBJ].place == game.loc || \
game.objects[OBJ].fixed == game.loc)
#define HERE(OBJ) (AT(OBJ) || TOTING(OBJ))
#define CNDBIT(L, N) (tstbit(conditions[L], N))
#define LIQUID() (game.objects[BOTTLE].prop == WATER_BOTTLE? WATER : game.objects[BOTTLE].prop == OIL_BOTTLE ? OIL : NO_OBJECT )
#define LIQLOC(LOC) (CNDBIT((LOC),COND_FLUID)? CNDBIT((LOC),COND_OILY) ? OIL : WATER : NO_OBJECT)
#define LIQUID() \
(game.objects[BOTTLE].prop == WATER_BOTTLE ? WATER \
: game.objects[BOTTLE].prop == OIL_BOTTLE ? OIL \
: NO_OBJECT)
#define LIQLOC(LOC) \
(CNDBIT((LOC), COND_FLUID) ? CNDBIT((LOC), COND_OILY) ? OIL : WATER \
: NO_OBJECT)
#define FORCED(LOC) CNDBIT(LOC, COND_FORCED)
#define DARK(DUMMY) (!CNDBIT(game.loc,COND_LIT) && (game.objects[LAMP].prop == LAMP_DARK || !HERE(LAMP)))
#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 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)
@ -204,9 +221,9 @@ struct game_t {
/* dflag controls the level of activation of dwarves:
* 0 No dwarf stuff yet (wait until reaches Hall Of Mists)
* 1 Reached Hall Of Mists, but hasn't met first dwarf
* 2 Met first dwarf, others start moving, no knives thrown yet
* 3 A knife has been thrown (first set always misses)
* 3+ Dwarves are mad (increases their accuracy) */
* 2 Met first dwarf, others start moving, no knives thrown
*yet 3 A knife has been thrown (first set always misses) 3+
*Dwarves are mad (increases their accuracy) */
int32_t dflag;
int32_t dkill; // dwarves killed
@ -275,7 +292,15 @@ typedef struct {
word_type_t type;
} command_word_t;
typedef enum {EMPTY, RAW, TOKENIZED, GIVEN, PREPROCESSED, PROCESSING, EXECUTED} command_state_t;
typedef enum {
EMPTY,
RAW,
TOKENIZED,
GIVEN,
PREPROCESSED,
PROCESSING,
EXECUTED
} command_state_t;
typedef struct {
enum speechpart part;
@ -288,9 +313,9 @@ typedef struct {
/*
* Bump on save format change.
*
* Note: Verify that the tests run clean before bumping this, then rebuild the check
* files afterwards. Otherwise you will get a spurious failure due to the old version
* having been generated into a check file.
* Note: Verify that the tests run clean before bumping this, then rebuild the
* check files afterwards. Otherwise you will get a spurious failure due to the
* old version having been generated into a check file.
*/
#define SAVE_VERSION 31
@ -301,8 +326,8 @@ typedef struct {
/*
* If you change the first three members, the resume function may not properly
* reject saves from older versions. Later members can change, but bump the version
* when you do that.
* reject saves from older versions. Later members can change, but bump the
* version when you do that.
*/
struct save_t {
char magic[sizeof(ADVENT_MAGIC)];

36
cheat.c
View file

@ -7,15 +7,14 @@
* SPDX-FileCopyrightText: (C) 1977, 2005 by Will Crowther and Don Woods
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <getopt.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <editline/readline.h>
#include "advent.h"
#include <editline/readline.h>
#include <getopt.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int main(int argc, char *argv[]) {
int ch;
char *savefilename = NULL;
FILE *fp = NULL;
@ -30,7 +29,9 @@ int main(int argc, char *argv[])
/* Options. */
const char *opts = "d:l:s:t:v:o:";
const char* usage = "Usage: %s [-d numdie] [-s numsaves] [-v version] -o savefilename \n"
const char *usage =
"Usage: %s [-d numdie] [-s numsaves] [-v version] -o savefilename "
"\n"
" -d number of deaths. Signed integer.\n"
" -l lifetime of lamp in turns. Signed integer.\n"
" -s number of saves. Signed integer.\n"
@ -64,8 +65,7 @@ int main(int argc, char *argv[])
savefilename = optarg;
break;
default:
fprintf(stderr,
usage, argv[0]);
fprintf(stderr, usage, argv[0]);
exit(EXIT_FAILURE);
break;
}
@ -73,17 +73,14 @@ int main(int argc, char *argv[])
// Save filename required; the point of cheat is to generate save file
if (savefilename == NULL) {
fprintf(stderr,
usage, argv[0]);
fprintf(stderr,
"ERROR: filename required\n");
fprintf(stderr, usage, argv[0]);
fprintf(stderr, "ERROR: filename required\n");
exit(EXIT_FAILURE);
}
fp = fopen(savefilename, WRITE_MODE);
if (fp == NULL) {
fprintf(stderr,
"Can't open file %s. Exiting.\n", savefilename);
fprintf(stderr, "Can't open file %s. Exiting.\n", savefilename);
exit(EXIT_FAILURE);
}
@ -102,12 +99,7 @@ int main(int argc, char *argv[])
* See the actually useful version of this in main.c
*/
char *myreadline(const char *prompt)
{
return readline(prompt);
}
char *myreadline(const char *prompt) { return readline(prompt); }
// LCOV_EXCL_STOP
/* end */

31
init.c
View file

@ -5,39 +5,28 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <time.h>
#include <assert.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include "advent.h"
struct settings_t settings = {
.logfp = NULL,
.oldstyle = false,
.prompt = true
};
struct settings_t settings = {.logfp = NULL, .oldstyle = false, .prompt = true};
struct game_t game = {
/* Last dwarf is special (the pirate). He always starts at his
* chest's eventual location inside the maze. This loc is saved
* in chloc for ref. The dead end in the other maze has its
* loc stored in chloc2. */
.chloc = LOC_MAZEEND12,
.chloc2 = LOC_DEADEND13,
.abbnum = 5,
.clock1 = WARNTIME,
.clock2 = FLASHTIME,
.newloc = LOC_START,
.loc = LOC_START,
.limit = GAMELIMIT,
.foobar = WORD_EMPTY,
.chloc = LOC_MAZEEND12, .chloc2 = LOC_DEADEND13, .abbnum = 5,
.clock1 = WARNTIME, .clock2 = FLASHTIME, .newloc = LOC_START,
.loc = LOC_START, .limit = GAMELIMIT, .foobar = WORD_EMPTY,
};
int initialise(void)
{
int initialise(void) {
if (settings.oldstyle)
printf("Initialising...\n");

534
main.c

File diff suppressed because it is too large Load diff

276
misc.c
View file

@ -5,25 +5,25 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <sys/time.h>
#include <ctype.h>
#include <editline/readline.h>
#include <inttypes.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <unistd.h>
#include "advent.h"
#include "dungeon.h"
static void* xcalloc(size_t size)
{
static void *xcalloc(size_t size) {
void *ptr = calloc(size, 1);
if (ptr == NULL) {
// LCOV_EXCL_START
// exclude from coverage analysis because we can't simulate an out of memory error in testing
// exclude from coverage analysis because we can't simulate an
// out of memory error in testing
fprintf(stderr, "Out of memory!\n");
exit(EXIT_FAILURE);
// LCOV_EXCL_STOP
@ -33,19 +33,21 @@ static void* xcalloc(size_t size)
/* I/O routines (speak, pspeak, rspeak, sspeak, get_input, yes) */
static void vspeak(const char* msg, bool blank, va_list ap)
static void vspeak(const char *msg, bool blank, va_list ap) {
/* Engine for various speak functions */
{
// Do nothing if we got a null pointer.
if (msg == NULL)
if (msg == NULL) {
return;
}
// Do nothing if we got an empty string.
if (strlen(msg) == 0)
if (strlen(msg) == 0) {
return;
}
if (blank == true)
if (blank == true) {
printf("\n");
}
int msglen = strlen(msg);
@ -60,9 +62,11 @@ static void vspeak(const char* msg, bool blank, va_list ap)
bool pluralize = false;
for (int i = 0; i < msglen; i++) {
if (msg[i] != '%') {
/* Ugh. Least obtrusive way to deal with artifacts "on the floor"
* being dropped outside of both cave and building. */
if (strncmp(msg + i, "floor", 5) == 0 && strchr(" .", msg[i + 5]) && !INSIDE(game.loc)) {
/* Ugh. Least obtrusive way to deal with artifacts "on
* the floor" being dropped outside of both cave and
* building. */
if (strncmp(msg + i, "floor", 5) == 0 &&
strchr(" .", msg[i + 5]) && !INSIDE(game.loc)) {
strcpy(renderp, "ground");
renderp += 6;
i += 4;
@ -76,7 +80,8 @@ static void vspeak(const char* msg, bool blank, va_list ap)
// Integer specifier.
if (msg[i] == 'd') {
int32_t arg = va_arg(ap, int32_t);
int ret = snprintf(renderp, size, "%" PRId32, arg);
int ret =
snprintf(renderp, size, "%" PRId32, arg);
if (ret < size) {
renderp += ret;
size -= ret;
@ -121,18 +126,16 @@ static void vspeak(const char* msg, bool blank, va_list ap)
free(rendered);
}
void speak(const char* msg, ...)
void speak(const char *msg, ...) {
/* speak a specified string */
{
va_list ap;
va_start(ap, msg);
vspeak(msg, true, ap);
va_end(ap);
}
void sspeak(const int msg, ...)
void sspeak(const int msg, ...) {
/* Speak a message from the arbitrary-messages list */
{
va_list ap;
va_start(ap, msg);
fputc('\n', stdout);
@ -141,13 +144,12 @@ void sspeak(const int msg, ...)
va_end(ap);
}
void pspeak(vocab_t msg, enum speaktype mode, bool blank, int skip, ...)
void pspeak(vocab_t msg, enum speaktype mode, bool blank, int skip, ...) {
/* Find the skip+1st message from msg and print it. Modes are:
* feel = for inventory, what you can touch
* look = the full description for the state the object is in
* listen = the sound for the state the object is in
* study = text on the object. */
{
va_list ap;
va_start(ap, skip);
switch (mode) {
@ -170,17 +172,16 @@ void pspeak(vocab_t msg, enum speaktype mode, bool blank, int skip, ...)
va_end(ap);
}
void rspeak(vocab_t i, ...)
void rspeak(vocab_t i, ...) {
/* Print the i-th "random" message (section 6 of database). */
{
va_list ap;
va_start(ap, i);
vspeak(arbitrary_messages[i], true, ap);
va_end(ap);
}
void echo_input(FILE* destination, const char* input_prompt, const char* input)
{
void echo_input(FILE *destination, const char *input_prompt,
const char *input) {
size_t len = strlen(input_prompt) + strlen(input) + 1;
char *prompt_and_input = (char *)xcalloc(len);
strcpy(prompt_and_input, input_prompt);
@ -189,8 +190,7 @@ void echo_input(FILE* destination, const char* input_prompt, const char* input)
free(prompt_and_input);
}
static int word_count(char* str)
{
static int word_count(char *str) {
char delims[] = " \t";
int count = 0;
int inblanks = true;
@ -210,8 +210,7 @@ static int word_count(char* str)
return (count);
}
static char* get_input(void)
{
static char *get_input(void) {
// Set up the prompt
char input_prompt[] = PROMPT;
if (!settings.prompt)
@ -248,8 +247,7 @@ static char* get_input(void)
return (input);
}
bool silent_yes_or_no(void)
{
bool silent_yes_or_no(void) {
bool outcome = false;
for (;;) {
@ -294,11 +292,10 @@ bool silent_yes_or_no(void)
return (outcome);
}
bool yes_or_no(const char* question, const char* yes_response, const char* no_response)
/* Print message X, wait for yes/no answer. If yes, print Y and return true;
* if no, print Z and return false. */
{
bool yes_or_no(const char *question, const char *yes_response,
const char *no_response) {
/* Print message X, wait for yes/no answer. If yes, print Y and return
* true; if no, print Z and return false. */
bool outcome = false;
for (;;) {
@ -324,8 +321,9 @@ bool yes_or_no(const char* question, const char* yes_response, const char* no_re
free(reply);
for (int i = 0; i < (int)strlen(firstword); ++i)
for (int i = 0; i < (int)strlen(firstword); ++i) {
firstword[i] = tolower(firstword[i]);
}
int yes = strncmp("yes", firstword, sizeof("yes") - 1);
int y = strncmp("y", firstword, sizeof("y") - 1);
@ -344,7 +342,6 @@ bool yes_or_no(const char* question, const char* yes_response, const char* no_re
break;
} else
rspeak(PLEASE_ANSWER);
}
return (outcome);
@ -352,12 +349,13 @@ bool yes_or_no(const char* question, const char* yes_response, const char* no_re
/* Data structure routines */
static int get_motion_vocab_id(const char* word)
static int get_motion_vocab_id(const char *word) {
// Return the first motion number that has 'word' as one of its words.
{
for (int i = 0; i < NMOTIONS; ++i) {
for (int j = 0; j < motions[i].words.n; ++j) {
if (strncasecmp(word, motions[i].words.strs[j], TOKLEN) == 0 && (strlen(word) > 1 ||
if (strncasecmp(word, motions[i].words.strs[j],
TOKLEN) == 0 &&
(strlen(word) > 1 ||
strchr(ignore, word[0]) == NULL ||
!settings.oldstyle))
return (i);
@ -367,12 +365,14 @@ static int get_motion_vocab_id(const char* word)
return (WORD_NOT_FOUND);
}
static int get_object_vocab_id(const char* word)
static int get_object_vocab_id(const char *word) {
// Return the first object number that has 'word' as one of its words.
{
for (int i = 0; i < NOBJECTS + 1; ++i) { // FIXME: the + 1 should go when 1-indexing for objects is removed
for (int i = 0; i < NOBJECTS + 1;
++i) { // FIXME: the + 1 should go when 1-indexing for objects is
// removed
for (int j = 0; j < objects[i].words.n; ++j) {
if (strncasecmp(word, objects[i].words.strs[j], TOKLEN) == 0)
if (strncasecmp(word, objects[i].words.strs[j],
TOKLEN) == 0)
return (i);
}
}
@ -380,47 +380,51 @@ static int get_object_vocab_id(const char* word)
return (WORD_NOT_FOUND);
}
static int get_action_vocab_id(const char* word)
static int get_action_vocab_id(const char *word) {
// Return the first motion number that has 'word' as one of its words.
{
for (int i = 0; i < NACTIONS; ++i) {
for (int j = 0; j < actions[i].words.n; ++j) {
if (strncasecmp(word, actions[i].words.strs[j], TOKLEN) == 0 && (strlen(word) > 1 ||
if (strncasecmp(word, actions[i].words.strs[j],
TOKLEN) == 0 &&
(strlen(word) > 1 ||
strchr(ignore, word[0]) == NULL ||
!settings.oldstyle))
!settings.oldstyle)) {
return (i);
}
}
}
// If execution reaches here, we didn't find the word.
return (WORD_NOT_FOUND);
}
static bool is_valid_int(const char *str)
static bool is_valid_int(const char *str) {
/* Returns true if the string passed in is represents a valid integer,
* that could then be parsed by atoi() */
{
// Handle negative number
if (*str == '-')
if (*str == '-') {
++str;
}
// Handle empty string or just "-". Should never reach this
// point, because this is only used with transitive verbs.
if (!*str)
if (!*str) {
return false; // LCOV_EXCL_LINE
}
// Check for non-digit chars in the rest of the string.
while (*str) {
if (!isdigit(*str))
if (!isdigit(*str)) {
return false;
else
} else {
++str;
}
}
return true;
}
static void get_vocab_metadata(const char* word, vocab_t* id, word_type_t* type)
{
static void get_vocab_metadata(const char *word, vocab_t *id,
word_type_t *type) {
/* Check for an empty string */
if (strncmp(word, "", sizeof("")) == 0) {
*id = WORD_EMPTY;
@ -431,7 +435,8 @@ static void get_vocab_metadata(const char* word, vocab_t* id, word_type_t* type)
vocab_t ref_num;
ref_num = get_motion_vocab_id(word);
// Second conjunct is because the magic-word placeholder is a bit special
// Second conjunct is because the magic-word placeholder is a bit
// special
if (ref_num != WORD_NOT_FOUND) {
*id = ref_num;
*type = MOTION;
@ -471,8 +476,7 @@ static void get_vocab_metadata(const char* word, vocab_t* id, word_type_t* type)
return;
}
static void tokenize(char* raw, command_t *cmd)
{
static void tokenize(char *raw, command_t *cmd) {
/*
* Be careful about modifying this. We do not want to nuke the
* the speech part or ID from the previous turn.
@ -500,22 +504,26 @@ static void tokenize(char* raw, command_t *cmd)
* possible an emulation of the original UI.
*/
if (settings.oldstyle) {
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[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]);
for (size_t i = 0; i < strlen(cmd->word[1].raw); i++)
}
for (size_t i = 0; i < strlen(cmd->word[1].raw); i++) {
cmd->word[1].raw[i] = toupper(cmd->word[1].raw[i]);
}
}
/* populate command with parsed vocabulary metadata */
get_vocab_metadata(cmd->word[0].raw, &(cmd->word[0].id), &(cmd->word[0].type));
get_vocab_metadata(cmd->word[1].raw, &(cmd->word[1].id), &(cmd->word[1].type));
get_vocab_metadata(cmd->word[0].raw, &(cmd->word[0].id),
&(cmd->word[0].type));
get_vocab_metadata(cmd->word[1].raw, &(cmd->word[1].id),
&(cmd->word[1].type));
cmd->state = TOKENIZED;
}
bool get_command_input(command_t *command)
bool get_command_input(command_t *command) {
/* Get user input on stdin, parse and map to command */
{
char inputbuf[LINESIZE];
char *input;
@ -528,8 +536,9 @@ bool get_command_input(command_t *command)
free(input);
continue;
}
if (strcmp(input, "") != 0)
if (strcmp(input, "") != 0) {
break;
}
free(input);
}
@ -540,14 +549,14 @@ bool get_command_input(command_t *command)
#ifdef GDEBUG
/* Needs to stay synced with enum word_type_t */
const char *types[] = {"NO_WORD_TYPE", "MOTION", "OBJECT", "ACTION", "NUMERIC"};
const char *types[] = {"NO_WORD_TYPE", "MOTION", "OBJECT", "ACTION",
"NUMERIC"};
/* needs to stay synced with enum speechpart */
const char *roles[] = {"unknown", "intransitive", "transitive"};
printf("Command: role = %s type1 = %s, id1 = %d, type2 = %s, id2 = %d\n",
roles[command->part],
types[command->word[0].type],
command->word[0].id,
types[command->word[1].type],
printf(
"Command: role = %s type1 = %s, id1 = %d, type2 = %s, id2 = %d\n",
roles[command->part], types[command->word[0].type],
command->word[0].id, types[command->word[1].type],
command->word[1].id);
#endif
@ -555,9 +564,8 @@ bool get_command_input(command_t *command)
return true;
}
void clear_command(command_t *cmd)
void clear_command(command_t *cmd) {
/* Resets the state of the command to empty */
{
cmd->verb = ACT_NULL;
cmd->part = unknown;
game.oldobj = cmd->obj;
@ -565,10 +573,10 @@ void clear_command(command_t *cmd)
cmd->state = EMPTY;
}
void juggle(obj_t object)
/* Juggle an object by picking it up and putting it down again, the purpose
* being to get the object to the front of the chain of things at its loc. */
{
void juggle(obj_t object) {
/* Juggle an object by picking it up and putting it down again, the
* purpose being to get the object to the front of the chain of things
* at its loc. */
loc_t i, j;
i = game.objects[object].place;
@ -577,28 +585,29 @@ void juggle(obj_t object)
move(object + NOBJECTS, j);
}
void move(obj_t object, loc_t where)
void move(obj_t object, loc_t where) {
/* Place any object anywhere by picking it up and dropping it. May
* already be toting, in which case the carry is a no-op. Mustn't
* pick up objects which are not at any loc, since carry wants to
* remove objects from game atloc chains. */
{
loc_t from;
if (object > NOBJECTS)
if (object > NOBJECTS) {
from = game.objects[object - NOBJECTS].fixed;
else
} else {
from = game.objects[object].place;
/* (ESR) Used to check for !SPECIAL(from). I *think* that was wrong... */
if (from != LOC_NOWHERE && from != CARRIED)
}
/* (ESR) Used to check for !SPECIAL(from). I *think* that was wrong...
*/
if (from != LOC_NOWHERE && from != CARRIED) {
carry(object, from);
}
drop(object, 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. */
{
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. */
move(object, where);
/* (ESR) Read this in combination with the macro defintions in advebt.h.
*/
@ -608,16 +617,17 @@ void put(obj_t object, loc_t where, int pval)
#endif
}
void carry(obj_t object, loc_t where)
/* Start toting an object, removing it from the list of things at its former
* location. Incr holdng unless it was already being toted. If object>NOBJECTS
* (moving "fixed" second loc), don't change game.place or game.holdng. */
{
void carry(obj_t object, loc_t where) {
/* Start toting an object, removing it from the list of things at its
* former location. Incr holdng unless it was already being toted. If
* object>NOBJECTS (moving "fixed" second loc), don't change game.place
* or game.holdng. */
int temp;
if (object <= NOBJECTS) {
if (game.objects[object].place == CARRIED)
if (game.objects[object].place == CARRIED) {
return;
}
game.objects[object].place = CARRIED;
/*
@ -641,68 +651,69 @@ void carry(obj_t object, loc_t where)
game.link[temp] = game.link[object];
}
void drop(obj_t object, loc_t where)
/* Place an object at a given loc, prefixing it onto the game atloc list. Decr
* game.holdng if the object was being toted. No state change on the object. */
{
if (object > NOBJECTS)
void drop(obj_t object, loc_t where) {
/* Place an object at a given loc, prefixing it onto the game atloc
* list. Decr game.holdng if the object was being toted. No state
* change on the object. */
if (object > NOBJECTS) {
game.objects[object - NOBJECTS].fixed = where;
else {
} else {
if (game.objects[object].place == CARRIED)
if (object != BIRD)
/* The bird has to be weightless. This ugly hack (and the
* corresponding code in the carry function) brought to you
* by the fact that when the bird is caged, we need to be able
* to either 'take bird' or 'take cage' and have the right thing
* happen.
/* The bird has to be weightless. This ugly
* hack (and the corresponding code in the carry
* function) brought to you by the fact that
* when the bird is caged, we need to be able to
* either 'take bird' or 'take cage' and have
* the right thing happen.
*/
--game.holdng;
game.objects[object].place = where;
}
if (where == LOC_NOWHERE || where == CARRIED)
if (where == LOC_NOWHERE || where == CARRIED) {
return;
}
game.link[object] = game.locs[where].atloc;
game.locs[where].atloc = object;
}
int atdwrf(loc_t where)
/* Return the index of first dwarf at the given location, zero if no dwarf is
* there (or if dwarves not active yet), -1 if all dwarves are dead. Ignore
* the pirate (6th dwarf). */
{
int atdwrf(loc_t where) {
/* Return the index of first dwarf at the given location, zero if no
* dwarf is there (or if dwarves not active yet), -1 if all dwarves are
* dead. Ignore the pirate (6th dwarf). */
int at;
at = 0;
if (game.dflag < 2)
if (game.dflag < 2) {
return at;
}
at = -1;
for (int i = 1; i <= NDWARVES - 1; i++) {
if (game.dwarves[i].loc == where)
if (game.dwarves[i].loc == where) {
return i;
if (game.dwarves[i].loc != 0)
}
if (game.dwarves[i].loc != 0) {
at = 0;
}
}
return at;
}
/* Utility routines (setbit, tstbit, set_seed, get_next_lcg_value,
* randrange) */
int setbit(int bit)
int setbit(int bit) {
/* Returns 2**bit for use in constructing bit-masks. */
{
return (1L << bit);
}
bool tstbit(int mask, int bit)
bool tstbit(int mask, int bit) {
/* Returns true if the specified bit is set in the mask. */
{
return (mask & (1 << bit)) != 0;
}
void set_seed(int32_t seedval)
void set_seed(int32_t seedval) {
/* Set the LCG1 seed */
{
game.lcg_x = seedval % LCG_M;
if (game.lcg_x < 0) {
game.lcg_x = LCG_M + game.lcg_x;
@ -715,9 +726,8 @@ void set_seed(int32_t seedval)
game.zzword[5] = '\0';
}
static int32_t get_next_lcg_value(void)
static int32_t get_next_lcg_value(void) {
/* Return the LCG's current value, and then iterate it. */
{
int32_t old_x = game.lcg_x;
game.lcg_x = (LCG_A * game.lcg_x + LCG_C) % LCG_M;
if (settings.debug) {
@ -726,23 +736,21 @@ static int32_t get_next_lcg_value(void)
return old_x;
}
int32_t randrange(int32_t range)
int32_t randrange(int32_t range) {
/* Return a random integer from [0, range). */
{
return range * get_next_lcg_value() / LCG_M;
}
// LCOV_EXCL_START
void bug(enum bugtype num, const char *error_string)
{
void bug(enum bugtype num, const char *error_string) {
fprintf(stderr, "Fatal error %d, %s.\n", num, error_string);
exit(EXIT_FAILURE);
}
// LCOV_EXCL_STOP
void state_change(obj_t obj, int state)
/* Object must have a change-message list for this to be useful; only some do */
{
void state_change(obj_t obj, int state) {
/* Object must have a change-message list for this to be useful; only
* some do */
game.objects[obj].prop = state;
pspeak(obj, change, true, state);
}

View file

@ -8,11 +8,11 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <ctype.h>
#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <inttypes.h>
#include "advent.h"
@ -23,17 +23,21 @@
struct save_t save;
#define IGNORE(r) do{if (r){}}while(0)
#define IGNORE(r) \
do { \
if (r) { \
} \
} while (0)
int savefile(FILE *fp)
int savefile(FILE *fp) {
/* Save game to file. No input or output from user. */
{
memcpy(&save.magic, ADVENT_MAGIC, sizeof(ADVENT_MAGIC));
if (save.version == 0)
if (save.version == 0) {
save.version = SAVE_VERSION;
if (save.canary == 0)
}
if (save.canary == 0) {
save.canary = ENDIAN_MAGIC;
}
save.game = game;
IGNORE(fwrite(&save, sizeof(struct save_t), 1, fp));
return (0);
@ -41,17 +45,18 @@ int savefile(FILE *fp)
/* Suspend and resume */
static char *strip(char *name)
{
static char *strip(char *name) {
// Trim leading whitespace
while(isspace((unsigned char)*name))
while (isspace((unsigned char)*name)) {
name++; // LCOV_EXCL_LINE
}
if (*name != '\0') {
// Trim trailing whitespace;
// might be left there by autocomplete
char *end = name + strlen(name) - 1;
while(end > name && isspace((unsigned char)*end))
while (end > name && isspace((unsigned char)*end)) {
end--;
}
// Write new null terminator character
end[1] = '\0';
}
@ -59,8 +64,7 @@ static char *strip(char *name)
return name;
}
int suspend(void)
{
int suspend(void) {
/* Suspend. Offer to save things in a file, but charging
* some points (so can't win by using saved games to retry
* battles or to start over after learning zzword).
@ -73,20 +77,26 @@ int suspend(void)
FILE *fp = NULL;
rspeak(SUSPEND_WARNING);
if (!yes_or_no(arbitrary_messages[THIS_ACCEPTABLE], arbitrary_messages[OK_MAN], arbitrary_messages[OK_MAN]))
if (!yes_or_no(arbitrary_messages[THIS_ACCEPTABLE],
arbitrary_messages[OK_MAN],
arbitrary_messages[OK_MAN])) {
return GO_CLEAROBJ;
}
game.saved = game.saved + 5;
while (fp == NULL) {
char *name = myreadline("\nFile name: ");
if (name == NULL)
if (name == NULL) {
return GO_TOP;
}
name = strip(name);
if (strlen(name) == 0)
if (strlen(name) == 0) {
return GO_TOP; // LCOV_EXCL_LINE
}
fp = fopen(strip(name), WRITE_MODE);
if (fp == NULL)
if (fp == NULL) {
printf("Can't open file %s, try again.\n", name);
}
free(name);
}
@ -96,8 +106,7 @@ int suspend(void)
exit(EXIT_SUCCESS);
}
int resume(void)
{
int resume(void) {
/* Resume. Read a suspended game back from a file.
* If ADVENT_NOSAVE is defined, gripe instead. */
@ -109,9 +118,12 @@ int resume(void)
if (game.loc != LOC_START || game.locs[LOC_START].abbrev != 1) {
rspeak(RESUME_ABANDON);
if (!yes_or_no(arbitrary_messages[THIS_ACCEPTABLE], arbitrary_messages[OK_MAN], arbitrary_messages[OK_MAN]))
if (!yes_or_no(arbitrary_messages[THIS_ACCEPTABLE],
arbitrary_messages[OK_MAN],
arbitrary_messages[OK_MAN])) {
return GO_CLEAROBJ;
}
}
while (fp == NULL) {
char *name = myreadline("\nFile name: ");
@ -121,16 +133,16 @@ int resume(void)
if (strlen(name) == 0)
return GO_TOP; // LCOV_EXCL_LINE
fp = fopen(name, READ_MODE);
if (fp == NULL)
if (fp == NULL) {
printf("Can't open file %s, try again.\n", name);
}
free(name);
}
return restore(fp);
}
int restore(FILE* fp)
{
int restore(FILE *fp) {
/* Read and restore game state from file, assuming
* sane initial state.
* If ADVENT_NOSAVE is defined, gripe instead. */
@ -141,10 +153,12 @@ int restore(FILE* fp)
IGNORE(fread(&save, sizeof(struct save_t), 1, fp));
fclose(fp);
if (memcmp(save.magic, ADVENT_MAGIC, sizeof(ADVENT_MAGIC)) != 0 || save.canary != ENDIAN_MAGIC)
if (memcmp(save.magic, ADVENT_MAGIC, sizeof(ADVENT_MAGIC)) != 0 ||
save.canary != ENDIAN_MAGIC) {
rspeak(BAD_SAVE);
else if (save.version != SAVE_VERSION) {
rspeak(VERSION_SKEW, save.version / 10, MOD(save.version, 10), SAVE_VERSION / 10, MOD(SAVE_VERSION, 10));
} else if (save.version != SAVE_VERSION) {
rspeak(VERSION_SKEW, save.version / 10, MOD(save.version, 10),
SAVE_VERSION / 10, MOD(SAVE_VERSION, 10));
} else if (!is_valid(save.game)) {
rspeak(SAVE_TAMPERING);
exit(EXIT_SUCCESS);
@ -154,8 +168,7 @@ int restore(FILE* fp)
return GO_TOP;
}
bool is_valid(struct game_t valgame)
{
bool is_valid(struct game_t valgame) {
/* Save files can be roughly grouped into three groups:
* With valid, reachable state, with valid, but unreachable
* state and with invalid state. We check that state is
@ -180,23 +193,27 @@ bool is_valid(struct game_t valgame)
/* Bounds check for locations */
if (valgame.chloc < -1 || valgame.chloc > NLOCATIONS ||
valgame.chloc2 < -1 || valgame.chloc2 > NLOCATIONS ||
valgame.loc < 0 || valgame.loc > NLOCATIONS ||
valgame.newloc < 0 || valgame.newloc > NLOCATIONS ||
valgame.oldloc < 0 || valgame.oldloc > NLOCATIONS ||
valgame.oldlc2 < 0 || valgame.oldlc2 > NLOCATIONS) {
valgame.loc < 0 || valgame.loc > NLOCATIONS || valgame.newloc < 0 ||
valgame.newloc > NLOCATIONS || valgame.oldloc < 0 ||
valgame.oldloc > NLOCATIONS || valgame.oldlc2 < 0 ||
valgame.oldlc2 > NLOCATIONS) {
return false; // LCOV_EXCL_LINE
}
/* Bounds check for location arrays */
for (int i = 0; i <= NDWARVES; i++) {
if (valgame.dwarves[i].loc < -1 || valgame.dwarves[i].loc > NLOCATIONS ||
valgame.dwarves[i].oldloc < -1 || valgame.dwarves[i].oldloc > NLOCATIONS) {
if (valgame.dwarves[i].loc < -1 ||
valgame.dwarves[i].loc > NLOCATIONS ||
valgame.dwarves[i].oldloc < -1 ||
valgame.dwarves[i].oldloc > NLOCATIONS) {
return false; // LCOV_EXCL_LINE
}
}
for (int i = 0; i <= NOBJECTS; i++) {
if (valgame.objects[i].place < -1 || valgame.objects[i].place > NLOCATIONS ||
valgame.objects[i].fixed < -1 || valgame.objects[i].fixed > NLOCATIONS) {
if (valgame.objects[i].place < -1 ||
valgame.objects[i].place > NLOCATIONS ||
valgame.objects[i].fixed < -1 ||
valgame.objects[i].fixed > NLOCATIONS) {
return false; // LCOV_EXCL_LINE
}
}
@ -232,14 +249,17 @@ bool is_valid(struct game_t valgame)
}
}
/* Check that values in linked lists for objects in locations are inside bounds */
/* Check that values in linked lists for objects in locations are inside
* bounds */
for (loc_t loc = LOC_NOWHERE; loc <= NLOCATIONS; loc++) {
if (valgame.locs[loc].atloc < NO_OBJECT || valgame.locs[loc].atloc > NOBJECTS * 2) {
if (valgame.locs[loc].atloc < NO_OBJECT ||
valgame.locs[loc].atloc > NOBJECTS * 2) {
return false; // LCOV_EXCL_LINE
}
}
for (obj_t obj = 0; obj <= NOBJECTS * 2; obj++) {
if (valgame.link[obj] < NO_OBJECT || valgame.link[obj] > NOBJECTS * 2) {
if (valgame.link[obj] < NO_OBJECT ||
valgame.link[obj] > NOBJECTS * 2) {
return false; // LCOV_EXCL_LINE
}
}

16
score.c
View file

@ -4,15 +4,15 @@
* SPDX-FileCopyrightText: (C) 1977, 2005 by Will Crowther and Don Woods
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <stdlib.h>
#include "advent.h"
#include "dungeon.h"
#include <stdlib.h>
static int mxscor; /* ugh..the price for having score() not exit. */
int score(enum termination mode) {
/* mode is 'scoregame' if scoring, 'quitgame' if quitting, 'endgame' if died
* or won */
/* mode is 'scoregame' if scoring, 'quitgame' if quitting, 'endgame' if
* died or won */
int score = 0;
/* The present scoring algorithm is as follows:
@ -31,8 +31,8 @@ int score(enum termination mode) {
* Came to Witt's End 1 1
* Round out the total 2 2
* TOTAL: 430
* Points can also be deducted for using hints or too many turns, or for
* saving intermediate positions. */
* Points can also be deducted for using hints or too many turns, or
* for saving intermediate positions. */
/* First tally up the treasures. Must be in building and not broken.
* Give the poor guy 2 points just for finding each treasure. */
@ -52,7 +52,8 @@ int score(enum termination mode) {
if (!PROP_IS_STASHED(i) && !PROP_IS_NOTFOUND(i)) {
score += 2;
}
if (game.objects[i].place == LOC_BUILDING && PROP_IS_FOUND(i)) {
if (game.objects[i].place == LOC_BUILDING &&
PROP_IS_FOUND(i)) {
score += k - 2;
}
mxscor += k;
@ -105,7 +106,8 @@ int score(enum termination mode) {
score += 2;
mxscor += 2;
/* Deduct for hints/turns/saves. Hints < 4 are special; see database desc. */
/* Deduct for hints/turns/saves. Hints < 4 are special; see database
* desc. */
for (int i = 0; i < NHINTS; i++) {
if (game.hints[i].used) {
score = score - hints[i].penalty;