1 /* NetHack 3.6 mkobj.c $NHDT-Date: 1548978605 2019/01/31 23:50:05 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.142 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /*-Copyright (c) Derek S. Ray, 2015. */
4 /* NetHack may be freely redistributed. See license for details. */
8 STATIC_DCL void FDECL(mkbox_cnts, (struct obj *));
9 STATIC_DCL unsigned FDECL(nextoid, (struct obj *, struct obj *));
10 STATIC_DCL void FDECL(maybe_adjust_light, (struct obj *, int));
11 STATIC_DCL void FDECL(obj_timer_checks, (struct obj *,
12 XCHAR_P, XCHAR_P, int));
13 STATIC_DCL void FDECL(container_weight, (struct obj *));
14 STATIC_DCL struct obj *FDECL(save_mtraits, (struct obj *, struct monst *));
15 STATIC_DCL void FDECL(objlist_sanity, (struct obj *, int, const char *));
16 STATIC_DCL void FDECL(mon_obj_sanity, (struct monst *, const char *));
17 STATIC_DCL const char *FDECL(where_name, (struct obj *));
18 STATIC_DCL void FDECL(insane_object, (struct obj *, const char *,
19 const char *, struct monst *));
20 STATIC_DCL void FDECL(check_contained, (struct obj *, const char *));
21 STATIC_DCL void FDECL(sanity_check_worn, (struct obj *));
24 int iprob; /* probability of an item type */
25 char iclass; /* item class */
28 static const struct icp mkobjprobs[] = { { 10, WEAPON_CLASS },
38 { 1, AMULET_CLASS } };
40 static const struct icp boxiprobs[] = { { 18, GEM_CLASS },
48 { 1, AMULET_CLASS } };
50 static const struct icp rogueprobs[] = { { 12, WEAPON_CLASS },
58 static const struct icp hellprobs[] = { { 20, WEAPON_CLASS },
67 { 4, AMULET_CLASS } };
72 struct oextra *oextra;
74 oextra = (struct oextra *) alloc(sizeof (struct oextra));
87 struct oextra *x = o->oextra;
91 free((genericptr_t) x->oname);
93 free_omonst(o); /* 'o' rather than 'x' */
95 free((genericptr_t) x->omid);
97 free((genericptr_t) x->olong);
99 free((genericptr_t) x->omailcmd);
101 free((genericptr_t) x);
102 o->oextra = (struct oextra *) 0;
111 otmp->oextra = newoextra();
114 struct monst *m = newmonst();
126 struct monst *m = OMONST(otmp);
131 free((genericptr_t) m);
132 OMONST(otmp) = (struct monst *) 0;
142 otmp->oextra = newoextra();
144 OMID(otmp) = (unsigned *) alloc(sizeof (unsigned));
145 (void) memset((genericptr_t) OMID(otmp), 0, sizeof (unsigned));
153 if (otmp->oextra && OMID(otmp)) {
154 free((genericptr_t) OMID(otmp));
155 OMID(otmp) = (unsigned *) 0;
164 otmp->oextra = newoextra();
166 OLONG(otmp) = (long *) alloc(sizeof (long));
167 (void) memset((genericptr_t) OLONG(otmp), 0, sizeof (long));
175 if (otmp->oextra && OLONG(otmp)) {
176 free((genericptr_t) OLONG(otmp));
177 OLONG(otmp) = (long *) 0;
182 new_omailcmd(otmp, response_cmd)
184 const char *response_cmd;
187 otmp->oextra = newoextra();
190 OMAILCMD(otmp) = dupstr(response_cmd);
197 if (otmp->oextra && OMAILCMD(otmp)) {
198 free((genericptr_t) OMAILCMD(otmp));
199 OMAILCMD(otmp) = (char *) 0;
204 mkobj_at(let, x, y, artif)
211 otmp = mkobj(let, artif);
212 place_object(otmp, x, y);
217 mksobj_at(otyp, x, y, init, artif)
223 otmp = mksobj(otyp, init, artif);
224 place_object(otmp, x, y);
229 mksobj_migr_to_species(otyp, mflags2, init, artif)
236 otmp = mksobj(otyp, init, artif);
238 add_to_migration(otmp);
239 otmp->owornmask = (long) MIGR_TO_SPECIES;
240 otmp->corpsenm = mflags2;
245 /* mkobj(): select a type of item from a class, use mksobj() to create it */
251 int tprob, i, prob = rnd(1000);
253 if (oclass == RANDOM_CLASS) {
254 const struct icp *iprobs = Is_rogue_level(&u.uz)
255 ? (const struct icp *) rogueprobs
256 : Inhell ? (const struct icp *) hellprobs
257 : (const struct icp *) mkobjprobs;
259 for (tprob = rnd(100); (tprob -= iprobs->iprob) > 0; iprobs++)
261 oclass = iprobs->iclass;
264 i = bases[(int) oclass];
265 while ((prob -= objects[i].oc_prob) > 0)
268 if (objects[i].oc_class != oclass || !OBJ_NAME(objects[i]))
269 panic("probtype error, oclass=%d i=%d", (int) oclass, i);
271 return mksobj(i, TRUE, artif);
279 register struct obj *otmp;
281 box->cobj = (struct obj *) 0;
288 n = box->olocked ? 7 : 5;
291 n = box->olocked ? 5 : 3;
295 /* initial inventory: sack starts out empty */
296 if (moves <= 1 && !in_mklev) {
309 for (n = rn2(n + 1); n > 0; n--) {
310 if (box->otyp == ICE_BOX) {
311 if (!(otmp = mksobj(CORPSE, TRUE, TRUE)))
313 /* Note: setting age to 0 is correct. Age has a different
314 * from usual meaning for objects stored in ice boxes. -KAA
318 (void) stop_timer(ROT_CORPSE, obj_to_any(otmp));
319 (void) stop_timer(REVIVE_MON, obj_to_any(otmp));
323 const struct icp *iprobs = boxiprobs;
325 for (tprob = rnd(100); (tprob -= iprobs->iprob) > 0; iprobs++)
327 if (!(otmp = mkobj(iprobs->iclass, TRUE)))
330 /* handle a couple of special cases */
331 if (otmp->oclass == COIN_CLASS) {
332 /* 2.5 x level's usual amount; weight adjusted below */
333 otmp->quan = (long) (rnd(level_difficulty() + 2) * rnd(75));
334 otmp->owt = weight(otmp);
336 while (otmp->otyp == ROCK) {
337 otmp->otyp = rnd_class(DILITHIUM_CRYSTAL, LOADSTONE);
340 otmp->owt = weight(otmp);
342 if (box->otyp == BAG_OF_HOLDING) {
346 otmp->owt = weight(otmp);
348 while (otmp->otyp == WAN_CANCELLATION)
349 otmp->otyp = rnd_class(WAN_LIGHT, WAN_LIGHTNING);
352 (void) add_to_container(box, otmp);
356 /* select a random, common monster type */
360 register struct permonst *ptr;
362 unsigned short excludeflags;
364 /* Plan A: get a level-appropriate common monster */
369 /* Plan B: get any common monster */
370 excludeflags = G_UNIQ | G_NOGEN | (Inhell ? G_NOHELL : G_HELL);
372 i = rn1(SPECIAL_PM - LOW_PM, LOW_PM);
374 } while ((ptr->geno & excludeflags) != 0);
380 copy_oextra(obj2, obj1)
381 struct obj *obj2, *obj1;
383 if (!obj2 || !obj1 || !obj1->oextra)
387 obj2->oextra = newoextra();
389 oname(obj2, ONAME(obj1));
390 if (has_omonst(obj1)) {
393 (void) memcpy((genericptr_t) OMONST(obj2),
394 (genericptr_t) OMONST(obj1), sizeof (struct monst));
395 OMONST(obj2)->mextra = (struct mextra *) 0;
396 OMONST(obj2)->nmon = (struct monst *) 0;
398 OMONST(obj2)->m_id = context.ident++;
399 if (OMONST(obj2)->m_id) /* ident overflowed */
400 OMONST(obj2)->m_id = context.ident++;
402 if (OMONST(obj1)->mextra)
403 copy_mextra(OMONST(obj2), OMONST(obj1));
405 if (has_omid(obj1)) {
408 (void) memcpy((genericptr_t) OMID(obj2), (genericptr_t) OMID(obj1),
411 if (has_olong(obj1)) {
414 (void) memcpy((genericptr_t) OLONG(obj2), (genericptr_t) OLONG(obj1),
417 if (has_omailcmd(obj1)) {
418 new_omailcmd(obj2, OMAILCMD(obj1));
423 * Split obj so that it gets size gets reduced by num. The quantity num is
424 * put in the object structure delivered by this call. The returned object
425 * has its wornmask cleared and is positioned just following the original
426 * in the nobj chain (and nexthere chain when on the floor).
435 if (obj->cobj || num <= 0L || obj->quan <= num)
436 panic("splitobj"); /* can't split containers */
438 *otmp = *obj; /* copies whole structure */
439 otmp->oextra = (struct oextra *) 0;
440 otmp->o_id = nextoid(obj, otmp);
441 otmp->timed = 0; /* not timed, yet */
442 otmp->lamplit = 0; /* ditto */
443 otmp->owornmask = 0L; /* new object isn't worn */
445 obj->owt = weight(obj);
447 otmp->owt = weight(otmp); /* -= obj->owt ? */
449 context.objsplit.parent_oid = obj->o_id;
450 context.objsplit.child_oid = otmp->o_id;
452 /* Only set nexthere when on the floor, nexthere is also used */
453 /* as a back pointer to the container object when contained. */
454 if (obj->where == OBJ_FLOOR)
455 obj->nexthere = otmp;
456 copy_oextra(otmp, obj);
458 free_omid(otmp); /* only one association with m_id*/
460 splitbill(obj, otmp);
462 obj_split_timers(obj, otmp);
463 if (obj_sheds_light(obj))
464 obj_split_light_source(obj, otmp);
468 /* when splitting a stack that has o_id-based shop prices, pick an
469 o_id value for the new stack that will maintain the same price */
471 nextoid(oldobj, newobj)
472 struct obj *oldobj, *newobj;
474 int olddif, newdif, trylimit = 256; /* limit of 4 suffices at present */
475 unsigned oid = context.ident - 1; /* loop increment will reverse -1 */
477 olddif = oid_price_adjustment(oldobj, oldobj->o_id);
480 if (!oid) /* avoid using 0 (in case value wrapped) */
482 newdif = oid_price_adjustment(newobj, oid);
483 } while (newdif != olddif && --trylimit >= 0);
484 context.ident = oid + 1; /* ready for next new object */
488 /* try to find the stack obj was split from, then merge them back together;
489 returns the combined object if unsplit is successful, null otherwise */
494 unsigned target_oid = 0;
495 struct obj *oparent = 0, *ochild = 0, *list = 0;
498 * We don't operate on floor objects (we're following o->nobj rather
499 * than o->nexthere), on free objects (don't know which list to use when
500 * looking for obj's parent or child), on bill objects (too complicated,
501 * not needed), or on buried or migrating objects (not needed).
502 * [This could be improved, but at present additional generality isn't
505 switch (obj->where) {
512 return (struct obj *) 0;
517 list = obj->ocarry->minvent;
520 list = obj->ocontainer->cobj;
524 /* first try the expected case; obj is split from another stack */
525 if (obj->o_id == context.objsplit.child_oid) {
526 /* parent probably precedes child and will require list traversal */
528 target_oid = context.objsplit.parent_oid;
529 if (obj->nobj && obj->nobj->o_id == target_oid)
531 } else if (obj->o_id == context.objsplit.parent_oid) {
532 /* alternate scenario: another stack was split from obj;
533 child probably follows parent and will be found here */
535 target_oid = context.objsplit.child_oid;
536 if (obj->nobj && obj->nobj->o_id == target_oid)
539 /* if we have only half the split, scan obj's list to find other half */
540 if (ochild && !oparent) {
542 for (obj = list; obj; obj = obj->nobj)
543 if (obj->o_id == target_oid) {
547 } else if (oparent && !ochild) {
548 /* alternate scenario */
549 for (obj = list; obj; obj = obj->nobj)
550 if (obj->o_id == target_oid) {
555 /* if we have both parent and child, try to merge them;
556 if successful, return the combined stack, otherwise return null */
557 return (oparent && ochild && merged(&oparent, &ochild)) ? oparent : 0;
560 /* reset splitobj()/unsplitobj() context */
564 context.objsplit.parent_oid = context.objsplit.child_oid = 0;
568 * Insert otmp right after obj in whatever chain(s) it is on. Then extract
569 * obj from the chain(s). This function does a literal swap. It is up to
570 * the caller to provide a valid context for the swap. When done, obj will
571 * still exist, but not on any chain.
573 * Note: Don't use use obj_extract_self() -- we are doing an in-place swap,
574 * not actually moving something.
577 replace_object(obj, otmp)
581 otmp->where = obj->where;
582 switch (obj->where) {
587 otmp->nobj = obj->nobj;
589 extract_nobj(obj, &invent);
592 otmp->nobj = obj->nobj;
593 otmp->ocontainer = obj->ocontainer;
595 extract_nobj(obj, &obj->ocontainer->cobj);
598 otmp->nobj = obj->nobj;
599 otmp->ocarry = obj->ocarry;
601 extract_nobj(obj, &obj->ocarry->minvent);
604 otmp->nobj = obj->nobj;
605 otmp->nexthere = obj->nexthere;
609 obj->nexthere = otmp;
610 extract_nobj(obj, &fobj);
611 extract_nexthere(obj, &level.objects[obj->ox][obj->oy]);
614 panic("replace_object: obj position");
619 /* is 'obj' inside a container whose contents aren't known?
620 if so, return the outermost container meeting that criterium */
622 unknwn_contnr_contents(obj)
625 struct obj *result = 0, *parent;
627 while (obj->where == OBJ_CONTAINED) {
628 parent = obj->ocontainer;
637 * Create a dummy duplicate to put on shop bill. The duplicate exists
638 * only in the billobjs chain. This function is used when a shop object
639 * is being altered, and a copy of the original is needed for billing
640 * purposes. For example, when eating, where an interruption will yield
641 * an object which is different from what it started out as; the "I x"
642 * command needs to display the original object.
644 * The caller is responsible for checking otmp->unpaid and
645 * costly_spot(u.ux, u.uy). This function will make otmp no charge.
647 * Note that check_unpaid_usage() should be used instead for partial
648 * usage of an object.
651 bill_dummy_object(otmp)
652 register struct obj *otmp;
654 register struct obj *dummy;
658 cost = unpaid_cost(otmp, FALSE);
659 subfrombill(otmp, shop_keeper(*u.ushops));
663 dummy->oextra = (struct oextra *) 0;
664 dummy->where = OBJ_FREE;
665 dummy->o_id = context.ident++;
667 dummy->o_id = context.ident++; /* ident overflowed */
669 copy_oextra(dummy, otmp);
671 free_omid(dummy); /* only one association with m_id*/
672 if (Is_candle(dummy))
674 dummy->owornmask = 0L; /* dummy object is not worn */
675 addtobill(dummy, FALSE, TRUE, TRUE);
677 alter_cost(dummy, -cost);
678 /* no_charge is only valid for some locations */
680 (otmp->where == OBJ_FLOOR || otmp->where == OBJ_CONTAINED) ? 1 : 0;
685 /* alteration types; must match COST_xxx macros in hack.h */
686 static const char *const alteration_verbs[] = {
688 "cancel", "drain", "uncharge", "unbless", "uncurse", "disenchant",
689 "degrade", "dilute", "erase", "burn", "neutralize", "destroy", "splatter",
690 "bite", "open", "break the lock on", "rust", "rot", "tarnish"
692 "
\96³
\8cø
\89»
\82µ
\82½", "
\97ò
\89»
\82³
\82¹
\82½", "
\95ú
\8fo
\82³
\82¹
\82½", "
\8fj
\95\9f\82ð
\89ð
\82¢
\82½", "
\8eô
\82¢
\82ð
\89ð
\82¢
\82½", "
\96\82\97Í
\82ð
\8c¸
\82ç
\82µ
\82½",
693 "
\97ò
\89»
\82³
\82¹
\82½", "
\94\96\82ß
\82½", "
\8fÁ
\82µ
\82½", "
\94R
\82â
\82µ
\82½", "
\96³
\93Å
\89»
\82µ
\82½", "
\89ó
\82µ
\82½", "
\8eg
\82Á
\82½",
694 "
\90H
\82×
\82½", "
\8aJ
\82¯
\82½", "
\8c®
\82ð
\89ó
\82µ
\82½", "
\8eK
\82Ñ
\82³
\82¹
\82½", "
\95\85\82ç
\82¹
\82½", "
\8f\9d\82Â
\82¯
\82½"
698 /* possibly bill for an object which the player has just modified */
700 costly_alteration(obj, alter_type)
707 #if 0 /*JP*//*
\8eg
\82í
\82È
\82¢*/
708 const char *those, *them;
710 struct monst *shkp = 0;
712 if (alter_type < 0 || alter_type >= SIZE(alteration_verbs)) {
713 impossible("invalid alteration type (%d)", alter_type);
717 ox = oy = 0; /* lint suppression */
718 objroom = '\0'; /* ditto */
719 if (carried(obj) || obj->where == OBJ_FREE) {
720 /* OBJ_FREE catches obj_no_longer_held()'s transformation
721 of crysknife back into worm tooth; the object has been
722 removed from inventory but not necessarily placed at
723 its new location yet--the unpaid flag will still be set
724 if this item is owned by a shop */
728 /* this get_obj_location shouldn't fail, but if it does,
729 use hero's location */
730 if (!get_obj_location(obj, &ox, &oy, CONTAINED_TOO))
731 ox = u.ux, oy = u.uy;
732 if (!costly_spot(ox, oy))
734 objroom = *in_rooms(ox, oy, SHOPBASE);
735 /* if no shop cares about it, we're done */
736 if (!billable(&shkp, obj, objroom, FALSE))
740 #if 0 /*JP*//*
\93ú
\96{
\8cê
\82Å
\82Í
\95s
\97v*/
742 those = "that", them = "it";
744 those = "those", them = "them";
747 /* when shopkeeper describes the object as being uncursed or unblessed
748 hero will know that it is now uncursed; will also make the feedback
749 from `I x' after bill_dummy_object() be more specific for this item */
750 set_bknown = (alter_type == COST_UNCURS || alter_type == COST_UNBLSS);
752 switch (obj->where) {
753 case OBJ_FREE: /* obj_no_longer_held() */
758 verbalize("You %s %s %s, you pay for %s!",
759 alteration_verbs[alter_type], those, simpleonames(obj),
762 verbalize("%s
\82ð%s
\82Ì
\82È
\82ç
\81C
\94\83\82Á
\82Ä
\82à
\82ç
\82¤
\82æ
\81I",
763 simpleonames(obj), alteration_verbs[alter_type]);
765 bill_dummy_object(obj);
770 if (costly_spot(u.ux, u.uy) && objroom == *u.ushops) {
772 verbalize("You %s %s, you pay for %s!",
773 alteration_verbs[alter_type], those, them);
775 verbalize("%s
\82Ì
\82È
\82ç
\81C
\94\83\82Á
\82Ä
\82à
\82ç
\82¤
\82æ
\81I",
776 alteration_verbs[alter_type]);
778 bill_dummy_object(obj);
780 (void) stolen_value(obj, ox, oy, FALSE, FALSE);
786 static const char dknowns[] = { WAND_CLASS, RING_CLASS, POTION_CLASS,
787 SCROLL_CLASS, GEM_CLASS, SPBOOK_CLASS,
788 WEAPON_CLASS, TOOL_CLASS, 0 };
790 /* mksobj(): create a specific type of object */
792 mksobj(otyp, init, artif)
799 char let = objects[otyp].oc_class;
803 otmp->age = monstermoves;
804 otmp->o_id = context.ident++;
806 otmp->o_id = context.ident++; /* ident overflowed */
810 otmp->where = OBJ_FREE;
811 otmp->dknown = index(dknowns, let) ? 0 : 1;
812 if ((otmp->otyp >= ELVEN_SHIELD && otmp->otyp <= ORCISH_SHIELD)
813 || otmp->otyp == SHIELD_OF_REFLECTION
814 || objects[otmp->otyp].oc_merge)
816 if (!objects[otmp->otyp].oc_uses_known)
820 otmp->corpsenm = NON_PM;
825 otmp->quan = is_multigen(otmp) ? (long) rn1(6, 6) : 1L;
828 otmp->blessed = rn2(2);
829 } else if (!rn2(10)) {
833 blessorcurse(otmp, 10);
834 if (is_poisonable(otmp) && !rn2(100))
837 if (artif && !rn2(20))
838 otmp = mk_artifact(otmp, (aligntyp) A_NONE);
842 switch (otmp->otyp) {
844 /* possibly overridden by mkcorpstat() */
847 otmp->corpsenm = undead_to_corpse(rndmonnum());
848 while ((mvitals[otmp->corpsenm].mvflags & G_NOCORPSE)
851 /* perhaps rndmonnum() only wants to make G_NOCORPSE
852 monsters on this level; create an adventurer's
853 corpse instead, then */
854 otmp->corpsenm = PM_HUMAN;
856 /* timer set below */
859 otmp->corpsenm = NON_PM; /* generic egg */
861 for (tryct = 200; tryct > 0; --tryct) {
862 mndx = can_be_hatched(rndmonnum());
863 if (mndx != NON_PM && !dead_species(mndx, TRUE)) {
864 otmp->corpsenm = mndx; /* typed egg */
868 /* timer set below */
871 otmp->corpsenm = NON_PM; /* empty (so far) */
873 set_tin_variety(otmp, SPINACH_TIN);
875 for (tryct = 200; tryct > 0; --tryct) {
876 mndx = undead_to_corpse(rndmonnum());
877 if (mons[mndx].cnutrit
878 && !(mvitals[mndx].mvflags & G_NOCORPSE)) {
879 otmp->corpsenm = mndx;
880 set_tin_variety(otmp, RANDOM_TIN);
884 blessorcurse(otmp, 10);
887 otmp->spe = context.current_fruit;
888 flags.made_fruit = TRUE;
891 otmp->quan = (long) rnd(2);
894 if (Is_pudding(otmp)) {
896 otmp->known = otmp->dknown = 1;
897 otmp->corpsenm = PM_GRAY_OOZE
898 + (otmp->otyp - GLOB_OF_GRAY_OOZE);
900 if (otmp->otyp != CORPSE && otmp->otyp != MEAT_RING
901 && otmp->otyp != KELP_FROND && !rn2(6)) {
907 otmp->corpsenm = 0; /* LOADSTONE hack */
908 if (otmp->otyp == LOADSTONE)
910 else if (otmp->otyp == ROCK)
911 otmp->quan = (long) rn1(6, 6);
912 else if (otmp->otyp != LUCKSTONE && !rn2(6))
918 switch (otmp->otyp) {
922 otmp->age = 20L * /* 400 or 200 */
923 (long) objects[otmp->otyp].oc_cost;
925 otmp->quan = 1L + (long) (rn2(2) ? rn2(7) : 0);
926 blessorcurse(otmp, 5);
931 otmp->age = (long) rn1(500, 1000);
933 blessorcurse(otmp, 5);
938 blessorcurse(otmp, 2);
942 otmp->olocked = !!(rn2(5));
943 otmp->otrapped = !(rn2(10));
951 case EXPENSIVE_CAMERA:
954 otmp->spe = rn1(70, 30);
958 blessorcurse(otmp, 10);
962 blessorcurse(otmp, 2);
971 otmp->corpsenm = rndmonnum();
972 while (is_human(&mons[otmp->corpsenm]) && tryct++ < 30);
973 blessorcurse(otmp, 4);
975 case BELL_OF_OPENING:
982 case DRUM_OF_EARTHQUAKE:
983 otmp->spe = rn1(5, 4);
988 if (otmp->otyp == AMULET_OF_YENDOR)
989 context.made_amulet = TRUE;
990 if (rn2(10) && (otmp->otyp == AMULET_OF_STRANGULATION
991 || otmp->otyp == AMULET_OF_CHANGE
992 || otmp->otyp == AMULET_OF_RESTFUL_SLEEP)) {
995 blessorcurse(otmp, 10);
1001 case POTION_CLASS: /* note: potions get some additional init below */
1004 if (otmp->otyp != SCR_MAIL)
1006 blessorcurse(otmp, 4);
1009 otmp->spestudied = 0;
1010 blessorcurse(otmp, 17);
1014 && (otmp->otyp == FUMBLE_BOOTS
1015 || otmp->otyp == LEVITATION_BOOTS
1016 || otmp->otyp == HELM_OF_OPPOSITE_ALIGNMENT
1017 || otmp->otyp == GAUNTLETS_OF_FUMBLING || !rn2(11))) {
1019 otmp->spe = -rne(3);
1020 } else if (!rn2(10)) {
1021 otmp->blessed = rn2(2);
1024 blessorcurse(otmp, 10);
1025 if (artif && !rn2(40))
1026 otmp = mk_artifact(otmp, (aligntyp) A_NONE);
1027 /* simulate lacquered armor for samurai */
1028 if (Role_if(PM_SAMURAI) && otmp->otyp == SPLINT_MAIL
1029 && (moves <= 1 || In_quest(&u.uz))) {
1031 /* optimizer bitfield bug */
1032 otmp->oerodeproof = 1;
1035 otmp->oerodeproof = otmp->rknown = 1;
1040 if (otmp->otyp == WAN_WISHING)
1044 rn1(5, (objects[otmp->otyp].oc_dir == NODIR) ? 11 : 4);
1045 blessorcurse(otmp, 17);
1046 otmp->recharged = 0; /* used to control recharging */
1049 if (objects[otmp->otyp].oc_charged) {
1050 blessorcurse(otmp, 3);
1052 if (rn2(10) && bcsign(otmp))
1053 otmp->spe = bcsign(otmp) * rne(3);
1055 otmp->spe = rn2(2) ? rne(3) : -rne(3);
1057 /* make useless +0 rings much less common */
1059 otmp->spe = rn2(4) - rn2(3);
1060 /* negative rings are usually cursed */
1061 if (otmp->spe < 0 && rn2(5))
1063 } else if (rn2(10) && (otmp->otyp == RIN_TELEPORTATION
1064 || otmp->otyp == RIN_POLYMORPH
1065 || otmp->otyp == RIN_AGGRAVATE_MONSTER
1066 || otmp->otyp == RIN_HUNGER || !rn2(9))) {
1071 switch (otmp->otyp) {
1073 /* possibly overridden by mkcorpstat() */
1074 otmp->corpsenm = rndmonnum();
1075 if (!verysmall(&mons[otmp->corpsenm])
1076 && rn2(level_difficulty() / 2 + 10) > 10)
1077 (void) add_to_container(otmp, mkobj(SPBOOK_CLASS, FALSE));
1081 break; /* do nothing */
1083 impossible("impossible mkobj %d, sym '%c'.", otmp->otyp,
1084 objects[otmp->otyp].oc_class);
1085 return (struct obj *) 0;
1089 /* some things must get done (corpsenm, timers) even if init = 0 */
1090 switch ((otmp->oclass == POTION_CLASS && otmp->otyp != POT_OIL)
1094 if (otmp->corpsenm == NON_PM) {
1095 otmp->corpsenm = undead_to_corpse(rndmonnum());
1096 if (mvitals[otmp->corpsenm].mvflags & (G_NOCORPSE | G_GONE))
1097 otmp->corpsenm = urole.malenum;
1102 if (otmp->corpsenm == NON_PM)
1103 otmp->corpsenm = rndmonnum();
1107 set_corpsenm(otmp, otmp->corpsenm);
1110 otmp->age = MAX_OIL_IN_FLASK; /* amount of oil */
1112 case POT_WATER: /* POTION_CLASS */
1113 otmp->fromsink = 0; /* overloads corpsenm, which was set to NON_PM */
1116 otmp->leashmon = 0; /* overloads corpsenm, which was set to NON_PM */
1119 otmp->novelidx = -1; /* "none of the above"; will be changed */
1120 otmp = oname(otmp, noveltitle(&otmp->novelidx));
1124 /* unique objects may have an associated artifact entry */
1125 if (objects[otyp].oc_unique && !otmp->oartifact)
1126 otmp = mk_artifact(otmp, (aligntyp) A_NONE);
1127 otmp->owt = weight(otmp);
1132 * Several areas of the code made direct reassignments
1133 * to obj->corpsenm. Because some special handling is
1134 * required in certain cases, place that handling here
1135 * and call this routine in place of the direct assignment.
1137 * If the object was a lizard or lichen corpse:
1138 * - ensure that you don't end up with some
1139 * other corpse type which has no rot-away timer.
1141 * If the object was a troll corpse:
1142 * - ensure that you don't end up with some other
1143 * corpse type which resurrects from the dead.
1145 * Re-calculates the weight of figurines and corpses to suit the
1148 * Existing timeout value for egg hatch is preserved.
1152 set_corpsenm(obj, id)
1159 if (obj->otyp == EGG)
1160 when = stop_timer(HATCH_EGG, obj_to_any(obj));
1163 obj_stop_timers(obj); /* corpse or figurine */
1167 switch (obj->otyp) {
1169 start_corpse_timeout(obj);
1170 obj->owt = weight(obj);
1173 if (obj->corpsenm != NON_PM && !dead_species(obj->corpsenm, TRUE)
1174 && (carried(obj) || mcarried(obj)))
1175 attach_fig_transform_timeout(obj);
1176 obj->owt = weight(obj);
1179 if (obj->corpsenm != NON_PM && !dead_species(obj->corpsenm, TRUE))
1180 attach_egg_hatch_timeout(obj, when);
1182 default: /* tin, etc. */
1183 obj->owt = weight(obj);
1189 * Start a corpse decay or revive timer.
1190 * This takes the age of the corpse into consideration as of 3.4.0.
1193 start_corpse_timeout(body)
1196 long when; /* rot away when this old */
1197 long corpse_age; /* age of corpse */
1201 #define TAINT_AGE (50L) /* age when corpses go bad */
1202 #define TROLL_REVIVE_CHANCE 37 /* 1/37 chance for 50 turns ~ 75% chance */
1203 #define ROT_AGE (250L) /* age when corpses rot away */
1205 /* lizards and lichen don't rot or revive */
1206 if (body->corpsenm == PM_LIZARD || body->corpsenm == PM_LICHEN)
1209 action = ROT_CORPSE; /* default action: rot away */
1210 rot_adjust = in_mklev ? 25 : 10; /* give some variation */
1211 corpse_age = monstermoves - body->age;
1212 if (corpse_age > ROT_AGE)
1215 when = ROT_AGE - corpse_age;
1216 when += (long) (rnz(rot_adjust) - rot_adjust);
1218 if (is_rider(&mons[body->corpsenm])) {
1220 * Riders always revive. They have a 1/3 chance per turn
1221 * of reviving after 12 turns. Always revive by 500.
1223 action = REVIVE_MON;
1224 for (when = 12L; when < 500L; when++)
1228 } else if (mons[body->corpsenm].mlet == S_TROLL && !body->norevive) {
1230 for (age = 2; age <= TAINT_AGE; age++)
1231 if (!rn2(TROLL_REVIVE_CHANCE)) { /* troll revives */
1232 action = REVIVE_MON;
1240 (void) start_timer(when, TIMER_OBJECT, action, obj_to_any(body));
1244 maybe_adjust_light(obj, old_range)
1250 int new_range = arti_light_radius(obj), delta = new_range - old_range;
1252 /* radius of light emitting artifact varies by curse/bless state
1253 so will change after blessing or cursing */
1255 obj_adjust_light_radius(obj, new_range);
1256 /* simplifying assumptions: hero is wielding this object;
1257 artifacts have to be in use to emit light and monsters'
1258 gear won't change bless or curse state */
1259 if (!Blind && get_obj_location(obj, &ox, &oy, 0)) {
1261 if (iflags.last_msg == PLNMSG_OBJ_GLOWS)
1262 /* we just saw "The <obj> glows <color>." from dipping */
1264 Strcpy(buf, (obj->quan == 1L) ? "It" : "They");
1266 Strcpy(buf, "
\82»
\82ê");
1268 else if (carried(obj) || cansee(ox, oy))
1269 Strcpy(buf, Yname2(obj));
1271 /* initial activation says "dimly" if cursed,
1272 "brightly" if uncursed, and "brilliantly" if blessed;
1273 when changing intensity, using "less brightly" is
1274 straightforward for dimming, but we need "brighter"
1275 rather than "more brightly" for brightening; ugh */
1277 pline("%s %s %s%s.", buf, otense(obj, "shine"),
1278 (abs(delta) > 1) ? "much " : "",
1279 (delta > 0) ? "brighter" : "less brightly");
1281 pline("%s
\82Ì
\8bP
\82«
\82Í%s%s
\81D", buf,
1282 (abs(delta) > 1) ? "
\82©
\82È
\82è" : "",
1283 (delta > 0) ? "
\91\9d\82µ
\82½" : "
\8c¸
\82Á
\82½");
1291 * bless(), curse(), unbless(), uncurse() -- any relevant message
1292 * about glowing amber/black/&c should be delivered prior to calling
1293 * these routines to make the actual curse/bless state change.
1298 register struct obj *otmp;
1302 if (otmp->oclass == COIN_CLASS)
1305 old_light = arti_light_radius(otmp);
1308 if (carried(otmp) && confers_luck(otmp))
1310 else if (otmp->otyp == BAG_OF_HOLDING)
1311 otmp->owt = weight(otmp);
1312 else if (otmp->otyp == FIGURINE && otmp->timed)
1313 (void) stop_timer(FIG_TRANSFORM, obj_to_any(otmp));
1315 maybe_adjust_light(otmp, old_light);
1321 register struct obj *otmp;
1326 old_light = arti_light_radius(otmp);
1328 if (carried(otmp) && confers_luck(otmp))
1330 else if (otmp->otyp == BAG_OF_HOLDING)
1331 otmp->owt = weight(otmp);
1333 maybe_adjust_light(otmp, old_light);
1338 register struct obj *otmp;
1340 unsigned already_cursed;
1343 if (otmp->oclass == COIN_CLASS)
1346 old_light = arti_light_radius(otmp);
1347 already_cursed = otmp->cursed;
1350 /* welded two-handed weapon interferes with some armor removal */
1351 if (otmp == uwep && bimanual(uwep))
1353 /* rules at top of wield.c state that twoweapon cannot be done
1354 with cursed alternate weapon */
1355 if (otmp == uswapwep && u.twoweap)
1357 /* some cursed items need immediate updating */
1358 if (carried(otmp) && confers_luck(otmp)) {
1360 } else if (otmp->otyp == BAG_OF_HOLDING) {
1361 otmp->owt = weight(otmp);
1362 } else if (otmp->otyp == FIGURINE) {
1363 if (otmp->corpsenm != NON_PM && !dead_species(otmp->corpsenm, TRUE)
1364 && (carried(otmp) || mcarried(otmp)))
1365 attach_fig_transform_timeout(otmp);
1366 } else if (otmp->oclass == SPBOOK_CLASS) {
1367 /* if book hero is reading becomes cursed, interrupt */
1368 if (!already_cursed)
1372 maybe_adjust_light(otmp, old_light);
1378 register struct obj *otmp;
1383 old_light = arti_light_radius(otmp);
1385 if (carried(otmp) && confers_luck(otmp))
1387 else if (otmp->otyp == BAG_OF_HOLDING)
1388 otmp->owt = weight(otmp);
1389 else if (otmp->otyp == FIGURINE && otmp->timed)
1390 (void) stop_timer(FIG_TRANSFORM, obj_to_any(otmp));
1392 maybe_adjust_light(otmp, old_light);
1397 blessorcurse(otmp, chance)
1398 register struct obj *otmp;
1399 register int chance;
1401 if (otmp->blessed || otmp->cursed)
1416 register struct obj *otmp;
1418 return (!!otmp->blessed - !!otmp->cursed);
1422 * Calculate the weight of the given object. This will recursively follow
1423 * and calculate the weight of any containers.
1425 * Note: It is possible to end up with an incorrect weight if some part
1426 * of the code messes with a contained object and doesn't update the
1427 * container's weight.
1431 register struct obj *obj;
1433 int wt = (int) objects[obj->otyp].oc_weight;
1435 /* glob absorpsion means that merging globs accumulates weight while
1436 quantity stays 1, so update 'wt' to reflect that, unless owt is 0,
1437 when we assume this is a brand new glob so use objects[].oc_weight */
1438 if (obj->globby && obj->owt > 0)
1440 if (Is_container(obj) || obj->otyp == STATUE) {
1441 struct obj *contents;
1442 register int cwt = 0;
1444 if (obj->otyp == STATUE && obj->corpsenm >= LOW_PM)
1445 wt = (int) obj->quan * ((int) mons[obj->corpsenm].cwt * 3 / 2);
1447 for (contents = obj->cobj; contents; contents = contents->nobj)
1448 cwt += weight(contents);
1450 * The weight of bags of holding is calculated as the weight
1451 * of the bag plus the weight of the bag's contents modified
1454 * Bag status Weight of contents
1455 * ---------- ------------------
1457 * blessed x/4 [rounded up: (x+3)/4]
1458 * otherwise x/2 [rounded up: (x+1)/2]
1460 * The macro DELTA_CWT in pickup.c also implements these
1463 if (obj->otyp == BAG_OF_HOLDING)
1464 cwt = obj->cursed ? (cwt * 2) : obj->blessed ? ((cwt + 3) / 4)
1469 if (obj->otyp == CORPSE && obj->corpsenm >= LOW_PM) {
1470 long long_wt = obj->quan * (long) mons[obj->corpsenm].cwt;
1472 wt = (long_wt > LARGEST_INT) ? LARGEST_INT : (int) long_wt;
1474 wt = eaten_stat(wt, obj);
1476 } else if (obj->oclass == FOOD_CLASS && obj->oeaten) {
1477 return eaten_stat((int) obj->quan * wt, obj);
1478 } else if (obj->oclass == COIN_CLASS) {
1479 return (int) ((obj->quan + 50L) / 100L);
1480 } else if (obj->otyp == HEAVY_IRON_BALL && obj->owt != 0) {
1481 return (int) obj->owt; /* kludge for "very" heavy iron ball */
1482 } else if (obj->otyp == CANDELABRUM_OF_INVOCATION && obj->spe) {
1483 return wt + obj->spe * (int) objects[TALLOW_CANDLE].oc_weight;
1485 return (wt ? wt * (int) obj->quan : ((int) obj->quan + 1) >> 1);
1488 static int treefruits[] = { APPLE, ORANGE, PEAR, BANANA, EUCALYPTUS_LEAF };
1491 rnd_treefruit_at(x, y)
1494 return mksobj_at(treefruits[rn2(SIZE(treefruits))], x, y, TRUE, FALSE);
1498 mkgold(amount, x, y)
1502 register struct obj *gold = g_at(x, y);
1505 long mul = rnd(30 / max(12-depth(&u.uz), 2));
1506 amount = (long) (1 + rnd(level_difficulty() + 2) * mul);
1509 gold->quan += amount;
1511 gold = mksobj_at(GOLD_PIECE, x, y, TRUE, FALSE);
1512 gold->quan = amount;
1514 gold->owt = weight(gold);
1518 /* return TRUE if the corpse has special timing */
1519 #define special_corpse(num) \
1520 (((num) == PM_LIZARD) || ((num) == PM_LICHEN) || (is_rider(&mons[num])) \
1521 || (mons[num].mlet == S_TROLL))
1524 * OEXTRA note: Passing mtmp causes mtraits to be saved
1525 * even if ptr passed as well, but ptr is always used for
1526 * the corpse type (corpsenm). That allows the corpse type
1527 * to be different from the original monster,
1528 * i.e. vampire -> human corpse
1529 * yet still allow restoration of the original monster upon
1533 mkcorpstat(objtype, mtmp, ptr, x, y, corpstatflags)
1534 int objtype; /* CORPSE or STATUE */
1536 struct permonst *ptr;
1538 unsigned corpstatflags;
1540 register struct obj *otmp;
1541 boolean init = ((corpstatflags & CORPSTAT_INIT) != 0);
1543 if (objtype != CORPSE && objtype != STATUE)
1544 impossible("making corpstat type %d", objtype);
1545 if (x == 0 && y == 0) { /* special case - random placement */
1546 otmp = mksobj(objtype, init, FALSE);
1550 otmp = mksobj_at(objtype, x, y, init, FALSE);
1557 /* save_mtraits frees original data pointed to by otmp */
1558 otmp2 = save_mtraits(otmp, mtmp);
1562 /* use the corpse or statue produced by mksobj() as-is
1563 unless `ptr' is non-null */
1565 int old_corpsenm = otmp->corpsenm;
1567 otmp->corpsenm = monsndx(ptr);
1568 otmp->owt = weight(otmp);
1569 if (otmp->otyp == CORPSE && (special_corpse(old_corpsenm)
1570 || special_corpse(otmp->corpsenm))) {
1571 obj_stop_timers(otmp);
1572 start_corpse_timeout(otmp);
1580 * Return the type of monster that this corpse will
1581 * revive as, even if it has a monster structure
1582 * attached to it. In that case, you can't just
1583 * use obj->corpsenm, because the stored monster
1584 * type can, and often is, different.
1585 * The return value is an index into mons[].
1588 corpse_revive_type(obj)
1594 && ((mtmp = get_mtraits(obj, FALSE)) != (struct monst *) 0)) {
1595 /* mtmp is a temporary pointer to a monster's stored
1596 attributes, not a real monster */
1597 revivetype = mtmp->mnum;
1599 revivetype = obj->corpsenm;
1604 * Attach a monster id to an object, to provide
1605 * a lasting association between the two.
1608 obj_attach_mid(obj, mid)
1613 return (struct obj *) 0;
1620 save_mtraits(obj, mtmp)
1625 forget_temple_entry(mtmp); /* EPRI() */
1626 if (!has_omonst(obj))
1628 if (has_omonst(obj)) {
1629 struct monst *mtmp2 = OMONST(obj);
1632 mtmp2->mextra = (struct mextra *) 0;
1634 mtmp2->mnum = monsndx(mtmp->data);
1635 /* invalidate pointers */
1636 /* m_id is needed to know if this is a revived quest leader */
1637 /* but m_id must be cleared when loading bones */
1638 mtmp2->nmon = (struct monst *) 0;
1639 mtmp2->data = (struct permonst *) 0;
1640 mtmp2->minvent = (struct obj *) 0;
1642 copy_mextra(mtmp2, mtmp);
1647 /* returns a pointer to a new monst structure based on
1648 * the one contained within the obj.
1651 get_mtraits(obj, copyof)
1655 struct monst *mtmp = (struct monst *) 0;
1656 struct monst *mnew = (struct monst *) 0;
1658 if (has_omonst(obj))
1664 mnew->mextra = (struct mextra *) 0;
1666 copy_mextra(mnew, mtmp);
1668 /* Never insert this returned pointer into mon chains! */
1675 /* make an object named after someone listed in the scoreboard file */
1677 mk_tt_object(objtype, x, y)
1678 int objtype; /* CORPSE or STATUE */
1681 register struct obj *otmp, *otmp2;
1682 boolean initialize_it;
1684 /* player statues never contain books */
1685 initialize_it = (objtype != STATUE);
1686 if ((otmp = mksobj_at(objtype, x, y, initialize_it, FALSE)) != 0) {
1687 /* tt_oname will return null if the scoreboard is empty */
1688 if ((otmp2 = tt_oname(otmp)) != 0)
1694 /* make a new corpse or statue, uninitialized if a statue (i.e. no books) */
1696 mk_named_object(objtype, ptr, x, y, nm)
1697 int objtype; /* CORPSE or STATUE */
1698 struct permonst *ptr;
1703 unsigned corpstatflags =
1704 (objtype != STATUE) ? CORPSTAT_INIT : CORPSTAT_NONE;
1706 otmp = mkcorpstat(objtype, (struct monst *) 0, ptr, x, y, corpstatflags);
1708 otmp = oname(otmp, nm);
1714 register struct obj *otmp;
1716 int otyp = otmp->otyp;
1717 int omat = objects[otyp].oc_material;
1719 /* Candles can be burned, but they're not flammable in the sense that
1720 * they can't get fire damage and it makes no sense for them to be
1723 if (Is_candle(otmp))
1726 if (objects[otyp].oc_oprop == FIRE_RES || otyp == WAN_FIRE)
1729 return (boolean) ((omat <= WOOD && omat != LIQUID) || omat == PLASTIC);
1734 register struct obj *otmp;
1736 int otyp = otmp->otyp;
1738 return (boolean) (objects[otyp].oc_material <= WOOD
1739 && objects[otyp].oc_material != LIQUID);
1743 * These routines maintain the single-linked lists headed in level.objects[][]
1744 * and threaded through the nexthere fields in the object-instance structure.
1747 /* put the object at the given location */
1749 place_object(otmp, x, y)
1750 register struct obj *otmp;
1753 register struct obj *otmp2 = level.objects[x][y];
1755 if (otmp->where != OBJ_FREE)
1756 panic("place_object: obj not free");
1758 obj_no_longer_held(otmp);
1759 /* (could bypass this vision update if there is already a boulder here) */
1760 if (otmp->otyp == BOULDER)
1761 block_point(x, y); /* vision */
1763 /* obj goes under boulders */
1764 if (otmp2 && (otmp2->otyp == BOULDER)) {
1765 otmp->nexthere = otmp2->nexthere;
1766 otmp2->nexthere = otmp;
1768 otmp->nexthere = otmp2;
1769 level.objects[x][y] = otmp;
1772 /* set the new object's location */
1776 otmp->where = OBJ_FLOOR;
1778 /* add to floor chain */
1782 obj_timer_checks(otmp, x, y, 0);
1785 #define ROT_ICE_ADJUSTMENT 2 /* rotting on ice takes 2 times as long */
1787 /* If ice was affecting any objects correct that now
1788 * Also used for starting ice effects too. [zap.c]
1791 obj_ice_effects(x, y, do_buried)
1797 for (otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere) {
1799 obj_timer_checks(otmp, x, y, 0);
1802 for (otmp = level.buriedobjlist; otmp; otmp = otmp->nobj) {
1803 if (otmp->ox == x && otmp->oy == y) {
1805 obj_timer_checks(otmp, x, y, 0);
1812 * Returns an obj->age for a corpse object on ice, that would be the
1813 * actual obj->age if the corpse had just been lifted from the ice.
1814 * This is useful when just using obj->age in a check or calculation because
1815 * rot timers pertaining to the object don't have to be stopped and
1819 peek_at_iced_corpse_age(otmp)
1822 long age, retval = otmp->age;
1824 if (otmp->otyp == CORPSE && otmp->on_ice) {
1825 /* Adjust the age; must be same as obj_timer_checks() for off ice*/
1826 age = monstermoves - otmp->age;
1827 retval += age * (ROT_ICE_ADJUSTMENT - 1) / ROT_ICE_ADJUSTMENT;
1829 "The %s age has ice modifications: otmp->age = %ld, returning %ld.",
1830 s_suffix(doname(otmp)), otmp->age, retval);
1831 debugpline1("Effective age of corpse: %ld.", monstermoves - retval);
1837 obj_timer_checks(otmp, x, y, force)
1840 int force; /* 0 = no force so do checks, <0 = force off, >0 force on */
1843 short action = ROT_CORPSE;
1844 boolean restart_timer = FALSE;
1845 boolean on_floor = (otmp->where == OBJ_FLOOR);
1846 boolean buried = (otmp->where == OBJ_BURIED);
1848 /* Check for corpses just placed on or in ice */
1849 if (otmp->otyp == CORPSE && (on_floor || buried) && is_ice(x, y)) {
1850 tleft = stop_timer(action, obj_to_any(otmp));
1852 action = REVIVE_MON;
1853 tleft = stop_timer(action, obj_to_any(otmp));
1858 /* mark the corpse as being on ice */
1860 debugpline3("%s is now on ice at <%d,%d>.", The(xname(otmp)), x,
1862 /* Adjust the time remaining */
1863 tleft *= ROT_ICE_ADJUSTMENT;
1864 restart_timer = TRUE;
1865 /* Adjust the age; time spent off ice needs to be multiplied
1866 by the ice adjustment and subtracted from the age so that
1867 later calculations behave as if it had been on ice during
1868 that time (longwinded way of saying this is the inverse
1869 of removing it from the ice and of peeking at its age). */
1870 age = monstermoves - otmp->age;
1871 otmp->age = monstermoves - (age * ROT_ICE_ADJUSTMENT);
1874 /* Check for corpses coming off ice */
1875 } else if (force < 0 || (otmp->otyp == CORPSE && otmp->on_ice
1876 && !((on_floor || buried) && is_ice(x, y)))) {
1877 tleft = stop_timer(action, obj_to_any(otmp));
1879 action = REVIVE_MON;
1880 tleft = stop_timer(action, obj_to_any(otmp));
1886 debugpline3("%s is no longer on ice at <%d,%d>.",
1887 The(xname(otmp)), x, y);
1888 /* Adjust the remaining time */
1889 tleft /= ROT_ICE_ADJUSTMENT;
1890 restart_timer = TRUE;
1891 /* Adjust the age */
1892 age = monstermoves - otmp->age;
1893 otmp->age += age * (ROT_ICE_ADJUSTMENT - 1) / ROT_ICE_ADJUSTMENT;
1897 /* now re-start the timer with the appropriate modifications */
1899 (void) start_timer(tleft, TIMER_OBJECT, action, obj_to_any(otmp));
1902 #undef ROT_ICE_ADJUSTMENT
1906 register struct obj *otmp;
1911 if (otmp->where != OBJ_FLOOR)
1912 panic("remove_object: obj not on floor");
1913 extract_nexthere(otmp, &level.objects[x][y]);
1914 extract_nobj(otmp, &fobj);
1915 /* update vision iff this was the only boulder at its spot */
1916 if (otmp->otyp == BOULDER && !sobj_at(BOULDER, x, y))
1917 unblock_point(x, y); /* vision */
1919 obj_timer_checks(otmp, x, y, 0);
1922 /* throw away all of a monster's inventory */
1924 discard_minvent(mtmp)
1927 struct obj *otmp, *mwep = MON_WEP(mtmp);
1928 boolean keeping_mon = (!DEADMONSTER(mtmp));
1930 while ((otmp = mtmp->minvent) != 0) {
1931 /* this has now become very similar to m_useupall()... */
1932 obj_extract_self(otmp);
1933 if (otmp->owornmask) {
1936 mwepgone(mtmp), mwep = 0;
1937 mtmp->misc_worn_check &= ~otmp->owornmask;
1938 update_mon_intrinsics(mtmp, otmp, FALSE, TRUE);
1940 otmp->owornmask = 0L; /* obfree() expects this */
1942 obfree(otmp, (struct obj *) 0); /* dealloc_obj() isn't sufficient */
1947 * Free obj from whatever list it is on in preparation for deleting it
1948 * or moving it elsewhere; obj->where will end up set to OBJ_FREE.
1949 * Doesn't handle unwearing of objects in hero's or monsters' inventories.
1952 * OBJ_FREE not on any list
1953 * OBJ_FLOOR fobj, level.locations[][] chains (use remove_object)
1954 * OBJ_CONTAINED cobj chain of container object
1955 * OBJ_INVENT hero's invent chain (use freeinv)
1956 * OBJ_MINVENT monster's invent chain
1957 * OBJ_MIGRATING migrating chain
1958 * OBJ_BURIED level.buriedobjs chain
1959 * OBJ_ONBILL on billobjs chain
1962 obj_extract_self(obj)
1965 switch (obj->where) {
1972 extract_nobj(obj, &obj->ocontainer->cobj);
1973 container_weight(obj->ocontainer);
1974 obj->ocontainer = (struct obj *) 0; /* clear stale back-link */
1980 extract_nobj(obj, &obj->ocarry->minvent);
1981 obj->ocarry = (struct monst *) 0; /* clear stale back-link */
1984 extract_nobj(obj, &migrating_objs);
1987 extract_nobj(obj, &level.buriedobjlist);
1990 extract_nobj(obj, &billobjs);
1993 panic("obj_extract_self");
1998 /* Extract the given object from the chain, following nobj chain. */
2000 extract_nobj(obj, head_ptr)
2001 struct obj *obj, **head_ptr;
2003 struct obj *curr, *prev;
2006 for (prev = (struct obj *) 0; curr; prev = curr, curr = curr->nobj) {
2009 prev->nobj = curr->nobj;
2011 *head_ptr = curr->nobj;
2016 panic("extract_nobj: object lost");
2017 obj->where = OBJ_FREE;
2018 obj->nobj = (struct obj *) 0;
2022 * Extract the given object from the chain, following nexthere chain.
2024 * This does not set obj->where, this function is expected to be called
2025 * in tandem with extract_nobj, which does set it.
2028 extract_nexthere(obj, head_ptr)
2029 struct obj *obj, **head_ptr;
2031 struct obj *curr, *prev;
2034 for (prev = (struct obj *) 0; curr; prev = curr, curr = curr->nexthere) {
2037 prev->nexthere = curr->nexthere;
2039 *head_ptr = curr->nexthere;
2044 panic("extract_nexthere: object lost");
2045 obj->nexthere = (struct obj *) 0;
2049 * Add obj to mon's inventory. If obj is able to merge with something already
2050 * in the inventory, then the passed obj is deleted and 1 is returned.
2051 * Otherwise 0 is returned.
2054 add_to_minv(mon, obj)
2060 if (obj->where != OBJ_FREE)
2061 panic("add_to_minv: obj not free");
2063 /* merge if possible */
2064 for (otmp = mon->minvent; otmp; otmp = otmp->nobj)
2065 if (merged(&otmp, &obj))
2066 return 1; /* obj merged and then free'd */
2067 /* else insert; don't bother forcing it to end of chain */
2068 obj->where = OBJ_MINVENT;
2070 obj->nobj = mon->minvent;
2072 return 0; /* obj on mon's inventory chain */
2076 * Add obj to container, make sure obj is "free". Returns (merged) obj.
2077 * The input obj may be deleted in the process.
2080 add_to_container(container, obj)
2081 struct obj *container, *obj;
2085 if (obj->where != OBJ_FREE)
2086 panic("add_to_container: obj not free");
2087 if (container->where != OBJ_INVENT && container->where != OBJ_MINVENT)
2088 obj_no_longer_held(obj);
2090 /* merge if possible */
2091 for (otmp = container->cobj; otmp; otmp = otmp->nobj)
2092 if (merged(&otmp, &obj))
2095 obj->where = OBJ_CONTAINED;
2096 obj->ocontainer = container;
2097 obj->nobj = container->cobj;
2098 container->cobj = obj;
2103 add_to_migration(obj)
2106 if (obj->where != OBJ_FREE)
2107 panic("add_to_migration: obj not free");
2109 /* lock picking context becomes stale if it's for this object */
2110 if (Is_container(obj))
2111 maybe_reset_pick(obj);
2113 obj->where = OBJ_MIGRATING;
2114 obj->nobj = migrating_objs;
2115 migrating_objs = obj;
2122 if (obj->where != OBJ_FREE)
2123 panic("add_to_buried: obj not free");
2125 obj->where = OBJ_BURIED;
2126 obj->nobj = level.buriedobjlist;
2127 level.buriedobjlist = obj;
2130 /* Recalculate the weight of this container and all of _its_ containers. */
2132 container_weight(container)
2133 struct obj *container;
2135 container->owt = weight(container);
2136 if (container->where == OBJ_CONTAINED)
2137 container_weight(container->ocontainer);
2139 else if (container->where == OBJ_INVENT)
2140 recalculate load delay here ???
2145 * Deallocate the object. _All_ objects should be run through here for
2146 * them to be deallocated.
2152 if (obj->where != OBJ_FREE)
2153 panic("dealloc_obj: obj not free");
2155 panic("dealloc_obj with nobj");
2157 panic("dealloc_obj with cobj");
2159 /* free up any timers attached to the object */
2161 obj_stop_timers(obj);
2164 * Free up any light sources attached to the object.
2166 * We may want to just call del_light_source() without any
2167 * checks (requires a code change there). Otherwise this
2168 * list must track all objects that can have a light source
2169 * attached to it (and also requires lamplit to be set).
2171 if (obj_sheds_light(obj))
2172 del_light_source(LS_OBJECT, obj_to_any(obj));
2174 if (obj == thrownobj)
2176 if (obj == kickedobj)
2180 dealloc_oextra(obj);
2181 free((genericptr_t) obj);
2184 /* create an object from a horn of plenty; mirrors bagotricks(makemon.c) */
2186 hornoplenty(horn, tipping)
2188 boolean tipping; /* caller emptying entire contents; affects shop handling */
2192 if (!horn || horn->otyp != HORN_OF_PLENTY) {
2193 impossible("bad horn o' plenty");
2194 } else if (horn->spe < 1) {
2195 pline1(nothing_happens);
2200 consume_obj_charge(horn, !tipping);
2202 obj = mkobj(POTION_CLASS, FALSE);
2203 if (objects[obj->otyp].oc_magic)
2205 obj->otyp = rnd_class(POT_BOOZE, POT_WATER);
2206 } while (obj->otyp == POT_SICKNESS);
2208 what = (obj->quan > 1L) ? "Some potions" : "A potion";
2212 obj = mkobj(FOOD_CLASS, FALSE);
2213 if (obj->otyp == FOOD_RATION && !rn2(7))
2214 obj->otyp = LUMP_OF_ROYAL_JELLY;
2218 what = "
\90H
\82×
\95¨";
2222 pline("%s %s out.", what, vtense(what, "spill"));
2224 pline("%s
\82ª
\94ò
\82Ñ
\8fo
\82Ä
\82«
\82½
\81D", what);
2225 obj->blessed = horn->blessed;
2226 obj->cursed = horn->cursed;
2227 obj->owt = weight(obj);
2228 /* using a shop's horn of plenty entails a usage fee and also
2229 confers ownership of the created item to the shopkeeper */
2231 addtobill(obj, FALSE, FALSE, tipping);
2232 /* if it ended up on bill, we don't want "(unpaid, N zorkids)"
2233 being included in its formatted name during next message */
2234 iflags.suppress_price++;
2237 obj = hold_another_object(obj,
2239 ? "Oops! %s out of your reach!"
2240 : (Is_airlevel(&u.uz)
2241 || Is_waterlevel(&u.uz)
2242 || levl[u.ux][u.uy].typ < IRONBARS
2243 || levl[u.ux][u.uy].typ >= ICE)
2244 ? "Oops! %s away from you!"
2245 : "Oops! %s to the floor!",
2246 The(aobjnam(obj, "slip")), (char *) 0);
2248 obj = hold_another_object(obj,
2250 ? "
\82¨
\82Á
\82Æ
\81I%s
\82Í
\93Í
\82©
\82È
\82¢
\81I"
2251 : (Is_airlevel(&u.uz)
2252 || Is_waterlevel(&u.uz)
2253 || levl[u.ux][u.uy].typ < IRONBARS
2254 || levl[u.ux][u.uy].typ >= ICE)
2255 ? "
\82¨
\82Á
\82Æ
\81I%s
\82Í
\82 \82È
\82½
\82Ì
\8eè
\82©
\82ç
\8a\8a\82è
\97\8e\82¿
\82½
\81I"
2256 : "
\82¨
\82Á
\82Æ
\81I%s
\82Í
\8f°
\82É
\8a\8a\82è
\97\8e\82¿
\82½
\81I",
2257 xname(obj), (char *)0);
2261 /* assumes this is taking place at hero's location */
2262 if (!can_reach_floor(TRUE)) {
2263 hitfloor(obj, TRUE); /* does altar check, message, drop */
2265 if (IS_ALTAR(levl[u.ux][u.uy].typ))
2266 doaltarobj(obj); /* does its own drop message */
2269 pline("%s %s to the %s.", Doname2(obj),
2270 otense(obj, "drop"), surface(u.ux, u.uy));
2272 pline("%s
\82Í%s
\82É
\97\8e\82¿
\82½
\81D", Doname2(obj),
2273 surface(u.ux, u.uy));
2278 iflags.suppress_price--;
2280 makeknown(HORN_OF_PLENTY);
2285 /* support for wizard-mode's `sanity_check' option */
2287 static const char NEARDATA /* pline formats for insane_object() */
2288 ofmt0[] = "%s obj %s %s: %s",
2289 ofmt3[] = "%s [not null] %s %s: %s",
2290 /* " held by mon %p (%s)" will be appended, filled by M,mon_nam(M) */
2291 mfmt1[] = "%s obj %s %s (%s)",
2292 mfmt2[] = "%s obj %s %s (%s) *not*";
2294 /* Check all object lists for consistency. */
2303 * Should check whether the obj->bypass and/or obj->nomerge bits
2304 * are set. Those are both used for temporary purposes and should
2305 * be clear between moves.
2308 objlist_sanity(fobj, OBJ_FLOOR, "floor sanity");
2310 /* check that the map's record of floor objects is consistent;
2311 those objects should have already been sanity checked via
2312 the floor list so container contents are skipped here */
2313 for (x = 0; x < COLNO; x++)
2314 for (y = 0; y < ROWNO; y++)
2315 for (obj = level.objects[x][y]; obj; obj = obj->nexthere) {
2316 /* <ox,oy> should match <x,y>; <0,*> should always be empty */
2317 if (obj->where != OBJ_FLOOR || x == 0
2318 || obj->ox != x || obj->oy != y) {
2321 Sprintf(at_fmt, "%%s obj@<%d,%d> %%s %%s: %%s@<%d,%d>",
2322 x, y, obj->ox, obj->oy);
2323 insane_object(obj, at_fmt, "location sanity",
2324 (struct monst *) 0);
2328 objlist_sanity(invent, OBJ_INVENT, "invent sanity");
2329 objlist_sanity(migrating_objs, OBJ_MIGRATING, "migrating sanity");
2330 objlist_sanity(level.buriedobjlist, OBJ_BURIED, "buried sanity");
2331 objlist_sanity(billobjs, OBJ_ONBILL, "bill sanity");
2333 mon_obj_sanity(fmon, "minvent sanity");
2334 mon_obj_sanity(migrating_mons, "migrating minvent sanity");
2335 /* monsters temporarily in transit;
2336 they should have arrived with hero by the time we get called */
2338 impossible("mydogs sanity [not empty]");
2339 mon_obj_sanity(mydogs, "mydogs minvent sanity");
2342 /* objects temporarily freed from invent/floor lists;
2343 they should have arrived somewhere by the time we get called */
2345 insane_object(thrownobj, ofmt3, "thrownobj sanity",
2346 (struct monst *) 0);
2348 insane_object(kickedobj, ofmt3, "kickedobj sanity",
2349 (struct monst *) 0);
2350 /* current_wand isn't removed from invent while in use, but should
2351 be Null between moves when we're called */
2353 insane_object(current_wand, ofmt3, "current_wand sanity",
2354 (struct monst *) 0);
2357 /* sanity check for objects on specified list (fobj, &c) */
2359 objlist_sanity(objlist, wheretype, mesg)
2360 struct obj *objlist;
2366 for (obj = objlist; obj; obj = obj->nobj) {
2367 if (obj->where != wheretype)
2368 insane_object(obj, ofmt0, mesg, (struct monst *) 0);
2369 if (Has_contents(obj)) {
2370 if (wheretype == OBJ_ONBILL)
2371 /* containers on shop bill should always be empty */
2372 insane_object(obj, "%s obj contains something! %s %s: %s",
2373 mesg, (struct monst *) 0);
2374 check_contained(obj, mesg);
2376 if (obj->owornmask) {
2378 boolean bc_ok = FALSE;
2380 switch (obj->where) {
2383 sanity_check_worn(obj);
2386 /* migrating objects overload the owornmask field
2387 with a destination code; skip attempt to check it */
2390 /* note: ball and chain can also be OBJ_FREE, but not across
2391 turns so this sanity check shouldn't encounter that */
2395 if ((obj != uchain && obj != uball) || !bc_ok) {
2396 /* discovered an object not in inventory which
2397 erroneously has worn mask set */
2398 Sprintf(maskbuf, "worn mask 0x%08lx", obj->owornmask);
2399 insane_object(obj, ofmt0, maskbuf, (struct monst *) 0);
2407 /* sanity check for objects carried by all monsters in specified list */
2409 mon_obj_sanity(monlist, mesg)
2410 struct monst *monlist;
2414 struct obj *obj, *mwep;
2416 for (mon = monlist; mon; mon = mon->nmon) {
2417 if (DEADMONSTER(mon)) continue;
2418 mwep = MON_WEP(mon);
2420 if (!mcarried(mwep))
2421 insane_object(mwep, mfmt1, mesg, mon);
2422 if (mwep->ocarry != mon)
2423 insane_object(mwep, mfmt2, mesg, mon);
2425 for (obj = mon->minvent; obj; obj = obj->nobj) {
2426 if (obj->where != OBJ_MINVENT)
2427 insane_object(obj, mfmt1, mesg, mon);
2428 if (obj->ocarry != mon)
2429 insane_object(obj, mfmt2, mesg, mon);
2430 check_contained(obj, mesg);
2435 /* This must stay consistent with the defines in obj.h. */
2436 static const char *obj_state_names[NOBJ_STATES] = { "free", "floor",
2437 "contained", "invent",
2438 "minvent", "migrating",
2439 "buried", "onbill" };
2441 STATIC_OVL const char *
2445 static char unknown[32]; /* big enough to handle rogue 64-bit int */
2451 if (where < 0 || where >= NOBJ_STATES || !obj_state_names[where]) {
2452 Sprintf(unknown, "unknown[%d]", where);
2455 return obj_state_names[where];
2459 insane_object(obj, fmt, mesg, mon)
2461 const char *fmt, *mesg;
2464 const char *objnm, *monnm;
2467 objnm = monnm = "null!";
2469 iflags.override_ID++;
2470 objnm = doname(obj);
2471 iflags.override_ID--;
2473 if (mon || (strstri(mesg, "minvent") && !strstri(mesg, "contained"))) {
2474 Strcat(strcpy(altfmt, fmt), " held by mon %s (%s)");
2476 monnm = x_monnam(mon, ARTICLE_A, (char *) 0, EXACT_NAME, TRUE);
2477 impossible(altfmt, mesg, fmt_ptr((genericptr_t) obj), where_name(obj),
2478 objnm, fmt_ptr((genericptr_t) mon), monnm);
2480 impossible(fmt, mesg, fmt_ptr((genericptr_t) obj), where_name(obj), objnm);
2484 /* obj sanity check: check objects inside container */
2486 check_contained(container, mesg)
2487 struct obj *container;
2491 /* big enough to work with, not too big to blow out stack in recursion */
2492 char mesgbuf[40], nestedmesg[120];
2494 if (!Has_contents(container))
2496 /* change "invent sanity" to "contained invent sanity"
2497 but leave "nested contained invent sanity" as is */
2498 if (!strstri(mesg, "contained"))
2499 mesg = strcat(strcpy(mesgbuf, "contained "), mesg);
2501 for (obj = container->cobj; obj; obj = obj->nobj) {
2502 /* catch direct cycle to avoid unbounded recursion */
2503 if (obj == container)
2504 panic("failed sanity check: container holds itself");
2505 if (obj->where != OBJ_CONTAINED)
2506 insane_object(obj, "%s obj %s %s: %s", mesg, (struct monst *) 0);
2507 else if (obj->ocontainer != container)
2508 impossible("%s obj %s in container %s, not %s", mesg,
2509 fmt_ptr((genericptr_t) obj),
2510 fmt_ptr((genericptr_t) obj->ocontainer),
2511 fmt_ptr((genericptr_t) container));
2513 if (Has_contents(obj)) {
2514 /* catch most likely indirect cycle; we won't notice if
2515 parent is present when something comes before it, or
2516 notice more deeply embedded cycles (grandparent, &c) */
2517 if (obj->cobj == container)
2518 panic("failed sanity check: container holds its parent");
2519 /* change "contained... sanity" to "nested contained... sanity"
2520 and "nested contained..." to "nested nested contained..." */
2521 Strcpy(nestedmesg, "nested ");
2522 copynchars(eos(nestedmesg), mesg, (int) sizeof nestedmesg
2523 - (int) strlen(nestedmesg)
2525 /* recursively check contents */
2526 check_contained(obj, nestedmesg);
2531 /* check an object in hero's or monster's inventory which has worn mask set */
2533 sanity_check_worn(obj)
2536 #if defined(BETA) || defined(DEBUG)
2537 static unsigned long wearbits[] = {
2538 W_ARM, W_ARMC, W_ARMH, W_ARMS, W_ARMG, W_ARMF, W_ARMU,
2539 W_WEP, W_QUIVER, W_SWAPWEP, W_AMUL, W_RINGL, W_RINGR, W_TOOL,
2540 W_SADDLE, W_BALL, W_CHAIN, 0
2541 /* [W_ART,W_ARTI are property bits for items which aren't worn] */
2545 unsigned long owornmask, allmask = 0L;
2546 boolean embedded = FALSE;
2549 /* use owornmask for testing and bit twiddling, but use original
2550 obj->owornmask for printing */
2551 owornmask = obj->owornmask;
2552 /* figure out how many bits are set, and also which are viable */
2553 for (i = 0; wearbits[i]; ++i) {
2554 if ((owornmask & wearbits[i]) != 0L)
2556 allmask |= wearbits[i];
2559 /* embedded dragon scales have an extra bit set;
2560 make sure it's set, then suppress it */
2562 if ((owornmask & (W_ARM | I_SPECIAL)) == (W_ARM | I_SPECIAL))
2563 owornmask &= ~I_SPECIAL;
2565 n = 0, owornmask = ~0; /* force insane_object("bogus") below */
2567 if (n == 2 && carried(obj)
2568 && obj == uball && (owornmask & W_BALL) != 0L
2569 && (owornmask & W_WEAPON) != 0L) {
2570 /* chained ball can be wielded/alt-wielded/quivered; if so,
2571 pretend it's not chained in order to check the weapon pointer
2572 (we've already verified the ball pointer by successfully passing
2573 the if-condition to get here...) */
2574 owornmask &= ~W_BALL;
2578 /* multiple bits set */
2579 Sprintf(maskbuf, "worn mask (multiple) 0x%08lx", obj->owornmask);
2580 insane_object(obj, ofmt0, maskbuf, (struct monst *) 0);
2582 if ((owornmask & ~allmask) != 0L
2583 || (carried(obj) && (owornmask & W_SADDLE) != 0L)) {
2584 /* non-wearable bit(s) set */
2585 Sprintf(maskbuf, "worn mask (bogus)) 0x%08lx", obj->owornmask);
2586 insane_object(obj, ofmt0, maskbuf, (struct monst *) 0);
2588 if (n == 1 && (carried(obj) || (owornmask & (W_BALL | W_CHAIN)) != 0L)) {
2590 /* verify that obj in hero's invent (or ball/chain elsewhere)
2591 with owornmask of W_foo is the object pointed to by ufoo */
2592 switch (owornmask) {
2594 if (obj != (embedded ? uskin : uarm))
2595 what = embedded ? "skin" : "suit";
2623 what = "primary weapon";
2630 if (obj != uswapwep)
2631 what = u.twoweap ? "secondary weapon" : "alternate weapon";
2643 what = "right ring";
2649 /* case W_SADDLE: */
2662 Sprintf(maskbuf, "worn mask 0x%08lx != %s", obj->owornmask, what);
2663 insane_object(obj, ofmt0, maskbuf, (struct monst *) 0);
2666 if (n == 1 && (carried(obj) || (owornmask & (W_BALL | W_CHAIN)) != 0L
2667 || mcarried(obj))) {
2668 /* check for items worn in invalid slots; practically anything can
2669 be wielded/alt-wielded/quivered, so tests on those are limited */
2671 if (owornmask & W_ARMOR) {
2672 if (obj->oclass != ARMOR_CLASS)
2674 /* 3.6: dragon scale mail reverts to dragon scales when
2675 becoming embedded in poly'd hero's skin */
2676 if (embedded && !Is_dragon_scales(obj))
2678 } else if (owornmask & W_WEAPON) {
2679 /* monsters don't maintain alternate weapon or quiver */
2680 if (mcarried(obj) && (owornmask & (W_SWAPWEP | W_QUIVER)) != 0L)
2681 what = (owornmask & W_SWAPWEP) != 0L ? "monst alt weapon?"
2683 /* hero can quiver gold but not wield it (hence not alt-wield
2684 it either); also catches monster wielding gold */
2685 else if (obj->oclass == COIN_CLASS
2686 && (owornmask & (W_WEP | W_SWAPWEP)) != 0L)
2687 what = (owornmask & W_WEP) != 0L ? "weapon" : "alt weapon";
2688 } else if (owornmask & W_AMUL) {
2689 if (obj->oclass != AMULET_CLASS)
2691 } else if (owornmask & W_RING) {
2692 if (obj->oclass != RING_CLASS && obj->otyp != MEAT_RING)
2694 } else if (owornmask & W_TOOL) {
2695 if (obj->otyp != BLINDFOLD && obj->otyp != TOWEL
2696 && obj->otyp != LENSES)
2698 } else if (owornmask & W_BALL) {
2699 if (obj->oclass != BALL_CLASS)
2700 what = "chained ball";
2701 } else if (owornmask & W_CHAIN) {
2702 if (obj->oclass != CHAIN_CLASS)
2704 } else if (owornmask & W_SADDLE) {
2705 if (obj->otyp != SADDLE)
2709 char oclassname[30];
2710 struct monst *mon = mcarried(obj) ? obj->ocarry : 0;
2712 /* if we've found a potion worn in the amulet slot,
2713 this yields "worn (potion amulet)" */
2714 Strcpy(oclassname, def_oc_syms[(uchar) obj->oclass].name);
2715 Sprintf(maskbuf, "worn (%s %s)", makesingular(oclassname), what);
2716 insane_object(obj, ofmt0, maskbuf, mon);
2719 #else /* not (BETA || DEBUG) */
2720 /* dummy use of obj to avoid "arg not used" complaint */
2722 insane_object(obj, ofmt0, "<null>", (struct monst *) 0);
2727 * wrapper to make "near this object" convenient
2734 impossible("obj_nexto: wasn't given an object to check");
2735 return (struct obj *) 0;
2737 return obj_nexto_xy(otmp, otmp->ox, otmp->oy, TRUE);
2741 * looks for objects of a particular type next to x, y
2742 * skips over oid if found (lets us avoid ourselves if
2743 * we're looking for a second type of an existing object)
2745 * TODO: return a list of all objects near us so we can more
2746 * reliably predict which one we want to 'find' first
2749 obj_nexto_xy(obj, x, y, recurs)
2755 int fx, fy, ex, ey, otyp = obj->otyp;
2758 /* check under our "feet" first */
2759 otmp = sobj_at(otyp, x, y);
2761 /* don't be clever and find ourselves */
2762 if (otmp != obj && mergable(otmp, obj))
2764 otmp = nxtobj(otmp, otyp, TRUE);
2768 return (struct obj *) 0;
2770 /* search in a random order */
2771 dx = (rn2(2) ? -1 : 1);
2772 dy = (rn2(2) ? -1 : 1);
2776 for (fx = ex; abs(fx - ex) < 3; fx += dx) {
2777 for (fy = ey; abs(fy - ey) < 3; fy += dy) {
2778 /* 0, 0 was checked above */
2779 if (isok(fx, fy) && (fx != x || fy != y)) {
2780 if ((otmp = obj_nexto_xy(obj, fx, fy, FALSE)) != 0)
2785 return (struct obj *) 0;
2789 * Causes one object to absorb another, increasing
2790 * weight accordingly. Frees obj2; obj1 remains and
2794 obj_absorb(obj1, obj2)
2795 struct obj **obj1, **obj2;
2797 struct obj *otmp1, *otmp2;
2801 /* don't let people dumb it up */
2805 if (otmp1 && otmp2 && otmp1 != otmp2) {
2806 if (otmp1->bknown != otmp2->bknown)
2807 otmp1->bknown = otmp2->bknown = 0;
2808 if (otmp1->rknown != otmp2->rknown)
2809 otmp1->rknown = otmp2->rknown = 0;
2810 if (otmp1->greased != otmp2->greased)
2811 otmp1->greased = otmp2->greased = 0;
2812 if (otmp1->orotten || otmp2->orotten)
2813 otmp1->orotten = otmp2->orotten = 1;
2814 o1wt = otmp1->oeaten ? otmp1->oeaten : otmp1->owt;
2815 o2wt = otmp2->oeaten ? otmp2->oeaten : otmp2->owt;
2816 /* averaging the relative ages is less likely to overflow
2817 than averaging the absolute ages directly */
2818 agetmp = (((moves - otmp1->age) * o1wt
2819 + (moves - otmp2->age) * o2wt)
2821 otmp1->age = moves - agetmp; /* conv. relative back to absolute */
2824 otmp1->oeaten += o2wt;
2826 obj_extract_self(otmp2);
2827 newsym(otmp2->ox, otmp2->oy); /* in case of floor */
2829 *obj2 = (struct obj *) 0;
2834 impossible("obj_absorb: not called with two actual objects");
2835 return (struct obj *) 0;
2839 * Causes the heavier object to absorb the lighter object;
2840 * wrapper for obj_absorb so that floor_effects works more
2841 * cleanly (since we don't know which we want to stay around)
2844 obj_meld(obj1, obj2)
2845 struct obj **obj1, **obj2;
2847 struct obj *otmp1, *otmp2;
2852 if (otmp1 && otmp2 && otmp1 != otmp2) {
2853 if (otmp1->owt > otmp2->owt
2854 || (otmp1->owt == otmp2->owt && rn2(2))) {
2855 return obj_absorb(obj1, obj2);
2857 return obj_absorb(obj2, obj1);
2861 impossible("obj_meld: not called with two actual objects");
2862 return (struct obj *) 0;
2865 /* give a message if hero notices two globs merging [used to be in pline.c] */
2867 pudding_merge_message(otmp, otmp2)
2871 boolean visible = (cansee(otmp->ox, otmp->oy)
2872 || cansee(otmp2->ox, otmp2->oy)),
2873 onfloor = (otmp->where == OBJ_FLOOR || otmp2->where == OBJ_FLOOR),
2874 inpack = (carried(otmp) || carried(otmp2));
2876 /* the player will know something happened inside his own inventory */
2877 if ((!Blind && visible) || inpack) {
2878 if (Hallucination) {
2881 You_see("parts of the floor melting!");
2883 You_see("
\8f°
\82Ì
\88ê
\95\94\82ª
\97n
\82¯
\82Ä
\82¢
\82é
\82Ì
\82ð
\8c©
\82½
\81I");
2884 } else if (inpack) {
2886 Your("pack reaches out and grabs something!");
2888 Your("
\82©
\82Î
\82ñ
\82ª
\8eè
\82ð
\90L
\82Î
\82µ
\82Ä
\89½
\82©
\82ð
\82Â
\82©
\82ñ
\82¾
\81I");
2890 /* even though we can see where they should be,
2891 * they'll be out of our view (minvent or container)
2892 * so don't actually show anything */
2893 } else if (onfloor || inpack) {
2895 pline("The %s coalesce%s.", makeplural(obj_typename(otmp->otyp)),
2896 inpack ? " inside your pack" : "");
2898 pline("%s
\82ª%s
\8d\87\91Ì
\82µ
\82½
\81D", obj_typename(otmp->otyp),
2899 inpack ? "
\82 \82È
\82½
\82Ì
\82©
\82Î
\82ñ
\82Ì
\92\86\82Å" : "");
2904 You_hear("a faint sloshing sound.");
2906 You_hear("
\82©
\82·
\82©
\82È
\83o
\83V
\83\83\83o
\83V
\83\83\82Æ
\82¢
\82¤
\89¹
\82ð
\95·
\82¢
\82½
\81D");