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