OSDN Git Service

ifdef-ed official patches
[jnethack/source.git] / include / obj.h
1 /* NetHack 3.6  obj.h   $NHDT-Date: 1445126423 2015/10/18 00:00:23 $  $NHDT-Branch: master $:$NHDT-Revision: 1.50 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed.  See license for details. */
4
5 #ifndef OBJ_H
6 #define OBJ_H
7
8 /* #define obj obj_nh */ /* uncomment for SCO UNIX, which has a conflicting
9                           * typedef for "obj" in <sys/types.h> */
10
11 union vptrs {
12     struct obj *v_nexthere;   /* floor location lists */
13     struct obj *v_ocontainer; /* point back to container */
14     struct monst *v_ocarry;   /* point back to carrying monst */
15 };
16
17 /****
18  ***    oextra -- collection of all object extensions
19  **     (see the note at the bottom of this file before adding oextra fields)
20  */
21 struct oextra {
22     char *oname;          /* ptr to name of object */
23     struct monst *omonst; /* ptr to attached monst struct */
24     unsigned *omid;       /* ptr to m_id */
25     long *olong;          /* ptr to misc long (temporary gold object) */
26     char *omailcmd;       /* response_cmd for mail deliver */
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     schar spe; /* quality of weapon, armor or ring (+ or -)
44                   number of charges for wand ( >= -1 )
45                   marks your eggs, tin variety and spinach tins
46                   royal coffers for a court ( == 2)
47                   tells which fruit a fruit is
48                   special for uball and amulet
49                   historic and gender for statues */
50 #define STATUE_HISTORIC 0x01
51 #define STATUE_MALE 0x02
52 #define STATUE_FEMALE 0x04
53     char oclass;    /* object class */
54     char invlet;    /* designation in inventory */
55     char oartifact; /* artifact array index */
56
57     xchar where;        /* where the object thinks it is */
58 #define OBJ_FREE 0      /* object not attached to anything */
59 #define OBJ_FLOOR 1     /* object on floor */
60 #define OBJ_CONTAINED 2 /* object in a container */
61 #define OBJ_INVENT 3    /* object in the hero's inventory */
62 #define OBJ_MINVENT 4   /* object in a monster inventory */
63 #define OBJ_MIGRATING 5 /* object sent off to another level */
64 #define OBJ_BURIED 6    /* object buried */
65 #define OBJ_ONBILL 7    /* object on shk bill */
66 #define NOBJ_STATES 8
67     xchar timed; /* # of fuses (timers) attached to this obj */
68
69     Bitfield(cursed, 1);
70     Bitfield(blessed, 1);
71     Bitfield(unpaid, 1);    /* on some bill */
72     Bitfield(no_charge, 1); /* if shk shouldn't charge for this */
73     Bitfield(known, 1);     /* exact nature known */
74     Bitfield(dknown, 1);    /* color or text known */
75     Bitfield(bknown, 1);    /* blessing or curse known */
76     Bitfield(rknown, 1);    /* rustproof or not known */
77
78     Bitfield(oeroded, 2);  /* rusted/burnt weapon/armor */
79     Bitfield(oeroded2, 2); /* corroded/rotted weapon/armor */
80 #define greatest_erosion(otmp)                                 \
81     (int)((otmp)->oeroded > (otmp)->oeroded2 ? (otmp)->oeroded \
82                                              : (otmp)->oeroded2)
83 #define MAX_ERODE 3
84 #define orotten oeroded  /* rotten food */
85 #define odiluted oeroded /* diluted potions */
86 #define norevive oeroded2
87     Bitfield(oerodeproof, 1); /* erodeproof weapon/armor */
88     Bitfield(olocked, 1);     /* object is locked */
89     Bitfield(obroken, 1);     /* lock has been broken */
90 #define degraded_horn obroken /* unicorn horn will poly to non-magic */
91     Bitfield(otrapped, 1);    /* container is trapped */
92 /* or accidental tripped rolling boulder trap */
93 #define opoisoned otrapped /* object (weapon) is coated with poison */
94
95     Bitfield(recharged, 3); /* number of times it's been recharged */
96 #define on_ice recharged    /* corpse on ice */
97     Bitfield(lamplit, 1);   /* a light-source -- can be lit */
98     Bitfield(
99         globby,
100         1); /* globby; will combine with like types on adjacent squares */
101     Bitfield(greased, 1);    /* covered with grease */
102     Bitfield(nomerge, 1);    /* set temporarily to prevent merging */
103     Bitfield(was_thrown, 1); /* thrown by hero since last picked up */
104
105     Bitfield(in_use, 1); /* for magic items before useup items */
106     Bitfield(bypass, 1); /* mark this as an object to be skipped by bhito() */
107     Bitfield(cknown, 1); /* contents of container assumed to be known */
108     Bitfield(lknown, 1); /* locked/unlocked status is known */
109     /* 4 free bits */
110
111     int corpsenm;         /* type of corpse is mons[corpsenm] */
112 #define leashmon corpsenm /* gets m_id of attached pet */
113 #define fromsink corpsenm /* a potion from a sink */
114 #define novelidx corpsenm /* 3.6.0 tribute - the index of the novel title */
115 #define record_achieve_special corpsenm
116     int usecount;           /* overloaded for various things that tally */
117 #define spestudied usecount /* # of times a spellbook has been studied */
118     unsigned oeaten;        /* nutrition left in food, if partly eaten */
119     long age;               /* creation date */
120     long owornmask;
121     struct oextra *oextra; /* pointer to oextra struct */
122 };
123
124 #define newobj() (struct obj *) alloc(sizeof(struct obj))
125
126 /***
127  **     oextra referencing and testing macros
128  */
129
130 #define ONAME(o) ((o)->oextra->oname)
131 #define OMID(o) ((o)->oextra->omid)
132 #define OMONST(o) ((o)->oextra->omonst)
133 #define OLONG(o) ((o)->oextra->olong)
134 #define OMAILCMD(o) ((o)->oextra->omailcmd)
135
136 #define has_oname(o) ((o)->oextra && ONAME(o))
137 #define has_omid(o) ((o)->oextra && OMID(o))
138 #define has_omonst(o) ((o)->oextra && OMONST(o))
139 #define has_olong(o) ((o)->oextra && OLONG(o))
140 #define has_omailcmd(o) ((o)->oextra && OMAILCMD(o))
141
142 /* Weapons and weapon-tools */
143 /* KMH -- now based on skill categories.  Formerly:
144  *      #define is_sword(otmp)  (otmp->oclass == WEAPON_CLASS && \
145  *                       objects[otmp->otyp].oc_wepcat == WEP_SWORD)
146  *      #define is_blade(otmp)  (otmp->oclass == WEAPON_CLASS && \
147  *                       (objects[otmp->otyp].oc_wepcat == WEP_BLADE || \
148  *                        objects[otmp->otyp].oc_wepcat == WEP_SWORD))
149  *      #define is_weptool(o)   ((o)->oclass == TOOL_CLASS && \
150  *                       objects[(o)->otyp].oc_weptool)
151  *      #define is_multigen(otyp) (otyp <= SHURIKEN)
152  *      #define is_poisonable(otyp) (otyp <= BEC_DE_CORBIN)
153  */
154 #define is_blade(otmp)                           \
155     (otmp->oclass == WEAPON_CLASS                \
156      && objects[otmp->otyp].oc_skill >= P_DAGGER \
157      && objects[otmp->otyp].oc_skill <= P_SABER)
158 #define is_axe(otmp)                                              \
159     ((otmp->oclass == WEAPON_CLASS || otmp->oclass == TOOL_CLASS) \
160      && objects[otmp->otyp].oc_skill == P_AXE)
161 #define is_pick(otmp)                                             \
162     ((otmp->oclass == WEAPON_CLASS || otmp->oclass == TOOL_CLASS) \
163      && objects[otmp->otyp].oc_skill == P_PICK_AXE)
164 #define is_sword(otmp)                                \
165     (otmp->oclass == WEAPON_CLASS                     \
166      && objects[otmp->otyp].oc_skill >= P_SHORT_SWORD \
167      && objects[otmp->otyp].oc_skill <= P_SABER)
168 #define is_pole(otmp)                                             \
169     ((otmp->oclass == WEAPON_CLASS || otmp->oclass == TOOL_CLASS) \
170      && (objects[otmp->otyp].oc_skill == P_POLEARMS               \
171          || objects[otmp->otyp].oc_skill == P_LANCE))
172 #define is_spear(otmp) \
173     (otmp->oclass == WEAPON_CLASS && objects[otmp->otyp].oc_skill == P_SPEAR)
174 #define is_launcher(otmp)                                                  \
175     (otmp->oclass == WEAPON_CLASS && objects[otmp->otyp].oc_skill >= P_BOW \
176      && objects[otmp->otyp].oc_skill <= P_CROSSBOW)
177 #define is_ammo(otmp)                                            \
178     ((otmp->oclass == WEAPON_CLASS || otmp->oclass == GEM_CLASS) \
179      && objects[otmp->otyp].oc_skill >= -P_CROSSBOW              \
180      && objects[otmp->otyp].oc_skill <= -P_BOW)
181 #define matching_launcher(a, l) \
182     ((l) && objects[(a)->otyp].oc_skill == -objects[(l)->otyp].oc_skill)
183 #define ammo_and_launcher(a, l) (is_ammo(a) && matching_launcher(a, l))
184 #define is_missile(otmp)                                          \
185     ((otmp->oclass == WEAPON_CLASS || otmp->oclass == TOOL_CLASS) \
186      && objects[otmp->otyp].oc_skill >= -P_BOOMERANG              \
187      && objects[otmp->otyp].oc_skill <= -P_DART)
188 #define is_weptool(o) \
189     ((o)->oclass == TOOL_CLASS && objects[(o)->otyp].oc_skill != P_NONE)
190         /* towel is not a weptool:  spe isn't an enchantment, cursed towel
191            doesn't weld to hand, and twoweapon won't work with one */
192 #define is_wet_towel(o) ((o)->otyp == TOWEL && (o)->spe > 0)
193 #define bimanual(otmp)                                            \
194     ((otmp->oclass == WEAPON_CLASS || otmp->oclass == TOOL_CLASS) \
195      && objects[otmp->otyp].oc_bimanual)
196 #define is_multigen(otmp)                           \
197     (otmp->oclass == WEAPON_CLASS                   \
198      && objects[otmp->otyp].oc_skill >= -P_SHURIKEN \
199      && objects[otmp->otyp].oc_skill <= -P_BOW)
200 #define is_poisonable(otmp)                         \
201     (otmp->oclass == WEAPON_CLASS                   \
202      && objects[otmp->otyp].oc_skill >= -P_SHURIKEN \
203      && objects[otmp->otyp].oc_skill <= -P_BOW)
204 #define uslinging() (uwep && objects[uwep->otyp].oc_skill == P_SLING)
205
206 /* Armor */
207 #define is_shield(otmp)          \
208     (otmp->oclass == ARMOR_CLASS \
209      && objects[otmp->otyp].oc_armcat == ARM_SHIELD)
210 #define is_helmet(otmp) \
211     (otmp->oclass == ARMOR_CLASS && objects[otmp->otyp].oc_armcat == ARM_HELM)
212 #define is_boots(otmp)           \
213     (otmp->oclass == ARMOR_CLASS \
214      && objects[otmp->otyp].oc_armcat == ARM_BOOTS)
215 #define is_gloves(otmp)          \
216     (otmp->oclass == ARMOR_CLASS \
217      && objects[otmp->otyp].oc_armcat == ARM_GLOVES)
218 #define is_cloak(otmp)           \
219     (otmp->oclass == ARMOR_CLASS \
220      && objects[otmp->otyp].oc_armcat == ARM_CLOAK)
221 #define is_shirt(otmp)           \
222     (otmp->oclass == ARMOR_CLASS \
223      && objects[otmp->otyp].oc_armcat == ARM_SHIRT)
224 #define is_suit(otmp) \
225     (otmp->oclass == ARMOR_CLASS && objects[otmp->otyp].oc_armcat == ARM_SUIT)
226 #define is_elven_armor(otmp)                                              \
227     ((otmp)->otyp == ELVEN_LEATHER_HELM                                   \
228      || (otmp)->otyp == ELVEN_MITHRIL_COAT || (otmp)->otyp == ELVEN_CLOAK \
229      || (otmp)->otyp == ELVEN_SHIELD || (otmp)->otyp == ELVEN_BOOTS)
230 #define is_orcish_armor(otmp)                                            \
231     ((otmp)->otyp == ORCISH_HELM || (otmp)->otyp == ORCISH_CHAIN_MAIL    \
232      || (otmp)->otyp == ORCISH_RING_MAIL || (otmp)->otyp == ORCISH_CLOAK \
233      || (otmp)->otyp == URUK_HAI_SHIELD || (otmp)->otyp == ORCISH_SHIELD)
234 #define is_dwarvish_armor(otmp)               \
235     ((otmp)->otyp == DWARVISH_IRON_HELM       \
236      || (otmp)->otyp == DWARVISH_MITHRIL_COAT \
237      || (otmp)->otyp == DWARVISH_CLOAK        \
238      || (otmp)->otyp == DWARVISH_ROUNDSHIELD)
239 #define is_gnomish_armor(otmp) (FALSE)
240
241 /* Eggs and other food */
242 #define MAX_EGG_HATCH_TIME 200 /* longest an egg can remain unhatched */
243 #define stale_egg(egg) \
244     ((monstermoves - (egg)->age) > (2 * MAX_EGG_HATCH_TIME))
245 #define ofood(o) ((o)->otyp == CORPSE || (o)->otyp == EGG || (o)->otyp == TIN)
246 #define polyfodder(obj) (ofood(obj) && pm_to_cham((obj)->corpsenm) != NON_PM)
247 #define mlevelgain(obj) (ofood(obj) && (obj)->corpsenm == PM_WRAITH)
248 #define mhealup(obj) (ofood(obj) && (obj)->corpsenm == PM_NURSE)
249 #define Is_pudding(o)                                                 \
250     (o->otyp == GLOB_OF_GRAY_OOZE || o->otyp == GLOB_OF_BROWN_PUDDING \
251      || o->otyp == GLOB_OF_GREEN_SLIME || o->otyp == GLOB_OF_BLACK_PUDDING)
252
253 /* Containers */
254 #define carried(o) ((o)->where == OBJ_INVENT)
255 #define mcarried(o) ((o)->where == OBJ_MINVENT)
256 #define Has_contents(o)                                \
257     (/* (Is_container(o) || (o)->otyp == STATUE) && */ \
258      (o)->cobj != (struct obj *) 0)
259 #define Is_container(o) ((o)->otyp >= LARGE_BOX && (o)->otyp <= BAG_OF_TRICKS)
260 #define Is_box(otmp) (otmp->otyp == LARGE_BOX || otmp->otyp == CHEST)
261 #define Is_mbag(otmp) \
262     (otmp->otyp == BAG_OF_HOLDING || otmp->otyp == BAG_OF_TRICKS)
263 #define SchroedingersBox(o) ((o)->otyp == LARGE_BOX && (o)->spe == 1)
264
265 /* dragon gear */
266 #define Is_dragon_scales(obj) \
267     ((obj)->otyp >= GRAY_DRAGON_SCALES && (obj)->otyp <= YELLOW_DRAGON_SCALES)
268 #define Is_dragon_mail(obj)                \
269     ((obj)->otyp >= GRAY_DRAGON_SCALE_MAIL \
270      && (obj)->otyp <= YELLOW_DRAGON_SCALE_MAIL)
271 #define Is_dragon_armor(obj) (Is_dragon_scales(obj) || Is_dragon_mail(obj))
272 #define Dragon_scales_to_pm(obj) \
273     &mons[PM_GRAY_DRAGON + (obj)->otyp - GRAY_DRAGON_SCALES]
274 #define Dragon_mail_to_pm(obj) \
275     &mons[PM_GRAY_DRAGON + (obj)->otyp - GRAY_DRAGON_SCALE_MAIL]
276 #define Dragon_to_scales(pm) (GRAY_DRAGON_SCALES + (pm - mons))
277
278 /* Elven gear */
279 #define is_elven_weapon(otmp)                                             \
280     ((otmp)->otyp == ELVEN_ARROW || (otmp)->otyp == ELVEN_SPEAR           \
281      || (otmp)->otyp == ELVEN_DAGGER || (otmp)->otyp == ELVEN_SHORT_SWORD \
282      || (otmp)->otyp == ELVEN_BROADSWORD || (otmp)->otyp == ELVEN_BOW)
283 #define is_elven_obj(otmp) (is_elven_armor(otmp) || is_elven_weapon(otmp))
284
285 /* Orcish gear */
286 #define is_orcish_obj(otmp)                                           \
287     (is_orcish_armor(otmp) || (otmp)->otyp == ORCISH_ARROW            \
288      || (otmp)->otyp == ORCISH_SPEAR || (otmp)->otyp == ORCISH_DAGGER \
289      || (otmp)->otyp == ORCISH_SHORT_SWORD || (otmp)->otyp == ORCISH_BOW)
290
291 /* Dwarvish gear */
292 #define is_dwarvish_obj(otmp)                                  \
293     (is_dwarvish_armor(otmp) || (otmp)->otyp == DWARVISH_SPEAR \
294      || (otmp)->otyp == DWARVISH_SHORT_SWORD                   \
295      || (otmp)->otyp == DWARVISH_MATTOCK)
296
297 /* Gnomish gear */
298 #define is_gnomish_obj(otmp) (is_gnomish_armor(otmp))
299
300 /* Light sources */
301 #define Is_candle(otmp) \
302     (otmp->otyp == TALLOW_CANDLE || otmp->otyp == WAX_CANDLE)
303 #define MAX_OIL_IN_FLASK 400 /* maximum amount of oil in a potion of oil */
304
305 /* MAGIC_LAMP intentionally excluded below */
306 /* age field of this is relative age rather than absolute */
307 #define age_is_relative(otmp)                                       \
308     ((otmp)->otyp == BRASS_LANTERN || (otmp)->otyp == OIL_LAMP      \
309      || (otmp)->otyp == CANDELABRUM_OF_INVOCATION                   \
310      || (otmp)->otyp == TALLOW_CANDLE || (otmp)->otyp == WAX_CANDLE \
311      || (otmp)->otyp == POT_OIL)
312 /* object can be ignited */
313 #define ignitable(otmp)                                             \
314     ((otmp)->otyp == BRASS_LANTERN || (otmp)->otyp == OIL_LAMP      \
315      || (otmp)->otyp == CANDELABRUM_OF_INVOCATION                   \
316      || (otmp)->otyp == TALLOW_CANDLE || (otmp)->otyp == WAX_CANDLE \
317      || (otmp)->otyp == POT_OIL)
318
319 /* things that can be read */
320 #define is_readable(otmp)                                                    \
321     ((otmp)->otyp == FORTUNE_COOKIE || (otmp)->otyp == T_SHIRT               \
322      || (otmp)->otyp == ALCHEMY_SMOCK || (otmp)->otyp == CREDIT_CARD         \
323      || (otmp)->otyp == CAN_OF_GREASE || (otmp)->otyp == MAGIC_MARKER        \
324      || (otmp)->oclass == COIN_CLASS || (otmp)->oartifact == ART_ORB_OF_FATE \
325      || (otmp)->otyp == CANDY_BAR)
326
327 /* special stones */
328 #define is_graystone(obj)                                 \
329     ((obj)->otyp == LUCKSTONE || (obj)->otyp == LOADSTONE \
330      || (obj)->otyp == FLINT || (obj)->otyp == TOUCHSTONE)
331
332 /* misc */
333 #define is_flimsy(otmp)                           \
334     (objects[(otmp)->otyp].oc_material <= LEATHER \
335      || (otmp)->otyp == RUBBER_HOSE)
336
337 /* helpers, simple enough to be macros */
338 #define is_plural(o) \
339     ((o)->quan > 1 || (o)->oartifact == ART_EYES_OF_THE_OVERWORLD)
340
341 /* Flags for get_obj_location(). */
342 #define CONTAINED_TOO 0x1
343 #define BURIED_TOO 0x2
344
345 /* object erosion types */
346 #define ERODE_BURN 0
347 #define ERODE_RUST 1
348 #define ERODE_ROT 2
349 #define ERODE_CORRODE 3
350
351 /* erosion flags for erode_obj() */
352 #define EF_NONE 0
353 #define EF_GREASE 0x1  /* check for a greased object */
354 #define EF_DESTROY 0x2 /* potentially destroy the object */
355 #define EF_VERBOSE 0x4 /* print extra messages */
356 #define EF_PAY 0x8     /* it's the player's fault */
357
358 /* erosion return values for erode_obj(), water_damage() */
359 #define ER_NOTHING 0   /* nothing happened */
360 #define ER_GREASED 1   /* protected by grease */
361 #define ER_DAMAGED 2   /* object was damaged in some way */
362 #define ER_DESTROYED 3 /* object was destroyed */
363
364 /*
365  *  Notes for adding new oextra structures:
366  *
367  *       1. Add the structure definition and any required macros in an
368  *appropriate
369  *          header file that precedes this one.
370  *       2. Add a pointer to your new struct to the oextra struct in this
371  *file.
372  *       3. Add a referencing macro to this file after the newobj macro above
373  *          (see ONAME, OMONST, OMIN, OLONG, or OMAILCMD for examples).
374  *       4. Add a testing macro after the set of referencing macros
375  *          (see has_oname(), has_omonst(), has_omin(), has_olong(),
376  *          has_omailcmd() for examples).
377  *       5. Create a newXX(otmp) function and possibly a free_XX(otmp)
378  *function
379  *          in an appropriate new or existing source file and add a prototype
380  *          for it to include/extern.h.  The majority of these are currently
381  *          located in mkobj.c for convenience.
382  *
383  *              void FDECL(newXX, (struct obj *));
384  *              void FDECL(free_XX, (struct obj *));
385  *
386  *                void
387  *                newxx(otmp)
388  *                struct obj *otmp;
389  *                {
390  *                    if (!otmp->oextra) otmp->oextra = newoextra();
391  *                    if (!XX(otmp)) {
392  *                        XX(otmp) = (struct XX *)alloc(sizeof(struct xx));
393  *                        (void) memset((genericptr_t) XX(otmp),
394  *                                   0, sizeof(struct xx));
395  *                    }
396  *                }
397  *
398  *       6. Adjust size_obj() in src/cmd.c appropriately.
399  *       7. Adjust dealloc_oextra() in src/mkobj.c to clean up
400  *          properly during obj deallocation.
401  *       8. Adjust copy_oextra() in src/mkobj.c to make duplicate
402  *          copies of your struct or data onto another obj struct.
403  *       9. Adjust restobj() in src/restore.c to deal with your
404  *          struct or data during a restore.
405  *      10. Adjust saveobj() in src/save.c to deal with your
406  *          struct or data during a save.
407  */
408
409 #endif /* OBJ_H */