1 /* aNetHack 0.0.1 mkobj.c $ANH-Date: 1462067745 2016/05/01 01:55:45 $ $ANH-Branch: master $:$ANH-Revision: 1.122 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* aNetHack may be freely redistributed. See license for details. */
7 STATIC_DCL
void FDECL(mkbox_cnts
, (struct obj
*));
8 STATIC_DCL
void FDECL(maybe_adjust_light
, (struct obj
*, int));
9 STATIC_DCL
void FDECL(obj_timer_checks
, (struct obj
*,
10 XCHAR_P
, XCHAR_P
, int));
11 STATIC_DCL
void FDECL(container_weight
, (struct obj
*));
12 STATIC_DCL
struct obj
*FDECL(save_mtraits
, (struct obj
*, struct monst
*));
13 STATIC_DCL
void FDECL(objlist_sanity
, (struct obj
*, int, const char *));
14 STATIC_DCL
void FDECL(mon_obj_sanity
, (struct monst
*, const char *));
15 STATIC_DCL
const char *FDECL(where_name
, (struct obj
*));
16 STATIC_DCL
void FDECL(insane_object
, (struct obj
*, const char *,
17 const char *, struct monst
*));
18 STATIC_DCL
void FDECL(check_contained
, (struct obj
*, const char *));
19 STATIC_DCL
void FDECL(sanity_check_worn
, (struct obj
*));
22 int iprob
; /* probability of an item type */
23 char iclass
; /* item class */
26 static const struct icp mkobjprobs
[] = { { 10, WEAPON_CLASS
},
36 { 1, AMULET_CLASS
} };
38 static const struct icp boxiprobs
[] = { { 18, GEM_CLASS
},
46 { 1, AMULET_CLASS
} };
48 static const struct icp rogueprobs
[] = { { 12, WEAPON_CLASS
},
56 static const struct icp hellprobs
[] = { { 20, WEAPON_CLASS
},
65 { 4, AMULET_CLASS
} };
70 struct oextra
*oextra
;
72 oextra
= (struct oextra
*) alloc(sizeof(struct oextra
));
85 struct oextra
*x
= o
->oextra
;
89 free((genericptr_t
) x
->oname
);
91 free_omonst(o
); /* 'o' rather than 'x' */
93 free((genericptr_t
) x
->omid
);
95 free((genericptr_t
) x
->olong
);
97 free((genericptr_t
) x
->omailcmd
);
99 free((genericptr_t
) x
);
100 o
->oextra
= (struct oextra
*) 0;
109 otmp
->oextra
= newoextra();
112 struct monst
*m
= newmonst();
124 struct monst
*m
= OMONST(otmp
);
129 free((genericptr_t
) m
);
130 OMONST(otmp
) = (struct monst
*) 0;
140 otmp
->oextra
= newoextra();
142 OMID(otmp
) = (unsigned *) alloc(sizeof (unsigned));
143 (void) memset((genericptr_t
) OMID(otmp
), 0, sizeof (unsigned));
151 if (otmp
->oextra
&& OMID(otmp
)) {
152 free((genericptr_t
) OMID(otmp
));
153 OMID(otmp
) = (unsigned *) 0;
162 otmp
->oextra
= newoextra();
164 OLONG(otmp
) = (long *) alloc(sizeof (long));
165 (void) memset((genericptr_t
) OLONG(otmp
), 0, sizeof (long));
173 if (otmp
->oextra
&& OLONG(otmp
)) {
174 free((genericptr_t
) OLONG(otmp
));
175 OLONG(otmp
) = (long *) 0;
180 new_omailcmd(otmp
, response_cmd
)
182 const char *response_cmd
;
185 otmp
->oextra
= newoextra();
188 OMAILCMD(otmp
) = dupstr(response_cmd
);
195 if (otmp
->oextra
&& OMAILCMD(otmp
)) {
196 free((genericptr_t
) OMAILCMD(otmp
));
197 OMAILCMD(otmp
) = (char *) 0;
202 mkobj_at(let
, x
, y
, artif
)
209 otmp
= mkobj(let
, artif
);
210 place_object(otmp
, x
, y
);
215 mksobj_at(otyp
, x
, y
, init
, artif
)
221 otmp
= mksobj(otyp
, init
, artif
);
222 place_object(otmp
, x
, y
);
231 int tprob
, i
, prob
= rnd(1000);
233 if (oclass
== RANDOM_CLASS
) {
234 const struct icp
*iprobs
= Is_rogue_level(&u
.uz
)
235 ? (const struct icp
*) rogueprobs
236 : Inhell
? (const struct icp
*) hellprobs
237 : (const struct icp
*) mkobjprobs
;
239 for (tprob
= rnd(100); (tprob
-= iprobs
->iprob
) > 0; iprobs
++)
241 oclass
= iprobs
->iclass
;
244 i
= bases
[(int) oclass
];
245 while ((prob
-= objects
[i
].oc_prob
) > 0)
248 if (objects
[i
].oc_class
!= oclass
|| !OBJ_NAME(objects
[i
]))
249 panic("probtype error, oclass=%d i=%d", (int) oclass
, i
);
251 return mksobj(i
, TRUE
, artif
);
259 register struct obj
*otmp
;
261 box
->cobj
= (struct obj
*) 0;
275 /* initial inventory: sack starts out empty */
276 if (moves
<= 1 && !in_mklev
) {
289 for (n
= rn2(n
+ 1); n
> 0; n
--) {
290 if (box
->otyp
== ICE_BOX
) {
291 if (!(otmp
= mksobj(CORPSE
, TRUE
, TRUE
)))
293 /* Note: setting age to 0 is correct. Age has a different
294 * from usual meaning for objects stored in ice boxes. -KAA
298 (void) stop_timer(ROT_CORPSE
, obj_to_any(otmp
));
299 (void) stop_timer(REVIVE_MON
, obj_to_any(otmp
));
303 const struct icp
*iprobs
= boxiprobs
;
305 for (tprob
= rnd(100); (tprob
-= iprobs
->iprob
) > 0; iprobs
++)
307 if (!(otmp
= mkobj(iprobs
->iclass
, TRUE
)))
310 /* handle a couple of special cases */
311 if (otmp
->oclass
== COIN_CLASS
) {
312 /* 2.5 x level's usual amount; weight adjusted below */
313 otmp
->quan
= (long) (rnd(level_difficulty() + 2) * rnd(75));
314 otmp
->owt
= weight(otmp
);
316 while (otmp
->otyp
== ROCK
) {
317 otmp
->otyp
= rnd_class(DILITHIUM_CRYSTAL
, LOADSTONE
);
320 otmp
->owt
= weight(otmp
);
322 if (box
->otyp
== BAG_OF_HOLDING
) {
326 otmp
->owt
= weight(otmp
);
328 while (otmp
->otyp
== WAN_CANCELLATION
)
329 otmp
->otyp
= rnd_class(WAN_LIGHT
, WAN_LIGHTNING
);
332 (void) add_to_container(box
, otmp
);
336 /* select a random, common monster type */
340 register struct permonst
*ptr
;
342 unsigned short excludeflags
;
344 /* Plan A: get a level-appropriate common monster */
349 /* Plan B: get any common monster */
350 excludeflags
= G_UNIQ
| G_NOGEN
| (Inhell
? G_NOHELL
: G_HELL
);
352 i
= rn1(SPECIAL_PM
- LOW_PM
, LOW_PM
);
354 } while ((ptr
->geno
& excludeflags
) != 0);
360 copy_oextra(obj2
, obj1
)
361 struct obj
*obj2
, *obj1
;
363 if (!obj2
|| !obj1
|| !obj1
->oextra
)
367 obj2
->oextra
= newoextra();
369 oname(obj2
, ONAME(obj1
));
370 if (has_omonst(obj1
)) {
373 (void) memcpy((genericptr_t
) OMONST(obj2
),
374 (genericptr_t
) OMONST(obj1
), sizeof(struct monst
));
375 OMONST(obj2
)->mextra
= (struct mextra
*) 0;
376 OMONST(obj2
)->nmon
= (struct monst
*) 0;
378 OMONST(obj2
)->m_id
= context
.ident
++;
379 if (OMONST(obj2
)->m_id
) /* ident overflowed */
380 OMONST(obj2
)->m_id
= context
.ident
++;
382 if (OMONST(obj1
)->mextra
)
383 copy_mextra(OMONST(obj2
), OMONST(obj1
));
385 if (has_omid(obj1
)) {
388 (void) memcpy((genericptr_t
) OMID(obj2
), (genericptr_t
) OMID(obj1
),
391 if (has_olong(obj1
)) {
394 (void) memcpy((genericptr_t
) OLONG(obj2
), (genericptr_t
) OLONG(obj1
),
397 if (has_omailcmd(obj1
)) {
398 new_omailcmd(obj2
, OMAILCMD(obj1
));
403 * Split obj so that it gets size gets reduced by num. The quantity num is
404 * put in the object structure delivered by this call. The returned object
405 * has its wornmask cleared and is positioned just following the original
406 * in the nobj chain (and nexthere chain when on the floor).
415 if (obj
->cobj
|| num
<= 0L || obj
->quan
<= num
)
416 panic("splitobj"); /* can't split containers */
418 *otmp
= *obj
; /* copies whole structure */
419 otmp
->oextra
= (struct oextra
*) 0;
420 otmp
->o_id
= context
.ident
++;
422 otmp
->o_id
= context
.ident
++; /* ident overflowed */
423 otmp
->timed
= 0; /* not timed, yet */
424 otmp
->lamplit
= 0; /* ditto */
425 otmp
->owornmask
= 0L; /* new object isn't worn */
427 obj
->owt
= weight(obj
);
429 otmp
->owt
= weight(otmp
); /* -= obj->owt ? */
431 context
.objsplit
.parent_oid
= obj
->o_id
;
432 context
.objsplit
.child_oid
= otmp
->o_id
;
434 /* Only set nexthere when on the floor, nexthere is also used */
435 /* as a back pointer to the container object when contained. */
436 if (obj
->where
== OBJ_FLOOR
)
437 obj
->nexthere
= otmp
;
438 copy_oextra(otmp
, obj
);
440 free_omid(otmp
); /* only one association with m_id*/
442 splitbill(obj
, otmp
);
444 obj_split_timers(obj
, otmp
);
445 if (obj_sheds_light(obj
))
446 obj_split_light_source(obj
, otmp
);
450 /* try to find the stack obj was split from, then merge them back together;
451 returns the combined object if unsplit is successful, null otherwise */
456 unsigned target_oid
= 0;
457 struct obj
*oparent
= 0, *ochild
= 0, *list
= 0;
460 * We don't operate on floor objects (we're following o->nobj rather
461 * than o->nexthere), on free objects (don't know which list to use when
462 * looking for obj's parent or child), on bill objects (too complicated,
463 * not needed), or on buried or migrating objects (not needed).
464 * [This could be improved, but at present additional generality isn't
467 switch (obj
->where
) {
474 return (struct obj
*) 0;
479 list
= obj
->ocarry
->minvent
;
482 list
= obj
->ocontainer
->cobj
;
486 /* first try the expected case; obj is split from another stack */
487 if (obj
->o_id
== context
.objsplit
.child_oid
) {
488 /* parent probably precedes child and will require list traversal */
490 target_oid
= context
.objsplit
.parent_oid
;
491 if (obj
->nobj
&& obj
->nobj
->o_id
== target_oid
)
493 } else if (obj
->o_id
== context
.objsplit
.parent_oid
) {
494 /* alternate scenario: another stack was split from obj;
495 child probably follows parent and will be found here */
497 target_oid
= context
.objsplit
.child_oid
;
498 if (obj
->nobj
&& obj
->nobj
->o_id
== target_oid
)
501 /* if we have only half the split, scan obj's list to find other half */
502 if (ochild
&& !oparent
) {
504 for (obj
= list
; obj
; obj
= obj
->nobj
)
505 if (obj
->o_id
== target_oid
) {
509 } else if (oparent
&& !ochild
) {
510 /* alternate scenario */
511 for (obj
= list
; obj
; obj
= obj
->nobj
)
512 if (obj
->o_id
== target_oid
) {
517 /* if we have both parent and child, try to merge them;
518 if successful, return the combined stack, otherwise return null */
519 return (oparent
&& ochild
&& merged(&oparent
, &ochild
)) ? oparent
: 0;
522 /* reset splitobj()/unsplitobj() context */
526 context
.objsplit
.parent_oid
= context
.objsplit
.child_oid
= 0;
530 * Insert otmp right after obj in whatever chain(s) it is on. Then extract
531 * obj from the chain(s). This function does a literal swap. It is up to
532 * the caller to provide a valid context for the swap. When done, obj will
533 * still exist, but not on any chain.
535 * Note: Don't use use obj_extract_self() -- we are doing an in-place swap,
536 * not actually moving something.
539 replace_object(obj
, otmp
)
543 otmp
->where
= obj
->where
;
544 switch (obj
->where
) {
549 otmp
->nobj
= obj
->nobj
;
551 extract_nobj(obj
, &invent
);
554 otmp
->nobj
= obj
->nobj
;
555 otmp
->ocontainer
= obj
->ocontainer
;
557 extract_nobj(obj
, &obj
->ocontainer
->cobj
);
560 otmp
->nobj
= obj
->nobj
;
561 otmp
->ocarry
= obj
->ocarry
;
563 extract_nobj(obj
, &obj
->ocarry
->minvent
);
566 otmp
->nobj
= obj
->nobj
;
567 otmp
->nexthere
= obj
->nexthere
;
571 obj
->nexthere
= otmp
;
572 extract_nobj(obj
, &fobj
);
573 extract_nexthere(obj
, &level
.objects
[obj
->ox
][obj
->oy
]);
576 panic("replace_object: obj position");
582 * Create a dummy duplicate to put on shop bill. The duplicate exists
583 * only in the billobjs chain. This function is used when a shop object
584 * is being altered, and a copy of the original is needed for billing
585 * purposes. For example, when eating, where an interruption will yield
586 * an object which is different from what it started out as; the "I x"
587 * command needs to display the original object.
589 * The caller is responsible for checking otmp->unpaid and
590 * costly_spot(u.ux, u.uy). This function will make otmp no charge.
592 * Note that check_unpaid_usage() should be used instead for partial
593 * usage of an object.
596 bill_dummy_object(otmp
)
597 register struct obj
*otmp
;
599 register struct obj
*dummy
;
603 cost
= unpaid_cost(otmp
, FALSE
);
604 subfrombill(otmp
, shop_keeper(*u
.ushops
));
608 dummy
->oextra
= (struct oextra
*) 0;
609 dummy
->where
= OBJ_FREE
;
610 dummy
->o_id
= context
.ident
++;
612 dummy
->o_id
= context
.ident
++; /* ident overflowed */
614 copy_oextra(dummy
, otmp
);
616 free_omid(dummy
); /* only one association with m_id*/
617 if (Is_candle(dummy
))
619 dummy
->owornmask
= 0L; /* dummy object is not worn */
620 addtobill(dummy
, FALSE
, TRUE
, TRUE
);
622 alter_cost(dummy
, -cost
);
623 /* no_charge is only valid for some locations */
625 (otmp
->where
== OBJ_FLOOR
|| otmp
->where
== OBJ_CONTAINED
) ? 1 : 0;
630 /* alteration types; must match COST_xxx macros in hack.h */
631 static const char *const alteration_verbs
[] = {
632 "cancel", "drain", "uncharge", "unbless", "uncurse", "disenchant",
633 "degrade", "dilute", "erase", "burn", "neutralize", "destroy", "splatter",
634 "bite", "open", "break the lock on", "rust", "rot", "tarnish"
637 /* possibly bill for an object which the player has just modified */
639 costly_alteration(obj
, alter_type
)
646 const char *those
, *them
;
647 struct monst
*shkp
= 0;
649 if (alter_type
< 0 || alter_type
>= SIZE(alteration_verbs
)) {
650 impossible("invalid alteration type (%d)", alter_type
);
654 ox
= oy
= 0; /* lint suppression */
655 objroom
= '\0'; /* ditto */
656 if (carried(obj
) || obj
->where
== OBJ_FREE
) {
657 /* OBJ_FREE catches obj_no_longer_held()'s transformation
658 of crysknife back into worm tooth; the object has been
659 removed from inventory but not necessarily placed at
660 its new location yet--the unpaid flag will still be set
661 if this item is owned by a shop */
665 /* this get_obj_location shouldn't fail, but if it does,
666 use hero's location */
667 if (!get_obj_location(obj
, &ox
, &oy
, CONTAINED_TOO
))
668 ox
= u
.ux
, oy
= u
.uy
;
669 if (!costly_spot(ox
, oy
))
671 objroom
= *in_rooms(ox
, oy
, SHOPBASE
);
672 /* if no shop cares about it, we're done */
673 if (!billable(&shkp
, obj
, objroom
, FALSE
))
678 those
= "that", them
= "it";
680 those
= "those", them
= "them";
682 /* when shopkeeper describes the object as being uncursed or unblessed
683 hero will know that it is now uncursed; will also make the feedback
684 from `I x' after bill_dummy_object() be more specific for this item */
685 set_bknown
= (alter_type
== COST_UNCURS
|| alter_type
== COST_UNBLSS
);
687 switch (obj
->where
) {
688 case OBJ_FREE
: /* obj_no_longer_held() */
692 verbalize("You %s %s %s, you pay for %s!",
693 alteration_verbs
[alter_type
], those
, simpleonames(obj
),
695 bill_dummy_object(obj
);
700 if (costly_spot(u
.ux
, u
.uy
) && objroom
== *u
.ushops
) {
701 verbalize("You %s %s, you pay for %s!",
702 alteration_verbs
[alter_type
], those
, them
);
703 bill_dummy_object(obj
);
705 (void) stolen_value(obj
, ox
, oy
, FALSE
, FALSE
);
711 static const char dknowns
[] = { WAND_CLASS
, RING_CLASS
, POTION_CLASS
,
712 SCROLL_CLASS
, GEM_CLASS
, SPBOOK_CLASS
,
713 WEAPON_CLASS
, TOOL_CLASS
, 0 };
716 mksobj(otyp
, init
, artif
)
723 char let
= objects
[otyp
].oc_class
;
727 otmp
->age
= monstermoves
;
728 otmp
->o_id
= context
.ident
++;
730 otmp
->o_id
= context
.ident
++; /* ident overflowed */
734 otmp
->where
= OBJ_FREE
;
735 otmp
->dknown
= index(dknowns
, let
) ? 0 : 1;
736 if ((otmp
->otyp
>= ELVEN_SHIELD
&& otmp
->otyp
<= ORCISH_SHIELD
)
737 || otmp
->otyp
== SHIELD_OF_REFLECTION
738 || objects
[otmp
->otyp
].oc_merge
)
740 if (!objects
[otmp
->otyp
].oc_uses_known
)
744 otmp
->corpsenm
= NON_PM
;
749 otmp
->quan
= is_multigen(otmp
) ? (long) rn1(6, 6) : 1L;
752 otmp
->blessed
= rn2(2);
753 } else if (!rn2(10)) {
757 blessorcurse(otmp
, 10);
758 if (is_poisonable(otmp
) && !rn2(100))
761 if (artif
&& !rn2(20))
762 otmp
= mk_artifact(otmp
, (aligntyp
) A_NONE
);
766 switch (otmp
->otyp
) {
768 /* possibly overridden by mkcorpstat() */
771 otmp
->corpsenm
= undead_to_corpse(rndmonnum());
772 while ((mvitals
[otmp
->corpsenm
].mvflags
& G_NOCORPSE
)
775 /* perhaps rndmonnum() only wants to make G_NOCORPSE
777 this level; let's create an adventurer's corpse
779 otmp
->corpsenm
= PM_HUMAN
;
781 /* timer set below */
784 otmp
->corpsenm
= NON_PM
; /* generic egg */
786 for (tryct
= 200; tryct
> 0; --tryct
) {
787 mndx
= can_be_hatched(rndmonnum());
788 if (mndx
!= NON_PM
&& !dead_species(mndx
, TRUE
)) {
789 otmp
->corpsenm
= mndx
; /* typed egg */
793 /* timer set below */
796 otmp
->corpsenm
= NON_PM
; /* empty (so far) */
798 set_tin_variety(otmp
, SPINACH_TIN
);
800 for (tryct
= 200; tryct
> 0; --tryct
) {
801 mndx
= undead_to_corpse(rndmonnum());
802 if (mons
[mndx
].cnutrit
803 && !(mvitals
[mndx
].mvflags
& G_NOCORPSE
)) {
804 otmp
->corpsenm
= mndx
;
805 set_tin_variety(otmp
, RANDOM_TIN
);
809 blessorcurse(otmp
, 10);
812 otmp
->spe
= context
.current_fruit
;
813 flags
.made_fruit
= TRUE
;
816 otmp
->quan
= (long) rnd(2);
819 if (Is_pudding(otmp
)) {
821 otmp
->known
= otmp
->dknown
= 1;
822 otmp
->corpsenm
= PM_GRAY_OOZE
823 + (otmp
->otyp
- GLOB_OF_GRAY_OOZE
);
825 if (otmp
->otyp
!= CORPSE
&& otmp
->otyp
!= MEAT_RING
826 && otmp
->otyp
!= KELP_FROND
&& !rn2(6)) {
832 otmp
->corpsenm
= 0; /* LOADSTONE hack */
833 if (otmp
->otyp
== LOADSTONE
)
835 else if (otmp
->otyp
== ROCK
)
836 otmp
->quan
= (long) rn1(6, 6);
837 else if (otmp
->otyp
!= LUCKSTONE
&& !rn2(6))
843 switch (otmp
->otyp
) {
847 otmp
->age
= 20L * /* 400 or 200 */
848 (long) objects
[otmp
->otyp
].oc_cost
;
850 otmp
->quan
= 1L + (long) (rn2(2) ? rn2(7) : 0);
851 blessorcurse(otmp
, 5);
856 otmp
->age
= (long) rn1(500, 1000);
858 blessorcurse(otmp
, 5);
863 blessorcurse(otmp
, 2);
867 otmp
->olocked
= !!(rn2(5));
868 otmp
->otrapped
= !(rn2(10));
875 case EXPENSIVE_CAMERA
:
878 otmp
->spe
= rn1(70, 30);
882 blessorcurse(otmp
, 10);
886 blessorcurse(otmp
, 2);
895 otmp
->corpsenm
= rndmonnum();
896 while (is_human(&mons
[otmp
->corpsenm
]) && tryct2
++ < 30);
897 blessorcurse(otmp
, 4);
900 case BELL_OF_OPENING
:
907 case DRUM_OF_EARTHQUAKE
:
908 otmp
->spe
= rn1(5, 4);
913 if (otmp
->otyp
== AMULET_OF_YENDOR
)
914 context
.made_amulet
= TRUE
;
915 if (rn2(10) && (otmp
->otyp
== AMULET_OF_STRANGULATION
916 || otmp
->otyp
== AMULET_OF_CHANGE
917 || otmp
->otyp
== AMULET_OF_RESTFUL_SLEEP
)) {
920 blessorcurse(otmp
, 10);
927 if (otmp
->otyp
== POT_OIL
)
928 otmp
->age
= MAX_OIL_IN_FLASK
; /* amount of oil */
932 if (otmp
->otyp
!= SCR_MAIL
)
934 blessorcurse(otmp
, 4);
937 otmp
->spestudied
= 0;
938 blessorcurse(otmp
, 17);
942 && (otmp
->otyp
== FUMBLE_BOOTS
943 || otmp
->otyp
== LEVITATION_BOOTS
944 || otmp
->otyp
== HELM_OF_OPPOSITE_ALIGNMENT
945 || otmp
->otyp
== GAUNTLETS_OF_FUMBLING
|| !rn2(11))) {
948 } else if (!rn2(10)) {
949 otmp
->blessed
= rn2(2);
952 blessorcurse(otmp
, 10);
953 if (artif
&& !rn2(40))
954 otmp
= mk_artifact(otmp
, (aligntyp
) A_NONE
);
955 /* simulate lacquered armor for samurai */
956 if (Role_if(PM_SAMURAI
) && otmp
->otyp
== SPLINT_MAIL
957 && (moves
<= 1 || In_quest(&u
.uz
))) {
959 /* optimizer bitfield bug */
960 otmp
->oerodeproof
= 1;
963 otmp
->oerodeproof
= otmp
->rknown
= 1;
968 if (otmp
->otyp
== WAN_WISHING
)
972 rn1(5, (objects
[otmp
->otyp
].oc_dir
== NODIR
) ? 11 : 4);
973 blessorcurse(otmp
, 17);
974 otmp
->recharged
= 0; /* used to control recharging */
977 if (objects
[otmp
->otyp
].oc_charged
) {
978 blessorcurse(otmp
, 3);
980 if (rn2(10) && bcsign(otmp
))
981 otmp
->spe
= bcsign(otmp
) * rne(3);
983 otmp
->spe
= rn2(2) ? rne(3) : -rne(3);
985 /* make useless +0 rings much less common */
987 otmp
->spe
= rn2(4) - rn2(3);
988 /* negative rings are usually cursed */
989 if (otmp
->spe
< 0 && rn2(5))
991 } else if (rn2(10) && (otmp
->otyp
== RIN_TELEPORTATION
992 || otmp
->otyp
== RIN_POLYMORPH
993 || otmp
->otyp
== RIN_AGGRAVATE_MONSTER
994 || otmp
->otyp
== RIN_HUNGER
|| !rn2(9))) {
999 switch (otmp
->otyp
) {
1001 /* possibly overridden by mkcorpstat() */
1002 otmp
->corpsenm
= rndmonnum();
1003 if (!verysmall(&mons
[otmp
->corpsenm
])
1004 && rn2(level_difficulty() / 2 + 10) > 10)
1005 (void) add_to_container(otmp
, mkobj(SPBOOK_CLASS
, FALSE
));
1009 break; /* do nothing */
1011 impossible("impossible mkobj %d, sym '%c'.", otmp
->otyp
,
1012 objects
[otmp
->otyp
].oc_class
);
1013 return (struct obj
*) 0;
1016 /* some things must get done (corpsenm, timers) even if init = 0 */
1017 switch (otmp
->otyp
) {
1019 if (otmp
->corpsenm
== NON_PM
) {
1020 otmp
->corpsenm
= undead_to_corpse(rndmonnum());
1021 if (mvitals
[otmp
->corpsenm
].mvflags
& (G_NOCORPSE
| G_GONE
))
1022 otmp
->corpsenm
= urole
.malenum
;
1027 if (otmp
->corpsenm
== NON_PM
)
1028 otmp
->corpsenm
= rndmonnum();
1032 set_corpsenm(otmp
, otmp
->corpsenm
);
1038 otmp
->novelidx
= -1; /* "none of the above"; will be changed */
1039 otmp
= oname(otmp
, noveltitle(&otmp
->novelidx
));
1043 /* unique objects may have an associated artifact entry */
1044 if (objects
[otyp
].oc_unique
&& !otmp
->oartifact
)
1045 otmp
= mk_artifact(otmp
, (aligntyp
) A_NONE
);
1046 otmp
->owt
= weight(otmp
);
1051 * Several areas of the code made direct reassignments
1052 * to obj->corpsenm. Because some special handling is
1053 * required in certain cases, place that handling here
1054 * and call this routine in place of the direct assignment.
1056 * If the object was a lizard or lichen corpse:
1057 * - ensure that you don't end up with some
1058 * other corpse type which has no rot-away timer.
1060 * If the object was a troll corpse:
1061 * - ensure that you don't end up with some other
1062 * corpse type which resurrects from the dead.
1064 * Re-calculates the weight of figurines and corpses to suit the
1067 * Existing timeout value for egg hatch is preserved.
1071 set_corpsenm(obj
, id
)
1078 if (obj
->otyp
== EGG
)
1079 when
= stop_timer(HATCH_EGG
, obj_to_any(obj
));
1082 obj_stop_timers(obj
); /* corpse or figurine */
1086 switch (obj
->otyp
) {
1088 start_corpse_timeout(obj
);
1089 obj
->owt
= weight(obj
);
1092 if (obj
->corpsenm
!= NON_PM
&& !dead_species(obj
->corpsenm
, TRUE
)
1093 && (carried(obj
) || mcarried(obj
)))
1094 attach_fig_transform_timeout(obj
);
1095 obj
->owt
= weight(obj
);
1098 if (obj
->corpsenm
!= NON_PM
&& !dead_species(obj
->corpsenm
, TRUE
))
1099 attach_egg_hatch_timeout(obj
, when
);
1101 default: /* tin, etc. */
1102 obj
->owt
= weight(obj
);
1108 * Start a corpse decay or revive timer.
1109 * This takes the age of the corpse into consideration as of 3.4.0.
1112 start_corpse_timeout(body
)
1115 long when
; /* rot away when this old */
1116 long corpse_age
; /* age of corpse */
1120 #define TAINT_AGE (50L) /* age when corpses go bad */
1121 #define TROLL_REVIVE_CHANCE 37 /* 1/37 chance for 50 turns ~ 75% chance */
1122 #define ROT_AGE (250L) /* age when corpses rot away */
1124 /* lizards and lichen don't rot or revive */
1125 if (body
->corpsenm
== PM_LIZARD
|| body
->corpsenm
== PM_LICHEN
)
1128 action
= ROT_CORPSE
; /* default action: rot away */
1129 rot_adjust
= in_mklev
? 25 : 10; /* give some variation */
1130 corpse_age
= monstermoves
- body
->age
;
1131 if (corpse_age
> ROT_AGE
)
1134 when
= ROT_AGE
- corpse_age
;
1135 when
+= (long) (rnz(rot_adjust
) - rot_adjust
);
1137 if (is_rider(&mons
[body
->corpsenm
])) {
1139 * Riders always revive. They have a 1/3 chance per turn
1140 * of reviving after 12 turns. Always revive by 500.
1142 action
= REVIVE_MON
;
1143 for (when
= 12L; when
< 500L; when
++)
1147 } else if (mons
[body
->corpsenm
].mlet
== S_TROLL
&& !body
->norevive
) {
1149 for (age
= 2; age
<= TAINT_AGE
; age
++)
1150 if (!rn2(TROLL_REVIVE_CHANCE
)) { /* troll revives */
1151 action
= REVIVE_MON
;
1159 (void) start_timer(when
, TIMER_OBJECT
, action
, obj_to_any(body
));
1163 maybe_adjust_light(obj
, old_range
)
1169 int new_range
= arti_light_radius(obj
), delta
= new_range
- old_range
;
1171 /* radius of light emitting artifact varies by curse/bless state
1172 so will change after blessing or cursing */
1174 obj_adjust_light_radius(obj
, new_range
);
1175 /* simplifying assumptions: hero is wielding this object;
1176 artifacts have to be in use to emit light and monsters'
1177 gear won't change bless or curse state */
1178 if (!Blind
&& get_obj_location(obj
, &ox
, &oy
, 0)) {
1180 if (iflags
.last_msg
== PLNMSG_OBJ_GLOWS
)
1181 /* we just saw "The <obj> glows <color>." from dipping */
1182 Strcpy(buf
, (obj
->quan
== 1L) ? "It" : "They");
1183 else if (carried(obj
) || cansee(ox
, oy
))
1184 Strcpy(buf
, Yname2(obj
));
1186 /* initial activation says "dimly" if cursed,
1187 "brightly" if uncursed, and "brilliantly" if blessed;
1188 when changing intensity, using "less brightly" is
1189 straightforward for dimming, but we need "brighter"
1190 rather than "more brightly" for brightening; ugh */
1191 pline("%s %s %s%s.", buf
, otense(obj
, "shine"),
1192 (abs(delta
) > 1) ? "much " : "",
1193 (delta
> 0) ? "brighter" : "less brightly");
1200 * bless(), curse(), unbless(), uncurse() -- any relevant message
1201 * about glowing amber/black/&c should be delivered prior to calling
1202 * these routines to make the actual curse/bless state change.
1207 register struct obj
*otmp
;
1211 if (otmp
->oclass
== COIN_CLASS
)
1214 old_light
= arti_light_radius(otmp
);
1217 if (carried(otmp
) && confers_luck(otmp
))
1219 else if (otmp
->otyp
== BAG_OF_HOLDING
)
1220 otmp
->owt
= weight(otmp
);
1221 else if (otmp
->otyp
== FIGURINE
&& otmp
->timed
)
1222 (void) stop_timer(FIG_TRANSFORM
, obj_to_any(otmp
));
1224 maybe_adjust_light(otmp
, old_light
);
1230 register struct obj
*otmp
;
1235 old_light
= arti_light_radius(otmp
);
1237 if (carried(otmp
) && confers_luck(otmp
))
1239 else if (otmp
->otyp
== BAG_OF_HOLDING
)
1240 otmp
->owt
= weight(otmp
);
1242 maybe_adjust_light(otmp
, old_light
);
1247 register struct obj
*otmp
;
1249 unsigned already_cursed
;
1252 if (otmp
->oclass
== COIN_CLASS
)
1255 old_light
= arti_light_radius(otmp
);
1256 already_cursed
= otmp
->cursed
;
1259 /* welded two-handed weapon interferes with some armor removal */
1260 if (otmp
== uwep
&& bimanual(uwep
))
1262 /* rules at top of wield.c state that twoweapon cannot be done
1263 with cursed alternate weapon */
1264 if (otmp
== uswapwep
&& u
.twoweap
)
1266 /* some cursed items need immediate updating */
1267 if (carried(otmp
) && confers_luck(otmp
)) {
1269 } else if (otmp
->otyp
== BAG_OF_HOLDING
) {
1270 otmp
->owt
= weight(otmp
);
1271 } else if (otmp
->otyp
== FIGURINE
) {
1272 if (otmp
->corpsenm
!= NON_PM
&& !dead_species(otmp
->corpsenm
, TRUE
)
1273 && (carried(otmp
) || mcarried(otmp
)))
1274 attach_fig_transform_timeout(otmp
);
1275 } else if (otmp
->oclass
== SPBOOK_CLASS
) {
1276 /* if book hero is reading becomes cursed, interrupt */
1277 if (!already_cursed
)
1281 maybe_adjust_light(otmp
, old_light
);
1287 register struct obj
*otmp
;
1292 old_light
= arti_light_radius(otmp
);
1294 if (carried(otmp
) && confers_luck(otmp
))
1296 else if (otmp
->otyp
== BAG_OF_HOLDING
)
1297 otmp
->owt
= weight(otmp
);
1298 else if (otmp
->otyp
== FIGURINE
&& otmp
->timed
)
1299 (void) stop_timer(FIG_TRANSFORM
, obj_to_any(otmp
));
1301 maybe_adjust_light(otmp
, old_light
);
1306 blessorcurse(otmp
, chance
)
1307 register struct obj
*otmp
;
1308 register int chance
;
1310 if (otmp
->blessed
|| otmp
->cursed
)
1325 register struct obj
*otmp
;
1327 return (!!otmp
->blessed
- !!otmp
->cursed
);
1331 * Calculate the weight of the given object. This will recursively follow
1332 * and calculate the weight of any containers.
1334 * Note: It is possible to end up with an incorrect weight if some part
1335 * of the code messes with a contained object and doesn't update the
1336 * container's weight.
1340 register struct obj
*obj
;
1342 int wt
= objects
[obj
->otyp
].oc_weight
;
1344 /* glob absorpsion means that merging globs accumulates weight while
1345 quantity stays 1, so update 'wt' to reflect that, unless owt is 0,
1346 when we assume this is a brand new glob so use objects[].oc_weight */
1347 if (obj
->globby
&& obj
->owt
> 0)
1349 if (SchroedingersBox(obj
))
1350 wt
+= mons
[PM_HOUSECAT
].cwt
;
1351 if (Is_container(obj
) || obj
->otyp
== STATUE
) {
1352 struct obj
*contents
;
1353 register int cwt
= 0;
1355 if (obj
->otyp
== STATUE
&& obj
->corpsenm
>= LOW_PM
)
1356 wt
= (int) obj
->quan
* ((int) mons
[obj
->corpsenm
].cwt
* 3 / 2);
1358 for (contents
= obj
->cobj
; contents
; contents
= contents
->nobj
)
1359 cwt
+= weight(contents
);
1361 * The weight of bags of holding is calculated as the weight
1362 * of the bag plus the weight of the bag's contents modified
1365 * Bag status Weight of contents
1366 * ---------- ------------------
1368 * blessed x/4 [rounded up: (x+3)/4]
1369 * otherwise x/2 [rounded up: (x+1)/2]
1371 * The macro DELTA_CWT in pickup.c also implements these
1374 if (obj
->otyp
== BAG_OF_HOLDING
)
1375 cwt
= obj
->cursed
? (cwt
* 2) : obj
->blessed
? ((cwt
+ 3) / 4)
1380 if (obj
->otyp
== CORPSE
&& obj
->corpsenm
>= LOW_PM
) {
1381 long long_wt
= obj
->quan
* (long) mons
[obj
->corpsenm
].cwt
;
1383 wt
= (long_wt
> LARGEST_INT
) ? LARGEST_INT
: (int) long_wt
;
1385 wt
= eaten_stat(wt
, obj
);
1387 } else if (obj
->oclass
== FOOD_CLASS
&& obj
->oeaten
) {
1388 return eaten_stat((int) obj
->quan
* wt
, obj
);
1389 } else if (obj
->oclass
== COIN_CLASS
) {
1390 return (int) ((obj
->quan
+ 50L) / 100L);
1391 } else if (obj
->otyp
== HEAVY_IRON_BALL
&& obj
->owt
!= 0) {
1392 return (int) obj
->owt
; /* kludge for "very" heavy iron ball */
1394 return (wt
? wt
* (int) obj
->quan
: ((int) obj
->quan
+ 1) >> 1);
1397 static int treefruits
[] = { APPLE
, ORANGE
, PEAR
, BANANA
, EUCALYPTUS_LEAF
};
1400 rnd_treefruit_at(x
, y
)
1403 return mksobj_at(treefruits
[rn2(SIZE(treefruits
))], x
, y
, TRUE
, FALSE
);
1407 mkgold(amount
, x
, y
)
1411 register struct obj
*gold
= g_at(x
, y
);
1414 amount
= (long) (1 + rnd(level_difficulty() + 2) * rnd(30));
1416 gold
->quan
+= amount
;
1418 gold
= mksobj_at(GOLD_PIECE
, x
, y
, TRUE
, FALSE
);
1419 gold
->quan
= amount
;
1421 gold
->owt
= weight(gold
);
1425 /* return TRUE if the corpse has special timing */
1426 #define special_corpse(num) \
1427 (((num) == PM_LIZARD) || ((num) == PM_LICHEN) || (is_rider(&mons[num])) \
1428 || (mons[num].mlet == S_TROLL))
1431 * OEXTRA note: Passing mtmp causes mtraits to be saved
1432 * even if ptr passed as well, but ptr is always used for
1433 * the corpse type (corpsenm). That allows the corpse type
1434 * to be different from the original monster,
1435 * i.e. vampire -> human corpse
1436 * yet still allow restoration of the original monster upon
1440 mkcorpstat(objtype
, mtmp
, ptr
, x
, y
, corpstatflags
)
1441 int objtype
; /* CORPSE or STATUE */
1443 struct permonst
*ptr
;
1445 unsigned corpstatflags
;
1447 register struct obj
*otmp
;
1448 boolean init
= ((corpstatflags
& CORPSTAT_INIT
) != 0);
1450 if (objtype
!= CORPSE
&& objtype
!= STATUE
)
1451 impossible("making corpstat type %d", objtype
);
1452 if (x
== 0 && y
== 0) { /* special case - random placement */
1453 otmp
= mksobj(objtype
, init
, FALSE
);
1457 otmp
= mksobj_at(objtype
, x
, y
, init
, FALSE
);
1464 /* save_mtraits frees original data pointed to by otmp */
1465 otmp2
= save_mtraits(otmp
, mtmp
);
1469 /* use the corpse or statue produced by mksobj() as-is
1470 unless `ptr' is non-null */
1472 int old_corpsenm
= otmp
->corpsenm
;
1474 otmp
->corpsenm
= monsndx(ptr
);
1475 otmp
->owt
= weight(otmp
);
1476 if (otmp
->otyp
== CORPSE
&& (special_corpse(old_corpsenm
)
1477 || special_corpse(otmp
->corpsenm
))) {
1478 obj_stop_timers(otmp
);
1479 start_corpse_timeout(otmp
);
1487 * Return the type of monster that this corpse will
1488 * revive as, even if it has a monster structure
1489 * attached to it. In that case, you can't just
1490 * use obj->corpsenm, because the stored monster
1491 * type can, and often is, different.
1492 * The return value is an index into mons[].
1495 corpse_revive_type(obj
)
1501 && ((mtmp
= get_mtraits(obj
, FALSE
)) != (struct monst
*) 0)) {
1502 /* mtmp is a temporary pointer to a monster's stored
1503 attributes, not a real monster */
1504 revivetype
= mtmp
->mnum
;
1506 revivetype
= obj
->corpsenm
;
1511 * Attach a monster id to an object, to provide
1512 * a lasting association between the two.
1515 obj_attach_mid(obj
, mid
)
1520 return (struct obj
*) 0;
1527 save_mtraits(obj
, mtmp
)
1532 forget_temple_entry(mtmp
); /* EPRI() */
1533 if (!has_omonst(obj
))
1535 if (has_omonst(obj
)) {
1536 struct monst
*mtmp2
= OMONST(obj
);
1539 mtmp2
->mextra
= (struct mextra
*) 0;
1541 mtmp2
->mnum
= monsndx(mtmp
->data
);
1542 /* invalidate pointers */
1543 /* m_id is needed to know if this is a revived quest leader */
1544 /* but m_id must be cleared when loading bones */
1545 mtmp2
->nmon
= (struct monst
*) 0;
1546 mtmp2
->data
= (struct permonst
*) 0;
1547 mtmp2
->minvent
= (struct obj
*) 0;
1549 copy_mextra(mtmp2
, mtmp
);
1554 /* returns a pointer to a new monst structure based on
1555 * the one contained within the obj.
1558 get_mtraits(obj
, copyof
)
1562 struct monst
*mtmp
= (struct monst
*) 0;
1563 struct monst
*mnew
= (struct monst
*) 0;
1565 if (has_omonst(obj
))
1571 mnew
->mextra
= (struct mextra
*) 0;
1573 copy_mextra(mnew
, mtmp
);
1575 /* Never insert this returned pointer into mon chains! */
1582 /* make an object named after someone listed in the scoreboard file */
1584 mk_tt_object(objtype
, x
, y
)
1585 int objtype
; /* CORPSE or STATUE */
1588 register struct obj
*otmp
, *otmp2
;
1589 boolean initialize_it
;
1591 /* player statues never contain books */
1592 initialize_it
= (objtype
!= STATUE
);
1593 if ((otmp
= mksobj_at(objtype
, x
, y
, initialize_it
, FALSE
)) != 0) {
1594 /* tt_oname will return null if the scoreboard is empty */
1595 if ((otmp2
= tt_oname(otmp
)) != 0)
1601 /* make a new corpse or statue, uninitialized if a statue (i.e. no books) */
1603 mk_named_object(objtype
, ptr
, x
, y
, nm
)
1604 int objtype
; /* CORPSE or STATUE */
1605 struct permonst
*ptr
;
1610 unsigned corpstatflags
=
1611 (objtype
!= STATUE
) ? CORPSTAT_INIT
: CORPSTAT_NONE
;
1613 otmp
= mkcorpstat(objtype
, (struct monst
*) 0, ptr
, x
, y
, corpstatflags
);
1615 otmp
= oname(otmp
, nm
);
1621 register struct obj
*otmp
;
1623 int otyp
= otmp
->otyp
;
1624 int omat
= objects
[otyp
].oc_material
;
1626 /* Candles can be burned, but they're not flammable in the sense that
1627 * they can't get fire damage and it makes no sense for them to be
1630 if (Is_candle(otmp
))
1633 if (objects
[otyp
].oc_oprop
== FIRE_RES
|| otyp
== WAN_FIRE
)
1636 return (boolean
) ((omat
<= WOOD
&& omat
!= LIQUID
) || omat
== PLASTIC
);
1641 register struct obj
*otmp
;
1643 int otyp
= otmp
->otyp
;
1645 return (boolean
) (objects
[otyp
].oc_material
<= WOOD
1646 && objects
[otyp
].oc_material
!= LIQUID
);
1650 * These routines maintain the single-linked lists headed in level.objects[][]
1651 * and threaded through the nexthere fields in the object-instance structure.
1654 /* put the object at the given location */
1656 place_object(otmp
, x
, y
)
1657 register struct obj
*otmp
;
1660 register struct obj
*otmp2
= level
.objects
[x
][y
];
1662 if (otmp
->where
!= OBJ_FREE
)
1663 panic("place_object: obj not free");
1665 obj_no_longer_held(otmp
);
1666 /* (could bypass this vision update if there is already a boulder here) */
1667 if (otmp
->otyp
== BOULDER
)
1668 block_point(x
, y
); /* vision */
1670 /* obj goes under boulders */
1671 if (otmp2
&& (otmp2
->otyp
== BOULDER
)) {
1672 otmp
->nexthere
= otmp2
->nexthere
;
1673 otmp2
->nexthere
= otmp
;
1675 otmp
->nexthere
= otmp2
;
1676 level
.objects
[x
][y
] = otmp
;
1679 /* set the new object's location */
1683 otmp
->where
= OBJ_FLOOR
;
1685 /* add to floor chain */
1689 obj_timer_checks(otmp
, x
, y
, 0);
1692 #define ROT_ICE_ADJUSTMENT 2 /* rotting on ice takes 2 times as long */
1694 /* If ice was affecting any objects correct that now
1695 * Also used for starting ice effects too. [zap.c]
1698 obj_ice_effects(x
, y
, do_buried
)
1704 for (otmp
= level
.objects
[x
][y
]; otmp
; otmp
= otmp
->nexthere
) {
1706 obj_timer_checks(otmp
, x
, y
, 0);
1709 for (otmp
= level
.buriedobjlist
; otmp
; otmp
= otmp
->nobj
) {
1710 if (otmp
->ox
== x
&& otmp
->oy
== y
) {
1712 obj_timer_checks(otmp
, x
, y
, 0);
1719 * Returns an obj->age for a corpse object on ice, that would be the
1720 * actual obj->age if the corpse had just been lifted from the ice.
1721 * This is useful when just using obj->age in a check or calculation because
1722 * rot timers pertaining to the object don't have to be stopped and
1726 peek_at_iced_corpse_age(otmp
)
1729 long age
, retval
= otmp
->age
;
1731 if (otmp
->otyp
== CORPSE
&& otmp
->on_ice
) {
1732 /* Adjust the age; must be same as obj_timer_checks() for off ice*/
1733 age
= monstermoves
- otmp
->age
;
1734 retval
+= age
* (ROT_ICE_ADJUSTMENT
- 1) / ROT_ICE_ADJUSTMENT
;
1736 "The %s age has ice modifications: otmp->age = %ld, returning %ld.",
1737 s_suffix(doname(otmp
)), otmp
->age
, retval
);
1738 debugpline1("Effective age of corpse: %ld.", monstermoves
- retval
);
1744 obj_timer_checks(otmp
, x
, y
, force
)
1747 int force
; /* 0 = no force so do checks, <0 = force off, >0 force on */
1750 short action
= ROT_CORPSE
;
1751 boolean restart_timer
= FALSE
;
1752 boolean on_floor
= (otmp
->where
== OBJ_FLOOR
);
1753 boolean buried
= (otmp
->where
== OBJ_BURIED
);
1755 /* Check for corpses just placed on or in ice */
1756 if (otmp
->otyp
== CORPSE
&& (on_floor
|| buried
) && is_ice(x
, y
)) {
1757 tleft
= stop_timer(action
, obj_to_any(otmp
));
1759 action
= REVIVE_MON
;
1760 tleft
= stop_timer(action
, obj_to_any(otmp
));
1765 /* mark the corpse as being on ice */
1767 debugpline3("%s is now on ice at <%d,%d>.", The(xname(otmp
)), x
,
1769 /* Adjust the time remaining */
1770 tleft
*= ROT_ICE_ADJUSTMENT
;
1771 restart_timer
= TRUE
;
1772 /* Adjust the age; time spent off ice needs to be multiplied
1773 by the ice adjustment and subtracted from the age so that
1774 later calculations behave as if it had been on ice during
1775 that time (longwinded way of saying this is the inverse
1776 of removing it from the ice and of peeking at its age). */
1777 age
= monstermoves
- otmp
->age
;
1778 otmp
->age
= monstermoves
- (age
* ROT_ICE_ADJUSTMENT
);
1781 /* Check for corpses coming off ice */
1782 } else if (force
< 0 || (otmp
->otyp
== CORPSE
&& otmp
->on_ice
1783 && !((on_floor
|| buried
) && is_ice(x
, y
)))) {
1784 tleft
= stop_timer(action
, obj_to_any(otmp
));
1786 action
= REVIVE_MON
;
1787 tleft
= stop_timer(action
, obj_to_any(otmp
));
1793 debugpline3("%s is no longer on ice at <%d,%d>.",
1794 The(xname(otmp
)), x
, y
);
1795 /* Adjust the remaining time */
1796 tleft
/= ROT_ICE_ADJUSTMENT
;
1797 restart_timer
= TRUE
;
1798 /* Adjust the age */
1799 age
= monstermoves
- otmp
->age
;
1800 otmp
->age
+= age
* (ROT_ICE_ADJUSTMENT
- 1) / ROT_ICE_ADJUSTMENT
;
1804 /* now re-start the timer with the appropriate modifications */
1806 (void) start_timer(tleft
, TIMER_OBJECT
, action
, obj_to_any(otmp
));
1809 #undef ROT_ICE_ADJUSTMENT
1813 register struct obj
*otmp
;
1818 if (otmp
->where
!= OBJ_FLOOR
)
1819 panic("remove_object: obj not on floor");
1820 extract_nexthere(otmp
, &level
.objects
[x
][y
]);
1821 extract_nobj(otmp
, &fobj
);
1822 /* update vision iff this was the only boulder at its spot */
1823 if (otmp
->otyp
== BOULDER
&& !sobj_at(BOULDER
, x
, y
))
1824 unblock_point(x
, y
); /* vision */
1826 obj_timer_checks(otmp
, x
, y
, 0);
1829 /* throw away all of a monster's inventory */
1831 discard_minvent(mtmp
)
1834 struct obj
*otmp
, *mwep
= MON_WEP(mtmp
);
1835 boolean keeping_mon
= (mtmp
->mhp
> 0);
1837 while ((otmp
= mtmp
->minvent
) != 0) {
1838 /* this has now become very similar to m_useupall()... */
1839 obj_extract_self(otmp
);
1840 if (otmp
->owornmask
) {
1843 mwepgone(mtmp
), mwep
= 0;
1844 mtmp
->misc_worn_check
&= ~otmp
->owornmask
;
1845 update_mon_intrinsics(mtmp
, otmp
, FALSE
, TRUE
);
1847 otmp
->owornmask
= 0L; /* obfree() expects this */
1849 obfree(otmp
, (struct obj
*) 0); /* dealloc_obj() isn't sufficient */
1854 * Free obj from whatever list it is on in preparation for deleting it
1855 * or moving it elsewhere; obj->where will end up set to OBJ_FREE.
1856 * Doesn't handle unwearing of objects in hero's or monsters' inventories.
1859 * OBJ_FREE not on any list
1860 * OBJ_FLOOR fobj, level.locations[][] chains (use remove_object)
1861 * OBJ_CONTAINED cobj chain of container object
1862 * OBJ_INVENT hero's invent chain (use freeinv)
1863 * OBJ_MINVENT monster's invent chain
1864 * OBJ_MIGRATING migrating chain
1865 * OBJ_BURIED level.buriedobjs chain
1866 * OBJ_ONBILL on billobjs chain
1869 obj_extract_self(obj
)
1872 switch (obj
->where
) {
1879 extract_nobj(obj
, &obj
->ocontainer
->cobj
);
1880 container_weight(obj
->ocontainer
);
1886 extract_nobj(obj
, &obj
->ocarry
->minvent
);
1889 extract_nobj(obj
, &migrating_objs
);
1892 extract_nobj(obj
, &level
.buriedobjlist
);
1895 extract_nobj(obj
, &billobjs
);
1898 panic("obj_extract_self");
1903 /* Extract the given object from the chain, following nobj chain. */
1905 extract_nobj(obj
, head_ptr
)
1906 struct obj
*obj
, **head_ptr
;
1908 struct obj
*curr
, *prev
;
1911 for (prev
= (struct obj
*) 0; curr
; prev
= curr
, curr
= curr
->nobj
) {
1914 prev
->nobj
= curr
->nobj
;
1916 *head_ptr
= curr
->nobj
;
1921 panic("extract_nobj: object lost");
1922 obj
->where
= OBJ_FREE
;
1927 * Extract the given object from the chain, following nexthere chain.
1929 * This does not set obj->where, this function is expected to be called
1930 * in tandem with extract_nobj, which does set it.
1933 extract_nexthere(obj
, head_ptr
)
1934 struct obj
*obj
, **head_ptr
;
1936 struct obj
*curr
, *prev
;
1939 for (prev
= (struct obj
*) 0; curr
; prev
= curr
, curr
= curr
->nexthere
) {
1942 prev
->nexthere
= curr
->nexthere
;
1944 *head_ptr
= curr
->nexthere
;
1949 panic("extract_nexthere: object lost");
1953 * Add obj to mon's inventory. If obj is able to merge with something already
1954 * in the inventory, then the passed obj is deleted and 1 is returned.
1955 * Otherwise 0 is returned.
1958 add_to_minv(mon
, obj
)
1964 if (obj
->where
!= OBJ_FREE
)
1965 panic("add_to_minv: obj not free");
1967 /* merge if possible */
1968 for (otmp
= mon
->minvent
; otmp
; otmp
= otmp
->nobj
)
1969 if (merged(&otmp
, &obj
))
1970 return 1; /* obj merged and then free'd */
1971 /* else insert; don't bother forcing it to end of chain */
1972 obj
->where
= OBJ_MINVENT
;
1974 obj
->nobj
= mon
->minvent
;
1976 return 0; /* obj on mon's inventory chain */
1980 * Add obj to container, make sure obj is "free". Returns (merged) obj.
1981 * The input obj may be deleted in the process.
1984 add_to_container(container
, obj
)
1985 struct obj
*container
, *obj
;
1989 if (obj
->where
!= OBJ_FREE
)
1990 panic("add_to_container: obj not free");
1991 if (container
->where
!= OBJ_INVENT
&& container
->where
!= OBJ_MINVENT
)
1992 obj_no_longer_held(obj
);
1994 /* merge if possible */
1995 for (otmp
= container
->cobj
; otmp
; otmp
= otmp
->nobj
)
1996 if (merged(&otmp
, &obj
))
1999 obj
->where
= OBJ_CONTAINED
;
2000 obj
->ocontainer
= container
;
2001 obj
->nobj
= container
->cobj
;
2002 container
->cobj
= obj
;
2007 add_to_migration(obj
)
2010 if (obj
->where
!= OBJ_FREE
)
2011 panic("add_to_migration: obj not free");
2013 obj
->where
= OBJ_MIGRATING
;
2014 obj
->nobj
= migrating_objs
;
2015 migrating_objs
= obj
;
2022 if (obj
->where
!= OBJ_FREE
)
2023 panic("add_to_buried: obj not free");
2025 obj
->where
= OBJ_BURIED
;
2026 obj
->nobj
= level
.buriedobjlist
;
2027 level
.buriedobjlist
= obj
;
2030 /* Recalculate the weight of this container and all of _its_ containers. */
2032 container_weight(container
)
2033 struct obj
*container
;
2035 container
->owt
= weight(container
);
2036 if (container
->where
== OBJ_CONTAINED
)
2037 container_weight(container
->ocontainer
);
2039 else if (container->where == OBJ_INVENT)
2040 recalculate load delay here ???
2045 * Deallocate the object. _All_ objects should be run through here for
2046 * them to be deallocated.
2052 if (obj
->where
!= OBJ_FREE
)
2053 panic("dealloc_obj: obj not free");
2055 panic("dealloc_obj with nobj");
2057 panic("dealloc_obj with cobj");
2059 /* free up any timers attached to the object */
2061 obj_stop_timers(obj
);
2064 * Free up any light sources attached to the object.
2066 * We may want to just call del_light_source() without any
2067 * checks (requires a code change there). Otherwise this
2068 * list must track all objects that can have a light source
2069 * attached to it (and also requires lamplit to be set).
2071 if (obj_sheds_light(obj
))
2072 del_light_source(LS_OBJECT
, obj_to_any(obj
));
2074 if (obj
== thrownobj
)
2076 if (obj
== kickedobj
)
2080 dealloc_oextra(obj
);
2081 free((genericptr_t
) obj
);
2084 /* create an object from a horn of plenty; mirrors bagotricks(makemon.c) */
2086 hornoplenty(horn
, tipping
)
2088 boolean tipping
; /* caller emptying entire contents; affects shop handling */
2092 if (!horn
|| horn
->otyp
!= HORN_OF_PLENTY
) {
2093 impossible("bad horn o' plenty");
2094 } else if (horn
->spe
< 1) {
2095 pline1(nothing_happens
);
2100 consume_obj_charge(horn
, !tipping
);
2102 obj
= mkobj(POTION_CLASS
, FALSE
);
2103 if (objects
[obj
->otyp
].oc_magic
)
2105 obj
->otyp
= rnd_class(POT_BOOZE
, POT_WATER
);
2106 } while (obj
->otyp
== POT_SICKNESS
);
2107 what
= (obj
->quan
> 1L) ? "Some potions" : "A potion";
2109 obj
= mkobj(FOOD_CLASS
, FALSE
);
2110 if (obj
->otyp
== FOOD_RATION
&& !rn2(7))
2111 obj
->otyp
= LUMP_OF_ROYAL_JELLY
;
2115 pline("%s %s out.", what
, vtense(what
, "spill"));
2116 obj
->blessed
= horn
->blessed
;
2117 obj
->cursed
= horn
->cursed
;
2118 obj
->owt
= weight(obj
);
2119 /* using a shop's horn of plenty entails a usage fee and also
2120 confers ownership of the created item to the shopkeeper */
2122 addtobill(obj
, FALSE
, FALSE
, tipping
);
2123 /* if it ended up on bill, we don't want "(unpaid, N zorkids)"
2124 being included in its formatted name during next message */
2125 iflags
.suppress_price
++;
2127 obj
= hold_another_object(
2128 obj
, u
.uswallow
? "Oops! %s out of your reach!"
2129 : (Is_airlevel(&u
.uz
) || Is_waterlevel(&u
.uz
)
2130 || levl
[u
.ux
][u
.uy
].typ
< IRONBARS
2131 || levl
[u
.ux
][u
.uy
].typ
>= ICE
)
2132 ? "Oops! %s away from you!"
2133 : "Oops! %s to the floor!",
2134 The(aobjnam(obj
, "slip")), (const char *) 0);
2136 /* assumes this is taking place at hero's location */
2137 if (!can_reach_floor(TRUE
)) {
2138 hitfloor(obj
); /* does altar check, message, drop */
2140 if (IS_ALTAR(levl
[u
.ux
][u
.uy
].typ
))
2141 doaltarobj(obj
); /* does its own drop message */
2143 pline("%s %s to the %s.", Doname2(obj
),
2144 otense(obj
, "drop"), surface(u
.ux
, u
.uy
));
2148 iflags
.suppress_price
--;
2150 makeknown(HORN_OF_PLENTY
);
2155 /* support for wizard-mode's `sanity_check' option */
2157 static const char NEARDATA
/* pline formats for insane_object() */
2158 ofmt0
[] = "%s obj %s %s: %s",
2159 ofmt3
[] = "%s [not null] %s %s: %s",
2160 /* " held by mon %p (%s)" will be appended, filled by M,mon_nam(M) */
2161 mfmt1
[] = "%s obj %s %s (%s)", mfmt2
[] = "%s obj %s %s (%s) *not*";
2163 /* Check all object lists for consistency. */
2170 objlist_sanity(fobj
, OBJ_FLOOR
, "floor sanity");
2172 /* check that the map's record of floor objects is consistent;
2173 those objects should have already been sanity checked via
2174 the floor list so container contents are skipped here */
2175 for (x
= 0; x
< COLNO
; x
++)
2176 for (y
= 0; y
< ROWNO
; y
++)
2177 for (obj
= level
.objects
[x
][y
]; obj
; obj
= obj
->nexthere
) {
2178 /* <ox,oy> should match <x,y>; <0,*> should always be empty */
2179 if (obj
->where
!= OBJ_FLOOR
|| x
== 0 || obj
->ox
!= x
2183 Sprintf(at_fmt
, "%%s obj@<%d,%d> %%s %%s: %%s@<%d,%d>", x
,
2184 y
, obj
->ox
, obj
->oy
);
2185 insane_object(obj
, at_fmt
, "location sanity",
2186 (struct monst
*) 0);
2190 objlist_sanity(invent
, OBJ_INVENT
, "invent sanity");
2191 objlist_sanity(migrating_objs
, OBJ_MIGRATING
, "migrating sanity");
2192 objlist_sanity(level
.buriedobjlist
, OBJ_BURIED
, "buried sanity");
2193 objlist_sanity(billobjs
, OBJ_ONBILL
, "bill sanity");
2195 mon_obj_sanity(fmon
, "minvent sanity");
2196 mon_obj_sanity(migrating_mons
, "migrating minvent sanity");
2197 /* monsters temporarily in transit;
2198 they should have arrived with hero by the time we get called */
2200 pline("mydogs sanity [not empty]");
2201 mon_obj_sanity(mydogs
, "mydogs minvent sanity");
2204 /* objects temporarily freed from invent/floor lists;
2205 they should have arrived somewhere by the time we get called */
2207 insane_object(thrownobj
, ofmt3
, "thrownobj sanity",
2208 (struct monst
*) 0);
2210 insane_object(kickedobj
, ofmt3
, "kickedobj sanity",
2211 (struct monst
*) 0);
2212 /* [how about current_wand too?] */
2215 /* sanity check for objects on specified list (fobj, &c) */
2217 objlist_sanity(objlist
, wheretype
, mesg
)
2218 struct obj
*objlist
;
2224 for (obj
= objlist
; obj
; obj
= obj
->nobj
) {
2225 if (obj
->where
!= wheretype
)
2226 insane_object(obj
, ofmt0
, mesg
, (struct monst
*) 0);
2227 if (Has_contents(obj
)) {
2228 if (wheretype
== OBJ_ONBILL
)
2229 /* containers on shop bill should always be empty */
2230 insane_object(obj
, "%s obj contains something! %s %s: %s",
2231 mesg
, (struct monst
*) 0);
2232 check_contained(obj
, mesg
);
2234 if (obj
->owornmask
) {
2236 boolean bc_ok
= FALSE
;
2238 switch (obj
->where
) {
2241 sanity_check_worn(obj
);
2244 /* migrating objects overload the owornmask field
2245 with a destination code; skip attempt to check it */
2248 /* note: ball and chain can also be OBJ_FREE, but not across
2249 turns so this sanity check shouldn't encounter that */
2253 if ((obj
!= uchain
&& obj
!= uball
) || !bc_ok
) {
2254 /* discovered an object not in inventory which
2255 erroneously has worn mask set */
2256 Sprintf(maskbuf
, "worn mask 0x%08lx", obj
->owornmask
);
2257 insane_object(obj
, ofmt0
, maskbuf
, (struct monst
*) 0);
2265 /* sanity check for objects carried by all monsters in specified list */
2267 mon_obj_sanity(monlist
, mesg
)
2268 struct monst
*monlist
;
2272 struct obj
*obj
, *mwep
;
2274 for (mon
= monlist
; mon
; mon
= mon
->nmon
) {
2275 if (DEADMONSTER(mon
)) continue;
2276 mwep
= MON_WEP(mon
);
2278 if (!mcarried(mwep
))
2279 insane_object(mwep
, mfmt1
, mesg
, mon
);
2280 if (mwep
->ocarry
!= mon
)
2281 insane_object(mwep
, mfmt2
, mesg
, mon
);
2283 for (obj
= mon
->minvent
; obj
; obj
= obj
->nobj
) {
2284 if (obj
->where
!= OBJ_MINVENT
)
2285 insane_object(obj
, mfmt1
, mesg
, mon
);
2286 if (obj
->ocarry
!= mon
)
2287 insane_object(obj
, mfmt2
, mesg
, mon
);
2288 check_contained(obj
, mesg
);
2293 /* This must stay consistent with the defines in obj.h. */
2294 static const char *obj_state_names
[NOBJ_STATES
] = { "free", "floor",
2295 "contained", "invent",
2296 "minvent", "migrating",
2297 "buried", "onbill" };
2299 STATIC_OVL
const char *
2303 static char unknown
[32]; /* big enough to handle rogue 64-bit int */
2309 if (where
< 0 || where
>= NOBJ_STATES
|| !obj_state_names
[where
]) {
2310 Sprintf(unknown
, "unknown[%d]", where
);
2313 return obj_state_names
[where
];
2317 insane_object(obj
, fmt
, mesg
, mon
)
2319 const char *fmt
, *mesg
;
2322 const char *objnm
, *monnm
;
2325 objnm
= monnm
= "null!";
2327 iflags
.override_ID
++;
2328 objnm
= doname(obj
);
2329 iflags
.override_ID
--;
2331 if (mon
|| (strstri(mesg
, "minvent") && !strstri(mesg
, "contained"))) {
2332 Strcat(strcpy(altfmt
, fmt
), " held by mon %s (%s)");
2334 monnm
= x_monnam(mon
, ARTICLE_A
, (char *) 0, EXACT_NAME
, TRUE
);
2335 pline(altfmt
, mesg
, fmt_ptr((genericptr_t
) obj
), where_name(obj
),
2336 objnm
, fmt_ptr((genericptr_t
) mon
), monnm
);
2338 pline(fmt
, mesg
, fmt_ptr((genericptr_t
) obj
), where_name(obj
), objnm
);
2342 /* obj sanity check: check objects inside container */
2344 check_contained(container
, mesg
)
2345 struct obj
*container
;
2349 /* big enough to work with, not too big to blow out stack in recursion */
2350 char mesgbuf
[40], nestedmesg
[120];
2352 if (!Has_contents(container
))
2354 /* change "invent sanity" to "contained invent sanity"
2355 but leave "nested contained invent sanity" as is */
2356 if (!strstri(mesg
, "contained"))
2357 mesg
= strcat(strcpy(mesgbuf
, "contained "), mesg
);
2359 for (obj
= container
->cobj
; obj
; obj
= obj
->nobj
) {
2360 /* catch direct cycle to avoid unbounded recursion */
2361 if (obj
== container
)
2362 panic("failed sanity check: container holds itself");
2363 if (obj
->where
!= OBJ_CONTAINED
)
2364 insane_object(obj
, "%s obj %s %s: %s", mesg
, (struct monst
*) 0);
2365 else if (obj
->ocontainer
!= container
)
2366 pline("%s obj %s in container %s, not %s", mesg
,
2367 fmt_ptr((genericptr_t
) obj
),
2368 fmt_ptr((genericptr_t
) obj
->ocontainer
),
2369 fmt_ptr((genericptr_t
) container
));
2371 if (Has_contents(obj
)) {
2372 /* catch most likely indirect cycle; we won't notice if
2373 parent is present when something comes before it, or
2374 notice more deeply embedded cycles (grandparent, &c) */
2375 if (obj
->cobj
== container
)
2376 panic("failed sanity check: container holds its parent");
2377 /* change "contained... sanity" to "nested contained... sanity"
2378 and "nested contained..." to "nested nested contained..." */
2379 Strcpy(nestedmesg
, "nested ");
2380 copynchars(eos(nestedmesg
), mesg
, (int) sizeof nestedmesg
2381 - (int) strlen(nestedmesg
)
2383 /* recursively check contents */
2384 check_contained(obj
, nestedmesg
);
2389 /* check an object in hero's or monster's inventory which has worn mask set */
2391 sanity_check_worn(obj
)
2394 #if defined(BETA) || defined(DEBUG)
2395 static unsigned long wearbits
[] = {
2396 W_ARM
, W_ARMC
, W_ARMH
, W_ARMS
, W_ARMG
, W_ARMF
, W_ARMU
,
2397 W_WEP
, W_QUIVER
, W_SWAPWEP
, W_AMUL
, W_RINGL
, W_RINGR
, W_TOOL
,
2398 W_SADDLE
, W_BALL
, W_CHAIN
, 0
2399 /* [W_ART,W_ARTI are property bits for items which aren't worn] */
2403 unsigned long owornmask
, allmask
= 0L;
2404 boolean embedded
= FALSE
;
2407 /* use owornmask for testing and bit twiddling, but use original
2408 obj->owornmask for printing */
2409 owornmask
= obj
->owornmask
;
2410 /* figure out how many bits are set, and also which are viable */
2411 for (i
= 0; wearbits
[i
]; ++i
) {
2412 if ((owornmask
& wearbits
[i
]) != 0L)
2414 allmask
|= wearbits
[i
];
2417 /* embedded dragon scales have an extra bit set;
2418 make sure it's set, then suppress it */
2420 if ((owornmask
& (W_ARM
| I_SPECIAL
)) == (W_ARM
| I_SPECIAL
))
2421 owornmask
&= ~I_SPECIAL
;
2423 n
= 0, owornmask
= ~0; /* force insane_object("bogus") below */
2425 if (n
== 2 && carried(obj
)
2426 && obj
== uball
&& (owornmask
& W_BALL
) != 0L
2427 && (owornmask
& W_WEAPON
) != 0L) {
2428 /* chained ball can be wielded/alt-wielded/quivered; if so,
2429 pretend it's not chained in order to check the weapon pointer
2430 (we've already verified the ball pointer by successfully passing
2431 the if-condition to get here...) */
2432 owornmask
&= ~W_BALL
;
2436 /* multiple bits set */
2437 Sprintf(maskbuf
, "worn mask (multiple) 0x%08lx", obj
->owornmask
);
2438 insane_object(obj
, ofmt0
, maskbuf
, (struct monst
*) 0);
2440 if ((owornmask
& ~allmask
) != 0L
2441 || (carried(obj
) && (owornmask
& W_SADDLE
) != 0L)) {
2442 /* non-wearable bit(s) set */
2443 Sprintf(maskbuf
, "worn mask (bogus)) 0x%08lx", obj
->owornmask
);
2444 insane_object(obj
, ofmt0
, maskbuf
, (struct monst
*) 0);
2446 if (n
== 1 && (carried(obj
) || (owornmask
& (W_BALL
| W_CHAIN
)) != 0L)) {
2448 /* verify that obj in hero's invent (or ball/chain elsewhere)
2449 with owornmask of W_foo is the object pointed to by ufoo */
2450 switch (owornmask
) {
2452 if (obj
!= (embedded
? uskin
: uarm
))
2453 what
= embedded
? "skin" : "suit";
2481 what
= "primary weapon";
2488 if (obj
!= uswapwep
)
2489 what
= u
.twoweap
? "secondary weapon" : "alternate weapon";
2501 what
= "right ring";
2507 /* case W_SADDLE: */
2520 Sprintf(maskbuf
, "worn mask 0x%08lx != %s", obj
->owornmask
, what
);
2521 insane_object(obj
, ofmt0
, maskbuf
, (struct monst
*) 0);
2524 if (n
== 1 && (carried(obj
) || (owornmask
& (W_BALL
| W_CHAIN
)) != 0L
2525 || mcarried(obj
))) {
2526 /* check for items worn in invalid slots; practically anything can
2527 be wielded/alt-wielded/quivered, so tests on those are limited */
2529 if (owornmask
& W_ARMOR
) {
2530 if (obj
->oclass
!= ARMOR_CLASS
)
2532 /* 3.6: dragon scale mail reverts to dragon scales when
2533 becoming embedded in poly'd hero's skin */
2534 if (embedded
&& !Is_dragon_scales(obj
))
2536 } else if (owornmask
& W_WEAPON
) {
2537 /* monsters don't maintain alternate weapon or quiver */
2538 if (mcarried(obj
) && (owornmask
& (W_SWAPWEP
| W_QUIVER
)) != 0L)
2539 what
= (owornmask
& W_SWAPWEP
) != 0L ? "monst alt weapon?"
2541 /* hero can quiver gold but not wield it (hence not alt-wield
2542 it either); also catches monster wielding gold */
2543 else if (obj
->oclass
== COIN_CLASS
2544 && (owornmask
& (W_WEP
| W_SWAPWEP
)) != 0L)
2545 what
= (owornmask
& W_WEP
) != 0L ? "weapon" : "alt weapon";
2546 } else if (owornmask
& W_AMUL
) {
2547 if (obj
->oclass
!= AMULET_CLASS
)
2549 } else if (owornmask
& W_RING
) {
2550 if (obj
->oclass
!= RING_CLASS
&& obj
->otyp
!= MEAT_RING
)
2552 } else if (owornmask
& W_TOOL
) {
2553 if (obj
->otyp
!= BLINDFOLD
&& obj
->otyp
!= TOWEL
2554 && obj
->otyp
!= LENSES
)
2556 } else if (owornmask
& W_BALL
) {
2557 if (obj
->oclass
!= BALL_CLASS
)
2558 what
= "chained ball";
2559 } else if (owornmask
& W_CHAIN
) {
2560 if (obj
->oclass
!= CHAIN_CLASS
)
2562 } else if (owornmask
& W_SADDLE
) {
2563 if (obj
->otyp
!= SADDLE
)
2567 char oclassname
[30];
2568 struct monst
*mon
= mcarried(obj
) ? obj
->ocarry
: 0;
2570 /* if we've found a potion worn in the amulet slot,
2571 this yields "worn (potion amulet)" */
2572 Strcpy(oclassname
, def_oc_syms
[(uchar
) obj
->oclass
].name
);
2573 Sprintf(maskbuf
, "worn (%s %s)", makesingular(oclassname
), what
);
2574 insane_object(obj
, ofmt0
, maskbuf
, mon
);
2577 #else /* not (BETA || DEBUG) */
2578 /* dummy use of obj to avoid "arg not used" complaint */
2580 insane_object(obj
, ofmt0
, "<null>", (struct monst
*) 0);
2585 * wrapper to make "near this object" convenient
2592 impossible("obj_nexto: wasn't given an object to check");
2593 return (struct obj
*) 0;
2595 return obj_nexto_xy(otmp
, otmp
->ox
, otmp
->oy
, TRUE
);
2599 * looks for objects of a particular type next to x, y
2600 * skips over oid if found (lets us avoid ourselves if
2601 * we're looking for a second type of an existing object)
2603 * TODO: return a list of all objects near us so we can more
2604 * reliably predict which one we want to 'find' first
2607 obj_nexto_xy(obj
, x
, y
, recurs
)
2613 int fx
, fy
, ex
, ey
, otyp
= obj
->otyp
;
2616 /* check under our "feet" first */
2617 otmp
= sobj_at(otyp
, x
, y
);
2619 /* don't be clever and find ourselves */
2620 if (otmp
!= obj
&& mergable(otmp
, obj
))
2622 otmp
= nxtobj(otmp
, otyp
, TRUE
);
2626 return (struct obj
*) 0;
2628 /* search in a random order */
2629 dx
= (rn2(2) ? -1 : 1);
2630 dy
= (rn2(2) ? -1 : 1);
2634 for (fx
= ex
; abs(fx
- ex
) < 3; fx
+= dx
) {
2635 for (fy
= ey
; abs(fy
- ey
) < 3; fy
+= dy
) {
2636 /* 0, 0 was checked above */
2637 if (isok(fx
, fy
) && (fx
!= x
|| fy
!= y
)) {
2638 if ((otmp
= obj_nexto_xy(obj
, fx
, fy
, FALSE
)) != 0)
2643 return (struct obj
*) 0;
2647 * Causes one object to absorb another, increasing
2648 * weight accordingly. Frees obj2; obj1 remains and
2652 obj_absorb(obj1
, obj2
)
2653 struct obj
**obj1
, **obj2
;
2655 struct obj
*otmp1
, *otmp2
;
2659 /* don't let people dumb it up */
2663 if (otmp1
&& otmp2
&& otmp1
!= otmp2
) {
2664 if (otmp1
->bknown
!= otmp2
->bknown
)
2665 otmp1
->bknown
= otmp2
->bknown
= 0;
2666 if (otmp1
->rknown
!= otmp2
->rknown
)
2667 otmp1
->rknown
= otmp2
->rknown
= 0;
2668 if (otmp1
->greased
!= otmp2
->greased
)
2669 otmp1
->greased
= otmp2
->greased
= 0;
2670 if (otmp1
->orotten
|| otmp2
->orotten
)
2671 otmp1
->orotten
= otmp2
->orotten
= 1;
2672 o1wt
= otmp1
->oeaten
? otmp1
->oeaten
: otmp1
->owt
;
2673 o2wt
= otmp2
->oeaten
? otmp2
->oeaten
: otmp2
->owt
;
2674 /* averaging the relative ages is less likely to overflow
2675 than averaging the absolute ages directly */
2676 agetmp
= (((moves
- otmp1
->age
) * o1wt
2677 + (moves
- otmp2
->age
) * o2wt
)
2679 otmp1
->age
= moves
- agetmp
; /* conv. relative back to absolute */
2682 otmp1
->oeaten
+= o2wt
;
2684 obj_extract_self(otmp2
);
2685 newsym(otmp2
->ox
, otmp2
->oy
); /* in case of floor */
2687 *obj2
= (struct obj
*) 0;
2692 impossible("obj_absorb: not called with two actual objects");
2693 return (struct obj
*) 0;
2697 * Causes the heavier object to absorb the lighter object;
2698 * wrapper for obj_absorb so that floor_effects works more
2699 * cleanly (since we don't know which we want to stay around)
2702 obj_meld(obj1
, obj2
)
2703 struct obj
**obj1
, **obj2
;
2705 struct obj
*otmp1
, *otmp2
;
2710 if (otmp1
&& otmp2
&& otmp1
!= otmp2
) {
2711 if (otmp1
->owt
> otmp2
->owt
2712 || (otmp1
->owt
== otmp2
->owt
&& rn2(2))) {
2713 return obj_absorb(obj1
, obj2
);
2715 return obj_absorb(obj2
, obj1
);
2719 impossible("obj_meld: not called with two actual objects");
2720 return (struct obj
*) 0;