More goto elimination.
[open-adventure.git] / actions.c
index 356b2b9c7d1f524a2e57eee8fb81ac71e1466fc4..ebb5f4fc46782854f479656616a32967ada5e1f8 100644 (file)
--- a/actions.c
+++ b/actions.c
@@ -3,8 +3,6 @@
 #include "advent.h"
 #include "database.h"
 
-#define VRSION 25      /* bump on save format change */
-
 /*
  * Action handlers.  Eventually we'll do lookup through a method table
  * that calls these.  Absolutely nothing like the original FORTRAN.
@@ -216,7 +214,7 @@ static int carry(long obj)
     if (game.fixed[obj] != 0)
        return(2011);
     if (obj == WATER || obj == OIL) {
-       if (!HERE(BOTTLE) || LIQ(0) != obj) {
+       if (!HERE(BOTTLE) || LIQUID() != obj) {
            if (TOTING(BOTTLE) && game.prop[BOTTLE] == 1)
                return(fill(BOTTLE));
            if (game.prop[BOTTLE] != 1)SPK=105;
@@ -243,8 +241,8 @@ static int carry(long obj)
     if ((obj==BIRD || obj==CAGE) && (game.prop[BIRD]==1 || -1-game.prop[BIRD]==1))
        CARRY(BIRD+CAGE-obj,game.loc);
     CARRY(obj,game.loc);
-    if (obj == BOTTLE && LIQ(0) != 0)
-       game.place[LIQ(0)] = -1;
+    if (obj == BOTTLE && LIQUID() != 0)
+       game.place[LIQUID()] = -1;
     if (!GSTONE(obj) || game.prop[obj] == 0)
        return(2009);
     game.prop[obj]=0;
@@ -336,7 +334,7 @@ static int discard(long obj, bool just_do_it)
             if (game.prop[VASE] != 0)game.fixed[VASE]= -1;
         }
     }
-    K=LIQ(0);
+    K=LIQUID();
     if (K == obj)obj=BOTTLE;
     if (obj == BOTTLE && K != 0)game.place[K]=0;
     if (obj == CAGE && game.prop[BIRD] == 1)DROP(BIRD,game.loc);
@@ -351,11 +349,11 @@ static int drink(token_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. */
 {
-    if (obj == 0 && LIQLOC(game.loc) != WATER && (LIQ(0) != WATER || !HERE(BOTTLE)))
+    if (obj == 0 && LIQLOC(game.loc) != WATER && (LIQUID() != WATER || !HERE(BOTTLE)))
        return(8000);
     if (obj != BLOOD) {
        if (obj != 0 && obj != WATER)SPK=110;
-       if (SPK == 110 || LIQ(0) != WATER || !HERE(BOTTLE)) return(2011);
+       if (SPK == 110 || LIQUID() != WATER || !HERE(BOTTLE)) return(2011);
        game.prop[BOTTLE]=1;
        game.place[WATER]=0;
        SPK=74;
@@ -409,7 +407,7 @@ static int extinguish(int obj)
     if (obj == LAMP) {
        game.prop[LAMP]=0;
        RSPEAK(40);
-       if (DARK(0))
+       if (DARK(game.loc))
            RSPEAK(16);
        return(2012);
     }
@@ -490,7 +488,7 @@ int fill(long obj)
        SPK=213;
        if (game.prop[URN] != 0) return(2011);
        SPK=144;
-       k=LIQ(0);
+       k=LIQUID();
        if (k == 0 || !HERE(BOTTLE)) return(2011);
        game.place[k]=0;
        game.prop[BOTTLE]=1;
@@ -508,12 +506,12 @@ int fill(long obj)
        SPK=106;
     if (HERE(URN) && game.prop[URN] != 0)
        SPK=214;
-    if (LIQ(0) != 0)
+    if (LIQUID() != 0)
        SPK=105;
     if (SPK != 107)
        return(2011);
     game.prop[BOTTLE]=MOD(COND[game.loc],4)/2*2;
-    k=LIQ(0);
+    k=LIQUID();
     if (TOTING(BOTTLE))
        game.place[k]= -1;
     if (k == OIL)
@@ -525,7 +523,7 @@ static int find(token_t obj)
 /* Find.  Might be carrying it, or it might be here.  Else give caveat. */
 {
     if (AT(obj) ||
-       (LIQ(0) == obj && AT(BOTTLE)) ||
+       (LIQUID() == obj && AT(BOTTLE)) ||
        obj == LIQLOC(game.loc) ||
        (obj == DWARF && ATDWRF(game.loc) > 0))
        SPK=94;
@@ -669,7 +667,7 @@ static int pour(token_t obj)
 /*  Pour.  If no object, or object is bottle, assume contents of bottle.
  *  special tests for pouring water or oil on plant or rusty door. */
 {
-    if (obj == BOTTLE || obj == 0)obj=LIQ(0);
+    if (obj == BOTTLE || obj == 0)obj=LIQUID();
     if (obj == 0) return(8000);
     if (!TOTING(obj)) return(2011);
     SPK=78;
@@ -715,10 +713,10 @@ static int read(FILE *input, token_t obj)
            if (HERE(i) && OBJTXT[i] != 0 && game.prop[i] >= 0)
                obj = obj * NOBJECTS + i;
        }
-       if (obj > NOBJECTS || obj == 0 || DARK(0)) return(8000);
+       if (obj > NOBJECTS || obj == 0 || DARK(game.loc)) return(8000);
     }
        
-    if (DARK(0)) {
+    if (DARK(game.loc)) {
        SETPRM(1,WD1,WD1X);
        RSPEAK(256);
        return(2012);
@@ -754,7 +752,7 @@ static int rub(token_t obj)
     DSTROY(URN);
     DROP(AMBER,game.loc);
     game.prop[AMBER]=1;
-    game.tally=game.tally-1;
+    --game.tally;
     DROP(CAVITY,game.loc);
     SPK=216;
     return(2011);
@@ -776,88 +774,6 @@ static int say(void)
 
 }
 
-static int suspendresume(FILE *input, bool resume)
-/* Suspend and resume */
-{
-    int kk;
-    long i;
-    if (!resume) {
-       /*  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). */
-       SPK=201;
-       RSPEAK(260);
-       if (!YES(input,200,54,54)) return(2012);
-       game.saved=game.saved+5;
-       kk= -1;
-    }
-    else
-    {
-       /*  Resume.  Read a suspended game back from a file. */
-       kk=1;
-       if (game.loc != 1 || game.abbrev[1] != 1) {
-           RSPEAK(268);
-           if (!YES(input,200,54,54)) return(2012);
-       }
-    }
-
-    /*  Suspend vs resume cases are distinguished by the value of kk
-     *  (-1 for suspend, +1 for resume). */
-
-    /* 
-     * FIXME: This is way more complicated than it needs to be in C.
-     * What we ought to do is define a save-block structure that
-     * includes a game state block and then use a single fread/fwrite
-     * for I/O. All the SAV* functions can be scrapped.
-     */
-
-    DATIME(&i,&K);
-    K=i+650*K;
-    SAVWRD(kk,K);
-    K=VRSION;
-    SAVWRD(0,K);
-    if (K != VRSION) {
-       SETPRM(1,K/10,MOD(K,10));
-       SETPRM(3,VRSION/10,MOD(VRSION,10));
-       RSPEAK(269);
-       return(2000);
-    }
-    /* Herewith are all the variables whose values can change during a game,
-     * omitting a few (such as I, J) whose values between turns are
-     * irrelevant and some whose values when a game is
-     * suspended or resumed are guaranteed to match.  If unsure whether a value
-     * needs to be saved, include it.  Overkill can't hurt.  Pad the last savwds
-     * with junk variables to bring it up to 7 values. */
-    SAVWDS(game.abbnum,game.blklin,game.bonus,game.clock1,game.clock2,game.closed,game.closng);
-    SAVWDS(game.detail,game.dflag,game.dkill,game.dtotal,game.foobar,game.holdng,game.iwest);
-    SAVWDS(game.knfloc,game.limit,K,game.lmwarn,game.loc,game.newloc,game.numdie);
-    SAVWDS(K,game.oldlc2,game.oldloc,game.oldobj,game.panic,game.saved,game.setup);
-    SAVWDS(SPK,game.tally,game.thresh,game.trndex,game.trnluz,game.turns,OBJTXT[OYSTER]);
-    SAVWDS(K,WD1,WD1X,WD2,game.wzdark,game.zzword,OBJSND[BIRD]);
-    SAVWDS(OBJTXT[SIGN],game.clshnt,game.novice,K,K,K,K);
-    SAVARR(game.abbrev,LOCSIZ);
-    SAVARR(game.atloc,LOCSIZ);
-    SAVARR(game.dloc,NDWARVES);
-    SAVARR(game.dseen,NDWARVES);
-    SAVARR(game.fixed,NOBJECTS);
-    SAVARR(game.hinted,HNTSIZ);
-    SAVARR(game.hintlc,HNTSIZ);
-    SAVARR(game.link,NOBJECTS*2);
-    SAVARR(game.odloc,NDWARVES);
-    SAVARR(game.place,NOBJECTS);
-    SAVARR(game.prop,NOBJECTS);
-    SAVWRD(kk,K);
-    if (K != 0) {
-       RSPEAK(270);
-       exit(0);
-    }
-    K=NUL;
-    game.zzword=RNDVOC(3,game.zzword);
-    if (kk > 0) return(8);
-    RSPEAK(266);
-    exit(0);
-}
-
 static int throw_support(long spk)
 {
     RSPEAK(spk);
@@ -926,7 +842,7 @@ static int throw(FILE *cmdin, long verb, long obj)
     game.dseen[i]=false;
     game.dloc[i]=0;
     SPK=47;
-    game.dkill=game.dkill+1;
+    ++game.dkill;
     if (game.dkill == 1)SPK=149;
 
     return throw_support(SPK);
@@ -959,7 +875,7 @@ static int wave(token_t obj)
     if (SPK == 206 && game.loc == game.place[STEPS] && game.prop[JADE] < 0) {
        DROP(JADE,game.loc);
        game.prop[JADE]=0;
-       game.tally=game.tally-1;
+       --game.tally;
        SPK=208;
        return(2011);
     } else {
@@ -972,17 +888,67 @@ static int wave(token_t obj)
     }
 }
 
-/* We're called with a number that says what label the caller wanted
- * to "goto", and we return a similar label number for the caller to
- * "goto".
- */
-
 int action(FILE *input, enum speechpart part, long verb, long obj)
 /*  Analyse a verb.  Remember what it was, go back for object if second word
  *  unless verb is "say", which snarfs arbitrary second word.
  */
 {
     int kk;
+
+    if (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
+        *  yet to be analysed).  Water and oil are also funny, since
+        *  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(obj))
+           /* FALL THROUGH */;
+       else if (obj == GRATE) {
+           if (game.loc == 1 || game.loc == 4 || game.loc == 7)
+               obj=DPRSSN;
+           if (game.loc > 9 && game.loc < 15)
+               obj=ENTRNC;
+           if (obj != GRATE)
+               return(8);
+       }
+       else if (obj == DWARF && ATDWRF(game.loc) > 0)
+           /* FALL THROUGH */;
+       else if ((LIQUID() == obj && HERE(BOTTLE)) || obj == LIQLOC(game.loc))
+           /* FALL THROUGH */;
+       else if (obj == OIL && HERE(URN) && game.prop[URN] != 0) {
+           obj=URN;
+           /* FALL THROUGH */;
+       }
+       else if (obj == PLANT && AT(PLANT2) && game.prop[PLANT2] != 0) {
+           obj=PLANT2;
+           /* FALL THROUGH */;
+       }
+       else if (obj == KNIFE && game.knfloc == game.loc) {
+           game.knfloc= -1;
+           SPK=116;
+           return(2011);
+       }
+       else if (obj == ROD && HERE(ROD2)) {
+           obj=ROD2;
+           /* FALL THROUGH */;
+       }
+       else if ((verb == FIND || verb == INVENT) && WD2 <= 0)
+           /* FALL THROUGH */;
+       else {
+           SETPRM(1,WD1,WD1X);
+           RSPEAK(256);
+           return(2012);
+       }
+
+       if (WD2 > 0)
+           return(2800);
+       if (verb != 0)
+           part = transitive;
+    }
+
     switch(part)
     {
        case intransitive:
@@ -1021,8 +987,8 @@ int action(FILE *input, enum speechpart part, long verb, long obj)
                    case 26: /* READ  */ return read(input, INTRANSITIVE);   
                    case 27: /* BREAK */ return(8000); 
                    case 28: /* WAKE  */ return(8000); 
-                   case 29: /* SUSP  */ return suspendresume(input, false);   
-                   case 30: /* RESU  */ return suspendresume(input, true);   
+                   case 29: /* SUSP  */ return saveresume(input, false);   
+                   case 30: /* RESU  */ return saveresume(input, true);   
                    case 31: /* FLY   */ return fly(INTRANSITIVE);   
                    case 32: /* LISTE */ return listen();   
                    case 33: /* ZZZZ  */ return reservoir();   
@@ -1031,7 +997,6 @@ int action(FILE *input, enum speechpart part, long verb, long obj)
            }
            /* FALLTHRU */
        case transitive:
-       L4090:
            /*  Analyse a transitive verb. */
            switch (verb-1) {
                case  0: /* CARRY */ return carry(obj);    
@@ -1071,62 +1036,11 @@ int action(FILE *input, enum speechpart part, long verb, long obj)
            }
            BUG(24);
        case 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
-            *  yet to be analysed).  Water and oil are also funny, since
-            *  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(obj))
-               goto L5100;
-       L5010:
-           if (WD2 > 0)
-               return(2800);
-           if (verb != 0)
-               goto L4090;
+           /* Unknown verb, couldn't deduce object - might need hint */
            SETPRM(1,WD1,WD1X);
            RSPEAK(255);
            return(2600);
-
-       L5100:
-           if (obj == GRATE) {
-               if (game.loc == 1 || game.loc == 4 || game.loc == 7)
-                   obj=DPRSSN;
-               if (game.loc > 9 && game.loc < 15)
-                   obj=ENTRNC;
-               if (obj != GRATE)
-                   return(8);
-           }
-
-           if (obj == DWARF && ATDWRF(game.loc) > 0)
-               goto L5010;
-           if ((LIQ(0) == obj && HERE(BOTTLE)) || obj == LIQLOC(game.loc))
-               goto L5010;
-           if (obj == OIL && HERE(URN) && game.prop[URN] != 0) {
-               obj=URN;
-               goto L5010;
-           }
-           if (obj == PLANT && AT(PLANT2) && game.prop[PLANT2] != 0) {
-               obj=PLANT2;
-               goto L5010;
-           }
-           if (obj == KNIFE && game.knfloc == game.loc) {
-               game.knfloc= -1;
-               SPK=116;
-               return(2011);
-           }
-           if (obj == ROD && HERE(ROD2)) {
-               obj=ROD2;
-               goto L5010;
-           }
-           if ((verb == FIND || verb == INVENT) && WD2 <= 0)
-               goto L5010;
-
-           SETPRM(1,WD1,WD1X);
-           RSPEAK(256);
-           return(2012);
-       default:
+    default:
            BUG(99);
     }
 }