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 *
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 *
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 *
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
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
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 *
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
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
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 *
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
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
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
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
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
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
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
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
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 *
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 *
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 *
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 *
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 *
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 *
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 *
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 *
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 *
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
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*/