1 /*	SCCS Id: @(#)mkobj.c	3.3	2000/02/19	*/
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed.  See license for details. */
4 
5 #include "hack.h"
6 #include "artifact.h"
7 #include "prop.h"
8 
9 STATIC_DCL void FDECL(mkbox_cnts,(struct obj *));
10 STATIC_DCL void FDECL(obj_timer_checks,(struct obj *, XCHAR_P, XCHAR_P, int));
11 #ifdef OVL1
12 STATIC_DCL void FDECL(container_weight, (struct obj *));
13 STATIC_DCL struct obj *FDECL(save_mtraits, (struct obj *, struct monst *));
14 #ifdef WIZARD
15 STATIC_DCL const char *FDECL(where_name, (int));
16 STATIC_DCL void FDECL(check_contained, (struct obj *,const char *));
17 #endif
18 #endif /* OVL1 */
19 
20 /*#define DEBUG_EFFECTS*/	/* show some messages for debugging */
21 
22 struct icp {
23     int  iprob;		/* probability of an item type */
24     char iclass;	/* item class */
25 };
26 
27 #ifdef OVL1
28 
29 const struct icp mkobjprobs[] = {
30 {10, WEAPON_CLASS},
31 {10, ARMOR_CLASS},
32 {20, FOOD_CLASS},
33 { 8, TOOL_CLASS},
34 { 8, GEM_CLASS},
35 {16, POTION_CLASS},
36 {16, SCROLL_CLASS},
37 { 4, SPBOOK_CLASS},
38 { 4, WAND_CLASS},
39 { 3, RING_CLASS},
40 { 1, AMULET_CLASS}
41 };
42 
43 const struct icp boxiprobs[] = {
44 {18, GEM_CLASS},
45 {15, FOOD_CLASS},
46 {18, POTION_CLASS},
47 {18, SCROLL_CLASS},
48 {12, SPBOOK_CLASS},
49 { 7, GOLD_CLASS},
50 { 6, WAND_CLASS},
51 { 5, RING_CLASS},
52 { 1, AMULET_CLASS}
53 };
54 
55 #ifdef REINCARNATION
56 const struct icp rogueprobs[] = {
57 {12, WEAPON_CLASS},
58 {12, ARMOR_CLASS},
59 {22, FOOD_CLASS},
60 {22, POTION_CLASS},
61 {22, SCROLL_CLASS},
62 { 5, WAND_CLASS},
63 { 5, RING_CLASS}
64 };
65 #endif
66 
67 const struct icp hellprobs[] = {
68 {20, WEAPON_CLASS},
69 {20, ARMOR_CLASS},
70 {16, FOOD_CLASS},
71 {12, TOOL_CLASS},
72 {10, GEM_CLASS},
73 { 1, POTION_CLASS},
74 { 1, SCROLL_CLASS},
75 { 8, WAND_CLASS},
76 { 8, RING_CLASS},
77 { 4, AMULET_CLASS}
78 };
79 
80 struct obj *
mkobj_at(let,x,y,artif)81 mkobj_at(let,x,y, artif)
82 char let;
83 int x,y;
84 boolean artif;
85 {
86 	register struct obj *otmp;
87 
88 	otmp = mkobj(let,artif);
89 	place_object(otmp, x, y);
90 	return(otmp);
91 }
92 
93 struct obj *
mksobj_at(otyp,x,y,init)94 mksobj_at(otyp,x,y,init)
95 int otyp,x,y;
96 boolean init;
97 {
98 	register struct obj *otmp;
99 
100 	otmp = mksobj(otyp,init,TRUE);
101 	place_object(otmp, x, y);
102 	return(otmp);
103 }
104 
105 struct obj *
mkobj(oclass,artif)106 mkobj(oclass, artif)
107 char oclass;
108 boolean artif;
109 {
110 	register int tprob, i, prob = rnd(1000);
111 
112 	if(oclass == RANDOM_CLASS) {
113 		const struct icp *iprobs =
114 #ifdef REINCARNATION
115 				    (Is_rogue_level(&u.uz)) ?
116 				    (const struct icp *)rogueprobs :
117 #endif
118 				    Inhell ? (const struct icp *)hellprobs :
119 				    (const struct icp *)mkobjprobs;
120 
121 		for(tprob = rnd(100);
122 		    (tprob -= iprobs->iprob) > 0;
123 		    iprobs++);
124 		oclass = iprobs->iclass;
125 	}
126 
127 	i = bases[(int)oclass];
128 	while((prob -= objects[i].oc_prob) > 0) i++;
129 
130 	if(objects[i].oc_class != oclass || !OBJ_NAME(objects[i]))
131 		panic("probtype error, oclass=%d i=%d", (int) oclass, i);
132 
133 	return(mksobj(i, TRUE, artif));
134 }
135 
136 STATIC_OVL void
mkbox_cnts(box)137 mkbox_cnts(box)
138 struct obj *box;
139 {
140 	register int n;
141 	register struct obj *otmp, *gold = 0;
142 
143 	box->cobj = (struct obj *) 0;
144 
145 	switch(box->otyp) {
146 		case ICE_BOX:		n = 20; break;
147 		case CHEST:		n = 5; break;
148 		case LARGE_BOX:		n = 3; break;
149 		case SACK:
150 		case OILSKIN_SACK:
151 				/* initial inventory: sack starts out empty */
152 				if (moves <= 1 && !in_mklev) { n = 0; break; }
153 				/*else FALLTHRU*/
154 		case BAG_OF_HOLDING:	n = 1; break;
155 		default:		n = 0; break;
156 	}
157 
158 	for (n = rn2(n+1); n > 0; n--) {
159 	    if (box->otyp == ICE_BOX) {
160 		if (!(otmp = mksobj(CORPSE, TRUE, TRUE))) continue;
161 		/* Note: setting age to 0 is correct.  Age has a different
162 		 * from usual meaning for objects stored in ice boxes. -KAA
163 		 */
164 		otmp->age = 0L;
165 		if (otmp->timed) {
166 		    (void) stop_timer(ROT_CORPSE, (genericptr_t)otmp);
167 		    (void) stop_timer(REVIVE_MON, (genericptr_t)otmp);
168 		}
169 	    } else {
170 		register int tprob;
171 		const struct icp *iprobs = boxiprobs;
172 
173 		for (tprob = rnd(100); (tprob -= iprobs->iprob) > 0; iprobs++)
174 		    ;
175 		if (!(otmp = mkobj(iprobs->iclass, TRUE))) continue;
176 
177 		/* handle a couple of special cases */
178 		if (otmp->oclass == GOLD_CLASS) {
179 		    /* 2.5 x level's usual amount; weight adjusted below */
180 		    otmp->quan = (long)(rnd(level_difficulty()+2) * rnd(75));
181 		    if (gold) {			/* gold already in this box */
182 			gold->quan += otmp->quan;	/* merge */
183 			dealloc_obj(otmp);	/* note: not yet in any chain */
184 			continue;
185 		    } else {
186 			gold = otmp;		/* remember this object */
187 		    }
188 		} else while (otmp->otyp == ROCK) {
189 		    otmp->otyp = rnd_class(DILITHIUM_CRYSTAL, LOADSTONE);
190 		    if (otmp->quan > 2L) otmp->quan = 1L;
191 		    otmp->owt = weight(otmp);
192 		}
193 		if (box->otyp == BAG_OF_HOLDING) {
194 		    if (Is_mbag(otmp)) {
195 			otmp->otyp = SACK;
196 			otmp->spe = 0;
197 			otmp->owt = weight(otmp);
198 		    } else while (otmp->otyp == WAN_CANCELLATION)
199 			    otmp->otyp = rnd_class(WAN_LIGHT, WAN_LIGHTNING);
200 		}
201 	    }
202 	    add_to_container(box, otmp);
203 	}
204 	if (gold) gold->owt = weight(gold);	/* quantity was diddled */
205 	return;
206 }
207 
208 int
rndmonnum()209 rndmonnum()	/* select a random, common monster type */
210 {
211 	register struct permonst *ptr;
212 	register int	i;
213 
214 	/* Plan A: get a level-appropriate common monster */
215 	ptr = rndmonst();
216 	if (ptr) return(monsndx(ptr));
217 
218 	/* Plan B: get any common monster */
219 	do {
220 	    i = rn1(SPECIAL_PM - LOW_PM, LOW_PM);
221 	    ptr = &mons[i];
222 	} while((ptr->geno & G_NOGEN) || (!Inhell && (ptr->geno & G_HELL)));
223 
224 	return(i);
225 }
226 
227 /*
228  * Split obj so that it gets size num. The remainder is put in the object
229  * structure delivered by this call.  The object is positioned just
230  * following the original in the nobj chain (and nexthere chain when on
231  * the floor).
232  */
233 struct obj *
splitobj(obj,num)234 splitobj(obj, num)
235 struct obj *obj;
236 long num;
237 {
238 	struct obj *otmp;
239 
240 	if (obj->cobj || num <= 0L || obj->quan < num)
241 	    panic("splitobj");	/* can't split containers */
242 	otmp = newobj(obj->oxlth + obj->onamelth);
243 	*otmp = *obj;		/* copies whole structure */
244 	otmp->o_id = flags.ident++;
245 	if (!otmp->o_id) otmp->o_id = flags.ident++;	/* ident overflowed */
246 	otmp->timed = 0;	/* not timed, yet */
247 	otmp->lamplit = 0;	/* ditto */
248 	obj->quan = num;
249 	obj->owt = weight(obj);
250 	otmp->quan -= num;
251 	otmp->owt = weight(otmp);	/* -= obj->owt ? */
252 	obj->nobj = otmp;
253 	/* Only set nexthere when on the floor, nexthere is also used */
254 	/* as a back pointer to the container object when contained. */
255 	if (obj->where == OBJ_FLOOR)
256 	    obj->nexthere = otmp;
257 	if (obj->oxlth)
258 	    (void)memcpy((genericptr_t)otmp->oextra, (genericptr_t)obj->oextra,
259 			obj->oxlth);
260 	if (obj->onamelth)
261 	    (void)strncpy(ONAME(otmp), ONAME(obj), (int)obj->onamelth);
262 	if (obj->unpaid) splitbill(obj,otmp);
263 	if (obj->timed) obj_split_timers(obj, otmp);
264 	if (obj_sheds_light(obj)) obj_split_light_source(obj, otmp);
265 	return otmp;
266 }
267 
268 /*
269  * Insert otmp right after obj in whatever chain(s) it is on.  Then extract
270  * obj from the chain(s).  This function does a literal swap.  It is up to
271  * the caller to provide a valid context for the swap.  When done, obj will
272  * still exist, but not on any chain.
273  *
274  * Note:  Don't use use obj_extract_self() -- we are doing an in-place swap,
275  * not actually moving something.
276  */
277 void
replace_object(obj,otmp)278 replace_object(obj, otmp)
279 struct obj *obj;
280 struct obj *otmp;
281 {
282     otmp->where = obj->where;
283     switch (obj->where) {
284     case OBJ_FREE:
285 	/* do nothing */
286 	break;
287     case OBJ_INVENT:
288 	otmp->nobj = obj->nobj;
289 	obj->nobj = otmp;
290 	extract_nobj(obj, &invent);
291 	break;
292     case OBJ_CONTAINED:
293 	otmp->nobj = obj->nobj;
294 	otmp->ocontainer = obj->ocontainer;
295 	obj->nobj = otmp;
296 	extract_nobj(obj, &obj->ocontainer->cobj);
297 	break;
298     case OBJ_MINVENT:
299 	otmp->nobj = obj->nobj;
300 	otmp->ocarry =  obj->ocarry;
301 	obj->nobj = otmp;
302 	extract_nobj(obj, &obj->ocarry->minvent);
303 	break;
304     case OBJ_FLOOR:
305 	otmp->nobj = obj->nobj;
306 	otmp->nexthere = obj->nexthere;
307 	otmp->ox = obj->ox;
308 	otmp->oy = obj->oy;
309 	obj->nobj = otmp;
310 	obj->nexthere = otmp;
311 	extract_nobj(obj, &fobj);
312 	extract_nexthere(obj, &level.objects[obj->ox][obj->oy]);
313 	break;
314     default:
315 	panic("replace_object: obj position");
316 	break;
317     }
318 }
319 
320 /*
321  * Create a dummy duplicate to put on shop bill.  The duplicate exists
322  * only in the billobjs chain.  This function is used when a shop object
323  * is being altered, and a copy of the original is needed for billing
324  * purposes.  For example, when eating, where an interruption will yield
325  * an object which is different from what it started out as; the "I x"
326  * command needs to display the original object.
327  *
328  * The caller is responsible for checking otmp->unpaid and
329  * costly_spot(u.ux, u.uy).  This function will make otmp no charge.
330  *
331  * Note that check_unpaid_usage() should be used instead for partial
332  * usage of an object.
333  */
334 void
bill_dummy_object(otmp)335 bill_dummy_object(otmp)
336 register struct obj *otmp;
337 {
338 	register struct obj *dummy;
339 
340 	if (otmp->unpaid)
341 	    subfrombill(otmp, shop_keeper(*u.ushops));
342 	dummy = newobj(otmp->oxlth + otmp->onamelth);
343 	*dummy = *otmp;
344 	dummy->where = OBJ_FREE;
345 	dummy->o_id = flags.ident++;
346 	if (!dummy->o_id) dummy->o_id = flags.ident++;	/* ident overflowed */
347 	dummy->timed = 0;
348 	if (otmp->oxlth)
349 	    (void)memcpy((genericptr_t)dummy->oextra,
350 			(genericptr_t)otmp->oextra, otmp->oxlth);
351 	if (otmp->onamelth)
352 	    (void)strncpy(ONAME(dummy), ONAME(otmp), (int)otmp->onamelth);
353 	if (Is_candle(dummy)) dummy->lamplit = 0;
354 	addtobill(dummy, FALSE, TRUE, TRUE);
355 	otmp->no_charge = 1;
356 	otmp->unpaid = 0;
357 	return;
358 }
359 
360 #endif /* OVL1 */
361 #ifdef OVLB
362 
363 static const char dknowns[] = {
364 		WAND_CLASS, RING_CLASS, POTION_CLASS, SCROLL_CLASS,
365 		GEM_CLASS, SPBOOK_CLASS, WEAPON_CLASS, TOOL_CLASS, 0
366 };
367 
368 struct obj *
mksobj(otyp,init,artif)369 mksobj(otyp, init, artif)
370 int otyp;
371 boolean init;
372 boolean artif;
373 {
374 	int mndx, tryct;
375 	struct obj *otmp;
376 	char let = objects[otyp].oc_class;
377 
378 	otmp = newobj(0);
379 	*otmp = zeroobj;
380 	otmp->age = monstermoves;
381 	otmp->o_id = flags.ident++;
382 	if (!otmp->o_id) otmp->o_id = flags.ident++;	/* ident overflowed */
383 	otmp->quan = 1L;
384 	otmp->oclass = let;
385 	otmp->otyp = otyp;
386 	otmp->where = OBJ_FREE;
387 	otmp->dknown = index(dknowns, let) ? 0 : 1;
388 	if ((otmp->otyp >= ELVEN_SHIELD && otmp->otyp <= ORCISH_SHIELD) ||
389 			otmp->otyp == SHIELD_OF_REFLECTION)
390 		otmp->dknown = 0;
391 	if (!objects[otmp->otyp].oc_uses_known)
392 		otmp->known = 1;
393 #ifdef INVISIBLE_OBJECTS
394 	otmp->oinvis = !rn2(1250);
395 #endif
396 	if (init) switch (let) {
397 	case WEAPON_CLASS:
398 		otmp->quan = is_multigen(otmp) ? (long) rn1(6,6) : 1L;
399 		if(!rn2(11)) {
400 			otmp->spe = rne(3);
401 			otmp->blessed = rn2(2);
402 		} else if(!rn2(10)) {
403 			curse(otmp);
404 			otmp->spe = -rne(3);
405 		} else	blessorcurse(otmp, 10);
406 		if (is_poisonable(otmp) && !rn2(100))
407 			otmp->opoisoned = 1;
408 
409 		if (artif && !rn2(20))
410 		    otmp = mk_artifact(otmp, (aligntyp)A_NONE);
411 		break;
412 	case FOOD_CLASS:
413 	    otmp->oeaten = 0;
414 	    switch(otmp->otyp) {
415 	    case CORPSE:
416 		/* possibly overridden by mkcorpstat() */
417 		tryct = 50;
418 		do otmp->corpsenm = undead_to_corpse(rndmonnum());
419 		while ((mvitals[otmp->corpsenm].mvflags & G_NOCORPSE) && (--tryct > 0));
420 		if (tryct == 0) {
421 		/* perhaps rndmonnum() only wants to make G_NOCORPSE monsters on
422 		   this level; let's create an adventurer's corpse instead, then */
423 			otmp->corpsenm = PM_HUMAN;
424 		}
425 		start_corpse_timeout(otmp);
426 		break;
427 	    case EGG:
428 		otmp->corpsenm = NON_PM;	/* generic egg */
429 		if (!rn2(3)) for (tryct = 200; tryct > 0; --tryct) {
430 		    mndx = can_be_hatched(rndmonnum());
431 		    if (mndx != NON_PM && !dead_species(mndx, TRUE)) {
432 			otmp->corpsenm = mndx;		/* typed egg */
433 			attach_egg_hatch_timeout(otmp);
434 			break;
435 		    }
436 		}
437 		break;
438 	    case TIN:
439 		otmp->corpsenm = NON_PM;	/* empty (so far) */
440 		if (!rn2(6))
441 		    otmp->spe = 1;		/* spinach */
442 		else for (tryct = 200; tryct > 0; --tryct) {
443 		    mndx = undead_to_corpse(rndmonnum());
444 		    if (mons[mndx].cnutrit &&
445 			    !(mvitals[mndx].mvflags & G_NOCORPSE)) {
446 			otmp->corpsenm = mndx;
447 			break;
448 		    }
449 		}
450 		blessorcurse(otmp, 10);
451 		break;
452 	    case SLIME_MOLD:
453 		otmp->spe = current_fruit;
454 		break;
455 	    }
456 	    if (otmp->otyp == CORPSE || otmp->otyp == MEAT_RING) break;
457 	    /* fall into next case */
458 
459 	case GEM_CLASS:
460 		if (otmp->otyp == LOADSTONE) curse(otmp);
461 		else if (otmp->otyp == ROCK) otmp->quan = (long) rn1(6,6);
462 		else if (otmp->otyp == KELP_FROND) otmp->quan = (long) rnd(2);
463 		else if (otmp->otyp != LUCKSTONE && !rn2(6)) otmp->quan = 2L;
464 		else otmp->quan = 1L;
465 		break;
466 	case TOOL_CLASS:
467 	    switch(otmp->otyp) {
468 		case TALLOW_CANDLE:
469 		case WAX_CANDLE:	otmp->spe = 1;
470 					otmp->age = 20L * /* 400 or 200 */
471 					      (long)objects[otmp->otyp].oc_cost;
472 					otmp->lamplit = 0;
473 					otmp->quan = 1L +
474 					      (long)(rn2(2) ? rn2(7) : 0);
475 					blessorcurse(otmp, 5);
476 					break;
477 		case BRASS_LANTERN:
478 		case OIL_LAMP:		otmp->spe = 1;
479 					otmp->age = (long) rn1(500,1000);
480 					otmp->lamplit = 0;
481 					blessorcurse(otmp, 5);
482 					break;
483 		case MAGIC_LAMP:	otmp->spe = 1;
484 					otmp->lamplit = 0;
485 					blessorcurse(otmp, 2);
486 					break;
487 		case CHEST:
488 		case LARGE_BOX:		otmp->olocked = !!(rn2(5));
489 					otmp->otrapped = !(rn2(10));
490 		case ICE_BOX:
491 		case SACK:
492 		case OILSKIN_SACK:
493 		case BAG_OF_HOLDING:	mkbox_cnts(otmp);
494 					break;
495 #ifdef TOURIST
496 		case EXPENSIVE_CAMERA:
497 #endif
498 		case TINNING_KIT:
499 		case MAGIC_MARKER:	otmp->spe = rn1(70,30);
500 					break;
501 		case CAN_OF_GREASE:	otmp->spe = rnd(25);
502 					blessorcurse(otmp, 10);
503 					break;
504 		case CRYSTAL_BALL:	otmp->spe = rnd(5);
505 					blessorcurse(otmp, 2);
506 					break;
507 		case HORN_OF_PLENTY:
508 		case BAG_OF_TRICKS:	otmp->spe = rnd(20);
509 					break;
510 		case FIGURINE:	{	int tryct2 = 0;
511 					do
512 					    otmp->corpsenm = rndmonnum();
513 					while(is_human(&mons[otmp->corpsenm])
514 						&& tryct2++ < 30);
515 					blessorcurse(otmp, 4);
516 					break;
517 				}
518 		case BELL_OF_OPENING:   otmp->spe = 3;
519 					break;
520 		case MAGIC_FLUTE:
521 		case MAGIC_HARP:
522 		case FROST_HORN:
523 		case FIRE_HORN:
524 		case DRUM_OF_EARTHQUAKE:
525 					otmp->spe = rn1(5,4);
526 					break;
527 	    }
528 	    break;
529 	case AMULET_CLASS:
530 		if (otmp->otyp == AMULET_OF_YENDOR) flags.made_amulet = TRUE;
531 		if(rn2(10) && (otmp->otyp == AMULET_OF_STRANGULATION ||
532 		   otmp->otyp == AMULET_OF_CHANGE ||
533 		   otmp->otyp == AMULET_OF_RESTFUL_SLEEP)) {
534 			curse(otmp);
535 		} else	blessorcurse(otmp, 10);
536 	case VENOM_CLASS:
537 	case CHAIN_CLASS:
538 	case BALL_CLASS:
539 		break;
540 	case POTION_CLASS:
541 		if (otmp->otyp == POT_OIL)
542 		    otmp->age = MAX_OIL_IN_FLASK;	/* amount of oil */
543 		/* fall through */
544 	case SCROLL_CLASS:
545 #ifdef MAIL
546 		if (otmp->otyp != SCR_MAIL)
547 #endif
548 			blessorcurse(otmp, 4);
549 		break;
550 	case SPBOOK_CLASS:
551 		blessorcurse(otmp, 17);
552 		break;
553 	case ARMOR_CLASS:
554 		if(rn2(10) && (otmp->otyp == FUMBLE_BOOTS ||
555 		   otmp->otyp == LEVITATION_BOOTS ||
556 		   otmp->otyp == HELM_OF_OPPOSITE_ALIGNMENT ||
557 		   otmp->otyp == GAUNTLETS_OF_FUMBLING ||
558 		   !rn2(11))) {
559 			curse(otmp);
560 			otmp->spe = -rne(3);
561 		} else if(!rn2(10)) {
562 			otmp->blessed = rn2(2);
563 			otmp->spe = rne(3);
564 		} else	blessorcurse(otmp, 10);
565 		if (artif && !rn2(40))
566 		    otmp = mk_artifact(otmp, (aligntyp)A_NONE);
567 		/* simulate lacquered armor for samurai */
568 		if (Role_if(PM_SAMURAI) && otmp->otyp == SPLINT_MAIL &&
569 		    (moves <= 1 || In_quest(&u.uz))) {
570 #ifdef UNIXPC
571 			/* optimizer bitfield bug */
572 			otmp->oerodeproof = 1;
573 			otmp->rknown = 1;
574 #else
575 			otmp->oerodeproof = otmp->rknown = 1;
576 #endif
577 		}
578 		break;
579 	case WAND_CLASS:
580 		if(otmp->otyp == WAN_WISHING) otmp->spe = rnd(3); else
581 		otmp->spe = rn1(5,
582 			(objects[otmp->otyp].oc_dir == NODIR) ? 11 : 4);
583 		blessorcurse(otmp, 17);
584 		otmp->recharged = 0; /* used to control recharging */
585 		break;
586 	case RING_CLASS:
587 		if(objects[otmp->otyp].oc_charged) {
588 		    blessorcurse(otmp, 3);
589 		    if(rn2(10)) {
590 			if(rn2(10) && bcsign(otmp))
591 			    otmp->spe = bcsign(otmp) * rne(3);
592 			else otmp->spe = rn2(2) ? rne(3) : -rne(3);
593 		    }
594 		    /* make useless +0 rings much less common */
595 		    if (otmp->spe == 0) otmp->spe = rn2(4) - rn2(3);
596 		    /* negative rings are usually cursed */
597 		    if (otmp->spe < 0 && rn2(5)) curse(otmp);
598 		} else if(rn2(10) && (otmp->otyp == RIN_TELEPORTATION ||
599 			  otmp->otyp == RIN_POLYMORPH ||
600 			  otmp->otyp == RIN_AGGRAVATE_MONSTER ||
601 			  otmp->otyp == RIN_HUNGER || !rn2(9))) {
602 			curse(otmp);
603 		}
604 		break;
605 	case ROCK_CLASS:
606 		switch (otmp->otyp) {
607 		    case STATUE:
608 			/* possibly overridden by mkcorpstat() */
609 			otmp->corpsenm = rndmonnum();
610 			if (!verysmall(&mons[otmp->corpsenm]) &&
611 				rn2(level_difficulty()/2 + 10) > 10)
612 			    add_to_container(otmp, mkobj(SPBOOK_CLASS,FALSE));
613 		}
614 		break;
615 	case GOLD_CLASS:
616 		break;	/* do nothing */
617 	default:
618 		impossible("impossible mkobj %d, sym '%c'.", otmp->otyp,
619 						objects[otmp->otyp].oc_class);
620 		return (struct obj *)0;
621 	}
622 	/* unique objects may have an associated artifact entry */
623 	if (objects[otyp].oc_unique && !otmp->oartifact)
624 	    otmp = mk_artifact(otmp, (aligntyp)A_NONE);
625 	otmp->owt = weight(otmp);
626 	return(otmp);
627 }
628 
629 /*
630  * Start a corpse decay or revive timer.  This assumes that the corpse
631  * was just dropped and its age is 0.
632  */
633 void
start_corpse_timeout(body)634 start_corpse_timeout(body)
635 	struct obj *body;
636 {
637 	long when;
638 	int rot_adjust;
639 	short action;
640 
641 #define TAINT_AGE (50L)		/* age when corpses go bad */
642 #define TROLL_REVIVE_CHANCE 37	/* 1/37 chance for 50 turns ~ 75% chance */
643 #define ROT_AGE (250L)	/* age when corpses rot away */
644 
645 	/* lizards and lichen don't rot or revive */
646 	if (body->corpsenm == PM_LIZARD || body->corpsenm == PM_LICHEN) return;
647 
648 	action = ROT_CORPSE;		/* default action: rot away */
649 	when = ROT_AGE;			/* rot away when this old */
650 	rot_adjust = in_mklev ? 25 : 10;	/* give some variation */
651 	when += (long)(rnz(rot_adjust) - rot_adjust);
652 
653 	if (is_rider(&mons[body->corpsenm])) {
654 		/*
655 		 * Riders always revive.  They have a 1/3 chance per turn
656 		 * of reviving after 12 turns.  Always revive by 500.
657 		 */
658 		action = REVIVE_MON;
659 		for (when = 12L; when < 500L; when++)
660 		    if (!rn2(3)) break;
661 
662 	} else if (mons[body->corpsenm].mlet == S_TROLL) {
663 		long age;
664 		for (age = 2; age <= TAINT_AGE; age++)
665 		    if (!rn2(TROLL_REVIVE_CHANCE)) {	/* troll revives */
666 			action = REVIVE_MON;
667 			when = age;
668 			break;
669 		    }
670 	}
671 
672 	(void) start_timer(when, TIMER_OBJECT, action, (genericptr_t)body);
673 }
674 
675 void
bless(otmp)676 bless(otmp)
677 register struct obj *otmp;
678 {
679 	otmp->cursed = 0;
680 	otmp->blessed = 1;
681 	if (otmp->otyp == LUCKSTONE
682 		|| (otmp->oartifact && spec_ability(otmp, SPFX_LUCK)))
683 	    set_moreluck();
684 	else if (otmp->otyp == BAG_OF_HOLDING)
685 	    otmp->owt = weight(otmp);
686 	else if (otmp->otyp == FIGURINE && otmp->timed)
687 		(void) stop_timer(FIG_TRANSFORM, (genericptr_t) otmp);
688 	return;
689 }
690 
691 void
unbless(otmp)692 unbless(otmp)
693 register struct obj *otmp;
694 {
695 	otmp->blessed = 0;
696 	if (otmp->otyp == LUCKSTONE
697 		|| (otmp->oartifact && spec_ability(otmp, SPFX_LUCK)))
698 	    set_moreluck();
699 	else if (otmp->otyp == BAG_OF_HOLDING)
700 	    otmp->owt = weight(otmp);
701 }
702 
703 void
curse(otmp)704 curse(otmp)
705 register struct obj *otmp;
706 {
707 	otmp->blessed = 0;
708 	otmp->cursed = 1;
709 	if (otmp->otyp == LUCKSTONE
710 		|| (otmp->oartifact && spec_ability(otmp, SPFX_LUCK)))
711 	    set_moreluck();
712 	else if (otmp->otyp == BAG_OF_HOLDING)
713 	    otmp->owt = weight(otmp);
714 	else if (otmp->otyp == FIGURINE) {
715 		if (otmp->corpsenm != NON_PM
716 	    	    && !dead_species(otmp->corpsenm,TRUE)
717 		    && (carried(otmp) || mcarried(otmp)))
718 			attach_fig_transform_timeout(otmp);
719 	}
720  	return;
721 }
722 
723 void
uncurse(otmp)724 uncurse(otmp)
725 register struct obj *otmp;
726 {
727 	otmp->cursed = 0;
728 	if (otmp->otyp == LUCKSTONE
729 		|| (otmp->oartifact && spec_ability(otmp, SPFX_LUCK)))
730 	    set_moreluck();
731 	else if (otmp->otyp == BAG_OF_HOLDING)
732 		otmp->owt = weight(otmp);
733 	else if (otmp->otyp == FIGURINE && otmp->timed)
734 		(void) stop_timer(FIG_TRANSFORM, (genericptr_t) otmp);
735 	return;
736 }
737 
738 #endif /* OVLB */
739 #ifdef OVL1
740 
741 void
blessorcurse(otmp,chance)742 blessorcurse(otmp, chance)
743 register struct obj *otmp;
744 register int chance;
745 {
746 	if(otmp->blessed || otmp->cursed) return;
747 
748 	if(!rn2(chance)) {
749 	    if(!rn2(2)) {
750 		curse(otmp);
751 	    } else {
752 		bless(otmp);
753 	    }
754 	}
755 	return;
756 }
757 
758 #endif /* OVL1 */
759 #ifdef OVLB
760 
761 int
bcsign(otmp)762 bcsign(otmp)
763 register struct obj *otmp;
764 {
765 	return(!!otmp->blessed - !!otmp->cursed);
766 }
767 
768 #endif /* OVLB */
769 #ifdef OVL0
770 
771 /*
772  *  Calculate the weight of the given object.  This will recursively follow
773  *  and calculate the weight of any containers.
774  *
775  *  Note:  It is possible to end up with an incorrect weight if some part
776  *	   of the code messes with a contained object and doesn't update the
777  *	   container's weight.
778  */
779 int
weight(obj)780 weight(obj)
781 register struct obj *obj;
782 {
783 	int wt = objects[obj->otyp].oc_weight;
784 
785 	if (obj->otyp == LARGE_BOX && obj->spe == 1) /* Schroedinger's Cat */
786 		wt += mons[PM_HOUSECAT].cwt;
787 	if (Is_container(obj) || obj->otyp == STATUE) {
788 		struct obj *contents;
789 		register int cwt = 0;
790 
791 		if (obj->otyp == STATUE && obj->corpsenm >= LOW_PM)
792 		    wt = (int)obj->quan *
793 			 ((int)mons[obj->corpsenm].cwt * 3 / 2);
794 
795 		for(contents=obj->cobj; contents; contents=contents->nobj)
796 			cwt += weight(contents);
797 		/*
798 		 *  The weight of bags of holding is calculated as the weight
799 		 *  of the bag plus the weight of the bag's contents modified
800 		 *  as follows:
801 		 *
802 		 *	Bag status	Weight of contents
803 		 *	----------	------------------
804 		 *	cursed			2x
805 		 *	blessed			x/4 + 1
806 		 *	otherwise		x/2 + 1
807 		 *
808 		 *  The macro DELTA_CWT in pickup.c also implements these
809 		 *  weight equations.
810 		 *
811 		 *  Note:  The above checks are performed in the given order.
812 		 *	   this means that if an object is both blessed and
813 		 *	   cursed (not supposed to happen), it will be treated
814 		 *	   as cursed.
815 		 */
816 		if (obj->otyp == BAG_OF_HOLDING)
817 		    cwt = obj->cursed ? (cwt * 2) :
818 					(1 + (cwt / (obj->blessed ? 4 : 2)));
819 
820 		return wt + cwt;
821 	}
822 	if (obj->otyp == CORPSE && obj->corpsenm >= LOW_PM)
823 		return (int)obj->quan * mons[obj->corpsenm].cwt;
824 	else if (obj->oclass == GOLD_CLASS)
825 		return (int)((obj->quan + 50L) / 100L);
826 	else if (obj->otyp == HEAVY_IRON_BALL && obj->owt != 0)
827 		return((int)(obj->owt));	/* kludge for "very" heavy iron ball */
828 	return(wt ? wt*(int)obj->quan : ((int)obj->quan + 1)>>1);
829 }
830 
831 static int treefruits[] = {APPLE,ORANGE,PEAR,BANANA,EUCALYPTUS_LEAF};
832 
833 struct obj *
rnd_treefruit_at(x,y)834 rnd_treefruit_at(x,y)
835 {
836 	return mksobj_at(treefruits[rn2(SIZE(treefruits)-1)],x,y,TRUE);
837 }
838 #endif /* OVL0 */
839 #ifdef OVLB
840 
841 struct obj *
mkgold(amount,x,y)842 mkgold(amount, x, y)
843 long amount;
844 int x, y;
845 {
846     register struct obj *gold = g_at(x,y);
847 
848     if (amount <= 0L) amount = (long)(1 + rnd(level_difficulty()+2) * rnd(30));
849     if (gold) {
850 	gold->quan += amount;
851     } else {
852 	gold = mksobj_at(GOLD_PIECE,x,y,TRUE);
853 	gold->quan = amount;
854     }
855     gold->owt = weight(gold);
856     return (gold);
857 }
858 
859 #endif /* OVLB */
860 #ifdef OVL1
861 
862 /* return TRUE if the corpse has special timing */
863 #define special_corpse(num)  (((num) == PM_LIZARD)		\
864 				|| ((num) == PM_LICHEN)		\
865 				|| (is_rider(&mons[num]))	\
866 				|| (mons[num].mlet == S_TROLL))
867 
868 /*
869  * OEXTRA note: Passing mtmp causes mtraits to be saved
870  * even if ptr passed as well, but ptr is always used for
871  * the corpse type (corpsenm). That allows the corpse type
872  * to be different from the original monster,
873  *	i.e.  vampire -> human corpse
874  * yet still allow restoration of the original monster upon
875  * resurrection.
876  */
877 struct obj *
mkcorpstat(objtype,mtmp,ptr,x,y,init)878 mkcorpstat(objtype, mtmp, ptr, x, y, init)
879 int objtype;	/* CORPSE or STATUE */
880 struct monst *mtmp;
881 struct permonst *ptr;
882 int x, y;
883 boolean init;
884 {
885 	register struct obj *otmp;
886 
887 	if (objtype != CORPSE && objtype != STATUE)
888 	    impossible("making corpstat type %d", objtype);
889 	otmp = mksobj_at(objtype, x, y, init);
890 	if (otmp) {
891 	    if (mtmp) {
892 		struct obj *otmp2;
893 
894 		if (!ptr) ptr = mtmp->data;
895 		/* save_mtraits frees original data pointed to by otmp */
896 		otmp2 = save_mtraits(otmp, mtmp);
897 		if (otmp2) otmp = otmp2;
898 	    }
899 	    /* use the corpse or statue produced by mksobj() as-is
900 	       unless `ptr' is non-null */
901 	    if (ptr) {
902 		int old_corpsenm = otmp->corpsenm;
903 
904 		otmp->corpsenm = monsndx(ptr);
905 		otmp->owt = weight(otmp);
906 		if (otmp->otyp == CORPSE &&
907 			(special_corpse(old_corpsenm) ||
908 				special_corpse(otmp->corpsenm))) {
909 		    obj_stop_timers(otmp);
910 		    start_corpse_timeout(otmp);
911 		}
912 	    }
913 	}
914 	return(otmp);
915 }
916 
917 /*
918  * Attach a monster id to an object, to provide
919  * a lasting association between the two.
920  */
921 struct obj *
obj_attach_mid(obj,mid)922 obj_attach_mid(obj, mid)
923 struct obj *obj;
924 unsigned mid;
925 {
926     struct obj *otmp;
927     int lth, namelth;
928 
929     if (!mid || !obj) return (struct obj *)0;
930     lth = sizeof(mid);
931     namelth = obj->onamelth ? strlen(ONAME(obj)) + 1 : 0;
932     if (namelth)
933 	otmp = realloc_obj(obj, lth, (genericptr_t) &mid, namelth, ONAME(obj));
934     else {
935 	otmp = obj;
936 	otmp->oxlth = sizeof(mid);
937 	(void) memcpy((genericptr_t)otmp->oextra, (genericptr_t)&mid,
938 								sizeof(mid));
939     }
940     if (otmp && otmp->oxlth) otmp->oattached = OATTACHED_M_ID;	/* mark it */
941     return otmp;
942 }
943 
944 static struct obj *
save_mtraits(obj,mtmp)945 save_mtraits(obj, mtmp)
946 struct obj *obj;
947 struct monst *mtmp;
948 {
949 	struct obj *otmp;
950 	int lth, namelth;
951 
952 	lth = sizeof(struct monst) + mtmp->mxlth + mtmp->mnamelth;
953 	namelth = obj->onamelth ? strlen(ONAME(obj)) + 1 : 0;
954 	otmp = realloc_obj(obj, lth, (genericptr_t) mtmp, namelth, ONAME(obj));
955 	if (otmp && otmp->oxlth) {
956 		struct monst *mtmp2 = (struct monst *)otmp->oextra;
957 		if (mtmp->data) mtmp2->mnum = monsndx(mtmp->data);
958 		/* invalidate pointers and m_id */
959 		mtmp2->m_id     = 0;
960 		mtmp2->nmon     = (struct monst *)0;
961 		mtmp2->data     = (struct permonst *)0;
962 		mtmp2->minvent  = (struct obj *)0;
963 		otmp->oattached = OATTACHED_MONST;	/* mark it */
964 	}
965 	return otmp;
966 }
967 
968 /* returns a pointer to a new monst structure based on
969  * the one contained within the obj.
970  */
971 struct monst *
get_mtraits(obj,copyof)972 get_mtraits(obj, copyof)
973 struct obj *obj;
974 boolean copyof;
975 {
976 	struct monst *mtmp = (struct monst *)0;
977 	struct monst *mnew = (struct monst *)0;
978 
979 	if (obj->oxlth && obj->oattached == OATTACHED_MONST)
980 		mtmp = (struct monst *)obj->oextra;
981 	if (mtmp) {
982 	    if (copyof) {
983 		int lth = mtmp->mxlth + mtmp->mnamelth;
984 		mnew = newmonst(lth);
985 		lth += sizeof(struct monst);
986 		(void) memcpy((genericptr_t)mnew,
987 				(genericptr_t)mtmp, lth);
988 	    } else {
989 	      /* Never insert this returned pointer into mon chains! */
990 	    	mnew = mtmp;
991 	    }
992 	}
993 	return mnew;
994 }
995 
996 #endif /* OVL1 */
997 #ifdef OVLB
998 
999 /* make an object named after someone listed in the scoreboard file */
1000 struct obj *
mk_tt_object(objtype,x,y)1001 mk_tt_object(objtype, x, y)
1002 int objtype; /* CORPSE or STATUE */
1003 register int x, y;
1004 {
1005 	register struct obj *otmp, *otmp2;
1006 	boolean initialize_it;
1007 
1008 	/* player statues never contain books */
1009 	initialize_it = (objtype != STATUE);
1010 	if ((otmp = mksobj_at(objtype, x, y, initialize_it)) != 0) {
1011 	    /* tt_oname will return null if the scoreboard is empty */
1012 	    if ((otmp2 = tt_oname(otmp)) != 0) otmp = otmp2;
1013 	}
1014 	return(otmp);
1015 }
1016 
1017 /* make a new corpse or statue, uninitialized if a statue (i.e. no books) */
1018 struct obj *
mk_named_object(objtype,ptr,x,y,nm)1019 mk_named_object(objtype, ptr, x, y, nm)
1020 int objtype;	/* CORPSE or STATUE */
1021 struct permonst *ptr;
1022 int x, y;
1023 const char *nm;
1024 {
1025 	struct obj *otmp;
1026 
1027 	otmp = mkcorpstat(objtype, (struct monst *)0, ptr,
1028 				x, y, (boolean)(objtype != STATUE));
1029 	if (nm)
1030 		otmp = oname(otmp, nm);
1031 	return(otmp);
1032 }
1033 
1034 boolean
is_flammable(otmp)1035 is_flammable(otmp)
1036 register struct obj *otmp;
1037 {
1038 	int otyp = otmp->otyp;
1039 
1040 	if (objects[otyp].oc_oprop == FIRE_RES) return FALSE;
1041 
1042 	return((boolean)(objects[otyp].oc_material <= WOOD &&
1043 			objects[otyp].oc_material != LIQUID));
1044 }
1045 
1046 #endif /* OVLB */
1047 #ifdef OVL1
1048 
1049 /*
1050  * These routines maintain the single-linked lists headed in level.objects[][]
1051  * and threaded through the nexthere fields in the object-instance structure.
1052  */
1053 
1054 /* put the object at the given location */
1055 void
place_object(otmp,x,y)1056 place_object(otmp, x, y)
1057 register struct obj *otmp;
1058 int x, y;
1059 {
1060     register struct obj *otmp2 = level.objects[x][y];
1061 
1062     if (otmp->where != OBJ_FREE)
1063 	panic("place_object: obj not free");
1064 
1065     if (otmp->otyp == BOULDER) block_point(x,y);	/* vision */
1066 
1067     /* obj goes under boulders */
1068     if (otmp2 && (otmp2->otyp == BOULDER)) {
1069 	otmp->nexthere = otmp2->nexthere;
1070 	otmp2->nexthere = otmp;
1071     } else {
1072 	otmp->nexthere = otmp2;
1073 	level.objects[x][y] = otmp;
1074     }
1075 
1076     /* set the new object's location */
1077     otmp->ox = x;
1078     otmp->oy = y;
1079 
1080     otmp->where = OBJ_FLOOR;
1081 
1082     /* add to floor chain */
1083     otmp->nobj = fobj;
1084     fobj = otmp;
1085     if (otmp->timed) obj_timer_checks(otmp, x, y, 0);
1086 }
1087 
1088 #define ON_ICE(a) ((a)->recharged)
1089 #define ROT_ICE_ADJUSTMENT 2	/* rotting on ice takes 2 times as long */
1090 
1091 /* If ice was affecting any objects correct that now
1092  * Also used for starting ice effects too. [zap.c]
1093  */
1094 void
obj_ice_effects(x,y,do_buried)1095 obj_ice_effects(x, y, do_buried)
1096 int x, y;
1097 boolean do_buried;
1098 {
1099 	struct obj *otmp;
1100 
1101 	for (otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere) {
1102 		if (otmp->timed) obj_timer_checks(otmp, x, y, 0);
1103 	}
1104 	if (do_buried) {
1105 	    for (otmp = level.buriedobjlist; otmp; otmp = otmp->nobj) {
1106  		if (otmp->ox == x && otmp->oy == y) {
1107 			if (otmp->timed) obj_timer_checks(otmp, x, y, 0);
1108 		}
1109 	    }
1110 	}
1111 }
1112 
1113 /*
1114  * Returns an obj->age for a corpse object on ice, that would be the
1115  * actual obj->age if the corpse had just been lifted from the ice.
1116  * This is useful when just using obj->age in a check or calculation because
1117  * rot timers pertaining to the object don't have to be stopped and
1118  * restarted etc.
1119  */
1120 long
peek_at_iced_corpse_age(otmp)1121 peek_at_iced_corpse_age(otmp)
1122 struct obj *otmp;
1123 {
1124     long age, retval = otmp->age;
1125 
1126     if (otmp->otyp == CORPSE && ON_ICE(otmp)) {
1127 	/* Adjust the age; must be same as obj_timer_checks() for off ice*/
1128 	age = monstermoves - otmp->age;
1129 	retval = otmp->age + (age / ROT_ICE_ADJUSTMENT);
1130 #ifdef DEBUG_EFFECTS
1131 	pline_The("%s age has ice modifications:otmp->age = %ld, returning %ld.",
1132 		s_suffix(doname(otmp)),otmp->age, retval);
1133 	pline("Effective age of corpse: %ld.",
1134 		monstermoves - retval);
1135 #endif
1136     }
1137     return retval;
1138 }
1139 
1140 STATIC_OVL void
obj_timer_checks(otmp,x,y,force)1141 obj_timer_checks(otmp, x, y, force)
1142 struct obj *otmp;
1143 xchar x, y;
1144 int force;	/* 0 = no force so do checks, <0 = force off, >0 force on */
1145 {
1146     long tleft = 0L;
1147     short action = ROT_CORPSE;
1148     boolean restart_timer = FALSE;
1149     boolean on_floor = (otmp->where == OBJ_FLOOR);
1150     boolean buried = (otmp->where == OBJ_BURIED);
1151 
1152     /* Check for corpses just placed on or in ice */
1153     if (otmp->otyp == CORPSE && (on_floor || buried) && is_ice(x,y)) {
1154 	tleft = stop_timer(action, (genericptr_t)otmp);
1155 	if (tleft == 0L) {
1156 		action = REVIVE_MON;
1157 		tleft = stop_timer(action, (genericptr_t)otmp);
1158 	}
1159 	if (tleft != 0L) {
1160 	    long age;
1161 
1162 	    tleft = tleft - monstermoves;
1163 	    /* mark the corpse as being on ice */
1164 	    ON_ICE(otmp) = 1;
1165 #ifdef DEBUG_EFFECTS
1166 	    pline("%s is now on ice at %d,%d.", The(xname(otmp)),x,y);
1167 #endif
1168 	    /* Adjust the time remaining */
1169 	    tleft *= ROT_ICE_ADJUSTMENT;
1170 	    restart_timer = TRUE;
1171 	    /* Adjust the age; must be same as in obj_ice_age() */
1172 	    age = monstermoves - otmp->age;
1173 	    otmp->age = monstermoves - (age * ROT_ICE_ADJUSTMENT);
1174 	}
1175     }
1176     /* Check for corpses coming off ice */
1177     else if ((force < 0) ||
1178 	     (otmp->otyp == CORPSE && ON_ICE(otmp) &&
1179 	     ((on_floor && !is_ice(x,y)) || !on_floor))) {
1180 	tleft = stop_timer(action, (genericptr_t)otmp);
1181 	if (tleft == 0L) {
1182 		action = REVIVE_MON;
1183 		tleft = stop_timer(action, (genericptr_t)otmp);
1184 	}
1185 	if (tleft != 0L) {
1186 		long age;
1187 
1188 		tleft = tleft - monstermoves;
1189 		ON_ICE(otmp) = 0;
1190 #ifdef DEBUG_EFFECTS
1191 	    	pline("%s is no longer on ice at %d,%d.", The(xname(otmp)),x,y);
1192 #endif
1193 		/* Adjust the remaining time */
1194 		tleft /= ROT_ICE_ADJUSTMENT;
1195 		restart_timer = TRUE;
1196 		/* Adjust the age */
1197 		age = monstermoves - otmp->age;
1198 		otmp->age = otmp->age + (age / ROT_ICE_ADJUSTMENT);
1199 	}
1200     }
1201     /* now re-start the timer with the appropriate modifications */
1202     if (restart_timer)
1203 	(void) start_timer(tleft, TIMER_OBJECT, action, (genericptr_t)otmp);
1204 }
1205 
1206 #undef ON_ICE
1207 #undef ROT_ICE_ADJUSTMENT
1208 
1209 void
remove_object(otmp)1210 remove_object(otmp)
1211 register struct obj *otmp;
1212 {
1213     xchar x = otmp->ox;
1214     xchar y = otmp->oy;
1215 
1216     if (otmp->where != OBJ_FLOOR)
1217 	panic("remove_object: obj not on floor");
1218     if (otmp->otyp == BOULDER) unblock_point(x,y); /* vision */
1219     extract_nexthere(otmp, &level.objects[x][y]);
1220     extract_nobj(otmp, &fobj);
1221     if (otmp->timed) obj_timer_checks(otmp,x,y,0);
1222 }
1223 
1224 /* throw away all of a monster's inventory */
1225 void
discard_minvent(mtmp)1226 discard_minvent(mtmp)
1227 struct monst *mtmp;
1228 {
1229     struct obj *otmp;
1230 
1231     while ((otmp = mtmp->minvent) != 0) {
1232 	obj_extract_self(otmp);
1233 	obfree(otmp, (struct obj *)0);	/* dealloc_obj() isn't sufficient */
1234     }
1235 }
1236 
1237 /*
1238  * Free obj from whatever list it is on in preperation of deleting it or
1239  * moving it elsewhere.  This will perform all high-level consequences
1240  * involved with removing the item.  E.g. if the object is in the hero's
1241  * inventory and confers heat resistance, the hero will lose it.
1242  *
1243  * Object positions:
1244  *	OBJ_FREE	not on any list
1245  *	OBJ_FLOOR	fobj, level.locations[][] chains (use remove_object)
1246  *	OBJ_CONTAINED	cobj chain of container object
1247  *	OBJ_INVENT	hero's invent chain (use freeinv)
1248  *	OBJ_MINVENT	monster's invent chain
1249  *	OBJ_MIGRATING	migrating chain
1250  *	OBJ_BURIED	level.buriedobjs chain
1251  *	OBJ_ONBILL	on billobjs chain
1252  */
1253 void
obj_extract_self(obj)1254 obj_extract_self(obj)
1255     struct obj *obj;
1256 {
1257     switch (obj->where) {
1258 	case OBJ_FREE:
1259 	    break;
1260 	case OBJ_FLOOR:
1261 	    remove_object(obj);
1262 	    break;
1263 	case OBJ_CONTAINED:
1264 	    extract_nobj(obj, &obj->ocontainer->cobj);
1265 	    container_weight(obj->ocontainer);
1266 	    break;
1267 	case OBJ_INVENT:
1268 	    freeinv(obj);
1269 	    break;
1270 	case OBJ_MINVENT:
1271 	    extract_nobj(obj, &obj->ocarry->minvent);
1272 	    break;
1273 	case OBJ_MIGRATING:
1274 	    extract_nobj(obj, &migrating_objs);
1275 	    break;
1276 	case OBJ_BURIED:
1277 	    extract_nobj(obj, &level.buriedobjlist);
1278 	    break;
1279 	case OBJ_ONBILL:
1280 	    extract_nobj(obj, &billobjs);
1281 	    break;
1282 	default:
1283 	    panic("obj_extract_self");
1284 	    break;
1285     }
1286 }
1287 
1288 
1289 /* Extract the given object from the chain, following nobj chain. */
1290 void
extract_nobj(obj,head_ptr)1291 extract_nobj(obj, head_ptr)
1292     struct obj *obj, **head_ptr;
1293 {
1294     struct obj *curr, *prev;
1295 
1296     curr = *head_ptr;
1297     for (prev = (struct obj *) 0; curr; prev = curr, curr = curr->nobj) {
1298 	if (curr == obj) {
1299 	    if (prev)
1300 		prev->nobj = curr->nobj;
1301 	    else
1302 		*head_ptr = curr->nobj;
1303 	    break;
1304 	}
1305     }
1306     if (!curr) panic("extract_nobj: object lost");
1307     obj->where = OBJ_FREE;
1308 }
1309 
1310 
1311 /*
1312  * Extract the given object from the chain, following nexthere chain.
1313  *
1314  * This does not set obj->where, this function is expected to be called
1315  * in tandem with extract_nobj, which does set it.
1316  */
1317 void
extract_nexthere(obj,head_ptr)1318 extract_nexthere(obj, head_ptr)
1319     struct obj *obj, **head_ptr;
1320 {
1321     struct obj *curr, *prev;
1322 
1323     curr = *head_ptr;
1324     for (prev = (struct obj *) 0; curr; prev = curr, curr = curr->nexthere) {
1325 	if (curr == obj) {
1326 	    if (prev)
1327 		prev->nexthere = curr->nexthere;
1328 	    else
1329 		*head_ptr = curr->nexthere;
1330 	    break;
1331 	}
1332     }
1333     if (!curr) panic("extract_nexthere: object lost");
1334 }
1335 
1336 
1337 /*
1338  * Add obj to mon's inventory.  If obj is able to merge with something already
1339  * in the inventory, then the passed obj is deleted and 1 is returned.
1340  * Otherwise 0 is returned.
1341  */
1342 int
add_to_minv(mon,obj)1343 add_to_minv(mon, obj)
1344     struct monst *mon;
1345     struct obj *obj;
1346 {
1347     struct obj *otmp;
1348 
1349     if (obj->where != OBJ_FREE)
1350 	panic("add_to_minv: obj not free");
1351 
1352     /* merge if possible */
1353     for (otmp = mon->minvent; otmp; otmp = otmp->nobj)
1354 	if (merged(&otmp, &obj))
1355 	    return 1;	/* obj merged and then free'd */
1356     /* else insert; don't bother forcing it to end of chain */
1357     obj->where = OBJ_MINVENT;
1358     obj->ocarry = mon;
1359     obj->nobj = mon->minvent;
1360     mon->minvent = obj;
1361     return 0;	/* obj on mon's inventory chain */
1362 }
1363 
1364 void
add_to_container(container,obj)1365 add_to_container(container, obj)
1366     struct obj *container, *obj;
1367 {
1368     if (obj->where != OBJ_FREE)
1369 	panic("add_to_container: obj not free");
1370 
1371     obj->where = OBJ_CONTAINED;
1372     obj->ocontainer = container;
1373     obj->nobj = container->cobj;
1374     container->cobj = obj;
1375 }
1376 
1377 void
add_to_migration(obj)1378 add_to_migration(obj)
1379     struct obj *obj;
1380 {
1381     if (obj->where != OBJ_FREE)
1382 	panic("add_to_migration: obj not free");
1383 
1384     obj->where = OBJ_MIGRATING;
1385     obj->nobj = migrating_objs;
1386     migrating_objs = obj;
1387 }
1388 
1389 void
add_to_buried(obj)1390 add_to_buried(obj)
1391     struct obj *obj;
1392 {
1393     if (obj->where != OBJ_FREE)
1394 	panic("add_to_buried: obj not free");
1395 
1396     obj->where = OBJ_BURIED;
1397     obj->nobj = level.buriedobjlist;
1398     level.buriedobjlist = obj;
1399 }
1400 
1401 /* Recalculate the weight of this container and all of _its_ containers. */
1402 STATIC_OVL void
container_weight(container)1403 container_weight(container)
1404     struct obj *container;
1405 {
1406     container->owt = weight(container);
1407     if (container->where == OBJ_CONTAINED)
1408 	container_weight(container->ocontainer);
1409 /*
1410     else if (container->where == OBJ_INVENT)
1411 	recalculate load delay here ???
1412 */
1413 }
1414 
1415 /*
1416  * Deallocate the object.  _All_ objects should be run through here for
1417  * them to be deallocated.
1418  */
1419 void
dealloc_obj(obj)1420 dealloc_obj(obj)
1421     struct obj *obj;
1422 {
1423     if (obj->where != OBJ_FREE)
1424 	panic("dealloc_obj: obj not free");
1425 
1426     /* free up any timers attached to the object */
1427     if (obj->timed)
1428 	obj_stop_timers(obj);
1429 
1430     /*
1431      * Free up any light sources attached to the object.
1432      *
1433      * We may want to just call del_light_source() without any
1434      * checks (requires a code change there).  Otherwise this
1435      * list must track all objects that can have a light source
1436      * attached to it (and also requires lamplit to be set).
1437      */
1438     if (obj_sheds_light(obj))
1439 	del_light_source(LS_OBJECT, (genericptr_t) obj);
1440 
1441     free((genericptr_t) obj);
1442 }
1443 
1444 #ifdef WIZARD
1445 /* Check all object lists for consistency. */
1446 void
obj_sanity_check()1447 obj_sanity_check()
1448 {
1449     int x, y;
1450     struct obj *obj;
1451     struct monst *mon;
1452     const char *mesg;
1453     char obj_address[20], mon_address[20];  /* room for formatted pointers */
1454 
1455     mesg = "fobj sanity";
1456     for (obj = fobj; obj; obj = obj->nobj) {
1457 	if (obj->where != OBJ_FLOOR) {
1458 	    pline("%s obj %s %s@(%d,%d): %s\n", mesg,
1459 		fmt_ptr((genericptr_t)obj, obj_address),
1460 		where_name(obj->where),
1461 		obj->ox, obj->oy, doname(obj));
1462 	}
1463 	check_contained(obj, mesg);
1464     }
1465 
1466     mesg = "location sanity";
1467     for (x = 0; x < COLNO; x++)
1468 	for (y = 0; y < ROWNO; y++)
1469 	    for (obj = level.objects[x][y]; obj; obj = obj->nexthere)
1470 		if (obj->where != OBJ_FLOOR) {
1471 		    pline("%s obj %s %s@(%d,%d): %s\n", mesg,
1472 			fmt_ptr((genericptr_t)obj, obj_address),
1473 			where_name(obj->where),
1474 			obj->ox, obj->oy, doname(obj));
1475 		}
1476 
1477     mesg = "invent sanity";
1478     for (obj = invent; obj; obj = obj->nobj) {
1479 	if (obj->where != OBJ_INVENT) {
1480 	    pline("%s obj %s %s: %s\n", mesg,
1481 		fmt_ptr((genericptr_t)obj, obj_address),
1482 		where_name(obj->where), doname(obj));
1483 	}
1484 	check_contained(obj, mesg);
1485     }
1486 
1487     mesg = "migrating sanity";
1488     for (obj = migrating_objs; obj; obj = obj->nobj) {
1489 	if (obj->where != OBJ_MIGRATING) {
1490 	    pline("%s obj %s %s: %s\n", mesg,
1491 		fmt_ptr((genericptr_t)obj, obj_address),
1492 		where_name(obj->where), doname(obj));
1493 	}
1494 	check_contained(obj, mesg);
1495     }
1496 
1497     mesg = "buried sanity";
1498     for (obj = level.buriedobjlist; obj; obj = obj->nobj) {
1499 	if (obj->where != OBJ_BURIED) {
1500 	    pline("%s obj %s %s: %s\n", mesg,
1501 		fmt_ptr((genericptr_t)obj, obj_address),
1502 		where_name(obj->where), doname(obj));
1503 	}
1504 	check_contained(obj, mesg);
1505     }
1506 
1507     mesg = "bill sanity";
1508     for (obj = billobjs; obj; obj = obj->nobj) {
1509 	if (obj->where != OBJ_ONBILL) {
1510 	    pline("%s obj %s %s: %s\n", mesg,
1511 		fmt_ptr((genericptr_t)obj, obj_address),
1512 		where_name(obj->where), doname(obj));
1513 	}
1514 	/* shouldn't be a full container on the bill */
1515 	if (obj->cobj) {
1516 	    pline("%s obj %s contains %s! %s\n", mesg,
1517 		fmt_ptr((genericptr_t)obj, obj_address),
1518 		something, doname(obj));
1519 	}
1520     }
1521 
1522     mesg = "minvent sanity";
1523     for (mon = fmon; mon; mon = mon->nmon)
1524 	for (obj = mon->minvent; obj; obj = obj->nobj) {
1525 	    if (obj->where != OBJ_MINVENT) {
1526 		pline("%s obj %s %s: %s\n", mesg,
1527 			fmt_ptr((genericptr_t)obj, obj_address),
1528 			where_name(obj->where), doname(obj));
1529 	    }
1530 	    if (obj->ocarry != mon) {
1531 		pline("%s obj %s (%s) not held by mon %s (%s)\n", mesg,
1532 			fmt_ptr((genericptr_t)obj, obj_address),
1533 			doname(obj),
1534 			fmt_ptr((genericptr_t)mon, mon_address),
1535 			mon_nam(mon));
1536 	    }
1537 	    check_contained(obj, mesg);
1538 	}
1539 }
1540 
1541 /* This must stay consistent with the defines in obj.h. */
1542 static const char *obj_state_names[NOBJ_STATES] = {
1543 	"free",		"floor",	"contained",	"invent",
1544 	"minvent",	"migrating",	"buried",	"onbill"
1545 };
1546 
1547 STATIC_OVL const char *
where_name(where)1548 where_name(where)
1549     int where;
1550 {
1551     return (where<0 || where>=NOBJ_STATES) ? "unknown" : obj_state_names[where];
1552 }
1553 
1554 /* obj sanity check: check objs contained by container */
1555 STATIC_OVL void
check_contained(container,mesg)1556 check_contained(container, mesg)
1557     struct obj *container;
1558     const char *mesg;
1559 {
1560     struct obj *obj;
1561     char obj1_address[20], obj2_address[20];
1562 
1563     for (obj = container->cobj; obj; obj = obj->nobj) {
1564 	if (obj->where != OBJ_CONTAINED)
1565 	    pline("contained %s obj %s: %s\n", mesg,
1566 		fmt_ptr((genericptr_t)obj, obj1_address),
1567 		where_name(obj->where));
1568 	else if (obj->ocontainer != container)
1569 	    pline("%s obj %s not in container %s\n", mesg,
1570 		fmt_ptr((genericptr_t)obj, obj1_address),
1571 		fmt_ptr((genericptr_t)container, obj2_address));
1572     }
1573 }
1574 #endif /* WIZARD */
1575 
1576 #endif /* OVL1 */
1577 
1578 /*mkobj.c*/
1579