X-Git-Url: https://jxself.org/git/?p=open-adventure.git;a=blobdiff_plain;f=actions.c;h=06da68805481e1526c7a24687b09c9224188b6b1;hp=6351f0d9164dd0647c43baba63ccc260a6bd831d;hb=7be7ac9406512644886fbf4a99d16e1b4f7cefc3;hpb=85f918f9c06bc8c64678848a29d348e354fbc146 diff --git a/actions.c b/actions.c index 6351f0d..06da688 100644 --- a/actions.c +++ b/actions.c @@ -7,6 +7,7 @@ static int fill(token_t, token_t); static void state_change(long obj, long state) +/* Object must have a change-message list for this to be useful; only some do */ { game.prop[obj] = state; pspeak(obj, change, state, true); @@ -21,7 +22,6 @@ static int attack(struct command_t *command) vocab_t verb = command->verb; vocab_t obj = command->obj; - long spk = actions[verb].message; if (obj == NO_OBJECT || obj == INTRANSITIVE) { int changes = 0; @@ -69,69 +69,41 @@ static int attack(struct command_t *command) } if (changes >= 2) return GO_UNKNOWN; - } + if (obj == BIRD) { if (game.closed) { rspeak(UNHAPPY_BIRD); - return GO_CLEAROBJ; + } else { + DESTROY(BIRD); + rspeak(BIRD_DEAD); } - DESTROY(BIRD); - spk = BIRD_DEAD; - } else if (obj == VEND) { + return GO_CLEAROBJ; + } + if (obj == VEND) { state_change(VEND, game.prop[VEND] == VEND_BLOCKS ? VEND_UNBLOCKS : VEND_BLOCKS); return GO_CLEAROBJ; } - if (obj == NO_OBJECT) - spk = NO_TARGET; - if (obj == CLAM || - obj == OYSTER) - spk = SHELL_IMPERVIOUS; - if (obj == SNAKE) - spk = SNAKE_WARNING; - if (obj == DWARF) - spk = BARE_HANDS_QUERY; - if (obj == DWARF && game.closed) - return GO_DWARFWAKE; - if (obj == DRAGON) - spk = ALREADY_DEAD; - if (obj == TROLL) - spk = ROCKY_TROLL; - if (obj == OGRE) - spk = OGRE_DODGE; - if (obj == OGRE && atdwrf(game.loc) > 0) { - rspeak(spk); - rspeak(KNIFE_THROWN); - DESTROY(OGRE); - int dwarves = 0; - for (int i = 1; i < PIRATE; i++) { - if (game.dloc[i] == game.loc) { - ++dwarves; - game.dloc[i] = LOC_LONGWEST; - game.dseen[i] = false; - } - } - spk = (dwarves > 1) ? - OGRE_PANIC1 : - OGRE_PANIC2; - } else if (obj == BEAR) { + if (obj == BEAR) { switch (game.prop[BEAR]) { case UNTAMED_BEAR: - spk = BEAR_HANDS; + rspeak(BEAR_HANDS); break; case SITTING_BEAR: - spk = BEAR_CONFUSED; + rspeak(BEAR_CONFUSED); break; case CONTENTED_BEAR: - spk = BEAR_CONFUSED; + rspeak(BEAR_CONFUSED); break; case BEAR_DEAD: - spk = ALREADY_DEAD; + rspeak(ALREADY_DEAD); break; } - } else if (obj == DRAGON && game.prop[DRAGON] == DRAGON_BARS) { + return GO_CLEAROBJ; + } + if (obj == DRAGON && game.prop[DRAGON] == DRAGON_BARS) { /* Fun stuff for dragon. If he insists on attacking it, win! * Set game.prop to dead, move dragon to central loc (still * fixed), move rug there (not fixed), and move him there, @@ -163,7 +135,53 @@ static int attack(struct command_t *command) return GO_MOVE; } - rspeak(spk); + if (obj == OGRE) { + rspeak(OGRE_DODGE); + if (atdwrf(game.loc) == 0) + return GO_CLEAROBJ; + + rspeak(KNIFE_THROWN); + DESTROY(OGRE); + int dwarves = 0; + for (int i = 1; i < PIRATE; i++) { + if (game.dloc[i] == game.loc) { + ++dwarves; + game.dloc[i] = LOC_LONGWEST; + game.dseen[i] = false; + } + } + rspeak((dwarves > 1) ? + OGRE_PANIC1 : + OGRE_PANIC2); + return GO_CLEAROBJ; + } + + switch (obj) { + case NO_OBJECT: + rspeak(NO_TARGET); + break; + case CLAM: + case OYSTER: + rspeak(SHELL_IMPERVIOUS); + break; + case SNAKE: + rspeak(SNAKE_WARNING); + break; + case DWARF: + if (game.closed) { + return GO_DWARFWAKE; + } + rspeak(BARE_HANDS_QUERY); + break; + case DRAGON: + rspeak(ALREADY_DEAD); + break; + case TROLL: + rspeak(ROCKY_TROLL); + break; + default: + rspeak(actions[verb].message); + } return GO_CLEAROBJ; } @@ -210,38 +228,6 @@ static int bigwords(token_t foo) } } -static int bivalve(token_t verb, token_t obj) -/* Clam/oyster actions */ -{ - bool is_oyster = (obj == OYSTER); - if (verb == LOCK) { - rspeak(HUH_MAN); - return GO_CLEAROBJ; - } - if (!TOTING(TRIDENT)) { - rspeak(is_oyster ? - OYSTER_OPENER : - CLAM_OPENER); - return GO_CLEAROBJ; - } - if (TOTING(obj)) { - rspeak( is_oyster ? - DROP_OYSTER : - DROP_CLAM); - return GO_CLEAROBJ; - } - - if (!is_oyster) { - DESTROY(CLAM); - drop(OYSTER, game.loc); - drop(PEARL, LOC_CULDESAC); - } - rspeak(is_oyster ? - OYSTER_OPENS : - PEARL_FALLS); - return GO_CLEAROBJ; -} - static void blast(void) /* Blast. No effect unless you've got dynamite, which is a neat trick! */ { @@ -275,7 +261,7 @@ static int vbreak(token_t verb, token_t obj) if (TOTING(VASE)) drop(VASE, game.loc); state_change(VASE, VASE_BROKEN); - game.fixed[VASE] = -1; + game.fixed[VASE] = IS_FIXED; return GO_CLEAROBJ; } rspeak(actions[verb].message); @@ -296,7 +282,6 @@ static int vcarry(token_t verb, token_t obj) * take one without the other). Liquids also special, since they depend on * status of bottle. Also various side effects, etc. */ { - int spk; if (obj == INTRANSITIVE) { /* Carry, no object given yet. OK if only one object present. */ if (game.atloc[game.loc] == 0 || @@ -310,82 +295,100 @@ static int vcarry(token_t verb, token_t obj) rspeak(ALREADY_CARRYING); return GO_CLEAROBJ; } - spk = YOU_JOKING; - if (obj == PLANT && game.prop[PLANT] <= 0) - spk = DEEP_ROOTS; - if (obj == BEAR && game.prop[BEAR] == SITTING_BEAR) - spk = BEAR_CHAINED; - if (obj == CHAIN && game.prop[BEAR] != UNTAMED_BEAR) - spk = STILL_LOCKED; - if (obj == URN) - spk = URN_NOBUDGE; - if (obj == CAVITY) - spk = DOUGHNUT_HOLES; - if (obj == BLOOD) - spk = FEW_DROPS; - if (obj == RUG && game.prop[RUG] == RUG_HOVER) - spk = RUG_HOVERS; - if (obj == SIGN) - spk = HAND_PASSTHROUGH; + if (obj == MESSAG) { rspeak(REMOVE_MESSAGE); DESTROY(MESSAG); return GO_CLEAROBJ; } - if (game.fixed[obj] != 0) { - rspeak(spk); + + if (game.fixed[obj] != IS_FREE) { + /* Next guard tests whether plant is tiny or stashed */ + if (obj == PLANT && game.prop[PLANT] <= PLANT_THIRSTY) { + rspeak(DEEP_ROOTS); + return GO_CLEAROBJ; + } + if (obj == BEAR && game.prop[BEAR] == SITTING_BEAR) { + rspeak(BEAR_CHAINED); + return GO_CLEAROBJ; + } + if (obj == CHAIN && game.prop[BEAR] != UNTAMED_BEAR) { + rspeak(STILL_LOCKED); + return GO_CLEAROBJ; + } + if (obj == URN) { + rspeak(URN_NOBUDGE); + return GO_CLEAROBJ; + } + if (obj == CAVITY) { + rspeak(DOUGHNUT_HOLES); + return GO_CLEAROBJ; + } + if (obj == BLOOD) { + rspeak(FEW_DROPS); + return GO_CLEAROBJ; + } + if (obj == RUG && game.prop[RUG] == RUG_HOVER) { + rspeak(RUG_HOVERS); + return GO_CLEAROBJ; + } + if (obj == SIGN) { + rspeak(HAND_PASSTHROUGH); + return GO_CLEAROBJ; + } + rspeak(YOU_JOKING); return GO_CLEAROBJ; } + if (obj == WATER || obj == OIL) { if (!HERE(BOTTLE) || LIQUID() != obj) { - if (TOTING(BOTTLE) && game.prop[BOTTLE] == EMPTY_BOTTLE) - return (fill(verb, BOTTLE)); - else { - if (game.prop[BOTTLE] != EMPTY_BOTTLE) - spk = BOTTLE_FULL; - if (!TOTING(BOTTLE)) - spk = NO_CONTAINER; - rspeak(spk); + if (TOTING(BOTTLE)) { + if (game.prop[BOTTLE] == EMPTY_BOTTLE) { + return (fill(verb, BOTTLE)); + } else if (game.prop[BOTTLE] != EMPTY_BOTTLE) + rspeak(BOTTLE_FULL); return GO_CLEAROBJ; } + rspeak(NO_CONTAINER); + return GO_CLEAROBJ; } obj = BOTTLE; } - spk = CARRY_LIMIT; if (game.holdng >= INVLIMIT) { - rspeak(spk); + rspeak(CARRY_LIMIT); return GO_CLEAROBJ; - } else if (obj == BIRD && game.prop[BIRD] != BIRD_CAGED && -1 - game.prop[BIRD] != BIRD_CAGED) { + + } + + if (obj == BIRD && game.prop[BIRD] != BIRD_CAGED && STASHED(BIRD) != BIRD_CAGED) { if (game.prop[BIRD] == BIRD_FOREST_UNCAGED) { DESTROY(BIRD); rspeak(BIRD_CRAP); return GO_CLEAROBJ; } - if (!TOTING(CAGE)) - spk = CANNOT_CARRY; - if (TOTING(ROD)) - spk = BIRD_EVADES; - if (spk == CANNOT_CARRY || - spk == BIRD_EVADES) { - rspeak(spk); + if (!TOTING(CAGE)) { + rspeak(CANNOT_CARRY); + return GO_CLEAROBJ; + } + if (TOTING(ROD)) { + rspeak(BIRD_EVADES); return GO_CLEAROBJ; } game.prop[BIRD] = BIRD_CAGED; } - /* FIXME: Arithmetic on state numbers */ if ((obj == BIRD || obj == CAGE) && - (game.prop[BIRD] == BIRD_CAGED || - -1 - game.prop[BIRD] == 1)) + (game.prop[BIRD] == BIRD_CAGED || STASHED(BIRD) == BIRD_CAGED)) + /* expression maps BIRD to CAGE and CAGE to BIRD */ carry(BIRD + CAGE - obj, game.loc); carry(obj, game.loc); - if (obj == BOTTLE && LIQUID() != 0) + if (obj == BOTTLE && LIQUID() != NO_OBJECT) game.place[LIQUID()] = CARRIED; - if (GSTONE(obj) && game.prop[obj] != 0) { - game.prop[obj] = STATE_GROUND; + if (GSTONE(obj) && game.prop[obj] != STATE_FOUND) { + game.prop[obj] = STATE_FOUND; game.prop[CAVITY] = CAVITY_EMPTY; } rspeak(OK_MAN); @@ -405,16 +408,16 @@ static int chain(token_t verb) return GO_CLEAROBJ; } game.prop[CHAIN] = CHAIN_HEAP; - game.fixed[CHAIN] = CHAIN_HEAP; + game.fixed[CHAIN] = IS_FREE; if (game.prop[BEAR] != BEAR_DEAD) game.prop[BEAR] = CONTENTED_BEAR; switch (game.prop[BEAR]) { case BEAR_DEAD: - game.fixed[BEAR] = -1; + game.fixed[BEAR] = IS_FIXED; break; default: - game.fixed[BEAR] = 0; + game.fixed[BEAR] = IS_FREE; } rspeak(CHAIN_UNLOCKED); return GO_CLEAROBJ; @@ -433,7 +436,7 @@ static int chain(token_t verb) if (TOTING(CHAIN)) drop(CHAIN, game.loc); - game.fixed[CHAIN] = -1; + game.fixed[CHAIN] = IS_FIXED; rspeak(CHAIN_LOCKED); return GO_CLEAROBJ; @@ -444,12 +447,11 @@ static int discard(token_t verb, token_t obj, bool just_do_it) * bird (might attack snake or dragon) and cage (might contain bird) and vase. * Drop coins at vending machine for extra batteries. */ { - int spk = actions[verb].message; if (!just_do_it) { if (TOTING(ROD2) && obj == ROD && !TOTING(ROD)) obj = ROD2; if (!TOTING(obj)) { - rspeak(spk); + rspeak(actions[verb].message); return GO_CLEAROBJ; } if (obj == BIRD && HERE(SNAKE)) { @@ -462,11 +464,11 @@ static int discard(token_t verb, token_t obj, bool just_do_it) } else if ((GSTONE(obj) && AT(CAVITY) && game.prop[CAVITY] != CAVITY_FULL)) { rspeak(GEM_FITS); - game.prop[obj] = 1; + game.prop[obj] = STATE_IN_CAVITY; game.prop[CAVITY] = CAVITY_FULL; if (HERE(RUG) && ((obj == EMERALD && game.prop[RUG] != RUG_HOVER) || (obj == RUBY && game.prop[RUG] == RUG_HOVER))) { - spk = RUG_RISES; + int spk = RUG_RISES; if (TOTING(RUG)) spk = RUG_WIGGLES; if (obj == RUBY) @@ -476,7 +478,7 @@ static int discard(token_t verb, token_t obj, bool just_do_it) /* FIXME: Arithmetic on state numbers */ int k = 2 - game.prop[RUG]; game.prop[RUG] = k; - if (k == 2) + if (k == RUG_HOVER) k = objects[SAPPH].plac; move(RUG + NOBJECTS, k); } @@ -501,18 +503,17 @@ static int discard(token_t verb, token_t obj, bool just_do_it) game.loc == objects[PILLOW].plac) { rspeak(OK_MAN); } else { - game.prop[VASE] = VASE_BROKEN; - if (AT(PILLOW)) - game.prop[VASE] = VASE_WHOLE; - pspeak(VASE, look, game.prop[VASE] + 1, true); + state_change(VASE, AT(PILLOW) + ? VASE_WHOLE + : VASE_DROPPED); if (game.prop[VASE] != VASE_WHOLE) - game.fixed[VASE] = -1; + game.fixed[VASE] = IS_FIXED; } } int k = LIQUID(); if (k == obj) obj = BOTTLE; - if (obj == BOTTLE && k != 0) + if (obj == BOTTLE && k != NO_OBJECT) game.place[k] = LOC_NOWHERE; if (obj == CAGE && game.prop[BIRD] == BIRD_CAGED) drop(BIRD, game.loc); @@ -546,9 +547,8 @@ static int drink(token_t verb, token_t obj) return GO_CLEAROBJ; } if (LIQUID() == WATER && HERE(BOTTLE)) { - game.prop[BOTTLE] = EMPTY_BOTTLE; game.place[WATER] = LOC_NOWHERE; - rspeak(BOTTLE_EMPTY); + state_change(BOTTLE, EMPTY_BOTTLE); return GO_CLEAROBJ; } @@ -660,8 +660,8 @@ static int feed(token_t verb, token_t obj) if (HERE(FOOD)) { DESTROY(FOOD); game.prop[BEAR] = SITTING_BEAR; - game.fixed[AXE] = 0; - game.prop[AXE] = 0; + game.fixed[AXE] = IS_FREE; + game.prop[AXE] = AXE_HERE; spk = BEAR_TAMED; } } else if (obj == OGRE) { @@ -689,8 +689,8 @@ int fill(token_t verb, token_t obj) } rspeak(SHATTER_VASE); game.prop[VASE] = VASE_BROKEN; - game.fixed[VASE] = -1; - return (discard(verb, obj, true)); + game.fixed[VASE] = IS_FIXED; + return (discard(verb, VASE, true)); } if (obj == URN) { @@ -741,13 +741,11 @@ int fill(token_t verb, token_t obj) return GO_CLEAROBJ; } - game.prop[BOTTLE] = (LIQLOC(game.loc) == OIL) ? OIL_BOTTLE : WATER_BOTTLE; + state_change(BOTTLE, (LIQLOC(game.loc) == OIL) + ? OIL_BOTTLE + : WATER_BOTTLE); if (TOTING(BOTTLE)) game.place[LIQUID()] = CARRIED; - if (LIQUID() == OIL) - rspeak(BOTTLED_OIL); - else - rspeak(BOTTLED_WATER); return GO_CLEAROBJ; } @@ -805,10 +803,10 @@ static int fly(token_t verb, token_t obj) /* FIXME: Arithmetic on location values */ game.newloc = game.place[RUG] + game.fixed[RUG] - game.loc; - if (game.prop[SAPPH] >= 0) { - rspeak(RUG_RETURNS); - } else { + if (game.prop[SAPPH] == STATE_NOTFOUND) { rspeak(RUG_GOES); + } else { + rspeak(RUG_RETURNS); } return GO_TERMINATE; } @@ -871,7 +869,7 @@ static int light(token_t verb, token_t obj) } static int listen(void) -/* Listen. Intransitive only. Print stuff based on objsnd/locsnd. */ +/* Listen. Intransitive only. Print stuff based on object sound proprties. */ { long sound = locations[game.loc].sound; if (sound != SILENT) { @@ -891,8 +889,7 @@ static int listen(void) long packed_zzword = token_to_packed(game.zzword); pspeak(i, hear, mi, true, packed_zzword); rspeak(NO_MESSAGE); - /* FIXME: Magic number, sensitive to bird state logic */ - if (i == BIRD && game.prop[i] == 5) + if (i == BIRD && mi == BIRD_ENDSTATE) DESTROY(BIRD); return GO_CLEAROBJ; } @@ -946,8 +943,24 @@ static int lock(token_t verb, token_t obj) switch (obj) { case CLAM: + if (verb == LOCK) + rspeak(HUH_MAN); + else if (!TOTING(TRIDENT)) + rspeak(OYSTER_OPENER); + else { + DESTROY(CLAM); + drop(OYSTER, game.loc); + drop(PEARL, LOC_CULDESAC); + rspeak(PEARL_FALLS); + } + return GO_CLEAROBJ; case OYSTER: - return bivalve(verb, obj); + if (verb == LOCK) + rspeak(HUH_MAN); + else + rspeak(OYSTER_OPENER); + + return GO_CLEAROBJ; case DOOR: rspeak((game.prop[DOOR] == DOOR_UNRUSTED) ? OK_MAN : RUSTY_DOOR); break; @@ -993,14 +1006,14 @@ static int pour(token_t verb, token_t obj) } if (!AT(DOOR)) { if (obj == WATER) { - /* cycle through the three plant states */ - state_change(PLANT, MOD(game.prop[PLANT] + 1, 3)); - game.prop[PLANT2] = game.prop[PLANT]; - return GO_MOVE; + /* cycle through the three plant states */ + state_change(PLANT, MOD(game.prop[PLANT] + 1, 3)); + game.prop[PLANT2] = game.prop[PLANT]; + return GO_MOVE; } else { rspeak(SHAKING_LEAVES); return GO_CLEAROBJ; - } + } } else { state_change(DOOR, (obj == OIL) ? DOOR_UNRUSTED : @@ -1052,9 +1065,8 @@ static int reservoir(void) rspeak(NOTHING_HAPPENS); return GO_CLEAROBJ; } else { - /* FIXME: Arithmetic on state numbers */ - pspeak(RESER, look, game.prop[RESER] + 1, true); - game.prop[RESER] = 1 - game.prop[RESER]; + state_change(RESER, + game.prop[RESER] == WATERS_PARTED ? WATERS_UNPARTED : WATERS_PARTED); if (AT(RESER)) return GO_CLEAROBJ; else { @@ -1094,7 +1106,6 @@ static int say(struct command_t *command) char word1[TOKLEN + 1]; packed_to_token(command->wd1, word1); int wd = (int) get_vocab_id(word1); - /* FIXME: magic numbers */ if (wd == MOTION_WORD(XYZZY) || wd == MOTION_WORD(PLUGH) || wd == MOTION_WORD(PLOVER) || @@ -1121,8 +1132,6 @@ static int throw (struct command_t *command) * (Only way to do so!) Axe also special for dragon, bear, and * troll. Treasures special for troll. */ { - if (TOTING(ROD2) && command->obj == ROD && !TOTING(ROD)) - command->obj = ROD2; if (!TOTING(command->obj)) { rspeak(actions[command->verb].message); return GO_CLEAROBJ; @@ -1156,7 +1165,7 @@ static int throw (struct command_t *command) else if (HERE(BEAR) && game.prop[BEAR] == UNTAMED_BEAR) { /* This'll teach him to throw the axe at the bear! */ drop(AXE, game.loc); - game.fixed[AXE] = -1; + game.fixed[AXE] = IS_FIXED; juggle(BEAR); state_change(AXE, AXE_LOST); return GO_CLEAROBJ; @@ -1208,7 +1217,7 @@ static int wave(token_t verb, token_t obj) if (game.prop[BIRD] == BIRD_UNCAGED && game.loc == game.place[STEPS] && game.prop[JADE] < 0) { drop(JADE, game.loc); - game.prop[JADE] = 0; + game.prop[JADE] = STATE_FOUND; --game.tally; rspeak(NECKLACE_FLY); return GO_CLEAROBJ; @@ -1231,9 +1240,8 @@ static int wave(token_t verb, token_t obj) CAGE_FLY : FREE_FLY); - /* FIXME: Arithemetic on property values */ - game.prop[FISSURE] = 1 - game.prop[FISSURE]; - pspeak(FISSURE, look, 2 - game.prop[FISSURE], true); + state_change(FISSURE, + game.prop[FISSURE] == BRIDGED ? UNBRIDGED : BRIDGED); return GO_CLEAROBJ; } } @@ -1304,7 +1312,7 @@ int action(struct command_t *command) return GO_WORD2; if (command->verb == SAY) command->obj = command->wd2; - if (command->obj == 0 || + if (command->obj == NO_OBJECT || command->obj == INTRANSITIVE) { /* Analyse an intransitive verb (ie, no object given yet). */ switch (command->verb) {