1 /* NetHack 3.7	obj.h	$NHDT-Date: 1611097668 2021/01/19 23:07:48 $  $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.85 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /*-Copyright (c) Michael Allison, 2006. */
4 /* NetHack may be freely redistributed.  See license for details. */
5 
6 #ifndef OBJ_H
7 #define OBJ_H
8 
9 /* #define obj obj_nh */ /* uncomment for SCO UNIX, which has a conflicting
10                           * typedef for "obj" in <sys/types.h> */
11 
12 union vptrs {
13     struct obj *v_nexthere;   /* floor location lists */
14     struct obj *v_ocontainer; /* point back to container */
15     struct monst *v_ocarry;   /* point back to carrying monst */
16 };
17 
18 /****
19  ***    oextra -- collection of all object extensions
20  **     (see the note at the bottom of this file before adding oextra fields)
21  */
22 struct oextra {
23     char *oname;          /* ptr to name of object */
24     struct monst *omonst; /* ptr to attached monst struct */
25     char *omailcmd;       /* response_cmd for mail delivery */
26     unsigned omid;        /* for corpse; m_id of corpse's ghost */
27 };
28 
29 struct obj {
30     struct obj *nobj;
31     union vptrs v;
32 #define nexthere v.v_nexthere
33 #define ocontainer v.v_ocontainer
34 #define ocarry v.v_ocarry
35 
36     struct obj *cobj; /* contents list for containers */
37     unsigned o_id;
38     xchar ox, oy;
39     short otyp; /* object class number */
40     unsigned owt;
41     long quan; /* number of items */
42 
43 #define SPE_LIM 99 /* abs(obj->spe) <= 99, cap for enchanted and charged
44                     * objects (and others; named fruit index excepted) */
45     schar spe; /* quality of weapon, weptool, armor, or some rings (+ or -);
46                 * number of charges for wand or charged tool ( >= -1 );
47                 * number of candles attached to candelabrum (0..7);
48                 * magic lamp (1 iff djinni inside => lamp is lightable);
49                 * oil lamp, tallow/wax candle (1 for no apparent reason?);
50                 * marks spinach tins (1 iff corpsenm==NON_PM);
51                 * marks tin variety (various: homemade, stir fried, &c);
52                 * eggs laid by you (1), eggs upgraded with rojal jelly (2);
53                 * Schroedinger's Box (1) or royal coffers for a court (2) or a
54                 * mummy-trapped chest (3);
55                 * named fruit index;
56                 * candy bar wrapper index;
57                 * scroll of mail (normal==0, bones or wishing==1, written==2);
58                 * splash of venom (normal==0, wishing==1);
59                 * historic flag and gender for statues;
60                 * ledger number of keyed level for thiefstones */
61 #define STATUE_HISTORIC 0x01
62 #define STATUE_MALE 0x02
63 #define STATUE_FEMALE 0x04
64 #define keyed_ledger spe
65     char oclass;    /* object class */
66     char invlet;    /* designation in inventory */
67     char oartifact; /* artifact array index */
68 
69     xchar where;        /* where the object thinks it is */
70 #define OBJ_FREE 0      /* object not attached to anything */
71 #define OBJ_FLOOR 1     /* object on floor */
72 #define OBJ_CONTAINED 2 /* object in a container */
73 #define OBJ_INVENT 3    /* object in the hero's inventory */
74 #define OBJ_MINVENT 4   /* object in a monster inventory */
75 #define OBJ_MIGRATING 5 /* object sent off to another level */
76 #define OBJ_BURIED 6    /* object buried */
77 #define OBJ_ONBILL 7    /* object on shk bill */
78 #define OBJ_INTRAP 8    /* object is trap ammo */
79 #define OBJ_LUAFREE 9   /* object has been dealloc'd, but is ref'd by lua */
80 #define NOBJ_STATES 10
81     xchar timed; /* # of fuses (timers) attached to this obj */
82 
83     Bitfield(cursed, 1);
84     Bitfield(blessed, 1);
85     Bitfield(unpaid, 1);    /* on some bill */
86     Bitfield(no_charge, 1); /* if shk shouldn't charge for this */
87     Bitfield(known, 1);     /* exact nature known */
88     Bitfield(dknown, 1);    /* color or text known */
89     Bitfield(bknown, 1);    /* blessing or curse known */
90     Bitfield(rknown, 1);    /* rustproof or not known */
91 
92     Bitfield(oeroded, 2);  /* rusted/burnt weapon/armor */
93     Bitfield(oeroded2, 2); /* corroded/rotted weapon/armor */
94 #define greatest_erosion(otmp)                                 \
95     (int)((otmp)->oeroded > (otmp)->oeroded2 ? (otmp)->oeroded \
96                                              : (otmp)->oeroded2)
97 #define MAX_ERODE 3
98 #define orotten oeroded  /* rotten food */
99 #define odiluted oeroded /* diluted potions */
100 #define norevive oeroded2 /* frozen corpse */
101     Bitfield(oerodeproof, 1); /* erodeproof weapon/armor */
102     Bitfield(olocked, 1);     /* object is locked */
103     Bitfield(obroken, 1);     /* lock has been broken */
104 #define degraded_horn obroken /* unicorn horn will poly to non-magic */
105 #define tamed_zombie obroken  /* corpse is a zombie that will revive tame */
106     Bitfield(otrapped, 1);    /* container is trapped */
107 /* or accidental tripped rolling boulder trap */
108 #define opoisoned otrapped /* object (weapon) is coated with poison */
109 #define zombie_corpse otrapped /* corpse is a zombie that might revive */
110 
111     Bitfield(recharged, 3); /* number of times it's been recharged */
112 #define on_ice recharged    /* corpse on ice */
113     Bitfield(lamplit, 1);   /* a light-source -- can be lit */
114     Bitfield(globby, 1);    /* combines with like types on adjacent squares */
115     Bitfield(greased, 1);    /* covered with grease */
116     Bitfield(nomerge, 1);    /* set temporarily to prevent merging */
117     Bitfield(was_thrown, 1); /* thrown by hero since last picked up */
118 
119     Bitfield(material, 5); /* material this obj is made of */
120     Bitfield(in_use, 1); /* for magic items before useup items */
121     Bitfield(bypass, 1); /* mark this as an object to be skipped by bhito() */
122     Bitfield(cknown, 1); /* for containers (including statues): the contents
123                           * are known; also applicable to tins */
124     Bitfield(lknown, 1); /* locked/unlocked status is known */
125     /* 7 free bits */
126 
127     int corpsenm;         /* type of corpse is mons[corpsenm] */
128 #define leashmon corpsenm /* gets m_id of attached pet */
129 #define fromsink corpsenm /* a potion from a sink */
130 #define novelidx corpsenm /* 3.6 tribute - the index of the novel title */
131 #define migr_species corpsenm /* species to endow for MIGR_TO_SPECIES */
132 #define dragonscales corpsenm /* dragon-scaled body armor
133                                * (index into objects[], not mons[]) */
134     int usecount;           /* overloaded for various things that tally */
135 #define spestudied usecount /* # of times a spellbook has been studied */
136 #define tinseed usecount    /* seed for tin labels */
137     unsigned oeaten;        /* nutrition left in food, if partly eaten */
138     long age;               /* creation date */
139     long owornmask;
140 #define migrateflags owornmask /* migrating objects can't be worn anyway */
141     xchar mgrx, mgry;       /* when migrating, travel to these coords */
142     unsigned lua_ref_cnt;  /* # of lua script references for this object */
143     xchar omigr_from_dnum; /* where obj is migrating from */
144     xchar omigr_from_dlevel; /* where obj is migrating from */
145     struct oextra *oextra; /* pointer to oextra struct */
146 };
147 
148 #define newobj() (struct obj *) alloc(sizeof(struct obj))
149 
150 /***
151  **     oextra referencing and testing macros
152  */
153 
154 #define ONAME(o) ((o)->oextra->oname)
155 #define OMONST(o) ((o)->oextra->omonst)
156 #define OMAILCMD(o) ((o)->oextra->omailcmd)
157 #define OMID(o) ((o)->oextra->omid) /* non-zero => set, zero => not set */
158 
159 #define has_oname(o) ((o)->oextra && ONAME(o))
160 #define has_omonst(o) ((o)->oextra && OMONST(o))
161 #define has_omailcmd(o) ((o)->oextra && OMAILCMD(o))
162 #define has_omid(o) ((o)->oextra && OMID(o))
163 
164 /* Weapons and weapon-tools */
165 /* KMH -- now based on skill categories.  Formerly:
166  *      #define is_sword(otmp)  (otmp->oclass == WEAPON_CLASS && \
167  *                       objects[otmp->otyp].oc_wepcat == WEP_SWORD)
168  *      #define is_blade(otmp)  (otmp->oclass == WEAPON_CLASS && \
169  *                       (objects[otmp->otyp].oc_wepcat == WEP_BLADE || \
170  *                        objects[otmp->otyp].oc_wepcat == WEP_SWORD))
171  *      #define is_weptool(o)   ((o)->oclass == TOOL_CLASS && \
172  *                       objects[(o)->otyp].oc_weptool)
173  *      #define is_multigen(otyp) (otyp <= SHURIKEN)
174  *      #define is_poisonable(otyp) (otyp <= BEC_DE_CORBIN)
175  */
176 #define is_blade(otmp)                           \
177     (otmp->oclass == WEAPON_CLASS                \
178      && objects[otmp->otyp].oc_skill >= P_DAGGER \
179      && objects[otmp->otyp].oc_skill <= P_SABER)
180 #define is_axe(otmp)                                              \
181     ((otmp->oclass == WEAPON_CLASS || otmp->oclass == TOOL_CLASS) \
182      && objects[otmp->otyp].oc_skill == P_AXE)
183 #define is_pick(otmp)                                             \
184     ((otmp->oclass == WEAPON_CLASS || otmp->oclass == TOOL_CLASS) \
185      && objects[otmp->otyp].oc_skill == P_PICK_AXE)
186 #define is_sword(otmp)                                \
187     (otmp->oclass == WEAPON_CLASS                     \
188      && objects[otmp->otyp].oc_skill >= P_SHORT_SWORD \
189      && objects[otmp->otyp].oc_skill <= P_SABER)
190 #define is_pole(otmp)                                             \
191     ((otmp->oclass == WEAPON_CLASS || otmp->oclass == TOOL_CLASS) \
192      && (objects[otmp->otyp].oc_skill == P_POLEARMS               \
193          || objects[otmp->otyp].oc_skill == P_LANCE))
194 #define is_spear(otmp) \
195     (otmp->oclass == WEAPON_CLASS && objects[otmp->otyp].oc_skill == P_SPEAR)
196 #define is_launcher(otmp)                                                  \
197     (otmp->oclass == WEAPON_CLASS && objects[otmp->otyp].oc_skill >= P_BOW \
198      && objects[otmp->otyp].oc_skill <= P_CROSSBOW)
199 #define is_ammo(otmp)                                            \
200     ((otmp->oclass == WEAPON_CLASS || otmp->oclass == GEM_CLASS) \
201      && objects[otmp->otyp].oc_skill >= -P_CROSSBOW              \
202      && objects[otmp->otyp].oc_skill <= -P_BOW)
203 #define matching_launcher(a, l) \
204     ((l) && objects[(a)->otyp].oc_skill == -objects[(l)->otyp].oc_skill)
205 #define ammo_and_launcher(a, l) (is_ammo(a) && matching_launcher(a, l))
206 #define is_missile(otmp)                                          \
207     ((otmp->oclass == WEAPON_CLASS || otmp->oclass == TOOL_CLASS) \
208      && objects[otmp->otyp].oc_skill >= -P_BOOMERANG              \
209      && objects[otmp->otyp].oc_skill <= -P_DART)
210 #define is_weptool(o) \
211     ((o)->oclass == TOOL_CLASS && objects[(o)->otyp].oc_skill != P_NONE)
212         /* towel is not a weptool:  spe isn't an enchantment, cursed towel
213            doesn't weld to hand, and twoweapon won't work with one */
214 #define is_wet_towel(o) ((o)->otyp == TOWEL && (o)->spe > 0)
215 #define bimanual(otmp)                                            \
216     ((otmp->oclass == WEAPON_CLASS || otmp->oclass == TOOL_CLASS) \
217      && objects[otmp->otyp].oc_bimanual)
218 #define is_multigen(otmp)                           \
219     (otmp->oclass == WEAPON_CLASS                   \
220      && objects[otmp->otyp].oc_skill >= -P_SHURIKEN \
221      && objects[otmp->otyp].oc_skill <= -P_BOW)
222 #define is_poisonable(otmp)                          \
223     ((otmp->oclass == WEAPON_CLASS                   \
224       && objects[otmp->otyp].oc_skill >= -P_SHURIKEN \
225       && objects[otmp->otyp].oc_skill <= -P_BOW)     \
226      || permapoisoned(otmp))
227 #define uslinging() (uwep && objects[uwep->otyp].oc_skill == P_SLING)
228 /* 'is_quest_artifact()' only applies to the current role's artifact */
229 #define any_quest_artifact(o) ((o)->oartifact >= ART_ITLACHIAYAQUE)
230 /* used by will_weld() */
231 /* probably should be renamed */
232 #define erodeable_wep(optr)                             \
233     ((optr)->oclass == WEAPON_CLASS || is_weptool(optr) \
234      || (optr)->otyp == HEAVY_IRON_BALL || (optr)->otyp == IRON_CHAIN)
235 /* used by welded(), and also while wielding */
236 #define will_weld(optr) \
237     ((optr)->cursed && (erodeable_wep(optr) || (optr)->otyp == TIN_OPENER))
238 
239 /* Armor */
240 #define is_shield(otmp)          \
241     (otmp->oclass == ARMOR_CLASS \
242      && objects[otmp->otyp].oc_armcat == ARM_SHIELD)
243 #define is_helmet(otmp) \
244     (otmp->oclass == ARMOR_CLASS && objects[otmp->otyp].oc_armcat == ARM_HELM)
245 #define is_boots(otmp)           \
246     (otmp->oclass == ARMOR_CLASS \
247      && objects[otmp->otyp].oc_armcat == ARM_BOOTS)
248 #define is_gloves(otmp)          \
249     (otmp->oclass == ARMOR_CLASS \
250      && objects[otmp->otyp].oc_armcat == ARM_GLOVES)
251 #define is_cloak(otmp)           \
252     (otmp->oclass == ARMOR_CLASS \
253      && objects[otmp->otyp].oc_armcat == ARM_CLOAK)
254 #define is_shirt(otmp)           \
255     (otmp->oclass == ARMOR_CLASS \
256      && objects[otmp->otyp].oc_armcat == ARM_SHIRT)
257 #define is_suit(otmp) \
258     (otmp->oclass == ARMOR_CLASS && objects[otmp->otyp].oc_armcat == ARM_SUIT)
259 #define is_elven_armor(otmp)                                              \
260     ((otmp)->otyp == ELVEN_HELM || (otmp)->otyp == ELVEN_CLOAK \
261      || (otmp)->otyp == ELVEN_SHIELD || (otmp)->otyp == ELVEN_BOOTS \
262      || (otmp)->otyp == ELVEN_RING_MAIL)
263 #define is_orcish_armor(otmp)                                            \
264     ((otmp)->otyp == ORCISH_HELM || (otmp)->otyp == ORCISH_CLOAK \
265      || (otmp)->otyp == URUK_HAI_SHIELD || (otmp)->otyp == ORCISH_SHIELD \
266      || (otmp)->otyp == ORCISH_RING_MAIL)
267 #define is_dwarvish_armor(otmp)               \
268     ((otmp)->otyp == DWARVISH_HELM       \
269      || (otmp)->otyp == DWARVISH_CLOAK        \
270      || (otmp)->otyp == DWARVISH_ROUNDSHIELD \
271      || (otmp)->otyp == DWARVISH_RING_MAIL)
272 #define is_gnomish_armor(otmp) (FALSE)
273 
274 /* Eggs and other food */
275 #define MAX_EGG_HATCH_TIME 200 /* longest an egg can remain unhatched */
276 #define stale_egg(egg) \
277     ((g.monstermoves - (egg)->age) > (2 * MAX_EGG_HATCH_TIME))
278 #define ofood(o) ((o)->otyp == CORPSE || (o)->otyp == EGG || (o)->otyp == TIN)
279     /* note: sometimes eggs and tins have special corpsenm values that
280        shouldn't be used as an index into mons[]                       */
281 #define polyfodder(obj) \
282     (ofood(obj) && (obj)->corpsenm >= LOW_PM                            \
283      && (pm_to_cham((obj)->corpsenm) != NON_PM                          \
284                     || dmgtype(&mons[(obj)->corpsenm], AD_POLY)))
285 #define mlevelgain(obj) (ofood(obj) && (obj)->corpsenm == PM_WRAITH)
286 #define mhealup(obj) (ofood(obj) && (obj)->corpsenm == PM_NURSE)
287 #define Is_pudding(o) \
288     (o->otyp == GLOB_OF_GRAY_OOZE || o->otyp == GLOB_OF_BROWN_PUDDING   \
289      || o->otyp == GLOB_OF_GREEN_SLIME || o->otyp == GLOB_OF_BLACK_PUDDING)
290 
291 /* Containers */
292 #define carried(o) ((o)->where == OBJ_INVENT)
293 #define mcarried(o) ((o)->where == OBJ_MINVENT)
294 #define Has_contents(o)                                \
295     (/* (Is_container(o) || (o)->otyp == STATUE) && */ \
296      (o)->cobj != (struct obj *) 0)
297 #define Is_container(o) ((o)->otyp >= LARGE_BOX && (o)->otyp <= BAG_OF_TRICKS)
298 #define Is_box(o) ((o)->otyp == LARGE_BOX || (o)->otyp == CHEST)
299 #define Is_mbag(o) ((o)->otyp == BAG_OF_HOLDING || (o)->otyp == BAG_OF_TRICKS)
300 #define SchroedingersBox(o) ((o)->otyp == LARGE_BOX && (o)->spe == 1)
301 #define Is_mummychest(o) ((o)->otyp == CHEST && (o)->spe == 3)
302 
303 /* dragon gear
304  * NOTE: this assumes that gray dragons come first and yellow last, as detailed
305  * in monst.c. */
306 #define FIRST_DRAGON        PM_GRAY_DRAGON
307 #define LAST_DRAGON         PM_YELLOW_DRAGON
308 #define FIRST_DRAGON_SCALES GRAY_DRAGON_SCALES
309 #define LAST_DRAGON_SCALES  YELLOW_DRAGON_SCALES
310 
311 /* usually waterproof; random chance to be subjected to leakage if cursed;
312    excludes statues, which aren't vulernable to water even when cursed */
313 #define Waterproof_container(o) \
314     ((o)->otyp == OILSKIN_SACK || (o)->otyp == ICE_BOX || Is_box(o))
315 
316 /* dragon gear */
317 #define Is_dragon_scales(obj) \
318     ((obj)->otyp >= FIRST_DRAGON_SCALES && (obj)->otyp <= LAST_DRAGON_SCALES)
319 /* Note: dragonscales is corpsenm, and corpsenm is usually initialized to
320  * NON_PM, which is -1. Thus, check for > 0 rather than just nonzero. */
321 #define Is_dragon_scaled_armor(obj)                \
322     (is_suit(obj) && (obj)->dragonscales > 0)
323 #define Is_dragon_armor(obj) \
324     (Is_dragon_scales(obj) || Is_dragon_scaled_armor(obj))
325 /* any dragon armor -> FOO_DRAGON_SCALES object */
326 #define Dragon_armor_to_scales(obj) \
327     (Is_dragon_scales(obj) ? (obj)->otyp : (obj)->dragonscales)
328 /* any dragon armor -> associated dragon PM_ constant */
329 #define Dragon_armor_to_pm(obj) \
330     (FIRST_DRAGON \
331      + (Is_dragon_scales(obj) ? (obj)->otyp : (obj)->dragonscales) \
332      - FIRST_DRAGON_SCALES)
333 /* dragon PM_ constant -> dragon scales */
334 #define mndx_to_dragon_scales(mndx) \
335     (FIRST_DRAGON_SCALES + (mndx - FIRST_DRAGON))
336 
337 /* Elven gear */
338 #define is_elven_weapon(otmp)                                             \
339     ((otmp)->otyp == ELVEN_ARROW || (otmp)->otyp == ELVEN_SPEAR           \
340      || (otmp)->otyp == ELVEN_DAGGER || (otmp)->otyp == ELVEN_SHORT_SWORD \
341      || (otmp)->otyp == ELVEN_BROADSWORD || (otmp)->otyp == ELVEN_BOW)
342 #define is_elven_obj(otmp) (is_elven_armor(otmp) || is_elven_weapon(otmp))
343 
344 /* Orcish gear */
345 #define is_orcish_obj(otmp)                                           \
346     (is_orcish_armor(otmp) || (otmp)->otyp == ORCISH_ARROW            \
347      || (otmp)->otyp == ORCISH_SPEAR || (otmp)->otyp == ORCISH_DAGGER \
348      || (otmp)->otyp == ORCISH_SHORT_SWORD || (otmp)->otyp == ORCISH_BOW)
349 
350 /* Dwarvish gear */
351 #define is_dwarvish_obj(otmp)                                  \
352     (is_dwarvish_armor(otmp) || (otmp)->otyp == DWARVISH_SPEAR \
353      || (otmp)->otyp == DWARVISH_SHORT_SWORD                   \
354      || (otmp)->otyp == DWARVISH_MATTOCK)
355 
356 /* Gnomish gear */
357 #define is_gnomish_obj(otmp) (is_gnomish_armor(otmp))
358 
359 /* Light sources */
360 #define Is_candle(otmp) \
361     (otmp->otyp == TALLOW_CANDLE || otmp->otyp == WAX_CANDLE)
362 #define MAX_OIL_IN_FLASK 400 /* maximum amount of oil in a potion of oil */
363 
364 /* age field of this is relative age rather than absolute; does not include
365    magic lamp */
366 #define age_is_relative(otmp) \
367     ((otmp)->otyp == LANTERN || (otmp)->otyp == OIL_LAMP      \
368      || (otmp)->otyp == CANDELABRUM_OF_INVOCATION                   \
369      || (otmp)->otyp == TALLOW_CANDLE || (otmp)->otyp == WAX_CANDLE \
370      || (otmp)->otyp == POT_OIL)
371 /* object can be ignited; magic lamp used to excluded here too but all
372    usage of this macro ended up testing
373      (ignitable(obj) || obj->otyp == MAGIC_LAMP)
374    so include it; brass lantern can be lit but not by fire */
375 #define ignitable(otmp) \
376     ((otmp)->otyp == LANTERN || (otmp)->otyp == OIL_LAMP      \
377      || ((otmp)->otyp == MAGIC_LAMP && (otmp)->spe > 0)             \
378      || (otmp)->otyp == CANDELABRUM_OF_INVOCATION                   \
379      || (otmp)->otyp == TALLOW_CANDLE || (otmp)->otyp == WAX_CANDLE \
380      || (otmp)->otyp == POT_OIL)
381 
382 /* things that can be read */
383 #define is_readable(otmp) \
384     ((otmp)->otyp == FORTUNE_COOKIE || (otmp)->otyp == T_SHIRT               \
385      || (otmp)->otyp == ALCHEMY_SMOCK || (otmp)->otyp == CREDIT_CARD         \
386      || (otmp)->otyp == CAN_OF_GREASE || (otmp)->otyp == MAGIC_MARKER        \
387      || (otmp)->oclass == COIN_CLASS || (otmp)->oartifact == ART_ORB_OF_FATE \
388      || (otmp)->otyp == CANDY_BAR)
389 
390 /* special stones */
391 #define is_graystone(obj)                                 \
392     ((obj)->otyp == LUCKSTONE || (obj)->otyp == FLINT     \
393      || (obj)->otyp == TOUCHSTONE || (obj)->otyp == THIEFSTONE)
394 
395 /* worthless glass -- assumes all GLASS * are worthless glass */
396 #define is_worthless_glass(obj) \
397     ((obj)->oclass == GEM_CLASS && obj->material == GLASS)
398 
399 /* misc helpers, simple enough to be macros */
400 #define is_flimsy(otmp)                           \
401     (otmp->material <= LEATHER || (otmp)->otyp == RUBBER_HOSE)
402 #define is_plural(o) \
403     ((o)->quan != 1L                                                    \
404      /* "the Eyes of the Overworld" are plural, but                     \
405         "a pair of lenses named the Eyes of the Overworld" is not */    \
406      || ((o)->oartifact == ART_EYES_OF_THE_OVERWORLD                    \
407          && !undiscovered_artifact(ART_EYES_OF_THE_OVERWORLD)))
408 #define pair_of(o) ((o)->otyp == LENSES || is_gloves(o) || is_boots(o))
409 /* used to be used for loadstones, now unused;
410  * may still be used in the future */
411 #define undroppable(o) ( FALSE )
412 
413 #define unpolyable(o) ((o)->otyp == WAN_POLYMORPH \
414                        || (o)->otyp == SPE_POLYMORPH \
415                        || (o)->otyp == POT_POLYMORPH)
416 
417 /* achievement tracking; 3.6.x did this differently */
418 #define is_mines_prize(o) ((o)->o_id == g.context.achieveo.mines_prize_oid)
419 #define is_soko_prize(o) ((o)->o_id == g.context.achieveo.soko_prize_oid)
420 
421 /* Flags for get_obj_location(). */
422 #define CONTAINED_TOO 0x1
423 #define BURIED_TOO 0x2
424 
425 /* object erosion types */
426 #define ERODE_BURN 0
427 #define ERODE_RUST 1
428 #define ERODE_ROT 2
429 #define ERODE_CORRODE 3
430 
431 /* erosion flags for erode_obj() */
432 #define EF_NONE 0
433 #define EF_GREASE 0x1  /* check for a greased object */
434 #define EF_DESTROY 0x2 /* potentially destroy the object */
435 #define EF_VERBOSE 0x4 /* print extra messages */
436 #define EF_PAY 0x8     /* it's the player's fault */
437 
438 /* erosion return values for erode_obj(), water_damage() */
439 #define ER_NOTHING 0   /* nothing happened */
440 #define ER_GREASED 1   /* protected by grease */
441 #define ER_DAMAGED 2   /* object was damaged in some way */
442 #define ER_DESTROYED 3 /* object was destroyed */
443 
444 /* propeller method for potionhit() */
445 #define POTHIT_HERO_BASH   0 /* wielded by hero */
446 #define POTHIT_HERO_THROW  1 /* thrown by hero */
447 #define POTHIT_MONST_THROW 2 /* thrown by a monster */
448 #define POTHIT_OTHER_THROW 3 /* propelled by some other means [scatter()] */
449 
450 /* special thiefstone coordinate accessors (uses corpsenm) */
451 #define set_keyed_loc(stone, xx, yy) \
452     ((stone)->corpsenm = ((int)(xx) << 8) | ((int)(yy) & 0xFF))
453 #define keyed_x(stone) (((stone)->corpsenm >> 8) & 0xFF)
454 #define keyed_y(stone) ((stone)->corpsenm & 0xFF)
455 /* note that ledger numbers start at 1; 0 should not be a valid ledger */
456 #define THIEFSTONE_LEDGER_CANCELLED -1
457 #define thiefstone_ledger_valid(stone) \
458     ((stone)->keyed_ledger > 0 && (stone)->keyed_ledger <= maxledgerno())
459 
460 /*
461  *  Notes for adding new oextra structures:
462  *
463  *       1. Add the structure definition and any required macros in an
464  *          appropriate header file that precedes this one.
465  *       2. Add a pointer to your new struct to oextra struct in this file.
466  *       3. Add a referencing macro to this file after the newobj macro above
467  *          (see ONAME, OMONST, OMAILCMD, or OMIN for examples).
468  *       4. Add a testing macro after the set of referencing macros
469  *          (see has_oname(), has_omonst(), has_omailcmd(), and has_omin(),
470  *          for examples).
471  *       5. If your new field isn't a pointer and requires a non-zero value
472  *          on initialization, add code to init_oextra() in src/mkobj.c.
473  *       6. Create newXX(otmp) function and possibly free_XX(otmp) function
474  *          in an appropriate new or existing source file and add a prototype
475  *          for it to include/extern.h.  The majority of these are currently
476  *          located in mkobj.c for convenience.
477  *
478  *          void newXX(struct obj *);
479  *          void free_XX(struct obj *);
480  *
481  *          void
482  *          newxx(otmp)
483  *          struct obj *otmp;
484  *          {
485  *              if (!otmp->oextra)
486  *                  otmp->oextra = newoextra();
487  *              if (!XX(otmp)) {
488  *                  XX(otmp) = (struct XX *) alloc(sizeof (struct xx));
489  *                  (void) memset((genericptr_t) XX(otmp),
490  *                                0, sizeof (struct xx));
491  *              }
492  *         }
493  *
494  *       7. Adjust size_obj() in src/cmd.c appropriately.
495  *       8. Adjust dealloc_oextra() in src/mkobj.c to clean up
496  *          properly during obj deallocation.
497  *       9. Adjust copy_oextra() in src/mkobj.c to make duplicate
498  *          copies of your struct or data onto another obj struct.
499  *      10. Adjust restobj() in src/restore.c to deal with your
500  *          struct or data during a restore.
501  *      11. Adjust saveobj() in src/save.c to deal with your
502  *          struct or data during a save.
503  */
504 
505 #endif /* OBJ_H */
506