1/*	SCCS Id: @(#)obj.h	3.4	2002/01/07	*/
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
11union 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
17struct obj {
18	struct obj *nobj;
19	union vptrs v;
20#define nexthere	v.v_nexthere
21#define ocontainer	v.v_ocontainer
22#define ocarry		v.v_ocarry
23
24	struct obj *cobj;	/* contents list for containers */
25	unsigned o_id;
26	xchar ox,oy;
27	short otyp;		/* object class number */
28	unsigned owt;
29	long quan;		/* number of items */
30
31	schar spe;		/* quality of weapon, armor or ring (+ or -)
32				   number of charges for wand ( >= -1 )
33				   marks your eggs, spinach tins
34				   royal coffers for a court ( == 2)
35				   tells which fruit a fruit is
36				   special for uball and amulet
37				   historic and gender for statues */
38#define STATUE_HISTORIC 0x01
39#define STATUE_MALE     0x02
40#define STATUE_FEMALE   0x04
41	char	oclass;		/* object class */
42	char	invlet;		/* designation in inventory */
43	char	oartifact;	/* artifact array index */
44
45	xchar where;		/* where the object thinks it is */
46#define OBJ_FREE	0		/* object not attached to anything */
47#define OBJ_FLOOR	1		/* object on floor */
48#define OBJ_CONTAINED	2		/* object in a container */
49#define OBJ_INVENT	3		/* object in the hero's inventory */
50#define OBJ_MINVENT	4		/* object in a monster inventory */
51#define OBJ_MIGRATING	5		/* object sent off to another level */
52#define OBJ_BURIED	6		/* object buried */
53#define OBJ_ONBILL	7		/* object on shk bill */
54#define NOBJ_STATES	8
55	xchar timed;		/* # of fuses (timers) attached to this obj */
56
57	Bitfield(cursed,1);
58	Bitfield(blessed,1);
59	Bitfield(unpaid,1);	/* on some bill */
60	Bitfield(no_charge,1);	/* if shk shouldn't charge for this */
61	Bitfield(known,1);	/* exact nature known */
62	Bitfield(dknown,1);	/* color or text known */
63	Bitfield(bknown,1);	/* blessing or curse known */
64	Bitfield(rknown,1);	/* rustproof or not known */
65
66	Bitfield(oeroded,2);	/* rusted/burnt weapon/armor */
67	Bitfield(oeroded2,2);	/* corroded/rotted weapon/armor */
68#define greatest_erosion(otmp) (int)((otmp)->oeroded > (otmp)->oeroded2 ? (otmp)->oeroded : (otmp)->oeroded2)
69#define MAX_ERODE 3
70#define orotten oeroded		/* rotten food */
71#define odiluted oeroded	/* diluted potions */
72#define norevive oeroded2
73	Bitfield(oerodeproof,1); /* erodeproof weapon/armor */
74	Bitfield(olocked,1);	/* object is locked */
75	Bitfield(obroken,1);	/* lock has been broken */
76	Bitfield(otrapped,1);	/* container is trapped */
77				/* or accidental tripped rolling boulder trap */
78#define opoisoned otrapped	/* object (weapon) is coated with poison */
79
80	Bitfield(recharged,3);	/* number of times it's been recharged */
81	Bitfield(lamplit,1);	/* a light-source -- can be lit */
82#ifdef INVISIBLE_OBJECTS
83	Bitfield(oinvis,1);	/* invisible */
84#endif
85	Bitfield(greased,1);	/* covered with grease */
86	Bitfield(oattached,2);	/* obj struct has special attachment */
87#define OATTACHED_NOTHING 0
88#define OATTACHED_MONST   1	/* monst struct in oextra */
89#define OATTACHED_M_ID    2	/* monst id in oextra */
90#define OATTACHED_UNUSED3 3
91
92	Bitfield(in_use,1);	/* for magic items before useup items */
93	Bitfield(bypass,1);	/* mark this as an object to be skipped by bhito() */
94	/* 6 free bits */
95
96	int	corpsenm;	/* type of corpse is mons[corpsenm] */
97#define leashmon  corpsenm	/* gets m_id of attached pet */
98#define spestudied corpsenm	/* # of times a spellbook has been studied */
99#define fromsink  corpsenm	/* a potion from a sink */
100	unsigned oeaten;	/* nutrition left in food, if partly eaten */
101	long age;		/* creation date */
102
103	uchar onamelth;		/* length of name (following oxlth) */
104	short oxlth;		/* length of following data */
105	/* in order to prevent alignment problems oextra should
106	   be (or follow) a long int */
107	long owornmask;
108	long oextra[1];		/* used for name of ordinary objects - length
109				   is flexible; amount for tmp gold objects */
110};
111
112#define newobj(xl)	(struct obj *)alloc((unsigned)(xl) + sizeof(struct obj))
113#define ONAME(otmp)	(((char *)(otmp)->oextra) + (otmp)->oxlth)
114
115/* Weapons and weapon-tools */
116/* KMH -- now based on skill categories.  Formerly:
117 *	#define is_sword(otmp)	(otmp->oclass == WEAPON_CLASS && \
118 *			 objects[otmp->otyp].oc_wepcat == WEP_SWORD)
119 *	#define is_blade(otmp)	(otmp->oclass == WEAPON_CLASS && \
120 *			 (objects[otmp->otyp].oc_wepcat == WEP_BLADE || \
121 *			  objects[otmp->otyp].oc_wepcat == WEP_SWORD))
122 *	#define is_weptool(o)	((o)->oclass == TOOL_CLASS && \
123 *			 objects[(o)->otyp].oc_weptool)
124 *	#define is_multigen(otyp) (otyp <= SHURIKEN)
125 *	#define is_poisonable(otyp) (otyp <= BEC_DE_CORBIN)
126 */
127#define is_blade(otmp)	(otmp->oclass == WEAPON_CLASS && \
128			 objects[otmp->otyp].oc_skill >= P_DAGGER && \
129			 objects[otmp->otyp].oc_skill <= P_SABER)
130#define is_axe(otmp)	((otmp->oclass == WEAPON_CLASS || \
131			 otmp->oclass == TOOL_CLASS) && \
132			 objects[otmp->otyp].oc_skill == P_AXE)
133#define is_pick(otmp)	((otmp->oclass == WEAPON_CLASS || \
134			 otmp->oclass == TOOL_CLASS) && \
135			 objects[otmp->otyp].oc_skill == P_PICK_AXE)
136#define is_sword(otmp)	(otmp->oclass == WEAPON_CLASS && \
137			 objects[otmp->otyp].oc_skill >= P_SHORT_SWORD && \
138			 objects[otmp->otyp].oc_skill <= P_SABER)
139#define is_pole(otmp)	((otmp->oclass == WEAPON_CLASS || \
140			otmp->oclass == TOOL_CLASS) && \
141			 (objects[otmp->otyp].oc_skill == P_POLEARMS || \
142			 objects[otmp->otyp].oc_skill == P_LANCE))
143#define is_spear(otmp)	(otmp->oclass == WEAPON_CLASS && \
144			 objects[otmp->otyp].oc_skill >= P_SPEAR && \
145			 objects[otmp->otyp].oc_skill <= P_JAVELIN)
146#define is_launcher(otmp)	(otmp->oclass == WEAPON_CLASS && \
147			 objects[otmp->otyp].oc_skill >= P_BOW && \
148			 objects[otmp->otyp].oc_skill <= P_CROSSBOW)
149#define is_ammo(otmp)	((otmp->oclass == WEAPON_CLASS || \
150			 otmp->oclass == GEM_CLASS) && \
151			 objects[otmp->otyp].oc_skill >= -P_CROSSBOW && \
152			 objects[otmp->otyp].oc_skill <= -P_BOW)
153#define ammo_and_launcher(otmp,ltmp) \
154			 (is_ammo(otmp) && (ltmp) && \
155			 objects[(otmp)->otyp].oc_skill == -objects[(ltmp)->otyp].oc_skill)
156#define is_missile(otmp)	((otmp->oclass == WEAPON_CLASS || \
157			 otmp->oclass == TOOL_CLASS) && \
158			 objects[otmp->otyp].oc_skill >= -P_BOOMERANG && \
159			 objects[otmp->otyp].oc_skill <= -P_DART)
160#define is_weptool(o)	((o)->oclass == TOOL_CLASS && \
161			 objects[(o)->otyp].oc_skill != P_NONE)
162#define bimanual(otmp)	((otmp->oclass == WEAPON_CLASS || \
163			 otmp->oclass == TOOL_CLASS) && \
164			 objects[otmp->otyp].oc_bimanual)
165#define is_multigen(otmp)	(otmp->oclass == WEAPON_CLASS && \
166			 objects[otmp->otyp].oc_skill >= -P_SHURIKEN && \
167			 objects[otmp->otyp].oc_skill <= -P_BOW)
168#define is_poisonable(otmp)	(otmp->oclass == WEAPON_CLASS && \
169			 objects[otmp->otyp].oc_skill >= -P_SHURIKEN && \
170			 objects[otmp->otyp].oc_skill <= -P_BOW)
171#define uslinging()	(uwep && objects[uwep->otyp].oc_skill == P_SLING)
172
173/* Armor */
174#define is_shield(otmp) (otmp->oclass == ARMOR_CLASS && \
175			 objects[otmp->otyp].oc_armcat == ARM_SHIELD)
176#define is_helmet(otmp) (otmp->oclass == ARMOR_CLASS && \
177			 objects[otmp->otyp].oc_armcat == ARM_HELM)
178#define is_boots(otmp)	(otmp->oclass == ARMOR_CLASS && \
179			 objects[otmp->otyp].oc_armcat == ARM_BOOTS)
180#define is_gloves(otmp) (otmp->oclass == ARMOR_CLASS && \
181			 objects[otmp->otyp].oc_armcat == ARM_GLOVES)
182#define is_cloak(otmp)	(otmp->oclass == ARMOR_CLASS && \
183			 objects[otmp->otyp].oc_armcat == ARM_CLOAK)
184#define is_shirt(otmp)	(otmp->oclass == ARMOR_CLASS && \
185			 objects[otmp->otyp].oc_armcat == ARM_SHIRT)
186#define is_suit(otmp)	(otmp->oclass == ARMOR_CLASS && \
187			 objects[otmp->otyp].oc_armcat == ARM_SUIT)
188#define is_elven_armor(otmp)	((otmp)->otyp == ELVEN_LEATHER_HELM\
189				|| (otmp)->otyp == ELVEN_MITHRIL_COAT\
190				|| (otmp)->otyp == ELVEN_CLOAK\
191				|| (otmp)->otyp == ELVEN_SHIELD\
192				|| (otmp)->otyp == ELVEN_BOOTS)
193#define is_orcish_armor(otmp)	((otmp)->otyp == ORCISH_HELM\
194				|| (otmp)->otyp == ORCISH_CHAIN_MAIL\
195				|| (otmp)->otyp == ORCISH_RING_MAIL\
196				|| (otmp)->otyp == ORCISH_CLOAK\
197				|| (otmp)->otyp == URUK_HAI_SHIELD\
198				|| (otmp)->otyp == ORCISH_SHIELD)
199#define is_dwarvish_armor(otmp)	((otmp)->otyp == DWARVISH_IRON_HELM\
200				|| (otmp)->otyp == DWARVISH_MITHRIL_COAT\
201				|| (otmp)->otyp == DWARVISH_CLOAK\
202				|| (otmp)->otyp == DWARVISH_ROUNDSHIELD)
203#define is_gnomish_armor(otmp)	(FALSE)
204
205
206/* Eggs and other food */
207#define MAX_EGG_HATCH_TIME 200	/* longest an egg can remain unhatched */
208#define stale_egg(egg)	((monstermoves - (egg)->age) > (2*MAX_EGG_HATCH_TIME))
209#define ofood(o) ((o)->otyp == CORPSE || (o)->otyp == EGG || (o)->otyp == TIN)
210#define polyfodder(obj) (ofood(obj) && \
211			 pm_to_cham((obj)->corpsenm) != CHAM_ORDINARY)
212#define mlevelgain(obj) (ofood(obj) && (obj)->corpsenm == PM_WRAITH)
213#define mhealup(obj)	(ofood(obj) && (obj)->corpsenm == PM_NURSE)
214
215/* Containers */
216#define carried(o)	((o)->where == OBJ_INVENT)
217#define mcarried(o)	((o)->where == OBJ_MINVENT)
218#define Has_contents(o) (/* (Is_container(o) || (o)->otyp == STATUE) && */ \
219			 (o)->cobj != (struct obj *)0)
220#define Is_container(o) ((o)->otyp >= LARGE_BOX && (o)->otyp <= BAG_OF_TRICKS)
221#define Is_box(otmp)	(otmp->otyp == LARGE_BOX || otmp->otyp == CHEST)
222#define Is_mbag(otmp)	(otmp->otyp == BAG_OF_HOLDING || \
223			 otmp->otyp == BAG_OF_TRICKS)
224
225/* dragon gear */
226#define Is_dragon_scales(obj)	((obj)->otyp >= GRAY_DRAGON_SCALES && \
227				 (obj)->otyp <= YELLOW_DRAGON_SCALES)
228#define Is_dragon_mail(obj)	((obj)->otyp >= GRAY_DRAGON_SCALE_MAIL && \
229				 (obj)->otyp <= YELLOW_DRAGON_SCALE_MAIL)
230#define Is_dragon_armor(obj)	(Is_dragon_scales(obj) || Is_dragon_mail(obj))
231#define Dragon_scales_to_pm(obj) &mons[PM_GRAY_DRAGON + (obj)->otyp \
232				       - GRAY_DRAGON_SCALES]
233#define Dragon_mail_to_pm(obj)	&mons[PM_GRAY_DRAGON + (obj)->otyp \
234				      - GRAY_DRAGON_SCALE_MAIL]
235#define Dragon_to_scales(pm)	(GRAY_DRAGON_SCALES + (pm - mons))
236
237/* Elven gear */
238#define is_elven_weapon(otmp)	((otmp)->otyp == ELVEN_ARROW\
239				|| (otmp)->otyp == ELVEN_SPEAR\
240				|| (otmp)->otyp == ELVEN_DAGGER\
241				|| (otmp)->otyp == ELVEN_SHORT_SWORD\
242				|| (otmp)->otyp == ELVEN_BROADSWORD\
243				|| (otmp)->otyp == ELVEN_BOW)
244#define is_elven_obj(otmp)	(is_elven_armor(otmp) || is_elven_weapon(otmp))
245
246/* Orcish gear */
247#define is_orcish_obj(otmp)	(is_orcish_armor(otmp)\
248				|| (otmp)->otyp == ORCISH_ARROW\
249				|| (otmp)->otyp == ORCISH_SPEAR\
250				|| (otmp)->otyp == ORCISH_DAGGER\
251				|| (otmp)->otyp == ORCISH_SHORT_SWORD\
252				|| (otmp)->otyp == ORCISH_BOW)
253
254/* Dwarvish gear */
255#define is_dwarvish_obj(otmp)	(is_dwarvish_armor(otmp)\
256				|| (otmp)->otyp == DWARVISH_SPEAR\
257				|| (otmp)->otyp == DWARVISH_SHORT_SWORD\
258				|| (otmp)->otyp == DWARVISH_MATTOCK)
259
260/* Gnomish gear */
261#define is_gnomish_obj(otmp)	(is_gnomish_armor(otmp))
262
263/* Light sources */
264#define Is_candle(otmp) (otmp->otyp == TALLOW_CANDLE || \
265			 otmp->otyp == WAX_CANDLE)
266#define MAX_OIL_IN_FLASK 400	/* maximum amount of oil in a potion of oil */
267
268/* MAGIC_LAMP intentionally excluded below */
269/* age field of this is relative age rather than absolute */
270#define age_is_relative(otmp)	((otmp)->otyp == BRASS_LANTERN\
271				|| (otmp)->otyp == OIL_LAMP\
272				|| (otmp)->otyp == CANDELABRUM_OF_INVOCATION\
273				|| (otmp)->otyp == TALLOW_CANDLE\
274				|| (otmp)->otyp == WAX_CANDLE\
275				|| (otmp)->otyp == POT_OIL)
276/* object can be ignited */
277#define ignitable(otmp)	((otmp)->otyp == BRASS_LANTERN\
278				|| (otmp)->otyp == OIL_LAMP\
279				|| (otmp)->otyp == CANDELABRUM_OF_INVOCATION\
280				|| (otmp)->otyp == TALLOW_CANDLE\
281				|| (otmp)->otyp == WAX_CANDLE\
282				|| (otmp)->otyp == POT_OIL)
283
284/* special stones */
285#define is_graystone(obj)	((obj)->otyp == LUCKSTONE || \
286				 (obj)->otyp == LOADSTONE || \
287				 (obj)->otyp == FLINT     || \
288				 (obj)->otyp == TOUCHSTONE)
289
290/* misc */
291#ifdef KOPS
292#define is_flimsy(otmp)		(objects[(otmp)->otyp].oc_material <= LEATHER || \
293				 (otmp)->otyp == RUBBER_HOSE)
294#else
295#define is_flimsy(otmp)		(objects[(otmp)->otyp].oc_material <= LEATHER)
296#endif
297
298/* helpers, simple enough to be macros */
299#define is_plural(o)	((o)->quan > 1 || \
300			 (o)->oartifact == ART_EYES_OF_THE_OVERWORLD)
301
302/* Flags for get_obj_location(). */
303#define CONTAINED_TOO	0x1
304#define BURIED_TOO	0x2
305
306#endif /* OBJ_H */
307