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 8STATIC_DCL void FDECL(mkbox_cnts,(struct obj *)); 9STATIC_DCL void FDECL(obj_timer_checks,(struct obj *, XCHAR_P, XCHAR_P, int)); 10#ifdef OVL1 11STATIC_DCL void FDECL(container_weight, (struct obj *)); 12STATIC_DCL struct obj *FDECL(save_mtraits, (struct obj *, struct monst *)); 13#ifdef WIZARD 14STATIC_DCL const char *FDECL(where_name, (int)); 15STATIC_DCL void FDECL(check_contained, (struct obj *,const char *)); 16#endif 17#endif /* OVL1 */ 18 19extern struct obj *thrownobj; /* defined in dothrow.c */ 20 21/*#define DEBUG_EFFECTS*/ /* show some messages for debugging */ 22 23struct icp { 24 int iprob; /* probability of an item type */ 25 char iclass; /* item class */ 26}; 27 28#ifdef OVL1 29 30const 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 44const 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 57const 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 68const 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 81struct obj * 82mkobj_at(let, x, y, artif) 83char let; 84int x, y; 85boolean artif; 86{ 87 struct obj *otmp; 88 89 otmp = mkobj(let, artif); 90 place_object(otmp, x, y); 91 return(otmp); 92} 93 94struct obj * 95mksobj_at(otyp, x, y, init, artif) 96int otyp, x, y; 97boolean 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 106struct obj * 107mkobj(oclass, artif) 108char oclass; 109boolean 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 137STATIC_OVL void 138mkbox_cnts(box) 139struct 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 201int 202rndmonnum() /* 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 */ 226struct obj * 227splitobj(obj, num) 228struct obj *obj; 229long 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 */ 271void 272replace_object(obj, otmp) 273struct obj *obj; 274struct 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 */ 328void 329bill_dummy_object(otmp) 330register 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 357static const char dknowns[] = { 358 WAND_CLASS, RING_CLASS, POTION_CLASS, SCROLL_CLASS, 359 GEM_CLASS, SPBOOK_CLASS, WEAPON_CLASS, TOOL_CLASS, 0 360}; 361 362struct obj * 363mksobj(otyp, init, artif) 364int otyp; 365boolean init; 366boolean 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 */ 639void 640start_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 687void 688bless(otmp) 689register 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 705void 706unbless(otmp) 707register 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 716void 717curse(otmp) 718register 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 745void 746uncurse(otmp) 747register 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 762void 763blessorcurse(otmp, chance) 764register struct obj *otmp; 765register 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 782int 783bcsign(otmp) 784register 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 */ 800int 801weight(obj) 802register 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 858static int treefruits[] = {APPLE,ORANGE,PEAR,BANANA,EUCALYPTUS_LEAF}; 859 860struct obj * 861rnd_treefruit_at(x,y) 862int x, y; 863{ 864 return mksobj_at(treefruits[rn2(SIZE(treefruits))], x, y, TRUE, FALSE); 865} 866#endif /* OVL0 */ 867#ifdef OVLB 868 869struct obj * 870mkgold(amount, x, y) 871long amount; 872int 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 */ 906struct obj * 907mkcorpstat(objtype, mtmp, ptr, x, y, init) 908int objtype; /* CORPSE or STATUE */ 909struct monst *mtmp; 910struct permonst *ptr; 911int x, y; 912boolean 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 */ 954struct obj * 955obj_attach_mid(obj, mid) 956struct obj *obj; 957unsigned 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 977static struct obj * 978save_mtraits(obj, mtmp) 979struct obj *obj; 980struct 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 */ 1005struct monst * 1006get_mtraits(obj, copyof) 1007struct obj *obj; 1008boolean 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 */ 1034struct obj * 1035mk_tt_object(objtype, x, y) 1036int objtype; /* CORPSE or STATUE */ 1037register 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) */ 1052struct obj * 1053mk_named_object(objtype, ptr, x, y, nm) 1054int objtype; /* CORPSE or STATUE */ 1055struct permonst *ptr; 1056int x, y; 1057const 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 1068boolean 1069is_flammable(otmp) 1070register 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 1081boolean 1082is_rottable(otmp) 1083register 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 */ 1100void 1101place_object(otmp, x, y) 1102register struct obj *otmp; 1103int 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 */ 1140void 1141obj_ice_effects(x, y, do_buried) 1142int x, y; 1143boolean 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 */ 1166long 1167peek_at_iced_corpse_age(otmp) 1168struct 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 NETHACK_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 1186STATIC_OVL void 1187obj_timer_checks(otmp, x, y, force) 1188struct obj *otmp; 1189xchar x, y; 1190int 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 NETHACK_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 NETHACK_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 1255void 1256remove_object(otmp) 1257register 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 */ 1271void 1272discard_minvent(mtmp) 1273struct 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 */ 1299void 1300obj_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. */ 1336void 1337extract_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 */ 1363void 1364extract_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 */ 1388int 1389add_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 */ 1414struct obj * 1415add_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 1436void 1437add_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 1448void 1449add_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. */ 1461STATIC_OVL void 1462container_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 */ 1478void 1479dealloc_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. */ 1507void 1508obj_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. */ 1603static const char *obj_state_names[NOBJ_STATES] = { 1604 "free", "floor", "contained", "invent", 1605 "minvent", "migrating", "buried", "onbill" 1606}; 1607 1608STATIC_OVL const char * 1609where_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 */ 1616STATIC_OVL void 1617check_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