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