X-Git-Url: https://jxself.org/git/?a=blobdiff_plain;f=main.c;h=fd0852f696172871a8ddd19e19a84cd8fdd43b2f;hb=c11938aed5e261ac40a562781325996628663610;hp=98a1d7fbe30c7f9d53693dcf3fa0c2cd36af35c7;hpb=8fe07c8bf36b1c06e8cf8689c04629df0fe51504;p=open-adventure.git diff --git a/main.c b/main.c index 98a1d7f..fd0852f 100644 --- a/main.c +++ b/main.c @@ -1,6 +1,5 @@ /* - * SPDX-FileCopyrightText: 1977, 2005 by Will Crowther and Don Woods - * SPDX-FileCopyrightText: 2017 by Eric S. Raymond + * SPDX-FileCopyrightText: (C) 1977, 2005 by Will Crowther and Don Woods * SPDX-License-Identifier: BSD-2-Clause */ @@ -14,7 +13,6 @@ #include #include #include "advent.h" -#include "dungeon.h" #define DIM(a) (sizeof(a)/sizeof(a[0])) @@ -40,8 +38,9 @@ static void sig_handler(int signo) } #if defined ADVENT_AUTOSAVE - if (signo == SIGHUP || signo == SIGTERM) + if (signo == SIGHUP || signo == SIGTERM) { autosave(); + } #endif exit(EXIT_FAILURE); } @@ -73,12 +72,14 @@ char *myreadline(const char *prompt) char *next = settings.argv[settings.optind++]; - if (settings.scriptfp != NULL && feof(settings.scriptfp)) + if (settings.scriptfp != NULL && feof(settings.scriptfp)) { fclose(settings.scriptfp); - if (strcmp(next, "-") == 0) + } + if (strcmp(next, "-") == 0) { settings.scriptfp = stdin; // LCOV_EXCL_LINE - else + } else { settings.scriptfp = fopen(next, "r"); + } } if (isatty(fileno(settings.scriptfp))) { @@ -104,31 +105,36 @@ static void checkhints(void) { if (conditions[game.loc] >= game.conds) { for (int hint = 0; hint < NHINTS; hint++) { - if (game.hinted[hint]) - continue; - if (!CNDBIT(game.loc, hint + 1 + COND_HBASE)) - game.hintlc[hint] = -1; - ++game.hintlc[hint]; + if (game.hints[hint].used) { + continue; + } + if (!CNDBIT(game.loc, hint + 1 + COND_HBASE)) { + game.hints[hint].lc = -1; + } + ++game.hints[hint].lc; /* Come here if he's been int enough at required loc(s) for some * unused hint. */ - if (game.hintlc[hint] >= hints[hint].turns) { + if (game.hints[hint].lc >= hints[hint].turns) { int i; switch (hint) { case 0: /* cave */ - if (game.prop[GRATE] == GRATE_CLOSED && !HERE(KEYS)) - break; - game.hintlc[hint] = 0; + if (game.objects[GRATE].prop == GRATE_CLOSED && !HERE(KEYS)) { + break; + } + game.hints[hint].lc = 0; return; case 1: /* bird */ - if (game.place[BIRD] == game.loc && TOTING(ROD) && game.oldobj == BIRD) - break; + if (game.objects[BIRD].place == game.loc && TOTING(ROD) && game.oldobj == BIRD) { + break; + } return; case 2: /* snake */ - if (HERE(SNAKE) && !HERE(BIRD)) - break; - game.hintlc[hint] = 0; + if (HERE(SNAKE) && !HERE(BIRD)) { + break; + } + game.hints[hint].lc = 0; return; case 3: /* maze */ if (game.locs[game.loc].atloc == NO_OBJECT && @@ -136,19 +142,21 @@ static void checkhints(void) game.locs[game.oldlc2].atloc == NO_OBJECT && game.holdng > 1) break; - game.hintlc[hint] = 0; + game.hints[hint].lc = 0; return; case 4: /* dark */ - if (game.prop[EMERALD] != STATE_NOTFOUND && game.prop[PYRAMID] == STATE_NOTFOUND) - break; - game.hintlc[hint] = 0; + if (!PROP_IS_NOTFOUND(EMERALD) && PROP_IS_NOTFOUND(PYRAMID)) { + break; + } + game.hints[hint].lc = 0; return; case 5: /* witt */ break; case 6: /* urn */ - if (game.dflag == 0) - break; - game.hintlc[hint] = 0; + if (game.dflag == 0) { + break; + } + game.hints[hint].lc = 0; return; case 7: /* woods */ if (game.locs[game.loc].atloc == NO_OBJECT && @@ -159,16 +167,18 @@ static void checkhints(void) case 8: /* ogre */ i = atdwrf(game.loc); if (i < 0) { - game.hintlc[hint] = 0; + game.hints[hint].lc = 0; return; } - if (HERE(OGRE) && i == 0) + if (HERE(OGRE) && i == 0) { break; + } return; case 9: /* jade */ - if (game.tally == 1 && game.prop[JADE] < 0) - break; - game.hintlc[hint] = 0; + if (game.tally == 1 && PROP_IS_STASHED_OR_UNSEEN(JADE)) { + break; + } + game.hints[hint].lc = 0; return; default: // LCOV_EXCL_LINE // Should never happen @@ -176,13 +186,15 @@ static void checkhints(void) } /* Fall through to hint display */ - game.hintlc[hint] = 0; - if (!yes_or_no(hints[hint].question, arbitrary_messages[NO_MESSAGE], arbitrary_messages[OK_MAN])) + game.hints[hint].lc = 0; + if (!yes_or_no(hints[hint].question, arbitrary_messages[NO_MESSAGE], arbitrary_messages[OK_MAN])) { return; + } rspeak(HINT_COST, hints[hint].penalty, hints[hint].penalty); - game.hinted[hint] = yes_or_no(arbitrary_messages[WANT_HINT], hints[hint].hint, arbitrary_messages[OK_MAN]); - if (game.hinted[hint] && game.limit > WARNTIME) + game.hints[hint].used = yes_or_no(arbitrary_messages[WANT_HINT], hints[hint].hint, arbitrary_messages[OK_MAN]); + if (game.hints[hint].used && game.limit > WARNTIME) { game.limit += WARNTIME * hints[hint].penalty; + } } } } @@ -190,37 +202,41 @@ static void checkhints(void) static bool spotted_by_pirate(int i) { - if (i != PIRATE) - return false; + if (i != PIRATE) { + return false; + } /* The pirate's spotted him. Pirate leaves him alone once we've * found chest. K counts if a treasure is here. If not, and * tally=1 for an unseen chest, let the pirate be spotted. Note - * that game.place[CHEST] = LOC_NOWHERE might mean that he's thrown + * 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 - * (game.prop[CHEST] == STATE_FOUND). */ - if (game.loc == game.chloc || game.prop[CHEST] != STATE_NOTFOUND) + * PROP_IS_FOUND(CHEST) == true. */ + if (game.loc == game.chloc || !PROP_IS_NOTFOUND(CHEST)) { return true; + } int snarfed = 0; bool movechest = false, robplayer = false; for (int treasure = 1; treasure <= NOBJECTS; treasure++) { - if (!objects[treasure].is_treasure) + if (!objects[treasure].is_treasure) { continue; + } /* Pirate won't take pyramid from plover room or dark * room (too easy!). */ if (treasure == PYRAMID && (game.loc == objects[PYRAMID].plac || game.loc == objects[EMERALD].plac)) { continue; } - if (TOTING(treasure) || HERE(treasure)) + if (TOTING(treasure) || HERE(treasure)) { ++snarfed; + } if (TOTING(treasure)) { movechest = true; robplayer = true; } } /* Force chest placement before player finds last treasure */ - if (game.tally == 1 && snarfed == 0 && game.place[CHEST] == LOC_NOWHERE && HERE(LAMP) && game.prop[LAMP] == LAMP_BRIGHT) { + if (game.tally == 1 && snarfed == 0 && game.objects[CHEST].place == LOC_NOWHERE && HERE(LAMP) && game.objects[LAMP].prop == LAMP_BRIGHT) { rspeak(PIRATE_SPOTTED); movechest = true; } @@ -235,20 +251,24 @@ static bool spotted_by_pirate(int i) } else { /* You might get a hint of the pirate's presence even if the * chest doesn't move... */ - if (game.dwarves[PIRATE].oldloc != game.dwarves[PIRATE].loc && PCT(20)) - rspeak(PIRATE_RUSTLES); + if (game.dwarves[PIRATE].oldloc != game.dwarves[PIRATE].loc && PCT(20)) { + rspeak(PIRATE_RUSTLES); + } } if (robplayer) { rspeak(PIRATE_POUNCES); for (int treasure = 1; treasure <= NOBJECTS; treasure++) { - if (!objects[treasure].is_treasure) - continue; + if (!objects[treasure].is_treasure) { + continue; + } if (!(treasure == PYRAMID && (game.loc == objects[PYRAMID].plac || game.loc == objects[EMERALD].plac))) { - if (AT(treasure) && game.fixed[treasure] == IS_FREE) - carry(treasure, game.loc); - if (TOTING(treasure)) - drop(treasure, game.chloc); + if (AT(treasure) && game.objects[treasure].fixed == IS_FREE) { + carry(treasure, game.loc); + } + if (TOTING(treasure)) { + drop(treasure, game.chloc); + } } } } @@ -256,9 +276,8 @@ static bool spotted_by_pirate(int i) return true; } -static bool dwarfmove(void) +static bool dwarfmove(void) { /* Dwarves move. Return true if player survives, false if he dies. */ -{ int kk, stick, attack; loc_t tk[21]; @@ -274,8 +293,9 @@ static bool dwarfmove(void) * steal return toll, and dwarves can't meet the bear. Also * means dwarves won't follow him into dead end in maze, but * c'est la vie. They'll wait for him outside the dead end. */ - if (game.loc == LOC_NOWHERE || FORCED(game.loc) || CNDBIT(game.newloc, COND_NOARRR)) + if (game.loc == LOC_NOWHERE || FORCED(game.loc) || CNDBIT(game.newloc, COND_NOARRR)) { return true; + } /* Dwarf activity level ratchets up */ if (game.dflag == 0) { @@ -289,20 +309,23 @@ static bool dwarfmove(void) * replace him with the alternate. */ if (game.dflag == 1) { if (!INDEEP(game.loc) || - (PCT(95) && (!CNDBIT(game.loc, COND_NOBACK) || PCT(85)))) + (PCT(95) && (!CNDBIT(game.loc, COND_NOBACK) || PCT(85)))) { return true; + } game.dflag = 2; for (int i = 1; i <= 2; i++) { int j = 1 + randrange(NDWARVES - 1); - if (PCT(50)) + if (PCT(50)) { game.dwarves[j].loc = 0; + } } /* Alternate initial loc for dwarf, in case one of them * starts out on top of the adventurer. */ for (int i = 1; i <= NDWARVES - 1; i++) { - if (game.dwarves[i].loc == game.loc) - game.dwarves[i].loc = DALTLC; // + if (game.dwarves[i].loc == game.loc) { + game.dwarves[i].loc = DALTLC; + } game.dwarves[i].oldloc = game.dwarves[i].loc; } rspeak(DWARF_RAN); @@ -320,8 +343,9 @@ static bool dwarfmove(void) attack = 0; stick = 0; for (int i = 1; i <= NDWARVES; i++) { - if (game.dwarves[i].loc == 0) - continue; + if (game.dwarves[i].loc == 0) { + continue; + } /* Fill tk array with all the places this dwarf might go. */ unsigned int j = 1; kk = tkey[game.dwarves[i].loc]; @@ -353,38 +377,46 @@ static bool dwarfmove(void) } while (!travel[kk++].stop); tk[j] = game.dwarves[i].oldloc; - if (j >= 2) + if (j >= 2) { --j; + } j = 1 + randrange(j); game.dwarves[i].oldloc = game.dwarves[i].loc; game.dwarves[i].loc = tk[j]; game.dwarves[i].seen = (game.dwarves[i].seen && INDEEP(game.loc)) || (game.dwarves[i].loc == game.loc || game.dwarves[i].oldloc == game.loc); - if (!game.dwarves[i].seen) + if (!game.dwarves[i].seen) { continue; + } game.dwarves[i].loc = game.loc; - if (spotted_by_pirate(i)) + if (spotted_by_pirate(i)) { continue; + } /* This threatening little dwarf is in the room with him! */ ++game.dtotal; if (game.dwarves[i].oldloc == game.dwarves[i].loc) { ++attack; - if (game.knfloc >= LOC_NOWHERE) + if (game.knfloc >= LOC_NOWHERE) { game.knfloc = game.loc; - if (randrange(1000) < 95 * (game.dflag - 2)) + } + if (randrange(1000) < 95 * (game.dflag - 2)) { ++stick; + } } } /* Now we know what's happening. Let's tell the poor sucker about it. */ - if (game.dtotal == 0) + if (game.dtotal == 0) { return true; + } rspeak(game.dtotal == 1 ? DWARF_SINGLE : DWARF_PACK, game.dtotal); - if (attack == 0) + if (attack == 0) { return true; - if (game.dflag == 2) + } + if (game.dflag == 2) { game.dflag = 3; + } if (attack > 1) { rspeak(THROWN_KNIVES, attack); rspeak(stick > 1 ? MULTIPLE_HITS : (stick == 1 ? ONE_HIT : NONE_HIT), stick); @@ -392,8 +424,9 @@ static bool dwarfmove(void) rspeak(KNIFE_THROWN); rspeak(stick ? GETS_YOU : MISSES_YOU); } - if (stick == 0) + if (stick == 0) { return true; + } game.oldlc2 = game.loc; return false; } @@ -417,9 +450,8 @@ static bool dwarfmove(void) * building (and heaven help him if he tries to xyzzy back into the * cave without the lamp!). game.oldloc is zapped so he can't just * "retreat". */ -static void croak(void) +static void croak(void) { /* Okay, he's dead. Let's get on with it. */ -{ const char* query = obituaries[game.numdie].query; const char* yes_response = obituaries[game.numdie].yes_response; @@ -439,9 +471,9 @@ static void croak(void) /* If player wishes to continue, we empty the liquids in the * user's inventory, turn off the lamp, and drop all items * where he died. */ - game.place[WATER] = game.place[OIL] = LOC_NOWHERE; + game.objects[WATER].place = game.objects[OIL].place = LOC_NOWHERE; if (TOTING(LAMP)) - game.prop[LAMP] = LAMP_DARK; + game.objects[LAMP].prop = LAMP_DARK; for (int j = 1; j <= NOBJECTS; j++) { int i = NOBJECTS + 1 - j; if (TOTING(i)) { @@ -453,9 +485,8 @@ static void croak(void) } } -static void describe_location(void) +static void describe_location(void) { /* Describe the location to the user */ -{ const char* msg = locations[game.loc].description.small; if (MOD(game.locs[game.loc].abbrev, game.abbnum) == 0 || msg == NO_MESSAGE) @@ -465,8 +496,9 @@ static void describe_location(void) msg = arbitrary_messages[PITCH_DARK]; } - if (TOTING(BEAR)) + if (TOTING(BEAR)) { rspeak(TAME_BEAR); + } speak(msg); @@ -475,9 +507,8 @@ static void describe_location(void) } -static bool traveleq(int a, int b) +static bool traveleq(int a, int b) { /* Are two travel entries equal for purposes of skip after failed condition? */ -{ return (travel[a].condtype == travel[b].condtype) && (travel[a].condarg1 == travel[b].condarg1) && (travel[a].condarg2 == travel[b].condarg2) @@ -496,11 +527,12 @@ static void playermove(int motion) { int scratchloc, travel_entry = tkey[game.loc]; game.newloc = game.loc; - if (travel_entry == 0) + if (travel_entry == 0) { BUG(LOCATION_HAS_NO_TRAVEL_ENTRIES); // LCOV_EXCL_LINE - if (motion == NUL) + } + if (motion == NUL) { return; - else if (motion == BACK) { + } else if (motion == BACK) { /* Handle "go back". Look for verb which goes from game.loc to * game.oldloc, or to game.oldlc2 If game.oldloc has forced-motion. * te_tmp saves entry -> forced loc -> previous loc. */ @@ -547,8 +579,9 @@ static void playermove(int motion) /* Look. Can't give more detail. Pretend it wasn't dark * (though it may now be dark) so he won't fall into a * pit while staring into the gloom. */ - if (game.detail < 3) - rspeak(NO_MORE_DETAIL); + if (game.detail < 3) { + rspeak(NO_MORE_DETAIL); + } ++game.detail; game.wzdark = false; game.locs[game.loc].abbrev = 0; @@ -628,8 +661,9 @@ static void playermove(int motion) else if (TOTING(condarg1) || (condtype == cond_with && AT(condarg1))) break; /* else fall through to check [not OBJ STATE] */ - } else if (game.prop[condarg1] != condarg2) + } else if (game.objects[condarg1].prop != condarg2) { break; + } /* We arrive here on conditional failure. * Skip to next non-matching destination */ @@ -646,8 +680,9 @@ static void playermove(int motion) /* Found an eligible rule, now execute it */ enum desttype_t desttype = travel[travel_entry].desttype; game.newloc = travel[travel_entry].destval; - if (desttype == dest_goto) + if (desttype == dest_goto) { return; + } if (desttype == dest_speak) { /* Execute a speak rule */ @@ -698,9 +733,9 @@ static void playermove(int motion) * (standard travel entries check for * game.prop[TROLL]=TROLL_UNPAID.) Special stuff * for bear. */ - if (game.prop[TROLL] == TROLL_PAIDONCE) { + if (game.objects[TROLL].prop == TROLL_PAIDONCE) { pspeak(TROLL, look, true, TROLL_PAIDONCE); - game.prop[TROLL] = TROLL_UNPAID; + game.objects[TROLL].prop = TROLL_UNPAID; DESTROY(TROLL2); move(TROLL2 + NOBJECTS, IS_FREE); move(TROLL, objects[TROLL].plac); @@ -710,15 +745,16 @@ static void playermove(int motion) return; } else { game.newloc = objects[TROLL].plac + objects[TROLL].fixd - game.loc; - if (game.prop[TROLL] == TROLL_UNPAID) - game.prop[TROLL] = TROLL_PAIDONCE; - if (!TOTING(BEAR)) + if (game.objects[TROLL].prop == TROLL_UNPAID) + game.objects[TROLL].prop = TROLL_PAIDONCE; + if (!TOTING(BEAR)) { return; + } state_change(CHASM, BRIDGE_WRECKED); - game.prop[TROLL] = TROLL_GONE; + game.objects[TROLL].prop = TROLL_GONE; drop(BEAR, game.newloc); - game.fixed[BEAR] = IS_FIXED; - game.prop[BEAR] = BEAR_DEAD; + game.objects[BEAR].fixed = IS_FIXED; + game.objects[BEAR].prop = BEAR_DEAD; game.oldlc2 = game.newloc; croak(); return; @@ -733,11 +769,11 @@ static void playermove(int motion) (false); } -static void lampcheck(void) +static void lampcheck(void) { /* Check game limit and lamp timers */ -{ - if (game.prop[LAMP] == LAMP_BRIGHT) - --game.limit; + if (game.objects[LAMP].prop == LAMP_BRIGHT) { + --game.limit; + } /* Another way we can force an end to things is by having the * lamp give out. When it gets close, we come here to warn him. @@ -746,57 +782,59 @@ static void lampcheck(void) * Second is for other cases of lamp dying. Even after it goes * out, he can explore outside for a while if desired. */ if (game.limit <= WARNTIME) { - if (HERE(BATTERY) && game.prop[BATTERY] == FRESH_BATTERIES && HERE(LAMP)) { + if (HERE(BATTERY) && game.objects[BATTERY].prop == FRESH_BATTERIES && HERE(LAMP)) { rspeak(REPLACE_BATTERIES); - game.prop[BATTERY] = DEAD_BATTERIES; + game.objects[BATTERY].prop = DEAD_BATTERIES; #ifdef __unused__ /* This code from the original game seems to have been faulty. * No tests ever passed the guard, and with the guard removed * the game hangs when the lamp limit is reached. */ - if (TOTING(BATTERY)) + if (TOTING(BATTERY)) { drop(BATTERY, game.loc); + } #endif game.limit += BATTERYLIFE; game.lmwarn = false; } else if (!game.lmwarn && HERE(LAMP)) { game.lmwarn = true; - if (game.prop[BATTERY] == DEAD_BATTERIES) + if (game.objects[BATTERY].prop == DEAD_BATTERIES) { rspeak(MISSING_BATTERIES); - else if (game.place[BATTERY] == LOC_NOWHERE) + } else if (game.objects[BATTERY].place == LOC_NOWHERE) { rspeak(LAMP_DIM); - else + } else { rspeak(GET_BATTERIES); + } } } if (game.limit == 0) { game.limit = -1; - game.prop[LAMP] = LAMP_DARK; - if (HERE(LAMP)) + game.objects[LAMP].prop = LAMP_DARK; + if (HERE(LAMP)) { rspeak(LAMP_OUT); + } } } -static bool closecheck(void) /* Handle the closing of the cave. The cave closes "clock1" turns * after the last treasure has been located (including the pirate's * chest, which may of course never show up). Note that the * treasures need not have been taken yet, just located. Hence * clock1 must be large enough to get out of the cave (it only ticks - * while inside the cave). When it hits zero, we branch to 10000 to - * start closing the cave, and then sit back and wait for him to try - * to get out. If he doesn't within clock2 turns, we close the cave; - * if he does try, we assume he panics, and give him a few additional - * turns to get frantic before we close. When clock2 hits zero, we - * transport him into the final puzzle. Note that the puzzle depends - * upon all sorts of random things. For instance, there must be no - * water or oil, since there are beanstalks which we don't want to be - * able to water, since the code can't handle it. Also, we can have - * no keys, since there is a grate (having moved the fixed object!) - * there separating him from all the treasures. Most of these - * problems arise from the use of negative prop numbers to suppress - * the object descriptions until he's actually moved the objects. */ -{ + * while inside the cave). When it hits zero, we start closing the + * cave, and then sit back and wait for him to try to get out. If he + * doesn't within clock2 turns, we close the cave; if he does try, we + * assume he panics, and give him a few additional turns to get + * frantic before we close. When clock2 hits zero, we transport him + * into the final puzzle. Note that the puzzle depends upon all + * sorts of random things. For instance, there must be no water or + * oil, since there are beanstalks which we don't want to be able to + * water, since the code can't handle it. Also, we can have no keys, + * since there is a grate (having moved the fixed object!) there + * separating him from all the treasures. Most of these problems + * arise from the use of negative prop numbers to suppress the object + * descriptions until he's actually moved the objects. */ +static bool closecheck(void) { /* If a turn threshold has been met, apply penalties and tell * the player about it. */ for (int i = 0; i < NTHRESHOLDS; ++i) { @@ -807,8 +845,9 @@ static bool closecheck(void) } /* Don't tick game.clock1 unless well into cave (and not at Y2). */ - if (game.tally == 0 && INDEEP(game.loc) && game.loc != LOC_Y2) + if (game.tally == 0 && INDEEP(game.loc) && game.loc != LOC_Y2) { --game.clock1; + } /* When the first warning comes, we lock the grate, destroy * the bridge, kill all the dwarves (and the pirate), remove @@ -824,8 +863,8 @@ static bool closecheck(void) * know the bivalve is an oyster. *And*, the dwarves must * have been activated, since we've found chest. */ if (game.clock1 == 0) { - game.prop[GRATE] = GRATE_CLOSED; - game.prop[FISSURE] = UNBRIDGED; + game.objects[GRATE].prop = GRATE_CLOSED; + game.objects[FISSURE].prop = UNBRIDGED; for (int i = 1; i <= NDWARVES; i++) { game.dwarves[i].seen = false; game.dwarves[i].loc = LOC_NOWHERE; @@ -835,12 +874,13 @@ static bool closecheck(void) move(TROLL2, objects[TROLL].plac); move(TROLL2 + NOBJECTS, objects[TROLL].fixd); juggle(CHASM); - if (game.prop[BEAR] != BEAR_DEAD) + if (game.objects[BEAR].prop != BEAR_DEAD) { DESTROY(BEAR); - game.prop[CHAIN] = CHAIN_HEAP; - game.fixed[CHAIN] = IS_FREE; - game.prop[AXE] = AXE_HERE; - game.fixed[AXE] = IS_FREE; + } + game.objects[CHAIN].prop = CHAIN_HEAP; + game.objects[CHAIN].fixed = IS_FREE; + game.objects[AXE].prop = AXE_HERE; + game.objects[AXE].fixed = IS_FREE; rspeak(CAVE_CLOSING); game.clock1 = -1; game.closng = true; @@ -859,36 +899,37 @@ static bool closecheck(void) * objects come from known locations and/or states (e.g. the * snake is known to have been destroyed and needn't be * carried away from its old "place"), making the various - * objects be handled differently. We also drop all other - * objects he might be carrying (lest he have some which + * objects be handled differently. We also drop all other + * objects he might be carrying (lest he has some which * could cause trouble, such as the keys). We describe the * flash of light and trundle back. */ - game.prop[BOTTLE] = put(BOTTLE, LOC_NE, EMPTY_BOTTLE); - game.prop[PLANT] = put(PLANT, LOC_NE, PLANT_THIRSTY); - game.prop[OYSTER] = put(OYSTER, LOC_NE, STATE_FOUND); - game.prop[LAMP] = put(LAMP, LOC_NE, LAMP_DARK); - game.prop[ROD] = put(ROD, LOC_NE, STATE_FOUND); - game.prop[DWARF] = put(DWARF, LOC_NE, 0); + put(BOTTLE, LOC_NE, EMPTY_BOTTLE); + put(PLANT, LOC_NE, PLANT_THIRSTY); + put(OYSTER, LOC_NE, STATE_FOUND); + put(LAMP, LOC_NE, LAMP_DARK); + put(ROD, LOC_NE, STATE_FOUND); + put(DWARF, LOC_NE, STATE_FOUND); game.loc = LOC_NE; game.oldloc = LOC_NE; game.newloc = LOC_NE; /* Leave the grate with normal (non-negative) property. * Reuse sign. */ - put(GRATE, LOC_SW, 0); - put(SIGN, LOC_SW, 0); - game.prop[SIGN] = ENDGAME_SIGN; - game.prop[SNAKE] = put(SNAKE, LOC_SW, SNAKE_CHASED); - game.prop[BIRD] = put(BIRD, LOC_SW, BIRD_CAGED); - game.prop[CAGE] = put(CAGE, LOC_SW, STATE_FOUND); - game.prop[ROD2] = put(ROD2, LOC_SW, STATE_FOUND); - game.prop[PILLOW] = put(PILLOW, LOC_SW, STATE_FOUND); - - game.prop[MIRROR] = put(MIRROR, LOC_NE, STATE_FOUND); - game.fixed[MIRROR] = LOC_SW; + move(GRATE, LOC_SW); + move(SIGN, LOC_SW); + game.objects[SIGN].prop = ENDGAME_SIGN; + put(SNAKE, LOC_SW, SNAKE_CHASED); + put(BIRD, LOC_SW, BIRD_CAGED); + put(CAGE, LOC_SW, STATE_FOUND); + put(ROD2, LOC_SW, STATE_FOUND); + put(PILLOW, LOC_SW, STATE_FOUND); + + put(MIRROR, LOC_NE, STATE_FOUND); + game.objects[MIRROR].fixed = LOC_SW; for (int i = 1; i <= NOBJECTS; i++) { - if (TOTING(i)) - DESTROY(i); + if (TOTING(i)) { + DESTROY(i); + } } rspeak(CAVE_CLOSED); @@ -900,7 +941,7 @@ static bool closecheck(void) return false; } -static void listobjects(void) +static void listobjects(void) { /* Print out descriptions of objects at this location. If * not closing and property value is negative, tally off * another treasure. Rug is special case; once seen, its @@ -908,25 +949,34 @@ 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)) { ++game.locs[game.loc].abbrev; for (int i = game.locs[game.loc].atloc; i != 0; i = game.link[i]) { obj_t obj = i; - if (obj > NOBJECTS) + if (obj > NOBJECTS) { obj = obj - NOBJECTS; - if (obj == STEPS && TOTING(NUGGET)) + } + if (obj == STEPS && TOTING(NUGGET)) { continue; - if (game.prop[obj] < 0) { - if (game.closed) - continue; - game.prop[obj] = STATE_FOUND; - if (obj == RUG) - game.prop[RUG] = RUG_DRAGON; - if (obj == CHAIN) - game.prop[CHAIN] = CHAINING_BEAR; - if (obj == EGGS) + } + /* (ESR) Warning: it looks like you could get away with + * running this code only on objects with the treasure + * property set. Nope. There is mystery here. + */ + if (PROP_IS_STASHED_OR_UNSEEN(obj)) { + if (game.closed) { + continue; + } + PROP_SET_FOUND(obj); + if (obj == RUG) { + game.objects[RUG].prop = RUG_DRAGON; + } + if (obj == CHAIN) { + game.objects[CHAIN].prop = CHAINING_BEAR; + } + if (obj == EGGS) { game.seenbigwords = true; + } --game.tally; /* Note: There used to be a test here to see whether the * player had blown it so badly that he could never ever see @@ -943,17 +993,17 @@ static void listobjects(void) * gross blunder isn't likely to find everything else anyway * (so goes the rationalisation). */ } - int kk = game.prop[obj]; - if (obj == STEPS) - kk = (game.loc == game.fixed[STEPS]) + int kk = game.objects[obj].prop; + if (obj == STEPS) { + kk = (game.loc == game.objects[STEPS].fixed) ? STEPS_UP : STEPS_DOWN; + } pspeak(obj, look, true, kk); } } } -static bool preprocess_command(command_t *command) /* Pre-processes a command input to see if we need to tease out a few specific cases: * - "enter water" or "enter stream": * weird specific case that gets the user wet, and then kicks us back to get another command @@ -970,13 +1020,14 @@ static bool preprocess_command(command_t *command) * * Returns true if pre-processing is complete, and we're ready to move to the primary command * processing, false otherwise. */ -{ +static bool preprocess_command(command_t *command) { if (command->word[0].type == MOTION && command->word[0].id == ENTER && (command->word[1].id == STREAM || command->word[1].id == WATER)) { - if (LIQLOC(game.loc) == WATER) - rspeak(FEET_WET); - else - rspeak(WHERE_QUERY); + if (LIQLOC(game.loc) == WATER) { + rspeak(FEET_WET); + } else { + rspeak(WHERE_QUERY); + } } else { if (command->word[0].type == OBJECT) { /* From OV to VO form */ @@ -1026,15 +1077,15 @@ static bool preprocess_command(command_t *command) return false; } -static bool do_move(void) +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) { rspeak(EXIT_CLOSED); game.newloc = game.loc; - if (!game.panic) + if (!game.panic) { game.clock2 = PANICTIME; + } game.panic = true; } @@ -1053,11 +1104,13 @@ static bool do_move(void) } game.loc = game.newloc; - if (!dwarfmove()) + if (!dwarfmove()) { croak(); + } - if (game.loc == LOC_NOWHERE) + if (game.loc == LOC_NOWHERE) { croak(); + } /* The easiest way to get killed is to fall into a pit in * pitch darkness. */ @@ -1071,9 +1124,8 @@ static bool do_move(void) return true; } -static bool do_command(void) +static bool do_command(void) { /* Get and execute a command */ -{ static command_t command; clear_command(&command); @@ -1094,23 +1146,26 @@ static bool do_command(void) while (command.state <= GIVEN) { if (game.closed) { - /* If closing time, check for any objects being toted with - * game.prop < 0 and stash them. This way objects won't be - * described until they've been picked up and put down - * separate from their respective piles. */ - if (game.prop[OYSTER] < 0 && TOTING(OYSTER)) - pspeak(OYSTER, look, true, 1); + /* If closing time, check for any stashed objects + * being toted and unstash them. This 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)) && TOTING(OYSTER)) { + pspeak(OYSTER, look, true, 1); + } for (size_t i = 1; i <= NOBJECTS; i++) { - if (TOTING(i) && game.prop[i] < 0) - game.prop[i] = STASHED(i); + if (TOTING(i) && (PROP_IS_NOTFOUND(i) || PROP_IS_STASHED(i))) + game.objects[i].prop = PROP_STASHED(i); } } /* Check to see if the room is dark. If the knife is here, * and it's dark, the knife permanently disappears */ game.wzdark = DARK(game.loc); - if (game.knfloc != LOC_NOWHERE && game.knfloc != game.loc) + if (game.knfloc != LOC_NOWHERE && game.knfloc != game.loc) { game.knfloc = LOC_NOWHERE; + } /* Check some for hints, get input from user, increment * turn, and pre-process commands. Keep going until @@ -1119,8 +1174,9 @@ static bool do_command(void) checkhints(); /* Get command input from user */ - if (!get_command_input(&command)) + if (!get_command_input(&command)) { return false; + } /* Every input, check "foobar" flag. If zero, nothing's going * on. If pos, make neg. If neg, he skipped a word, so make it @@ -1133,8 +1189,9 @@ static bool do_command(void) } /* check if game is closed, and exit if it is */ - if (closecheck() ) + if (closecheck()) { return true; + } /* loop until all words in command are processed */ while (command.state == PREPROCESSED ) { @@ -1149,12 +1206,14 @@ static bool do_command(void) /* Give user hints of shortcuts */ if (strncasecmp(command.word[0].raw, "west", sizeof("west")) == 0) { - if (++game.iwest == 10) - rspeak(W_IS_WEST); + if (++game.iwest == 10) { + rspeak(W_IS_WEST); + } } if (strncasecmp(command.word[0].raw, "go", sizeof("go")) == 0 && command.word[1].id != WORD_EMPTY) { - if (++game.igo == 10) - rspeak(GO_UNNEEDED); + if (++game.igo == 10) { + rspeak(GO_UNNEEDED); + } } switch (command.word[0].type) { @@ -1167,10 +1226,11 @@ static bool do_command(void) command.obj = command.word[0].id; break; case ACTION: - if (command.word[1].type == NUMERIC) - command.part = transitive; - else - command.part = intransitive; + if (command.word[1].type == NUMERIC) { + command.part = transitive; + } else { + command.part = intransitive; + } command.verb = command.word[0].id; break; case NUMERIC: @@ -1272,10 +1332,11 @@ int main(int argc, char *argv[]) break; // LCOV_EXCL_LINE case 'l': settings.logfp = fopen(optarg, "w"); - if (settings.logfp == NULL) + if (settings.logfp == NULL) { fprintf(stderr, "advent: can't open logfile %s for write\n", optarg); + } signal(SIGINT, sig_handler); break; case 'o': @@ -1292,10 +1353,11 @@ int main(int argc, char *argv[]) #elif !defined ADVENT_NOSAVE case 'r': rfp = fopen(optarg, "r"); - if (rfp == NULL) + if (rfp == NULL) { fprintf(stderr, "advent: can't open save file %s for read\n", optarg); + } break; #endif default: @@ -1328,8 +1390,9 @@ int main(int argc, char *argv[]) #if !defined ADVENT_NOSAVE if (!rfp) { game.novice = yes_or_no(arbitrary_messages[WELCOME_YOU], arbitrary_messages[CAVE_NEARBY], arbitrary_messages[NO_MESSAGE]); - if (game.novice) + if (game.novice) { game.limit = NOVICELIMIT; + } } else { restore(rfp); #if defined ADVENT_AUTOSAVE @@ -1351,18 +1414,21 @@ int main(int argc, char *argv[]) game.limit = NOVICELIMIT; #endif - if (settings.logfp) + if (settings.logfp) { fprintf(settings.logfp, "seed %d\n", seedval); + } /* interpret commands until EOF or interrupt */ for (;;) { // if we're supposed to move, move - if (!do_move()) - continue; + if (!do_move()) { + continue; + } - // get command - if (!do_command()) - break; + // get command + if (!do_command()) { + break; + } } /* show score and exit */ terminate(quitgame);