Files
nethack/include/obj.h
nethack.allison e7948e258c oextra obj.h follow-up (trunk only)
Just add some notes to obj.h around oextra.
2006-04-15 13:09:57 +00:00

368 lines
14 KiB
C

/* SCCS Id: @(#)obj.h 3.5 2006/04/15 */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
#ifndef OBJ_H
#define OBJ_H
/* #define obj obj_nh */ /* uncomment for SCO UNIX, which has a conflicting
* typedef for "obj" in <sys/types.h> */
union vptrs {
struct obj *v_nexthere; /* floor location lists */
struct obj *v_ocontainer; /* point back to container */
struct monst *v_ocarry; /* point back to carrying monst */
};
/****
*** oextra -- collection of all object extensions
** (see the note at the bottom of this file before adding oextra fields)
*/
struct oextra {
char *oname; /* ptr to name of object */
struct monst *omonst; /* ptr to attached monst struct */
unsigned *omid; /* ptr to m_id */
long *olong; /* ptr to misc long (temporary gold object) */
char *omailcmd; /* response_cmd for mail deliver */
};
struct obj {
struct obj *nobj;
union vptrs v;
#define nexthere v.v_nexthere
#define ocontainer v.v_ocontainer
#define ocarry v.v_ocarry
struct obj *cobj; /* contents list for containers */
unsigned o_id;
xchar ox,oy;
short otyp; /* object class number */
unsigned owt;
long quan; /* number of items */
schar spe; /* quality of weapon, armor or ring (+ or -)
number of charges for wand ( >= -1 )
marks your eggs, tin variety and spinach tins
royal coffers for a court ( == 2)
tells which fruit a fruit is
special for uball and amulet
historic and gender for statues */
#define STATUE_HISTORIC 0x01
#define STATUE_MALE 0x02
#define STATUE_FEMALE 0x04
char oclass; /* object class */
char invlet; /* designation in inventory */
char oartifact; /* artifact array index */
xchar where; /* where the object thinks it is */
#define OBJ_FREE 0 /* object not attached to anything */
#define OBJ_FLOOR 1 /* object on floor */
#define OBJ_CONTAINED 2 /* object in a container */
#define OBJ_INVENT 3 /* object in the hero's inventory */
#define OBJ_MINVENT 4 /* object in a monster inventory */
#define OBJ_MIGRATING 5 /* object sent off to another level */
#define OBJ_BURIED 6 /* object buried */
#define OBJ_ONBILL 7 /* object on shk bill */
#define NOBJ_STATES 8
xchar timed; /* # of fuses (timers) attached to this obj */
Bitfield(cursed,1);
Bitfield(blessed,1);
Bitfield(unpaid,1); /* on some bill */
Bitfield(no_charge,1); /* if shk shouldn't charge for this */
Bitfield(known,1); /* exact nature known */
Bitfield(dknown,1); /* color or text known */
Bitfield(bknown,1); /* blessing or curse known */
Bitfield(rknown,1); /* rustproof or not known */
Bitfield(oeroded,2); /* rusted/burnt weapon/armor */
Bitfield(oeroded2,2); /* corroded/rotted weapon/armor */
#define greatest_erosion(otmp) (int)((otmp)->oeroded > (otmp)->oeroded2 ? (otmp)->oeroded : (otmp)->oeroded2)
#define MAX_ERODE 3
#define orotten oeroded /* rotten food */
#define odiluted oeroded /* diluted potions */
#define norevive oeroded2
Bitfield(oerodeproof,1); /* erodeproof weapon/armor */
Bitfield(olocked,1); /* object is locked */
Bitfield(obroken,1); /* lock has been broken */
Bitfield(otrapped,1); /* container is trapped */
/* or accidental tripped rolling boulder trap */
#define opoisoned otrapped /* object (weapon) is coated with poison */
Bitfield(recharged,3); /* number of times it's been recharged */
#define on_ice recharged /* corpse on ice */
Bitfield(lamplit,1); /* a light-source -- can be lit */
#ifdef INVISIBLE_OBJECTS
Bitfield(oinvis,1); /* invisible */
#endif
Bitfield(greased,1); /* covered with grease */
/* 2 free bits */
Bitfield(in_use,1); /* for magic items before useup items */
Bitfield(bypass,1); /* mark this as an object to be skipped by bhito() */
Bitfield(cknown,1); /* contents of container assumed to be known */
Bitfield(lknown,1); /* locked/unlocked status is known */
/* 4 free bits */
int corpsenm; /* type of corpse is mons[corpsenm] */
#define leashmon corpsenm /* gets m_id of attached pet */
#define spestudied corpsenm /* # of times a spellbook has been studied */
#define fromsink corpsenm /* a potion from a sink */
unsigned oeaten; /* nutrition left in food, if partly eaten */
long age; /* creation date */
long owornmask;
struct oextra *oextra; /* pointer to oextra struct */
};
#define newobj() (struct obj *)alloc(sizeof(struct obj))
/***
** oextra referencing and testing macros
*/
#define ONAME(o) ((o)->oextra->oname)
#define OMID(o) ((o)->oextra->omid)
#define OMONST(o) ((o)->oextra->omonst)
#define OLONG(o) ((o)->oextra->olong)
#define OMAILCMD(o) ((o)->oextra->omailcmd)
#define has_oname(o) ((o)->oextra && ONAME(o))
#define has_omid(o) ((o)->oextra && OMID(o))
#define has_omonst(o) ((o)->oextra && OMONST(o))
#define has_olong(o) ((o)->oextra && OLONG(o))
#define has_omailcmd(o) ((o)->oextra && OMAILCMD(o))
/* Weapons and weapon-tools */
/* KMH -- now based on skill categories. Formerly:
* #define is_sword(otmp) (otmp->oclass == WEAPON_CLASS && \
* objects[otmp->otyp].oc_wepcat == WEP_SWORD)
* #define is_blade(otmp) (otmp->oclass == WEAPON_CLASS && \
* (objects[otmp->otyp].oc_wepcat == WEP_BLADE || \
* objects[otmp->otyp].oc_wepcat == WEP_SWORD))
* #define is_weptool(o) ((o)->oclass == TOOL_CLASS && \
* objects[(o)->otyp].oc_weptool)
* #define is_multigen(otyp) (otyp <= SHURIKEN)
* #define is_poisonable(otyp) (otyp <= BEC_DE_CORBIN)
*/
#define is_blade(otmp) (otmp->oclass == WEAPON_CLASS && \
objects[otmp->otyp].oc_skill >= P_DAGGER && \
objects[otmp->otyp].oc_skill <= P_SABER)
#define is_axe(otmp) ((otmp->oclass == WEAPON_CLASS || \
otmp->oclass == TOOL_CLASS) && \
objects[otmp->otyp].oc_skill == P_AXE)
#define is_pick(otmp) ((otmp->oclass == WEAPON_CLASS || \
otmp->oclass == TOOL_CLASS) && \
objects[otmp->otyp].oc_skill == P_PICK_AXE)
#define is_sword(otmp) (otmp->oclass == WEAPON_CLASS && \
objects[otmp->otyp].oc_skill >= P_SHORT_SWORD && \
objects[otmp->otyp].oc_skill <= P_SABER)
#define is_pole(otmp) ((otmp->oclass == WEAPON_CLASS || \
otmp->oclass == TOOL_CLASS) && \
(objects[otmp->otyp].oc_skill == P_POLEARMS || \
objects[otmp->otyp].oc_skill == P_LANCE))
#define is_spear(otmp) (otmp->oclass == WEAPON_CLASS && \
objects[otmp->otyp].oc_skill >= P_SPEAR && \
objects[otmp->otyp].oc_skill <= P_JAVELIN)
#define is_launcher(otmp) (otmp->oclass == WEAPON_CLASS && \
objects[otmp->otyp].oc_skill >= P_BOW && \
objects[otmp->otyp].oc_skill <= P_CROSSBOW)
#define is_ammo(otmp) ((otmp->oclass == WEAPON_CLASS || \
otmp->oclass == GEM_CLASS) && \
objects[otmp->otyp].oc_skill >= -P_CROSSBOW && \
objects[otmp->otyp].oc_skill <= -P_BOW)
#define ammo_and_launcher(otmp,ltmp) \
(is_ammo(otmp) && (ltmp) && \
objects[(otmp)->otyp].oc_skill == -objects[(ltmp)->otyp].oc_skill)
#define is_missile(otmp) ((otmp->oclass == WEAPON_CLASS || \
otmp->oclass == TOOL_CLASS) && \
objects[otmp->otyp].oc_skill >= -P_BOOMERANG && \
objects[otmp->otyp].oc_skill <= -P_DART)
#define is_weptool(o) ((o)->oclass == TOOL_CLASS && \
objects[(o)->otyp].oc_skill != P_NONE)
#define bimanual(otmp) ((otmp->oclass == WEAPON_CLASS || \
otmp->oclass == TOOL_CLASS) && \
objects[otmp->otyp].oc_bimanual)
#define is_multigen(otmp) (otmp->oclass == WEAPON_CLASS && \
objects[otmp->otyp].oc_skill >= -P_SHURIKEN && \
objects[otmp->otyp].oc_skill <= -P_BOW)
#define is_poisonable(otmp) (otmp->oclass == WEAPON_CLASS && \
objects[otmp->otyp].oc_skill >= -P_SHURIKEN && \
objects[otmp->otyp].oc_skill <= -P_BOW)
#define uslinging() (uwep && objects[uwep->otyp].oc_skill == P_SLING)
/* Armor */
#define is_shield(otmp) (otmp->oclass == ARMOR_CLASS && \
objects[otmp->otyp].oc_armcat == ARM_SHIELD)
#define is_helmet(otmp) (otmp->oclass == ARMOR_CLASS && \
objects[otmp->otyp].oc_armcat == ARM_HELM)
#define is_boots(otmp) (otmp->oclass == ARMOR_CLASS && \
objects[otmp->otyp].oc_armcat == ARM_BOOTS)
#define is_gloves(otmp) (otmp->oclass == ARMOR_CLASS && \
objects[otmp->otyp].oc_armcat == ARM_GLOVES)
#define is_cloak(otmp) (otmp->oclass == ARMOR_CLASS && \
objects[otmp->otyp].oc_armcat == ARM_CLOAK)
#define is_shirt(otmp) (otmp->oclass == ARMOR_CLASS && \
objects[otmp->otyp].oc_armcat == ARM_SHIRT)
#define is_suit(otmp) (otmp->oclass == ARMOR_CLASS && \
objects[otmp->otyp].oc_armcat == ARM_SUIT)
#define is_elven_armor(otmp) ((otmp)->otyp == ELVEN_LEATHER_HELM\
|| (otmp)->otyp == ELVEN_MITHRIL_COAT\
|| (otmp)->otyp == ELVEN_CLOAK\
|| (otmp)->otyp == ELVEN_SHIELD\
|| (otmp)->otyp == ELVEN_BOOTS)
#define is_orcish_armor(otmp) ((otmp)->otyp == ORCISH_HELM\
|| (otmp)->otyp == ORCISH_CHAIN_MAIL\
|| (otmp)->otyp == ORCISH_RING_MAIL\
|| (otmp)->otyp == ORCISH_CLOAK\
|| (otmp)->otyp == URUK_HAI_SHIELD\
|| (otmp)->otyp == ORCISH_SHIELD)
#define is_dwarvish_armor(otmp) ((otmp)->otyp == DWARVISH_IRON_HELM\
|| (otmp)->otyp == DWARVISH_MITHRIL_COAT\
|| (otmp)->otyp == DWARVISH_CLOAK\
|| (otmp)->otyp == DWARVISH_ROUNDSHIELD)
#define is_gnomish_armor(otmp) (FALSE)
/* Eggs and other food */
#define MAX_EGG_HATCH_TIME 200 /* longest an egg can remain unhatched */
#define stale_egg(egg) ((monstermoves - (egg)->age) > (2*MAX_EGG_HATCH_TIME))
#define ofood(o) ((o)->otyp == CORPSE || (o)->otyp == EGG || (o)->otyp == TIN)
#define polyfodder(obj) (ofood(obj) && pm_to_cham((obj)->corpsenm) != NON_PM)
#define mlevelgain(obj) (ofood(obj) && (obj)->corpsenm == PM_WRAITH)
#define mhealup(obj) (ofood(obj) && (obj)->corpsenm == PM_NURSE)
/* Containers */
#define carried(o) ((o)->where == OBJ_INVENT)
#define mcarried(o) ((o)->where == OBJ_MINVENT)
#define Has_contents(o) (/* (Is_container(o) || (o)->otyp == STATUE) && */ \
(o)->cobj != (struct obj *)0)
#define Is_container(o) ((o)->otyp >= LARGE_BOX && (o)->otyp <= BAG_OF_TRICKS)
#define Is_box(otmp) (otmp->otyp == LARGE_BOX || otmp->otyp == CHEST)
#define Is_mbag(otmp) (otmp->otyp == BAG_OF_HOLDING || \
otmp->otyp == BAG_OF_TRICKS)
/* dragon gear */
#define Is_dragon_scales(obj) ((obj)->otyp >= GRAY_DRAGON_SCALES && \
(obj)->otyp <= YELLOW_DRAGON_SCALES)
#define Is_dragon_mail(obj) ((obj)->otyp >= GRAY_DRAGON_SCALE_MAIL && \
(obj)->otyp <= YELLOW_DRAGON_SCALE_MAIL)
#define Is_dragon_armor(obj) (Is_dragon_scales(obj) || Is_dragon_mail(obj))
#define Dragon_scales_to_pm(obj) &mons[PM_GRAY_DRAGON + (obj)->otyp \
- GRAY_DRAGON_SCALES]
#define Dragon_mail_to_pm(obj) &mons[PM_GRAY_DRAGON + (obj)->otyp \
- GRAY_DRAGON_SCALE_MAIL]
#define Dragon_to_scales(pm) (GRAY_DRAGON_SCALES + (pm - mons))
/* Elven gear */
#define is_elven_weapon(otmp) ((otmp)->otyp == ELVEN_ARROW\
|| (otmp)->otyp == ELVEN_SPEAR\
|| (otmp)->otyp == ELVEN_DAGGER\
|| (otmp)->otyp == ELVEN_SHORT_SWORD\
|| (otmp)->otyp == ELVEN_BROADSWORD\
|| (otmp)->otyp == ELVEN_BOW)
#define is_elven_obj(otmp) (is_elven_armor(otmp) || is_elven_weapon(otmp))
/* Orcish gear */
#define is_orcish_obj(otmp) (is_orcish_armor(otmp)\
|| (otmp)->otyp == ORCISH_ARROW\
|| (otmp)->otyp == ORCISH_SPEAR\
|| (otmp)->otyp == ORCISH_DAGGER\
|| (otmp)->otyp == ORCISH_SHORT_SWORD\
|| (otmp)->otyp == ORCISH_BOW)
/* Dwarvish gear */
#define is_dwarvish_obj(otmp) (is_dwarvish_armor(otmp)\
|| (otmp)->otyp == DWARVISH_SPEAR\
|| (otmp)->otyp == DWARVISH_SHORT_SWORD\
|| (otmp)->otyp == DWARVISH_MATTOCK)
/* Gnomish gear */
#define is_gnomish_obj(otmp) (is_gnomish_armor(otmp))
/* Light sources */
#define Is_candle(otmp) (otmp->otyp == TALLOW_CANDLE || \
otmp->otyp == WAX_CANDLE)
#define MAX_OIL_IN_FLASK 400 /* maximum amount of oil in a potion of oil */
/* MAGIC_LAMP intentionally excluded below */
/* age field of this is relative age rather than absolute */
#define age_is_relative(otmp) ((otmp)->otyp == BRASS_LANTERN\
|| (otmp)->otyp == OIL_LAMP\
|| (otmp)->otyp == CANDELABRUM_OF_INVOCATION\
|| (otmp)->otyp == TALLOW_CANDLE\
|| (otmp)->otyp == WAX_CANDLE\
|| (otmp)->otyp == POT_OIL)
/* object can be ignited */
#define ignitable(otmp) ((otmp)->otyp == BRASS_LANTERN\
|| (otmp)->otyp == OIL_LAMP\
|| (otmp)->otyp == CANDELABRUM_OF_INVOCATION\
|| (otmp)->otyp == TALLOW_CANDLE\
|| (otmp)->otyp == WAX_CANDLE\
|| (otmp)->otyp == POT_OIL)
/* special stones */
#define is_graystone(obj) ((obj)->otyp == LUCKSTONE || \
(obj)->otyp == LOADSTONE || \
(obj)->otyp == FLINT || \
(obj)->otyp == TOUCHSTONE)
/* misc */
#ifdef KOPS
#define is_flimsy(otmp) (objects[(otmp)->otyp].oc_material <= LEATHER || \
(otmp)->otyp == RUBBER_HOSE)
#else
#define is_flimsy(otmp) (objects[(otmp)->otyp].oc_material <= LEATHER)
#endif
/* helpers, simple enough to be macros */
#define is_plural(o) ((o)->quan > 1 || \
(o)->oartifact == ART_EYES_OF_THE_OVERWORLD)
/* Flags for get_obj_location(). */
#define CONTAINED_TOO 0x1
#define BURIED_TOO 0x2
/*
* Notes for adding new oextra structures:
*
* 1. Add the structure definition and any required macros in an appropriate
* header file that precedes this one.
* 2. Add a pointer to your new struct to the oextra struct in this file.
* 3. Add a referencing macro at the bottom of this file after the mextra
* struct (see ONAME, OMONST, OMIN, OLONG, or OMAILCMD for examples).
* 4. Add a testing macro after the set of referencing macros
* (see has_oname(), has_omonst(), has_omin(), has_olong(),
* has_omailcmd() for examples).
* 5. Create a newXX(otmp) function and possibly a free_XX(otmp) function
* in an appropriate new or existing source file and add a prototype
* for it to include/extern.h. The majority of these are currently
* located in mkobj.c for convenience.
*
* void FDECL(newXX, (struct obj *));
* void FDECL(free_XX, (struct obj *));
*
* void
* newxx(otmp)
* struct obj *otmp;
* {
* if (!otmp->mextra) otmp->oextra = newoextra();
* if (!XX(otmp)) {
* XX(otmp) = (struct XX *)alloc(sizeof(struct xx));
* (void) memset((genericptr_t) XX(otmp),
* 0, sizeof(struct xx));
* }
* }
*
* 6. Adjust size_obj() in src/cmd.c appropriately.
* 7. Adjust dealloc_oextra() in src/mkobj.c to clean up
* properly during obj deallocation.
* 8. Adjust copy_oextra() in src/mkobj.c to make duplicate
* copies of your struct or data onto another obj struct.
* 9. Adjust restobj() in src/restore.c to deal with your
* struct or data during a restore.
* 10. Adjust saveobj() in src/save.c to deal with your
* struct or data during a save.
*/
#endif /* OBJ_H */