From 9437ccca36057e2ba4b6f4b407304f23f14ab4c4 Mon Sep 17 00:00:00 2001 From: "Eric S. Raymond" Date: Tue, 20 Jun 2017 20:06:32 -0400 Subject: [PATCH] WD* globals abolished. They're now members of the command block. --- TODO | 4 -- actions.c | 203 +++++++++++++++++++++++++++--------------------------- advent.h | 4 +- main.c | 39 +++++------ 4 files changed, 124 insertions(+), 126 deletions(-) diff --git a/TODO b/TODO index 3e86529..188da49 100644 --- a/TODO +++ b/TODO @@ -3,10 +3,6 @@ The FORTRANish mess that once was is now mostly idiomatic C. Some issues remain to be cleaned up: -* The remaining shared globals: WD1, WD1X, WD2, WD2X. These are used - rather promiscuously to pass around information that ought to be function - arguments in a modern language. - * Remaining unstructured gotos in do_command(). * The program is still pretty much typeless - full of magic numbers being diff --git a/actions.c b/actions.c index 4fb8cf7..164d15e 100644 --- a/actions.c +++ b/actions.c @@ -4,17 +4,16 @@ #include "database.h" #include "newdb.h" -/* Limit visibility of ugly globals. Eventually these should go away. */ -extern token_t WD1, WD1X, WD2, WD2X; - static int fill(token_t, token_t); -static int attack(FILE *input, token_t verb, token_t obj) +static int attack(FILE *input, struct command_t *command) /* Attack. Assume target if unambiguous. "Throw" also links here. * Attackable objects fall into two categories: enemies (snake, * dwarf, etc.) and others (bird, clam, machine). Ambiguous if 2 * enemies, or no enemies but 2 others. */ { + vocab_t verb = command->verb; + vocab_t obj = command->obj; int spk = ACTSPK[verb]; if (obj == 0 || obj == INTRANSITIVE) { if (ATDWRF(game.loc) > 0) @@ -81,8 +80,8 @@ static int attack(FILE *input, token_t verb, token_t obj) * fixed), move rug there (not fixed), and move him there, * too. Then do a null motion to get new description. */ RSPEAK(BARE_HANDS_QUERY); - GETIN(input, &WD1, &WD1X, &WD2, &WD2X); - if (WD1 != MAKEWD(WORD_YINIT) && WD1 != MAKEWD(WORD_YES)) + GETIN(input, &command->wd1, &command->wd1x, &command->wd2, &command->wd2x); + if (command->wd1 != MAKEWD(WORD_YINIT) && command->wd1 != MAKEWD(WORD_YES)) return GO_CHECKFOO; PSPEAK(DRAGON, 3); game.prop[DRAGON] = 1; @@ -107,7 +106,7 @@ static int attack(FILE *input, token_t verb, token_t obj) static int bigwords(token_t foo) /* FEE FIE FOE FOO (AND FUM). Advance to next state if given in proper order. - * Look up WD1 in section 3 of vocab to determine which word we've got. Last + * Look up foo in section 3 of vocab to determine which word we've got. Last * word zips the eggs back to the giant room (unless already there). */ { int k = VOCAB(foo, 3); @@ -792,32 +791,32 @@ static int quit(void) return GO_CLEAROBJ; } -static int read(token_t verb, token_t obj) +static int read(struct command_t *command) /* Read. Print stuff based on objtxt. Oyster (?) is special case. */ { - if (obj == INTRANSITIVE) { - obj = 0; + if (command->obj == INTRANSITIVE) { + command->obj = 0; for (int i = 1; i <= NOBJECTS; i++) { if (HERE(i) && OBJTXT[i] != 0 && game.prop[i] >= 0) - obj = obj * NOBJECTS + i; + command->obj = command->obj * NOBJECTS + i; } - if (obj > NOBJECTS || obj == 0 || DARK(game.loc)) return GO_UNKNOWN; + if (command->obj > NOBJECTS || command->obj == 0 || DARK(game.loc)) return GO_UNKNOWN; } if (DARK(game.loc)) { - SETPRM(1, WD1, WD1X); + SETPRM(1, command->wd1, command->wd1x); RSPEAK(NO_SEE); return GO_CLEAROBJ; } - if (OBJTXT[obj] == 0 || game.prop[obj] < 0) { - RSPEAK(ACTSPK[verb]); + if (OBJTXT[command->obj] == 0 || game.prop[command->obj] < 0) { + RSPEAK(ACTSPK[command->verb]); return GO_CLEAROBJ; } - if (obj == OYSTER && !game.clshnt) { + if (command->obj == OYSTER && !game.clshnt) { game.clshnt = YES(arbitrary_messages[CLUE_QUERY], arbitrary_messages[WAYOUT_CLUE], arbitrary_messages[OK_MAN]); return GO_CLEAROBJ; } - PSPEAK(obj, OBJTXT[obj] + game.prop[obj]); + PSPEAK(command->obj, OBJTXT[command->obj] + game.prop[command->obj]); return GO_CLEAROBJ; } @@ -859,19 +858,19 @@ static int rub(token_t verb, token_t obj) return GO_CLEAROBJ; } -static int say(void) +static int say(struct command_t *command) /* Say. Echo WD2 (or WD1 if no WD2 (SAY WHAT?, etc.).) Magic words override. */ { /* FIXME: ugly use of globals */ - SETPRM(1, WD2, WD2X); - if (WD2 <= 0) - SETPRM(1, WD1, WD1X); - if (WD2 > 0) - WD1 = WD2; - int wd = VOCAB(WD1, -1); + SETPRM(1, command->wd2, command->wd2x); + if (command->wd2 <= 0) + SETPRM(1, command->wd1, command->wd1x); + if (command->wd2 > 0) + command->wd1 = command->wd2; + int wd = VOCAB(command->wd1, -1); /* FIXME: Magic numbers */ if (wd == 62 || wd == 65 || wd == 71 || wd == 2025 || wd == 2034) { - WD2 = 0; + command->wd2 = 0; return GO_LOOKUP; } RSPEAK(OKEY_DOKEY); @@ -885,22 +884,22 @@ static int throw_support(long spk) return GO_MOVE; } -static int throw (FILE *cmdin, long verb, token_t obj) +static int throw (FILE *cmdin, struct command_t *command) /* Throw. Same as discard unless axe. Then same as attack except * ignore bird, and if dwarf is present then one might be killed. * (Only way to do so!) Axe also special for dragon, bear, and * troll. Treasures special for troll. */ { - int spk = ACTSPK[verb]; - if (TOTING(ROD2) && obj == ROD && !TOTING(ROD))obj = ROD2; - if (!TOTING(obj)) { + int spk = ACTSPK[command->verb]; + if (TOTING(ROD2) && command->obj == ROD && !TOTING(ROD))command->obj = ROD2; + if (!TOTING(command->obj)) { RSPEAK(spk); return GO_CLEAROBJ; } - if (obj >= MINTRS && obj <= MAXTRS && AT(TROLL)) { + if (command->obj >= MINTRS && command->obj <= MAXTRS && AT(TROLL)) { spk = TROLL_SATISFIED; /* Snarf a treasure for the troll. */ - DROP(obj, 0); + DROP(command->obj, 0); MOVE(TROLL, 0); MOVE(TROLL + NOBJECTS, 0); DROP(TROLL2, PLAC[TROLL]); @@ -909,13 +908,13 @@ static int throw (FILE *cmdin, long verb, token_t obj) RSPEAK(spk); return GO_CLEAROBJ; } - if (obj == FOOD && HERE(BEAR)) { + if (command->obj == FOOD && HERE(BEAR)) { /* But throwing food is another story. */ - obj = BEAR; - return (feed(verb, obj)); + command->obj = BEAR; + return (feed(command->verb, command->obj)); } - if (obj != AXE) - return (discard(verb, obj, false)); + if (command->obj != AXE) + return (discard(command->verb, command->obj, false)); else { int i = ATDWRF(game.loc); if (i <= 0) { @@ -934,7 +933,8 @@ static int throw (FILE *cmdin, long verb, token_t obj) RSPEAK(AXE_LOST); return GO_CLEAROBJ; } - return (attack(cmdin, verb, 0)); + command->obj = 0; + return (attack(cmdin, command)); } if (randrange(NDWARVES + 1) < game.dflag) { @@ -995,14 +995,14 @@ static int wave(token_t verb, token_t obj) } } -int action(FILE *input, struct command_t command) +int action(FILE *input, struct 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. */ { - token_t spk = ACTSPK[command.verb]; + token_t spk = ACTSPK[command->verb]; - if (command.part == unknown) { + if (command->part == unknown) { /* Analyse an object word. See if the thing is here, whether * we've got a verb yet, and so on. Object must be here * unless verb is "find" or "invent(ory)" (and no new verb @@ -1010,74 +1010,74 @@ int action(FILE *input, struct command_t command) * they are never actually dropped at any location, but might * be here inside the bottle or urn or as a feature of the * location. */ - if (HERE(command.obj)) + if (HERE(command->obj)) /* FALL THROUGH */; - else if (command.obj == GRATE) { + else if (command->obj == GRATE) { if (game.loc == LOC_START || game.loc == LOC_VALLEY || game.loc == LOC_SLIT) - command.obj = DPRSSN; + command->obj = DPRSSN; if (game.loc == LOC_COBBLE || game.loc == LOC_DEBRIS || game.loc == LOC_AWKWARD || game.loc == LOC_BIRD || game.loc == LOC_PITTOP) - command.obj = ENTRNC; - if (command.obj != GRATE) + command->obj = ENTRNC; + if (command->obj != GRATE) return GO_MOVE; - } else if (command.obj == DWARF && ATDWRF(game.loc) > 0) + } else if (command->obj == DWARF && ATDWRF(game.loc) > 0) /* FALL THROUGH */; - else if ((LIQUID() == command.obj && HERE(BOTTLE)) || command.obj == LIQLOC(game.loc)) + else if ((LIQUID() == command->obj && HERE(BOTTLE)) || command->obj == LIQLOC(game.loc)) /* FALL THROUGH */; - else if (command.obj == OIL && HERE(URN) && game.prop[URN] != 0) { - command.obj = URN; + else if (command->obj == OIL && HERE(URN) && game.prop[URN] != 0) { + command->obj = URN; /* FALL THROUGH */; - } else if (command.obj == PLANT && AT(PLANT2) && game.prop[PLANT2] != 0) { - command.obj = PLANT2; + } else if (command->obj == PLANT && AT(PLANT2) && game.prop[PLANT2] != 0) { + command->obj = PLANT2; /* FALL THROUGH */; - } else if (command.obj == KNIFE && game.knfloc == game.loc) { + } else if (command->obj == KNIFE && game.knfloc == game.loc) { game.knfloc = -1; spk = KNIVES_VANISH; RSPEAK(spk); return GO_CLEAROBJ; - } else if (command.obj == ROD && HERE(ROD2)) { - command.obj = ROD2; + } else if (command->obj == ROD && HERE(ROD2)) { + command->obj = ROD2; /* FALL THROUGH */; - } else if ((command.verb == FIND || command.verb == INVENT) && WD2 <= 0) + } else if ((command->verb == FIND || command->verb == INVENT) && command->wd2 <= 0) /* FALL THROUGH */; else { - SETPRM(1, WD1, WD1X); + SETPRM(1, command->wd1, command->wd1x); RSPEAK(NO_SEE); return GO_CLEAROBJ; } - if (WD2 > 0) + if (command->wd2 > 0) return GO_WORD2; - if (command.verb != 0) - command.part = transitive; + if (command->verb != 0) + command->part = transitive; } - switch (command.part) { + switch (command->part) { case intransitive: - if (WD2 > 0 && command.verb != SAY) + if (command->wd2 > 0 && command->verb != SAY) return GO_WORD2; - if (command.verb == SAY)command.obj = WD2; - if (command.obj == 0 || command.obj == INTRANSITIVE) { + if (command->verb == SAY)command->obj = command->wd2; + if (command->obj == 0 || command->obj == INTRANSITIVE) { /* Analyse an intransitive verb (ie, no object given yet). */ - switch (command.verb - 1) { + switch (command->verb - 1) { case 0: /* CARRY */ - return carry(command.verb, INTRANSITIVE); + return carry(command->verb, INTRANSITIVE); case 1: /* DROP */ return GO_UNKNOWN; case 2: /* SAY */ return GO_UNKNOWN; case 3: /* UNLOC */ - return lock(command.verb, INTRANSITIVE); + return lock(command->verb, INTRANSITIVE); case 4: { /* NOTHI */ RSPEAK(OK_MAN); return (GO_CLEAROBJ); } case 5: /* LOCK */ - return lock(command.verb, INTRANSITIVE); + return lock(command->verb, INTRANSITIVE); case 6: /* LIGHT */ - return light(command.verb, INTRANSITIVE); + return light(command->verb, INTRANSITIVE); case 7: /* EXTIN */ - return extinguish(command.verb, INTRANSITIVE); + return extinguish(command->verb, INTRANSITIVE); case 8: /* WAVE */ return GO_UNKNOWN; case 9: /* CALM */ @@ -1087,13 +1087,13 @@ int action(FILE *input, struct command_t command) return GO_CLEAROBJ; } case 11: /* ATTAC */ - return attack(input, command.verb, command.obj); + return attack(input, command); case 12: /* POUR */ - return pour(command.verb, command.obj); + return pour(command->verb, command->obj); case 13: /* EAT */ - return eat(command.verb, INTRANSITIVE); + return eat(command->verb, INTRANSITIVE); case 14: /* DRINK */ - return drink(command.verb, command.obj); + return drink(command->verb, command->obj); case 15: /* RUB */ return GO_UNKNOWN; case 16: /* TOSS */ @@ -1107,7 +1107,7 @@ int action(FILE *input, struct command_t command) case 20: /* FEED */ return GO_UNKNOWN; case 21: /* FILL */ - return fill(command.verb, command.obj); + return fill(command->verb, command->obj); case 22: /* BLAST */ blast(); return GO_CLEAROBJ; @@ -1115,11 +1115,12 @@ int action(FILE *input, struct command_t command) score(scoregame); return GO_CLEAROBJ; case 24: /* FOO */ - return bigwords(WD1); + return bigwords(command->wd1); case 25: /* BRIEF */ return brief(); case 26: /* READ */ - return read(command.verb, INTRANSITIVE); + command->obj = INTRANSITIVE; + return read(command); case 27: /* BREAK */ return GO_UNKNOWN; case 28: /* WAKE */ @@ -1129,7 +1130,7 @@ int action(FILE *input, struct command_t command) case 30: /* RESU */ return resume(); case 31: /* FLY */ - return fly(command.verb, INTRANSITIVE); + return fly(command->verb, INTRANSITIVE); case 32: /* LISTE */ return listen(); case 33: /* ZZZZ */ @@ -1140,27 +1141,27 @@ int action(FILE *input, struct command_t command) /* FALLTHRU */ case transitive: /* Analyse a transitive verb. */ - switch (command.verb - 1) { + switch (command->verb - 1) { case 0: /* CARRY */ - return carry(command.verb, command.obj); + return carry(command->verb, command->obj); case 1: /* DROP */ - return discard(command.verb, command.obj, false); + return discard(command->verb, command->obj, false); case 2: /* SAY */ - return say(); + return say(command); case 3: /* UNLOC */ - return lock(command.verb, command.obj); + return lock(command->verb, command->obj); case 4: { /* NOTHI */ RSPEAK(OK_MAN); return (GO_CLEAROBJ); } case 5: /* LOCK */ - return lock(command.verb, command.obj); + return lock(command->verb, command->obj); case 6: /* LIGHT */ - return light(command.verb, command.obj); + return light(command->verb, command->obj); case 7: /* EXTI */ - return extinguish(command.verb, command.obj); + return extinguish(command->verb, command->obj); case 8: /* WAVE */ - return wave(command.verb, command.obj); + return wave(command->verb, command->obj); case 9: { /* CALM */ RSPEAK(spk); return GO_CLEAROBJ; @@ -1170,29 +1171,29 @@ int action(FILE *input, struct command_t command) return GO_CLEAROBJ; } case 11: /* ATTAC */ - return attack(input, command.verb, command.obj); + return attack(input, command); case 12: /* POUR */ - return pour(command.verb, command.obj); + return pour(command->verb, command->obj); case 13: /* EAT */ - return eat(command.verb, command.obj); + return eat(command->verb, command->obj); case 14: /* DRINK */ - return drink(command.verb, command.obj); + return drink(command->verb, command->obj); case 15: /* RUB */ - return rub(command.verb, command.obj); + return rub(command->verb, command->obj); case 16: /* TOSS */ - return throw (input, command.verb, command.obj); + return throw(input, command); case 17: { /* QUIT */ RSPEAK(spk); return GO_CLEAROBJ; } case 18: /* FIND */ - return find(command.verb, command.obj); + return find(command->verb, command->obj); case 19: /* INVEN */ - return find(command.verb, command.obj); + return find(command->verb, command->obj); case 20: /* FEED */ - return feed(command.verb, command.obj); + return feed(command->verb, command->obj); case 21: /* FILL */ - return fill(command.verb, command.obj); + return fill(command->verb, command->obj); case 22: /* BLAST */ blast(); return GO_CLEAROBJ; @@ -1209,11 +1210,11 @@ int action(FILE *input, struct command_t command) return GO_CLEAROBJ; } case 26: /* READ */ - return read(command.verb, command.obj); + return read(command); case 27: /* BREAK */ - return vbreak(command.verb, command.obj); + return vbreak(command->verb, command->obj); case 28: /* WAKE */ - return wake(command.verb, command.obj); + return wake(command->verb, command->obj); case 29: { /* SUSP */ RSPEAK(spk); return GO_CLEAROBJ; @@ -1223,7 +1224,7 @@ int action(FILE *input, struct command_t command) return GO_CLEAROBJ; } case 31: /* FLY */ - return fly(command.verb, command.obj); + return fly(command->verb, command->obj); case 32: { /* LISTE */ RSPEAK(spk); return GO_CLEAROBJ; @@ -1234,7 +1235,7 @@ int action(FILE *input, struct command_t command) BUG(TRANSITIVE_ACTION_VERB_EXCEEDS_GOTO_LIST); case unknown: /* Unknown verb, couldn't deduce object - might need hint */ - SETPRM(1, WD1, WD1X); + SETPRM(1, command->wd1, command->wd1x); RSPEAK(WHAT_DO); return GO_CHECKHINT; default: diff --git a/advent.h b/advent.h index af9d123..f7551d0 100644 --- a/advent.h +++ b/advent.h @@ -185,10 +185,12 @@ struct command_t { enum speechpart part; vocab_t verb; vocab_t obj; + token_t wd1, wd1x; + token_t wd2, wd2x; }; void initialise(void); -int action(FILE *input, struct command_t command); +int action(FILE *input, struct command_t *command); /* Phase codes for action returns. * These were at one time FORTRAN line numbers. diff --git a/main.c b/main.c index 15e7230..79572bb 100644 --- a/main.c +++ b/main.c @@ -41,7 +41,6 @@ long AMBER, AXE, BACK, BATTERY, BEAR, BIRD, BLOOD, RUBY, RUG, SAPPH, SAY, SIGN, SNAKE, STEPS, STREAM, THROW, TRIDENT, TROLL, TROLL2, URN, VASE, VEND, VOLCANO, WATER; -token_t WD1, WD1X, WD2, WD2X; FILE *logfp = NULL, *rfp = NULL; bool oldstyle = false; @@ -1015,7 +1014,7 @@ L2600: game.knfloc = 0; /* This is where we get a new command from the user */ - if (!GETIN(cmdin, &WD1, &WD1X, &WD2, &WD2X)) + if (!GETIN(cmdin, &command.wd1, &command.wd1x, &command.wd2, &command.wd2x)) return false; /* Every input, check "game.foobar" flag. If zero, nothing's @@ -1036,7 +1035,7 @@ L2607: } } - if (command.verb == SAY && WD2 > 0) + if (command.verb == SAY && command.wd2 > 0) command.verb = 0; if (command.verb == SAY) { command.part = transitive; @@ -1048,8 +1047,8 @@ L2607: } else lampcheck(); - V1 = VOCAB(WD1, -1); - V2 = VOCAB(WD2, -1); + V1 = VOCAB(command.wd1, -1); + V2 = VOCAB(command.wd2, -1); if (V1 == ENTER && (V2 == STREAM || V2 == 1000 + WATER)) { if (LIQLOC(game.loc) == WATER) { RSPEAK(FEET_WET); @@ -1058,37 +1057,37 @@ L2607: } goto L2012; } - if (V1 == ENTER && WD2 > 0) { - WD1 = WD2; - WD1X = WD2X; - wordclear(&WD2); + if (V1 == ENTER && command.wd2 > 0) { + command.wd1 = command.wd2; + command.wd1x = command.wd2x; + wordclear(&command.wd2); } else { /* FIXME: Magic numbers */ if (!((V1 != 1000 + WATER && V1 != 1000 + OIL) || (V2 != 1000 + PLANT && V2 != 1000 + DOOR))) { if (AT(V2 - 1000)) - WD2 = MAKEWD(WORD_POUR); + command.wd2 = MAKEWD(WORD_POUR); } if (V1 == 1000 + CAGE && V2 == 1000 + BIRD && HERE(CAGE) && HERE(BIRD)) - WD1 = MAKEWD(WORD_CATCH); + command.wd1 = MAKEWD(WORD_CATCH); } L2620: - if (wordeq(WD1, MAKEWD(WORD_WEST))) { + if (wordeq(command.wd1, MAKEWD(WORD_WEST))) { ++game.iwest; if (game.iwest == 10) RSPEAK(W_IS_WEST); } - if (wordeq(WD1, MAKEWD(WORD_GO)) && !wordempty(WD2)) { + if (wordeq(command.wd1, MAKEWD(WORD_GO)) && !wordempty(command.wd2)) { if (++igo == 10) RSPEAK(GO_UNNEEDED); } Lookup: - defn = VOCAB(WD1, -1); + defn = VOCAB(command.wd1, -1); if (defn == -1) { /* Gee, I don't understand. */ if (fallback_handler(rawbuf)) continue; - SETPRM(1, WD1, WD1X); + SETPRM(1, command.wd1, command.wd1x); RSPEAK(DONT_KNOW); goto L2600; } @@ -1115,7 +1114,7 @@ Lookup: } Laction: - switch (action(cmdin, command)) { + switch (action(cmdin, &command)) { case GO_TERMINATE: return true; case GO_MOVE: @@ -1133,14 +1132,14 @@ Laction: goto Lookup; case GO_WORD2: /* Get second word for analysis. */ - WD1 = WD2; - WD1X = WD2X; - wordclear(&WD2); + command.wd1 = command.wd2; + command.wd1x = command.wd2x; + wordclear(&command.wd2); goto L2620; case GO_UNKNOWN: /* Random intransitive verbs come here. Clear obj just in case * (see attack()). */ - SETPRM(1, WD1, WD1X); + SETPRM(1, command.wd1, command.wd1x); RSPEAK(DO_WHAT); command.obj = 0; goto L2600; -- 2.31.1