Proof of cobcept for state defines.
authorEric S. Raymond <esr@thyrsus.com>
Fri, 23 Jun 2017 18:07:44 +0000 (14:07 -0400)
committerEric S. Raymond <esr@thyrsus.com>
Fri, 23 Jun 2017 18:07:44 +0000 (14:07 -0400)
It is now possible in the YAML to declare defines for all state values
associated with an object.  This are visible in the C code and can be used
to replace magic numbers.

actions.c
adventure.yaml
main.c
newdungeon.py

index b6cfc33d0210328c7a2f7ed81c9fc180dfa229d6..0f7ece8e6c17ed69a3deeb4196204e65ac099ba1 100644 (file)
--- a/actions.c
+++ b/actions.c
@@ -242,10 +242,11 @@ static int carry(token_t verb, token_t obj)
     }
     if (obj == WATER || obj == OIL) {
         if (!HERE(BOTTLE) || LIQUID() != obj) {
-            if (TOTING(BOTTLE) && game.prop[BOTTLE] == 1)
+            if (TOTING(BOTTLE) && game.prop[BOTTLE] == EMPTY_BOTTLE)
                 return (fill(verb, BOTTLE));
             else {
-                if (game.prop[BOTTLE] != 1)spk = BOTTLE_FULL;
+                if (game.prop[BOTTLE] != EMPTY_BOTTLE)
+                   spk = BOTTLE_FULL;
                 if (!TOTING(BOTTLE))spk = NO_CONTAINER;
                 rspeak(spk);
                 return GO_CLEAROBJ;
@@ -356,7 +357,7 @@ static int discard(token_t verb, token_t obj, bool just_do_it)
         } else if (obj == COINS && HERE(VEND)) {
             DESTROY(COINS);
             DROP(BATTERY, game.loc);
-            pspeak(BATTERY, 0);
+            pspeak(BATTERY, FRESH_BATTERIES);
             return GO_CLEAROBJ;
         } else if (obj == BIRD && AT(DRAGON) && game.prop[DRAGON] == 0) {
             rspeak(BIRD_BURNT);
@@ -402,7 +403,7 @@ static int drink(token_t verb, token_t obj)
     if (obj != BLOOD) {
         if (obj != 0 && obj != WATER)spk = RIDICULOUS_ATTEMPT;
         if (spk != RIDICULOUS_ATTEMPT && LIQUID() == WATER && HERE(BOTTLE)) {
-            game.prop[BOTTLE] = 1;
+            game.prop[BOTTLE] = EMPTY_BOTTLE;
             game.place[WATER] = LOC_NOWHERE;
             spk = BOTTLE_EMPTY;
         }
@@ -534,7 +535,7 @@ int fill(token_t verb, token_t obj)
             return GO_CLEAROBJ;
         }
         game.place[k] = LOC_NOWHERE;
-        game.prop[BOTTLE] = 1;
+        game.prop[BOTTLE] = EMPTY_BOTTLE;
         if (k == OIL)game.prop[URN] = 1;
         spk = WATER_URN + game.prop[URN];
         rspeak(spk);
@@ -552,6 +553,7 @@ int fill(token_t verb, token_t obj)
     if (LIQUID() != 0)
         spk = BOTTLE_FULL;
     if (spk == BOTTLED_WATER) {
+       /* FIXME: Arithmetic on property values */
         game.prop[BOTTLE] = MOD(conditions[game.loc], 4) / 2 * 2;
         k = LIQUID();
         if (TOTING(BOTTLE))
@@ -756,7 +758,7 @@ static int pour(token_t verb, token_t obj)
     }
     if (HERE(URN) && game.prop[URN] == 0)
         return fill(verb, URN);
-    game.prop[BOTTLE] = 1;
+    game.prop[BOTTLE] = EMPTY_BOTTLE;
     game.place[obj] = LOC_NOWHERE;
     spk = GROUND_WET;
     if (!(AT(PLANT) || AT(DOOR))) {
index 24eb206bab2d3260f319a15d9da40d29561e5d97..f5df5c00f0c754cf5cf30ac2dd41b41987505b18 100644 (file)
 #
 # objects: Each item contains a description for use in the inventory command
 #    and one or more messages describing the object in different states.
-#    If the inventory desription begins with "*" the object is dungeon
-#    furniture that cannot be taken or carried.
+#    If a state message is a tuple then the first element is made the name
+#    of a #define viible to the code for the associayed state, numbered
+#    from zero upwards. If the inventory desription begins with "*" the
+#    object is dungeon furniture that cannot be taken or carried.
 #
 # obituaries: Death messages and reincarnation queries.  Order is
 #    significant, they're used in succession as the player racks up
@@ -1343,7 +1345,7 @@ arbitrary_messages:  !!omap
 - PIRATE_SPOTTED: 'There are faint rustling noises from the darkness behind you.  As you\nturn toward them, the beam of your lamp falls across a bearded pirate.\nHe is carrying a large chest.  "Shiver me timbers!" he cries, "I''ve\nbeen spotted!  I''d best hie meself off to the maze to hide me chest!"\nWith that, he vanishes into the gloom.'
 - GET_BATTERIES: 'Your lamp is getting dim.  You''d best go back for those batteries.'
 - REPLACE_BATTERIES: 'Your lamp is getting dim.  I''m taking the liberty of replacing the\nbatteries.'
-- MISSING_BATTERYIES: 'Your lamp is getting dim, and you''re out of spare batteries.  You''d\nbest start wrapping this up.'
+- MISSING_BATTERIES: 'Your lamp is getting dim, and you''re out of spare batteries.  You''d\nbest start wrapping this up.'
 - REMOVE_MESSAGE: 'You sift your fingers through the dust, but succeed only in\nobliterating the cryptic message.'
 - OGRE_QUERY: 'Do you need help dealing with the ogre?'
 - CLUE_QUERY: 'Hmmm, this looks like a clue, which means it''ll cost you 10 points to\nread it.  Should I go ahead and read it anyway?'
@@ -1574,9 +1576,9 @@ object_descriptions: !!omap
 - OBJ_20:
     inventory: 'Small bottle'
     longs:
-    - 'There is a bottle of water here.'
-    - 'There is an empty bottle here.'
-    - 'There is a bottle of oil here.'
+    - [WATER_BOTTLE, 'There is a bottle of water here.']
+    - [EMPTY_BOTTLE, 'There is an empty bottle here.']
+    - [OIL_BOTTLE, 'There is a bottle of oil here.']
 - OBJ_21:
     inventory: 'Water in the bottle'
     longs: !!null
@@ -1676,8 +1678,8 @@ object_descriptions: !!omap
 - OBJ_39:
     inventory: 'Batteries'
     longs:
-    - 'There are fresh batteries here.'
-    - 'Some worn-out batteries have been discarded nearby.'
+    - [FRESH_BATTERIES, 'There are fresh batteries here.']
+    - [DEAD_BATTERIES, 'Some worn-out batteries have been discarded nearby.']
 - OBJ_40:
     inventory: '*carpet and/or moss and/or curtains'
     longs: !!null
@@ -1764,10 +1766,10 @@ object_descriptions: !!omap
 - OBJ_58:
     inventory: 'Ming vase'
     longs:
-    - 'There is a delicate, precious, ming vase here!'
-    - 'The vase is now resting, delicately, on a velvet pillow.'
-    - 'The floor is littered with worthless shards of pottery.'
-    - 'The ming vase drops with a delicate crash.'
+    - [VASE_WHOLE, 'There is a delicate, precious, ming vase here!']
+    - [VASE_RESTING, 'The vase is now resting, delicately, on a velvet pillow.']
+    - [VASE_BROKEN, 'The floor is littered with worthless shards of pottery.']
+    - [VASE_DROPS, 'The ming vase drops with a delicate crash.']
 - OBJ_59:
     inventory: 'Egg-sized emerald'
     longs:
diff --git a/main.c b/main.c
index 90665c7b35a888b4bc0db37bf20ba052fbe56d68..3c4c034bfb94d2655812ffeeea4c56564525122a 100644 (file)
--- a/main.c
+++ b/main.c
@@ -799,7 +799,7 @@ static bool closecheck(void)
          *  objects he might be carrying (lest he have 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, 1);
+        game.prop[BOTTLE] = PUT(BOTTLE, LOC_NE, EMPTY_BOTTLE);
         game.prop[PLANT] = PUT(PLANT, LOC_NE, 0);
         game.prop[OYSTER] = PUT(OYSTER, LOC_NE, 0);
         OBJTXT[OYSTER] = 3;
@@ -848,9 +848,9 @@ static void lampcheck(void)
      *  here, in which case we replace the batteries and continue.
      *  Second is for other cases of lamp dying.  Eve after it goes
      *  out, he can explore outside for a while if desired. */
-    if (game.limit <= WARNTIME && HERE(BATTERY) && game.prop[BATTERY] == 0 && HERE(LAMP)) {
+    if (game.limit <= WARNTIME && HERE(BATTERY) && game.prop[BATTERY] == FRESH_BATTERIES && HERE(LAMP)) {
         rspeak(REPLACE_BATTERIES);
-        game.prop[BATTERY] = 1;
+        game.prop[BATTERY] = DEAD_BATTERIES;
         if (TOTING(BATTERY))
             DROP(BATTERY, game.loc);
         game.limit += BATTERYLIFE;
@@ -865,7 +865,8 @@ static void lampcheck(void)
             game.lmwarn = true;
             int spk = GET_BATTERIES;
             if (game.place[BATTERY] == LOC_NOWHERE)spk = LAMP_DIM;
-            if (game.prop[BATTERY] == 1)spk = MISSING_BATTERYIES;
+            if (game.prop[BATTERY] == DEAD_BATTERIES)
+               spk = MISSING_BATTERIES;
             rspeak(spk);
         }
     }
index 873990c46d10996c74c5665929f860333caf1de0..a981a1db4e0f2f23caa7cf866bee61f622afad70 100755 (executable)
@@ -8,6 +8,8 @@ yaml_name = "adventure.yaml"
 h_name = "newdb.h"
 c_name = "newdb.c"
 
+statedefines = ""
+
 h_template = """/* Generated from adventure.yaml - do not hand-hack! */
 #ifndef NEWDB_H
 #define NEWDB_H
@@ -65,7 +67,6 @@ extern turn_threshold_t turn_thresholds[];
 extern obituary_t obituaries[];
 extern hint_t hints[];
 extern long conditions[];
-
 extern const size_t CLSSES;
 extern const int maximum_deaths;
 extern const int turn_threshold_count;
@@ -83,6 +84,9 @@ enum object_descriptions_refs {{
 {}
 }};
 
+/* State definitions */
+
+{}
 #endif /* end NEWDB_H */
 """
 
@@ -223,9 +227,21 @@ def get_object_descriptions(obj):
         if item[1]["longs"] == None:
             longs_str = " " * 12 + "NULL,"
         else:
+            labels = []
             for l_msg in item[1]["longs"]:
+                if not isinstance(l_msg, str):
+                    labels.append(l_msg)
+                    l_msg = l_msg[1]
                 longs_str += " " * 12 + make_c_string(l_msg) + ",\n"
             longs_str = longs_str[:-1] # trim trailing newline
+            if labels:
+                global statedefines
+                statedefines += "/* States for %s */\n" % item[0]
+                for (i, (label, message)) in enumerate(labels):
+                    if len(message) >= 45:
+                        message = message[:45] + "..."
+                    statedefines += "#define %s\t%d /* %s */\n" % (label, i, message)
+                statedefines += "\n"
         obj_str += template.format(i_msg, longs_str)
     obj_str = obj_str[:-1] # trim trailing newline
     return obj_str
@@ -290,13 +306,6 @@ if __name__ == "__main__":
     with open(yaml_name, "r") as f:
         db = yaml.load(f)
 
-    h = h_template.format(
-        len(db["hints"]),
-        get_refs(db["arbitrary_messages"]),
-        get_refs(db["locations"]),
-        get_refs(db["object_descriptions"]),
-    )
-
     c = c_template.format(
         h_name,
         get_arbitrary_messages(db["arbitrary_messages"]),
@@ -312,6 +321,14 @@ if __name__ == "__main__":
         len(db["turn_thresholds"]),
     )
 
+    h = h_template.format(
+        len(db["hints"]),
+        get_refs(db["arbitrary_messages"]),
+        get_refs(db["locations"]),
+        get_refs(db["object_descriptions"]),
+        statedefines,
+    )
+
     with open(h_name, "w") as hf:
         hf.write(h)