1/* SCCS Id: @(#)zap.c 3.4 2003/08/24 */ 2/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ 3/* NetHack may be freely redistributed. See license for details. */ 4 5#include "hack.h" 6 7/* Disintegration rays have special treatment; corpses are never left. 8 * But the routine which calculates the damage is separate from the routine 9 * which kills the monster. The damage routine returns this cookie to 10 * indicate that the monster should be disintegrated. 11 */ 12#define MAGIC_COOKIE 1000 13 14#ifdef OVLB 15static NEARDATA boolean obj_zapped; 16static NEARDATA int poly_zapped; 17#endif 18 19extern boolean notonhead; /* for long worms */ 20 21/* kludge to use mondied instead of killed */ 22extern boolean m_using; 23 24STATIC_DCL void FDECL(costly_cancel, (struct obj *)); 25STATIC_DCL void FDECL(polyuse, (struct obj*, int, int)); 26STATIC_DCL void FDECL(create_polymon, (struct obj *, int)); 27STATIC_DCL boolean FDECL(zap_updown, (struct obj *)); 28STATIC_DCL int FDECL(zhitm, (struct monst *,int,int,struct obj **)); 29STATIC_DCL void FDECL(zhitu, (int,int,const char *,XCHAR_P,XCHAR_P)); 30STATIC_DCL void FDECL(revive_egg, (struct obj *)); 31#ifdef STEED 32STATIC_DCL boolean FDECL(zap_steed, (struct obj *)); 33#endif 34 35#ifdef OVLB 36STATIC_DCL int FDECL(zap_hit, (int,int)); 37#endif 38#ifdef OVL0 39STATIC_DCL void FDECL(backfire, (struct obj *)); 40STATIC_DCL int FDECL(spell_hit_bonus, (int)); 41#endif 42 43#define ZT_MAGIC_MISSILE (AD_MAGM-1) 44#define ZT_FIRE (AD_FIRE-1) 45#define ZT_COLD (AD_COLD-1) 46#define ZT_SLEEP (AD_SLEE-1) 47#define ZT_DEATH (AD_DISN-1) /* or disintegration */ 48#define ZT_LIGHTNING (AD_ELEC-1) 49#define ZT_POISON_GAS (AD_DRST-1) 50#define ZT_ACID (AD_ACID-1) 51/* 8 and 9 are currently unassigned */ 52 53#define ZT_WAND(x) (x) 54#define ZT_SPELL(x) (10+(x)) 55#define ZT_BREATH(x) (20+(x)) 56 57#define is_hero_spell(type) ((type) >= 10 && (type) < 20) 58 59#ifndef OVLB 60STATIC_VAR const char are_blinded_by_the_flash[]; 61extern const char * const flash_types[]; 62#else 63STATIC_VAR const char are_blinded_by_the_flash[] = "are blinded by the flash!"; 64 65const char * const flash_types[] = { /* also used in buzzmu(mcastu.c) */ 66 "magic missile", /* Wands must be 0-9 */ 67 "bolt of fire", 68 "bolt of cold", 69 "sleep ray", 70 "death ray", 71 "bolt of lightning", 72 "", 73 "", 74 "", 75 "", 76 77 "magic missile", /* Spell equivalents must be 10-19 */ 78 "fireball", 79 "cone of cold", 80 "sleep ray", 81 "finger of death", 82 "bolt of lightning", /* There is no spell, used for retribution */ 83 "", 84 "", 85 "", 86 "", 87 88 "blast of missiles", /* Dragon breath equivalents 20-29*/ 89 "blast of fire", 90 "blast of frost", 91 "blast of sleep gas", 92 "blast of disintegration", 93 "blast of lightning", 94 "blast of poison gas", 95 "blast of acid", 96 "", 97 "" 98}; 99 100/* Routines for IMMEDIATE wands and spells. */ 101/* bhitm: monster mtmp was hit by the effect of wand or spell otmp */ 102int 103bhitm(mtmp, otmp) 104struct monst *mtmp; 105struct obj *otmp; 106{ 107 boolean wake = TRUE; /* Most 'zaps' should wake monster */ 108 boolean reveal_invis = FALSE; 109 boolean dbldam = Role_if(PM_KNIGHT) && u.uhave.questart; 110 int dmg, otyp = otmp->otyp; 111 const char *zap_type_text = "spell"; 112 struct obj *obj; 113 boolean disguised_mimic = (mtmp->data->mlet == S_MIMIC && 114 mtmp->m_ap_type != M_AP_NOTHING); 115 116 if (u.uswallow && mtmp == u.ustuck) 117 reveal_invis = FALSE; 118 119 switch(otyp) { 120 case WAN_STRIKING: 121 zap_type_text = "wand"; 122 /* fall through */ 123 case SPE_FORCE_BOLT: 124 reveal_invis = TRUE; 125 if (resists_magm(mtmp)) { /* match effect on player */ 126 shieldeff(mtmp->mx, mtmp->my); 127 break; /* skip makeknown */ 128 } else if (u.uswallow || rnd(20) < 10 + find_mac(mtmp)) { 129 dmg = d(2,12); 130 if(dbldam) dmg *= 2; 131 if (otyp == SPE_FORCE_BOLT) 132 dmg += spell_damage_bonus(); 133 hit(zap_type_text, mtmp, exclam(dmg)); 134 (void) resist(mtmp, otmp->oclass, dmg, TELL); 135 } else miss(zap_type_text, mtmp); 136 makeknown(otyp); 137 break; 138 case WAN_SLOW_MONSTER: 139 case SPE_SLOW_MONSTER: 140 if (!resist(mtmp, otmp->oclass, 0, NOTELL)) { 141 mon_adjust_speed(mtmp, -1, otmp); 142 m_dowear(mtmp, FALSE); /* might want speed boots */ 143 if (u.uswallow && (mtmp == u.ustuck) && 144 is_whirly(mtmp->data)) { 145 You("disrupt %s!", mon_nam(mtmp)); 146 pline("A huge hole opens up..."); 147 expels(mtmp, mtmp->data, TRUE); 148 } 149 } 150 break; 151 case WAN_SPEED_MONSTER: 152 if (!resist(mtmp, otmp->oclass, 0, NOTELL)) { 153 mon_adjust_speed(mtmp, 1, otmp); 154 m_dowear(mtmp, FALSE); /* might want speed boots */ 155 } 156 break; 157 case WAN_UNDEAD_TURNING: 158 case SPE_TURN_UNDEAD: 159 wake = FALSE; 160 if (unturn_dead(mtmp)) wake = TRUE; 161 if (is_undead(mtmp->data)) { 162 reveal_invis = TRUE; 163 wake = TRUE; 164 dmg = rnd(8); 165 if(dbldam) dmg *= 2; 166 if (otyp == SPE_TURN_UNDEAD) 167 dmg += spell_damage_bonus(); 168 flags.bypasses = TRUE; /* for make_corpse() */ 169 if (!resist(mtmp, otmp->oclass, dmg, NOTELL)) { 170 if (mtmp->mhp > 0) monflee(mtmp, 0, FALSE, TRUE); 171 } 172 } 173 break; 174 case WAN_POLYMORPH: 175 case SPE_POLYMORPH: 176 case POT_POLYMORPH: 177 if (resists_magm(mtmp)) { 178 /* magic resistance protects from polymorph traps, so make 179 it guard against involuntary polymorph attacks too... */ 180 shieldeff(mtmp->mx, mtmp->my); 181 } else if (!resist(mtmp, otmp->oclass, 0, NOTELL)) { 182 /* natural shapechangers aren't affected by system shock 183 (unless protection from shapechangers is interfering 184 with their metabolism...) */ 185 if (mtmp->cham == CHAM_ORDINARY && !rn2(25)) { 186 if (canseemon(mtmp)) { 187 pline("%s shudders!", Monnam(mtmp)); 188 makeknown(otyp); 189 } 190 /* dropped inventory shouldn't be hit by this zap */ 191 for (obj = mtmp->minvent; obj; obj = obj->nobj) 192 bypass_obj(obj); 193 /* flags.bypasses = TRUE; ## for make_corpse() */ 194 /* no corpse after system shock */ 195 xkilled(mtmp, 3); 196 } else if (newcham(mtmp, (struct permonst *)0, 197 (otyp != POT_POLYMORPH), FALSE)) { 198 if (!Hallucination && canspotmon(mtmp)) 199 makeknown(otyp); 200 } 201 } 202 break; 203 case WAN_CANCELLATION: 204 case SPE_CANCELLATION: 205 (void) cancel_monst(mtmp, otmp, TRUE, TRUE, FALSE); 206 break; 207 case WAN_TELEPORTATION: 208 case SPE_TELEPORT_AWAY: 209 reveal_invis = !u_teleport_mon(mtmp, TRUE); 210 break; 211 case WAN_MAKE_INVISIBLE: 212 { 213 int oldinvis = mtmp->minvis; 214 char nambuf[BUFSZ]; 215 216 /* format monster's name before altering its visibility */ 217 Strcpy(nambuf, Monnam(mtmp)); 218 mon_set_minvis(mtmp); 219 if (!oldinvis && knowninvisible(mtmp)) { 220 pline("%s turns transparent!", nambuf); 221 makeknown(otyp); 222 } 223 break; 224 } 225 case WAN_NOTHING: 226 case WAN_LOCKING: 227 case SPE_WIZARD_LOCK: 228 wake = FALSE; 229 break; 230 case WAN_PROBING: 231 wake = FALSE; 232 reveal_invis = TRUE; 233 probe_monster(mtmp); 234 makeknown(otyp); 235 break; 236 case WAN_OPENING: 237 case SPE_KNOCK: 238 wake = FALSE; /* don't want immediate counterattack */ 239 if (u.uswallow && mtmp == u.ustuck) { 240 if (is_animal(mtmp->data)) { 241 if (Blind) You_feel("a sudden rush of air!"); 242 else pline("%s opens its mouth!", Monnam(mtmp)); 243 } 244 expels(mtmp, mtmp->data, TRUE); 245#ifdef STEED 246 } else if (!!(obj = which_armor(mtmp, W_SADDLE))) { 247 mtmp->misc_worn_check &= ~obj->owornmask; 248 update_mon_intrinsics(mtmp, obj, FALSE, FALSE); 249 obj->owornmask = 0L; 250 obj_extract_self(obj); 251 place_object(obj, mtmp->mx, mtmp->my); 252 /* call stackobj() if we ever drop anything that can merge */ 253 newsym(mtmp->mx, mtmp->my); 254#endif 255 } 256 break; 257 case SPE_HEALING: 258 case SPE_EXTRA_HEALING: 259 reveal_invis = TRUE; 260 if (mtmp->data != &mons[PM_PESTILENCE]) { 261 wake = FALSE; /* wakeup() makes the target angry */ 262 mtmp->mhp += d(6, otyp == SPE_EXTRA_HEALING ? 8 : 4); 263 if (mtmp->mhp > mtmp->mhpmax) 264 mtmp->mhp = mtmp->mhpmax; 265 if (mtmp->mblinded) { 266 mtmp->mblinded = 0; 267 mtmp->mcansee = 1; 268 } 269 if (canseemon(mtmp)) { 270 if (disguised_mimic) { 271 if (mtmp->m_ap_type == M_AP_OBJECT && 272 mtmp->mappearance == STRANGE_OBJECT) { 273 /* it can do better now */ 274 set_mimic_sym(mtmp); 275 newsym(mtmp->mx, mtmp->my); 276 } else 277 mimic_hit_msg(mtmp, otyp); 278 } else pline("%s looks%s better.", Monnam(mtmp), 279 otyp == SPE_EXTRA_HEALING ? " much" : "" ); 280 } 281 if (mtmp->mtame || mtmp->mpeaceful) { 282 adjalign(Role_if(PM_HEALER) ? 1 : sgn(u.ualign.type)); 283 } 284 } else { /* Pestilence */ 285 /* Pestilence will always resist; damage is half of 3d{4,8} */ 286 (void) resist(mtmp, otmp->oclass, 287 d(3, otyp == SPE_EXTRA_HEALING ? 8 : 4), TELL); 288 } 289 break; 290 case WAN_LIGHT: /* (broken wand) */ 291 if (flash_hits_mon(mtmp, otmp)) { 292 makeknown(WAN_LIGHT); 293 reveal_invis = TRUE; 294 } 295 break; 296 case WAN_SLEEP: /* (broken wand) */ 297 /* [wakeup() doesn't rouse victims of temporary sleep, 298 so it's okay to leave `wake' set to TRUE here] */ 299 reveal_invis = TRUE; 300 if (sleep_monst(mtmp, d(1 + otmp->spe, 12), WAND_CLASS)) 301 slept_monst(mtmp); 302 if (!Blind) makeknown(WAN_SLEEP); 303 break; 304 case SPE_STONE_TO_FLESH: 305 if (monsndx(mtmp->data) == PM_STONE_GOLEM) { 306 char *name = Monnam(mtmp); 307 /* turn into flesh golem */ 308 if (newcham(mtmp, &mons[PM_FLESH_GOLEM], FALSE, FALSE)) { 309 if (canseemon(mtmp)) 310 pline("%s turns to flesh!", name); 311 } else { 312 if (canseemon(mtmp)) 313 pline("%s looks rather fleshy for a moment.", 314 name); 315 } 316 } else 317 wake = FALSE; 318 break; 319 case SPE_DRAIN_LIFE: 320 dmg = rnd(8); 321 if(dbldam) dmg *= 2; 322 if (otyp == SPE_DRAIN_LIFE) 323 dmg += spell_damage_bonus(); 324 if (resists_drli(mtmp)) 325 shieldeff(mtmp->mx, mtmp->my); 326 else if (!resist(mtmp, otmp->oclass, dmg, NOTELL) && 327 mtmp->mhp > 0) { 328 mtmp->mhp -= dmg; 329 mtmp->mhpmax -= dmg; 330 if (mtmp->mhp <= 0 || mtmp->mhpmax <= 0 || mtmp->m_lev < 1) 331 xkilled(mtmp, 1); 332 else { 333 mtmp->m_lev--; 334 if (canseemon(mtmp)) 335 pline("%s suddenly seems weaker!", Monnam(mtmp)); 336 } 337 } 338 break; 339 default: 340 impossible("What an interesting effect (%d)", otyp); 341 break; 342 } 343 if(wake) { 344 if(mtmp->mhp > 0) { 345 wakeup(mtmp); 346 m_respond(mtmp); 347 if(mtmp->isshk && !*u.ushops) hot_pursuit(mtmp); 348 } else if(mtmp->m_ap_type) 349 seemimic(mtmp); /* might unblock if mimicing a boulder/door */ 350 } 351 /* note: bhitpos won't be set if swallowed, but that's okay since 352 * reveal_invis will be false. We can't use mtmp->mx, my since it 353 * might be an invisible worm hit on the tail. 354 */ 355 if (reveal_invis) { 356 if (mtmp->mhp > 0 && cansee(bhitpos.x, bhitpos.y) && 357 !canspotmon(mtmp)) 358 map_invisible(bhitpos.x, bhitpos.y); 359 } 360 return 0; 361} 362 363void 364probe_monster(mtmp) 365struct monst *mtmp; 366{ 367 struct obj *otmp; 368 369 mstatusline(mtmp); 370 if (notonhead) return; /* don't show minvent for long worm tail */ 371 372#ifndef GOLDOBJ 373 if (mtmp->minvent || mtmp->mgold) { 374#else 375 if (mtmp->minvent) { 376#endif 377 for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj) 378 otmp->dknown = 1; /* treat as "seen" */ 379 (void) display_minventory(mtmp, MINV_ALL, (char *)0); 380 } else { 381 pline("%s is not carrying anything.", noit_Monnam(mtmp)); 382 } 383} 384 385#endif /*OVLB*/ 386#ifdef OVL1 387 388/* 389 * Return the object's physical location. This only makes sense for 390 * objects that are currently on the level (i.e. migrating objects 391 * are nowhere). By default, only things that can be seen (in hero's 392 * inventory, monster's inventory, or on the ground) are reported. 393 * By adding BURIED_TOO and/or CONTAINED_TOO flags, you can also get 394 * the location of buried and contained objects. Note that if an 395 * object is carried by a monster, its reported position may change 396 * from turn to turn. This function returns FALSE if the position 397 * is not available or subject to the constraints above. 398 */ 399boolean 400get_obj_location(obj, xp, yp, locflags) 401struct obj *obj; 402xchar *xp, *yp; 403int locflags; 404{ 405 switch (obj->where) { 406 case OBJ_INVENT: 407 *xp = u.ux; 408 *yp = u.uy; 409 return TRUE; 410 case OBJ_FLOOR: 411 *xp = obj->ox; 412 *yp = obj->oy; 413 return TRUE; 414 case OBJ_MINVENT: 415 if (obj->ocarry->mx) { 416 *xp = obj->ocarry->mx; 417 *yp = obj->ocarry->my; 418 return TRUE; 419 } 420 break; /* !mx => migrating monster */ 421 case OBJ_BURIED: 422 if (locflags & BURIED_TOO) { 423 *xp = obj->ox; 424 *yp = obj->oy; 425 return TRUE; 426 } 427 break; 428 case OBJ_CONTAINED: 429 if (locflags & CONTAINED_TOO) 430 return get_obj_location(obj->ocontainer, xp, yp, locflags); 431 break; 432 } 433 *xp = *yp = 0; 434 return FALSE; 435} 436 437boolean 438get_mon_location(mon, xp, yp, locflags) 439struct monst *mon; 440xchar *xp, *yp; 441int locflags; /* non-zero means get location even if monster is buried */ 442{ 443 if (mon == &youmonst) { 444 *xp = u.ux; 445 *yp = u.uy; 446 return TRUE; 447 } else if (mon->mx > 0 && (!mon->mburied || locflags)) { 448 *xp = mon->mx; 449 *yp = mon->my; 450 return TRUE; 451 } else { /* migrating or buried */ 452 *xp = *yp = 0; 453 return FALSE; 454 } 455} 456 457/* used by revive() and animate_statue() */ 458struct monst * 459montraits(obj,cc) 460struct obj *obj; 461coord *cc; 462{ 463 struct monst *mtmp = (struct monst *)0; 464 struct monst *mtmp2 = (struct monst *)0; 465 466 if (obj->oxlth && (obj->oattached == OATTACHED_MONST)) 467 mtmp2 = get_mtraits(obj, TRUE); 468 if (mtmp2) { 469 /* save_mtraits() validated mtmp2->mnum */ 470 mtmp2->data = &mons[mtmp2->mnum]; 471 if (mtmp2->mhpmax <= 0 && !is_rider(mtmp2->data)) 472 return (struct monst *)0; 473 mtmp = makemon(mtmp2->data, 474 cc->x, cc->y, NO_MINVENT|MM_NOWAIT|MM_NOCOUNTBIRTH); 475 if (!mtmp) return mtmp; 476 477 /* heal the monster */ 478 if (mtmp->mhpmax > mtmp2->mhpmax && is_rider(mtmp2->data)) 479 mtmp2->mhpmax = mtmp->mhpmax; 480 mtmp2->mhp = mtmp2->mhpmax; 481 /* Get these ones from mtmp */ 482 mtmp2->minvent = mtmp->minvent; /*redundant*/ 483 /* monster ID is available if the monster died in the current 484 game, but should be zero if the corpse was in a bones level 485 (we cleared it when loading bones) */ 486 if (!mtmp2->m_id) 487 mtmp2->m_id = mtmp->m_id; 488 mtmp2->mx = mtmp->mx; 489 mtmp2->my = mtmp->my; 490 mtmp2->mux = mtmp->mux; 491 mtmp2->muy = mtmp->muy; 492 mtmp2->mw = mtmp->mw; 493 mtmp2->wormno = mtmp->wormno; 494 mtmp2->misc_worn_check = mtmp->misc_worn_check; 495 mtmp2->weapon_check = mtmp->weapon_check; 496 mtmp2->mtrapseen = mtmp->mtrapseen; 497 mtmp2->mflee = mtmp->mflee; 498 mtmp2->mburied = mtmp->mburied; 499 mtmp2->mundetected = mtmp->mundetected; 500 mtmp2->mfleetim = mtmp->mfleetim; 501 mtmp2->mlstmv = mtmp->mlstmv; 502 mtmp2->m_ap_type = mtmp->m_ap_type; 503 /* set these ones explicitly */ 504 mtmp2->mavenge = 0; 505 mtmp2->meating = 0; 506 mtmp2->mleashed = 0; 507 mtmp2->mtrapped = 0; 508 mtmp2->msleeping = 0; 509 mtmp2->mfrozen = 0; 510 mtmp2->mcanmove = 1; 511 /* most cancelled monsters return to normal, 512 but some need to stay cancelled */ 513 if (!dmgtype(mtmp2->data, AD_SEDU) 514#ifdef SEDUCE 515 && !dmgtype(mtmp2->data, AD_SSEX) 516#endif 517 ) mtmp2->mcan = 0; 518 mtmp2->mcansee = 1; /* set like in makemon */ 519 mtmp2->mblinded = 0; 520 mtmp2->mstun = 0; 521 mtmp2->mconf = 0; 522 replmon(mtmp,mtmp2); 523 } 524 return mtmp2; 525} 526 527/* 528 * get_container_location() returns the following information 529 * about the outermost container: 530 * loc argument gets set to: 531 * OBJ_INVENT if in hero's inventory; return 0. 532 * OBJ_FLOOR if on the floor; return 0. 533 * OBJ_BURIED if buried; return 0. 534 * OBJ_MINVENT if in monster's inventory; return monster. 535 * container_nesting is updated with the nesting depth of the containers 536 * if applicable. 537 */ 538struct monst * 539get_container_location(obj, loc, container_nesting) 540struct obj *obj; 541int *loc; 542int *container_nesting; 543{ 544 if (!obj || !loc) 545 return 0; 546 547 if (container_nesting) *container_nesting = 0; 548 while (obj && obj->where == OBJ_CONTAINED) { 549 if (container_nesting) *container_nesting += 1; 550 obj = obj->ocontainer; 551 } 552 if (obj) { 553 *loc = obj->where; /* outermost container's location */ 554 if (obj->where == OBJ_MINVENT) return obj->ocarry; 555 } 556 return (struct monst *)0; 557} 558 559/* 560 * Attempt to revive the given corpse, return the revived monster if 561 * successful. Note: this does NOT use up the corpse if it fails. 562 */ 563struct monst * 564revive(obj) 565register struct obj *obj; 566{ 567 register struct monst *mtmp = (struct monst *)0; 568 struct obj *container = (struct obj *)0; 569 int container_nesting = 0; 570 schar savetame = 0; 571 boolean recorporealization = FALSE; 572 boolean in_container = FALSE; 573 if(obj->otyp == CORPSE) { 574 int montype = obj->corpsenm; 575 xchar x, y; 576 577 if (obj->where == OBJ_CONTAINED) { 578 /* deal with corpses in [possibly nested] containers */ 579 struct monst *carrier; 580 int holder = 0; 581 582 container = obj->ocontainer; 583 carrier = get_container_location(container, &holder, 584 &container_nesting); 585 switch(holder) { 586 case OBJ_MINVENT: 587 x = carrier->mx; y = carrier->my; 588 in_container = TRUE; 589 break; 590 case OBJ_INVENT: 591 x = u.ux; y = u.uy; 592 in_container = TRUE; 593 break; 594 case OBJ_FLOOR: 595 if (!get_obj_location(obj, &x, &y, CONTAINED_TOO)) 596 return (struct monst *) 0; 597 in_container = TRUE; 598 break; 599 default: 600 return (struct monst *)0; 601 } 602 } else { 603 /* only for invent, minvent, or floor */ 604 if (!get_obj_location(obj, &x, &y, 0)) 605 return (struct monst *) 0; 606 } 607 if (in_container) { 608 /* Rules for revival from containers: 609 - the container cannot be locked 610 - the container cannot be heavily nested (>2 is arbitrary) 611 - the container cannot be a statue or bag of holding 612 (except in very rare cases for the latter) 613 */ 614 if (!x || !y || container->olocked || container_nesting > 2 || 615 container->otyp == STATUE || 616 (container->otyp == BAG_OF_HOLDING && rn2(40))) 617 return (struct monst *)0; 618 } 619 620 if (MON_AT(x,y)) { 621 coord new_xy; 622 623 if (enexto(&new_xy, x, y, &mons[montype])) 624 x = new_xy.x, y = new_xy.y; 625 } 626 627 if(cant_create(&montype, TRUE)) { 628 /* make a zombie or worm instead */ 629 mtmp = makemon(&mons[montype], x, y, 630 NO_MINVENT|MM_NOWAIT); 631 if (mtmp) { 632 mtmp->mhp = mtmp->mhpmax = 100; 633 mon_adjust_speed(mtmp, 2, (struct obj *)0); /* MFAST */ 634 } 635 } else { 636 if (obj->oxlth && (obj->oattached == OATTACHED_MONST)) { 637 coord xy; 638 xy.x = x; xy.y = y; 639 mtmp = montraits(obj, &xy); 640 if (mtmp && mtmp->mtame && !mtmp->isminion) 641 wary_dog(mtmp, TRUE); 642 } else 643 mtmp = makemon(&mons[montype], x, y, 644 NO_MINVENT|MM_NOWAIT|MM_NOCOUNTBIRTH); 645 if (mtmp) { 646 if (obj->oxlth && (obj->oattached == OATTACHED_M_ID)) { 647 unsigned m_id; 648 struct monst *ghost; 649 (void) memcpy((genericptr_t)&m_id, 650 (genericptr_t)obj->oextra, sizeof(m_id)); 651 ghost = find_mid(m_id, FM_FMON); 652 if (ghost && ghost->data == &mons[PM_GHOST]) { 653 int x2, y2; 654 x2 = ghost->mx; y2 = ghost->my; 655 if (ghost->mtame) 656 savetame = ghost->mtame; 657 if (canseemon(ghost)) 658 pline("%s is suddenly drawn into its former body!", 659 Monnam(ghost)); 660 mondead(ghost); 661 recorporealization = TRUE; 662 newsym(x2, y2); 663 } 664 /* don't mess with obj->oxlth here */ 665 obj->oattached = OATTACHED_NOTHING; 666 } 667 /* Monster retains its name */ 668 if (obj->onamelth) 669 mtmp = christen_monst(mtmp, ONAME(obj)); 670 /* flag the quest leader as alive. */ 671 if (mtmp->data->msound == MS_LEADER || mtmp->m_id == 672 quest_status.leader_m_id) 673 quest_status.leader_is_dead = FALSE; 674 } 675 } 676 if (mtmp) { 677 if (obj->oeaten) 678 mtmp->mhp = eaten_stat(mtmp->mhp, obj); 679 /* track that this monster was revived at least once */ 680 mtmp->mrevived = 1; 681 682 if (recorporealization) { 683 /* If mtmp is revivification of former tame ghost*/ 684 if (savetame) { 685 struct monst *mtmp2 = tamedog(mtmp, (struct obj *)0); 686 if (mtmp2) { 687 mtmp2->mtame = savetame; 688 mtmp = mtmp2; 689 } 690 } 691 /* was ghost, now alive, it's all very confusing */ 692 mtmp->mconf = 1; 693 } 694 695 switch (obj->where) { 696 case OBJ_INVENT: 697 useup(obj); 698 break; 699 case OBJ_FLOOR: 700 /* in case MON_AT+enexto for invisible mon */ 701 x = obj->ox, y = obj->oy; 702 /* not useupf(), which charges */ 703 if (obj->quan > 1L) 704 obj = splitobj(obj, 1L); 705 delobj(obj); 706 newsym(x, y); 707 break; 708 case OBJ_MINVENT: 709 m_useup(obj->ocarry, obj); 710 break; 711 case OBJ_CONTAINED: 712 obj_extract_self(obj); 713 obfree(obj, (struct obj *) 0); 714 break; 715 default: 716 panic("revive"); 717 } 718 } 719 } 720 return mtmp; 721} 722 723STATIC_OVL void 724revive_egg(obj) 725struct obj *obj; 726{ 727 /* 728 * Note: generic eggs with corpsenm set to NON_PM will never hatch. 729 */ 730 if (obj->otyp != EGG) return; 731 if (obj->corpsenm != NON_PM && !dead_species(obj->corpsenm, TRUE)) 732 attach_egg_hatch_timeout(obj); 733} 734 735/* try to revive all corpses and eggs carried by `mon' */ 736int 737unturn_dead(mon) 738struct monst *mon; 739{ 740 struct obj *otmp, *otmp2; 741 struct monst *mtmp2; 742 char owner[BUFSZ], corpse[BUFSZ]; 743 boolean youseeit; 744 int once = 0, res = 0; 745 746 youseeit = (mon == &youmonst) ? TRUE : canseemon(mon); 747 otmp2 = (mon == &youmonst) ? invent : mon->minvent; 748 749 while ((otmp = otmp2) != 0) { 750 otmp2 = otmp->nobj; 751 if (otmp->otyp == EGG) 752 revive_egg(otmp); 753 if (otmp->otyp != CORPSE) continue; 754 /* save the name; the object is liable to go away */ 755 if (youseeit) Strcpy(corpse, corpse_xname(otmp, TRUE)); 756 757 /* for a merged group, only one is revived; should this be fixed? */ 758 if ((mtmp2 = revive(otmp)) != 0) { 759 ++res; 760 if (youseeit) { 761 if (!once++) Strcpy(owner, 762 (mon == &youmonst) ? "Your" : 763 s_suffix(Monnam(mon))); 764 pline("%s %s suddenly comes alive!", owner, corpse); 765 } else if (canseemon(mtmp2)) 766 pline("%s suddenly appears!", Amonnam(mtmp2)); 767 } 768 } 769 return res; 770} 771#endif /*OVL1*/ 772 773#ifdef OVLB 774static const char charged_objs[] = { WAND_CLASS, WEAPON_CLASS, ARMOR_CLASS, 0 }; 775 776STATIC_OVL void 777costly_cancel(obj) 778register struct obj *obj; 779{ 780 char objroom; 781 struct monst *shkp = (struct monst *)0; 782 783 if (obj->no_charge) return; 784 785 switch (obj->where) { 786 case OBJ_INVENT: 787 if (obj->unpaid) { 788 shkp = shop_keeper(*u.ushops); 789 if (!shkp) return; 790 Norep("You cancel an unpaid object, you pay for it!"); 791 bill_dummy_object(obj); 792 } 793 break; 794 case OBJ_FLOOR: 795 objroom = *in_rooms(obj->ox, obj->oy, SHOPBASE); 796 shkp = shop_keeper(objroom); 797 if (!shkp || !inhishop(shkp)) return; 798 if (costly_spot(u.ux, u.uy) && objroom == *u.ushops) { 799 Norep("You cancel it, you pay for it!"); 800 bill_dummy_object(obj); 801 } else 802 (void) stolen_value(obj, obj->ox, obj->oy, FALSE, FALSE); 803 break; 804 } 805} 806 807/* cancel obj, possibly carried by you or a monster */ 808void 809cancel_item(obj) 810register struct obj *obj; 811{ 812 boolean u_ring = (obj == uleft) || (obj == uright); 813 register boolean holy = (obj->otyp == POT_WATER && obj->blessed); 814 815 switch(obj->otyp) { 816 case RIN_GAIN_STRENGTH: 817 if ((obj->owornmask & W_RING) && u_ring) { 818 ABON(A_STR) -= obj->spe; 819 flags.botl = 1; 820 } 821 break; 822 case RIN_GAIN_CONSTITUTION: 823 if ((obj->owornmask & W_RING) && u_ring) { 824 ABON(A_CON) -= obj->spe; 825 flags.botl = 1; 826 } 827 break; 828 case RIN_ADORNMENT: 829 if ((obj->owornmask & W_RING) && u_ring) { 830 ABON(A_CHA) -= obj->spe; 831 flags.botl = 1; 832 } 833 break; 834 case RIN_INCREASE_ACCURACY: 835 if ((obj->owornmask & W_RING) && u_ring) 836 u.uhitinc -= obj->spe; 837 break; 838 case RIN_INCREASE_DAMAGE: 839 if ((obj->owornmask & W_RING) && u_ring) 840 u.udaminc -= obj->spe; 841 break; 842 case GAUNTLETS_OF_DEXTERITY: 843 if ((obj->owornmask & W_ARMG) && (obj == uarmg)) { 844 ABON(A_DEX) -= obj->spe; 845 flags.botl = 1; 846 } 847 break; 848 case HELM_OF_BRILLIANCE: 849 if ((obj->owornmask & W_ARMH) && (obj == uarmh)) { 850 ABON(A_INT) -= obj->spe; 851 ABON(A_WIS) -= obj->spe; 852 flags.botl = 1; 853 } 854 break; 855 /* case RIN_PROTECTION: not needed */ 856 } 857 if (objects[obj->otyp].oc_magic 858 || (obj->spe && (obj->oclass == ARMOR_CLASS || 859 obj->oclass == WEAPON_CLASS || is_weptool(obj))) 860 || obj->otyp == POT_ACID || obj->otyp == POT_SICKNESS) { 861 if (obj->spe != ((obj->oclass == WAND_CLASS) ? -1 : 0) && 862 obj->otyp != WAN_CANCELLATION && 863 /* can't cancel cancellation */ 864 obj->otyp != MAGIC_LAMP && 865 obj->otyp != CANDELABRUM_OF_INVOCATION) { 866 costly_cancel(obj); 867 obj->spe = (obj->oclass == WAND_CLASS) ? -1 : 0; 868 } 869 switch (obj->oclass) { 870 case SCROLL_CLASS: 871 costly_cancel(obj); 872 obj->otyp = SCR_BLANK_PAPER; 873 obj->spe = 0; 874 break; 875 case SPBOOK_CLASS: 876 if (obj->otyp != SPE_CANCELLATION && 877 obj->otyp != SPE_BOOK_OF_THE_DEAD) { 878 costly_cancel(obj); 879 obj->otyp = SPE_BLANK_PAPER; 880 } 881 break; 882 case POTION_CLASS: 883 costly_cancel(obj); 884 if (obj->otyp == POT_SICKNESS || 885 obj->otyp == POT_SEE_INVISIBLE) { 886 /* sickness is "biologically contaminated" fruit juice; cancel it 887 * and it just becomes fruit juice... whereas see invisible 888 * tastes like "enchanted" fruit juice, it similarly cancels. 889 */ 890 obj->otyp = POT_FRUIT_JUICE; 891 } else { 892 obj->otyp = POT_WATER; 893 obj->odiluted = 0; /* same as any other water */ 894 } 895 break; 896 } 897 } 898 if (holy) costly_cancel(obj); 899 unbless(obj); 900 uncurse(obj); 901#ifdef INVISIBLE_OBJECTS 902 if (obj->oinvis) obj->oinvis = 0; 903#endif 904 return; 905} 906 907/* Remove a positive enchantment or charge from obj, 908 * possibly carried by you or a monster 909 */ 910boolean 911drain_item(obj) 912register struct obj *obj; 913{ 914 boolean u_ring; 915 916 /* Is this a charged/enchanted object? */ 917 if (!obj || (!objects[obj->otyp].oc_charged && 918 obj->oclass != WEAPON_CLASS && 919 obj->oclass != ARMOR_CLASS && !is_weptool(obj)) || 920 obj->spe <= 0) 921 return (FALSE); 922 if (obj_resists(obj, 10, 90)) 923 return (FALSE); 924 925 /* Charge for the cost of the object */ 926 costly_cancel(obj); /* The term "cancel" is okay for now */ 927 928 /* Drain the object and any implied effects */ 929 obj->spe--; 930 u_ring = (obj == uleft) || (obj == uright); 931 switch(obj->otyp) { 932 case RIN_GAIN_STRENGTH: 933 if ((obj->owornmask & W_RING) && u_ring) { 934 ABON(A_STR)--; 935 flags.botl = 1; 936 } 937 break; 938 case RIN_GAIN_CONSTITUTION: 939 if ((obj->owornmask & W_RING) && u_ring) { 940 ABON(A_CON)--; 941 flags.botl = 1; 942 } 943 break; 944 case RIN_ADORNMENT: 945 if ((obj->owornmask & W_RING) && u_ring) { 946 ABON(A_CHA)--; 947 flags.botl = 1; 948 } 949 break; 950 case RIN_INCREASE_ACCURACY: 951 if ((obj->owornmask & W_RING) && u_ring) 952 u.uhitinc--; 953 break; 954 case RIN_INCREASE_DAMAGE: 955 if ((obj->owornmask & W_RING) && u_ring) 956 u.udaminc--; 957 break; 958 case HELM_OF_BRILLIANCE: 959 if ((obj->owornmask & W_ARMH) && (obj == uarmh)) { 960 ABON(A_INT)--; 961 ABON(A_WIS)--; 962 flags.botl = 1; 963 } 964 break; 965 case GAUNTLETS_OF_DEXTERITY: 966 if ((obj->owornmask & W_ARMG) && (obj == uarmg)) { 967 ABON(A_DEX)--; 968 flags.botl = 1; 969 } 970 break; 971 case RIN_PROTECTION: 972 flags.botl = 1; 973 break; 974 } 975 if (carried(obj)) update_inventory(); 976 return (TRUE); 977} 978 979#endif /*OVLB*/ 980#ifdef OVL0 981 982boolean 983obj_resists(obj, ochance, achance) 984struct obj *obj; 985int ochance, achance; /* percent chance for ordinary objects, artifacts */ 986{ 987 if (obj->otyp == AMULET_OF_YENDOR || 988 obj->otyp == SPE_BOOK_OF_THE_DEAD || 989 obj->otyp == CANDELABRUM_OF_INVOCATION || 990 obj->otyp == BELL_OF_OPENING || 991 (obj->otyp == CORPSE && is_rider(&mons[obj->corpsenm]))) { 992 return TRUE; 993 } else { 994 int chance = rn2(100); 995 996 return((boolean)(chance < (obj->oartifact ? achance : ochance))); 997 } 998} 999 1000boolean 1001obj_shudders(obj) 1002struct obj *obj; 1003{ 1004 int zap_odds; 1005 1006 if (obj->oclass == WAND_CLASS) 1007 zap_odds = 3; /* half-life = 2 zaps */ 1008 else if (obj->cursed) 1009 zap_odds = 3; /* half-life = 2 zaps */ 1010 else if (obj->blessed) 1011 zap_odds = 12; /* half-life = 8 zaps */ 1012 else 1013 zap_odds = 8; /* half-life = 6 zaps */ 1014 1015 /* adjust for "large" quantities of identical things */ 1016 if(obj->quan > 4L) zap_odds /= 2; 1017 1018 return((boolean)(! rn2(zap_odds))); 1019} 1020#endif /*OVL0*/ 1021#ifdef OVLB 1022 1023/* Use up at least minwt number of things made of material mat. 1024 * There's also a chance that other stuff will be used up. Finally, 1025 * there's a random factor here to keep from always using the stuff 1026 * at the top of the pile. 1027 */ 1028STATIC_OVL void 1029polyuse(objhdr, mat, minwt) 1030 struct obj *objhdr; 1031 int mat, minwt; 1032{ 1033 register struct obj *otmp, *otmp2; 1034 1035 for(otmp = objhdr; minwt > 0 && otmp; otmp = otmp2) { 1036 otmp2 = otmp->nexthere; 1037 if (otmp == uball || otmp == uchain) continue; 1038 if (obj_resists(otmp, 0, 0)) continue; /* preserve unique objects */ 1039#ifdef MAIL 1040 if (otmp->otyp == SCR_MAIL) continue; 1041#endif 1042 1043 if (((int) objects[otmp->otyp].oc_material == mat) == 1044 (rn2(minwt + 1) != 0)) { 1045 /* appropriately add damage to bill */ 1046 if (costly_spot(otmp->ox, otmp->oy)) { 1047 if (*u.ushops) 1048 addtobill(otmp, FALSE, FALSE, FALSE); 1049 else 1050 (void)stolen_value(otmp, 1051 otmp->ox, otmp->oy, FALSE, FALSE); 1052 } 1053 if (otmp->quan < LARGEST_INT) 1054 minwt -= (int)otmp->quan; 1055 else 1056 minwt = 0; 1057 delobj(otmp); 1058 } 1059 } 1060} 1061 1062/* 1063 * Polymorph some of the stuff in this pile into a monster, preferably 1064 * a golem of the kind okind. 1065 */ 1066STATIC_OVL void 1067create_polymon(obj, okind) 1068 struct obj *obj; 1069 int okind; 1070{ 1071 struct permonst *mdat = (struct permonst *)0; 1072 struct monst *mtmp; 1073 const char *material; 1074 int pm_index; 1075 1076 /* no golems if you zap only one object -- not enough stuff */ 1077 if(!obj || (!obj->nexthere && obj->quan == 1L)) return; 1078 1079 /* some of these choices are arbitrary */ 1080 switch(okind) { 1081 case IRON: 1082 case METAL: 1083 case MITHRIL: 1084 pm_index = PM_IRON_GOLEM; 1085 material = "metal "; 1086 break; 1087 case COPPER: 1088 case SILVER: 1089 case PLATINUM: 1090 case GEMSTONE: 1091 case MINERAL: 1092 pm_index = rn2(2) ? PM_STONE_GOLEM : PM_CLAY_GOLEM; 1093 material = "lithic "; 1094 break; 1095 case 0: 1096 case FLESH: 1097 /* there is no flesh type, but all food is type 0, so we use it */ 1098 pm_index = PM_FLESH_GOLEM; 1099 material = "organic "; 1100 break; 1101 case WOOD: 1102 pm_index = PM_WOOD_GOLEM; 1103 material = "wood "; 1104 break; 1105 case LEATHER: 1106 pm_index = PM_LEATHER_GOLEM; 1107 material = "leather "; 1108 break; 1109 case CLOTH: 1110 pm_index = PM_ROPE_GOLEM; 1111 material = "cloth "; 1112 break; 1113 case BONE: 1114 pm_index = PM_SKELETON; /* nearest thing to "bone golem" */ 1115 material = "bony "; 1116 break; 1117 case GOLD: 1118 pm_index = PM_GOLD_GOLEM; 1119 material = "gold "; 1120 break; 1121 case GLASS: 1122 pm_index = PM_GLASS_GOLEM; 1123 material = "glassy "; 1124 break; 1125 case PAPER: 1126 pm_index = PM_PAPER_GOLEM; 1127 material = "paper "; 1128 break; 1129 default: 1130 /* if all else fails... */ 1131 pm_index = PM_STRAW_GOLEM; 1132 material = ""; 1133 break; 1134 } 1135 1136 if (!(mvitals[pm_index].mvflags & G_GENOD)) 1137 mdat = &mons[pm_index]; 1138 1139 mtmp = makemon(mdat, obj->ox, obj->oy, NO_MM_FLAGS); 1140 polyuse(obj, okind, (int)mons[pm_index].cwt); 1141 1142 if(mtmp && cansee(mtmp->mx, mtmp->my)) { 1143 pline("Some %sobjects meld, and %s arises from the pile!", 1144 material, a_monnam(mtmp)); 1145 } 1146} 1147 1148/* Assumes obj is on the floor. */ 1149void 1150do_osshock(obj) 1151struct obj *obj; 1152{ 1153 long i; 1154 1155#ifdef MAIL 1156 if (obj->otyp == SCR_MAIL) return; 1157#endif 1158 obj_zapped = TRUE; 1159 1160 if(poly_zapped < 0) { 1161 /* some may metamorphosize */ 1162 for (i = obj->quan; i; i--) 1163 if (! rn2(Luck + 45)) { 1164 poly_zapped = objects[obj->otyp].oc_material; 1165 break; 1166 } 1167 } 1168 1169 /* if quan > 1 then some will survive intact */ 1170 if (obj->quan > 1L) { 1171 if (obj->quan > LARGEST_INT) 1172 obj = splitobj(obj, (long)rnd(30000)); 1173 else 1174 obj = splitobj(obj, (long)rnd((int)obj->quan - 1)); 1175 } 1176 1177 /* appropriately add damage to bill */ 1178 if (costly_spot(obj->ox, obj->oy)) { 1179 if (*u.ushops) 1180 addtobill(obj, FALSE, FALSE, FALSE); 1181 else 1182 (void)stolen_value(obj, 1183 obj->ox, obj->oy, FALSE, FALSE); 1184 } 1185 1186 /* zap the object */ 1187 delobj(obj); 1188} 1189 1190/* 1191 * Polymorph the object to the given object ID. If the ID is STRANGE_OBJECT 1192 * then pick random object from the source's class (this is the standard 1193 * "polymorph" case). If ID is set to a specific object, inhibit fusing 1194 * n objects into 1. This could have been added as a flag, but currently 1195 * it is tied to not being the standard polymorph case. The new polymorphed 1196 * object replaces obj in its link chains. Return value is a pointer to 1197 * the new object. 1198 * 1199 * This should be safe to call for an object anywhere. 1200 */ 1201struct obj * 1202poly_obj(obj, id) 1203 struct obj *obj; 1204 int id; 1205{ 1206 struct obj *otmp; 1207 xchar ox, oy; 1208 boolean can_merge = (id == STRANGE_OBJECT); 1209 int obj_location = obj->where; 1210 1211 if (obj->otyp == BOULDER && In_sokoban(&u.uz)) 1212 change_luck(-1); /* Sokoban guilt */ 1213 if (id == STRANGE_OBJECT) { /* preserve symbol */ 1214 int try_limit = 3; 1215 /* Try up to 3 times to make the magic-or-not status of 1216 the new item be the same as it was for the old one. */ 1217 otmp = (struct obj *)0; 1218 do { 1219 if (otmp) delobj(otmp); 1220 otmp = mkobj(obj->oclass, FALSE); 1221 } while (--try_limit > 0 && 1222 objects[obj->otyp].oc_magic != objects[otmp->otyp].oc_magic); 1223 } else { 1224 /* literally replace obj with this new thing */ 1225 otmp = mksobj(id, FALSE, FALSE); 1226 /* Actually more things use corpsenm but they polymorph differently */ 1227#define USES_CORPSENM(typ) ((typ)==CORPSE || (typ)==STATUE || (typ)==FIGURINE) 1228 if (USES_CORPSENM(obj->otyp) && USES_CORPSENM(id)) 1229 otmp->corpsenm = obj->corpsenm; 1230#undef USES_CORPSENM 1231 } 1232 1233 /* preserve quantity */ 1234 otmp->quan = obj->quan; 1235 /* preserve the shopkeepers (lack of) interest */ 1236 otmp->no_charge = obj->no_charge; 1237 /* preserve inventory letter if in inventory */ 1238 if (obj_location == OBJ_INVENT) 1239 otmp->invlet = obj->invlet; 1240#ifdef MAIL 1241 /* You can't send yourself 100 mail messages and then 1242 * polymorph them into useful scrolls 1243 */ 1244 if (obj->otyp == SCR_MAIL) { 1245 otmp->otyp = SCR_MAIL; 1246 otmp->spe = 1; 1247 } 1248#endif 1249 1250 /* avoid abusing eggs laid by you */ 1251 if (obj->otyp == EGG && obj->spe) { 1252 int mnum, tryct = 100; 1253 1254 /* first, turn into a generic egg */ 1255 if (otmp->otyp == EGG) 1256 kill_egg(otmp); 1257 else { 1258 otmp->otyp = EGG; 1259 otmp->owt = weight(otmp); 1260 } 1261 otmp->corpsenm = NON_PM; 1262 otmp->spe = 0; 1263 1264 /* now change it into something layed by the hero */ 1265 while (tryct--) { 1266 mnum = can_be_hatched(random_monster()); 1267 if (mnum != NON_PM && !dead_species(mnum, TRUE)) { 1268 otmp->spe = 1; /* layed by hero */ 1269 otmp->corpsenm = mnum; 1270 attach_egg_hatch_timeout(otmp); 1271 break; 1272 } 1273 } 1274 } 1275 1276 /* keep special fields (including charges on wands) */ 1277 if (index(charged_objs, otmp->oclass)) otmp->spe = obj->spe; 1278 otmp->recharged = obj->recharged; 1279 1280 otmp->cursed = obj->cursed; 1281 otmp->blessed = obj->blessed; 1282 otmp->oeroded = obj->oeroded; 1283 otmp->oeroded2 = obj->oeroded2; 1284 if (!is_flammable(otmp) && !is_rustprone(otmp)) otmp->oeroded = 0; 1285 if (!is_corrodeable(otmp) && !is_rottable(otmp)) otmp->oeroded2 = 0; 1286 if (is_damageable(otmp)) 1287 otmp->oerodeproof = obj->oerodeproof; 1288 1289 /* Keep chest/box traps and poisoned ammo if we may */ 1290 if (obj->otrapped && Is_box(otmp)) otmp->otrapped = TRUE; 1291 1292 if (obj->opoisoned && is_poisonable(otmp)) 1293 otmp->opoisoned = TRUE; 1294 1295 if (id == STRANGE_OBJECT && obj->otyp == CORPSE) { 1296 /* turn crocodile corpses into shoes */ 1297 if (obj->corpsenm == PM_CROCODILE) { 1298 otmp->otyp = LOW_BOOTS; 1299 otmp->oclass = ARMOR_CLASS; 1300 otmp->spe = 0; 1301 otmp->oeroded = 0; 1302 otmp->oerodeproof = TRUE; 1303 otmp->quan = 1L; 1304 otmp->cursed = FALSE; 1305 } 1306 } 1307 1308 /* no box contents --KAA */ 1309 if (Has_contents(otmp)) delete_contents(otmp); 1310 1311 /* 'n' merged objects may be fused into 1 object */ 1312 if (otmp->quan > 1L && (!objects[otmp->otyp].oc_merge || 1313 (can_merge && otmp->quan > (long)rn2(1000)))) 1314 otmp->quan = 1L; 1315 1316 switch (otmp->oclass) { 1317 1318 case TOOL_CLASS: 1319 if (otmp->otyp == MAGIC_LAMP) { 1320 otmp->otyp = OIL_LAMP; 1321 otmp->age = 1500L; /* "best" oil lamp possible */ 1322 } else if (otmp->otyp == MAGIC_MARKER) { 1323 otmp->recharged = 1; /* degraded quality */ 1324 } 1325 /* don't care about the recharge count of other tools */ 1326 break; 1327 1328 case WAND_CLASS: 1329 while (otmp->otyp == WAN_WISHING || otmp->otyp == WAN_POLYMORPH) 1330 otmp->otyp = rnd_class(WAN_LIGHT, WAN_LIGHTNING); 1331 /* altering the object tends to degrade its quality 1332 (analogous to spellbook `read count' handling) */ 1333 if ((int)otmp->recharged < rn2(7)) /* recharge_limit */ 1334 otmp->recharged++; 1335 break; 1336 1337 case POTION_CLASS: 1338 while (otmp->otyp == POT_POLYMORPH) 1339 otmp->otyp = rnd_class(POT_GAIN_ABILITY, POT_WATER); 1340 break; 1341 1342 case SPBOOK_CLASS: 1343 while (otmp->otyp == SPE_POLYMORPH) 1344 otmp->otyp = rnd_class(SPE_DIG, SPE_BLANK_PAPER); 1345 /* reduce spellbook abuse */ 1346 otmp->spestudied = obj->spestudied + 1; 1347 break; 1348 1349 case GEM_CLASS: 1350 if (otmp->quan > (long) rnd(4) && 1351 objects[obj->otyp].oc_material == MINERAL && 1352 objects[otmp->otyp].oc_material != MINERAL) { 1353 otmp->otyp = ROCK; /* transmutation backfired */ 1354 otmp->quan /= 2L; /* some material has been lost */ 1355 } 1356 break; 1357 } 1358 1359 /* update the weight */ 1360 otmp->owt = weight(otmp); 1361 1362 /* for now, take off worn items being polymorphed */ 1363 if (obj_location == OBJ_INVENT) { 1364 if (id == STRANGE_OBJECT) 1365 remove_worn_item(obj, TRUE); 1366 else { 1367 /* This is called only for stone to flesh. It's a lot simpler 1368 * than it otherwise might be. We don't need to check for 1369 * special effects when putting them on (no meat objects have 1370 * any) and only three worn masks are possible. 1371 */ 1372 otmp->owornmask = obj->owornmask; 1373 remove_worn_item(obj, TRUE); 1374 setworn(otmp, otmp->owornmask); 1375 if (otmp->owornmask & LEFT_RING) 1376 uleft = otmp; 1377 if (otmp->owornmask & RIGHT_RING) 1378 uright = otmp; 1379 if (otmp->owornmask & W_WEP) 1380 uwep = otmp; 1381 if (otmp->owornmask & W_SWAPWEP) 1382 uswapwep = otmp; 1383 if (otmp->owornmask & W_QUIVER) 1384 uquiver = otmp; 1385 goto no_unwear; 1386 } 1387 } 1388 1389 /* preserve the mask in case being used by something else */ 1390 otmp->owornmask = obj->owornmask; 1391no_unwear: 1392 1393 if (obj_location == OBJ_FLOOR && obj->otyp == BOULDER && 1394 otmp->otyp != BOULDER) 1395 unblock_point(obj->ox, obj->oy); 1396 1397 /* ** we are now done adjusting the object ** */ 1398 1399 1400 /* swap otmp for obj */ 1401 replace_object(obj, otmp); 1402 if (obj_location == OBJ_INVENT) { 1403 /* 1404 * We may need to do extra adjustments for the hero if we're 1405 * messing with the hero's inventory. The following calls are 1406 * equivalent to calling freeinv on obj and addinv on otmp, 1407 * while doing an in-place swap of the actual objects. 1408 */ 1409 freeinv_core(obj); 1410 addinv_core1(otmp); 1411 addinv_core2(otmp); 1412 } 1413 1414 if ((!carried(otmp) || obj->unpaid) && 1415 get_obj_location(otmp, &ox, &oy, BURIED_TOO|CONTAINED_TOO) && 1416 costly_spot(ox, oy)) { 1417 register struct monst *shkp = 1418 shop_keeper(*in_rooms(ox, oy, SHOPBASE)); 1419 1420 if ((!obj->no_charge || 1421 (Has_contents(obj) && 1422 (contained_cost(obj, shkp, 0L, FALSE, FALSE) != 0L))) 1423 && inhishop(shkp)) { 1424 if(shkp->mpeaceful) { 1425 if(*u.ushops && *in_rooms(u.ux, u.uy, 0) == 1426 *in_rooms(shkp->mx, shkp->my, 0) && 1427 !costly_spot(u.ux, u.uy)) 1428 make_angry_shk(shkp, ox, oy); 1429 else { 1430 pline("%s gets angry!", Monnam(shkp)); 1431 hot_pursuit(shkp); 1432 } 1433 } else Norep("%s is furious!", Monnam(shkp)); 1434 } 1435 } 1436 delobj(obj); 1437 return otmp; 1438} 1439 1440/* 1441 * Object obj was hit by the effect of the wand/spell otmp. Return 1442 * non-zero if the wand/spell had any effect. 1443 */ 1444int 1445bhito(obj, otmp) 1446struct obj *obj, *otmp; 1447{ 1448 int res = 1; /* affected object by default */ 1449 xchar refresh_x, refresh_y; 1450 1451 if (obj->bypass) { 1452 /* The bypass bit is currently only used as follows: 1453 * 1454 * POLYMORPH - When a monster being polymorphed drops something 1455 * from its inventory as a result of the change. 1456 * If the items fall to the floor, they are not 1457 * subject to direct subsequent polymorphing 1458 * themselves on that same zap. This makes it 1459 * consistent with items that remain in the 1460 * monster's inventory. They are not polymorphed 1461 * either. 1462 * UNDEAD_TURNING - When an undead creature gets killed via 1463 * undead turning, prevent its corpse from being 1464 * immediately revived by the same effect. 1465 * 1466 * The bypass bit on all objects is reset each turn, whenever 1467 * flags.bypasses is set. 1468 * 1469 * We check the obj->bypass bit above AND flags.bypasses 1470 * as a safeguard against any stray occurrence left in an obj 1471 * struct someplace, although that should never happen. 1472 */ 1473 if (flags.bypasses) 1474 return 0; 1475 else { 1476#ifdef NETHACK_DEBUG 1477 pline("%s for a moment.", Tobjnam(obj, "pulsate")); 1478#endif 1479 obj->bypass = 0; 1480 } 1481 } 1482 1483 /* 1484 * Some parts of this function expect the object to be on the floor 1485 * obj->{ox,oy} to be valid. The exception to this (so far) is 1486 * for the STONE_TO_FLESH spell. 1487 */ 1488 if (!(obj->where == OBJ_FLOOR || otmp->otyp == SPE_STONE_TO_FLESH)) 1489 impossible("bhito: obj is not floor or Stone To Flesh spell"); 1490 1491 if (obj == uball) { 1492 res = 0; 1493 } else if (obj == uchain) { 1494 if (otmp->otyp == WAN_OPENING || otmp->otyp == SPE_KNOCK) { 1495 unpunish(); 1496 makeknown(otmp->otyp); 1497 } else 1498 res = 0; 1499 } else 1500 switch(otmp->otyp) { 1501 case WAN_POLYMORPH: 1502 case SPE_POLYMORPH: 1503 if (obj->otyp == WAN_POLYMORPH || 1504 obj->otyp == SPE_POLYMORPH || 1505 obj->otyp == POT_POLYMORPH || 1506 obj_resists(obj, 5, 95)) { 1507 res = 0; 1508 break; 1509 } 1510 /* KMH, conduct */ 1511 u.uconduct.polypiles++; 1512 /* any saved lock context will be dangerously obsolete */ 1513 if (Is_box(obj)) (void) boxlock(obj, otmp); 1514 1515 if (obj_shudders(obj)) { 1516 if (cansee(obj->ox, obj->oy)) 1517 makeknown(otmp->otyp); 1518 do_osshock(obj); 1519 break; 1520 } 1521 obj = poly_obj(obj, STRANGE_OBJECT); 1522 newsym(obj->ox,obj->oy); 1523 break; 1524 case WAN_PROBING: 1525 res = !obj->dknown; 1526 /* target object has now been "seen (up close)" */ 1527 obj->dknown = 1; 1528 if (Is_container(obj) || obj->otyp == STATUE) { 1529 if (!obj->cobj) 1530 pline("%s empty.", Tobjnam(obj, "are")); 1531 else { 1532 struct obj *o; 1533 /* view contents (not recursively) */ 1534 for (o = obj->cobj; o; o = o->nobj) 1535 o->dknown = 1; /* "seen", even if blind */ 1536 (void) display_cinventory(obj); 1537 } 1538 res = 1; 1539 } 1540 if (res) makeknown(WAN_PROBING); 1541 break; 1542 case WAN_STRIKING: 1543 case SPE_FORCE_BOLT: 1544 if (obj->otyp == BOULDER) 1545 fracture_rock(obj); 1546 else if (obj->otyp == STATUE) 1547 (void) break_statue(obj); 1548 else { 1549 if (!flags.mon_moving) 1550 (void)hero_breaks(obj, obj->ox, obj->oy, FALSE); 1551 else 1552 (void)breaks(obj, obj->ox, obj->oy); 1553 res = 0; 1554 } 1555 /* BUG[?]: shouldn't this depend upon you seeing it happen? */ 1556 makeknown(otmp->otyp); 1557 break; 1558 case WAN_CANCELLATION: 1559 case SPE_CANCELLATION: 1560 cancel_item(obj); 1561#ifdef TEXTCOLOR 1562 newsym(obj->ox,obj->oy); /* might change color */ 1563#endif 1564 break; 1565 case SPE_DRAIN_LIFE: 1566 (void) drain_item(obj); 1567 break; 1568 case WAN_TELEPORTATION: 1569 case SPE_TELEPORT_AWAY: 1570 rloco(obj); 1571 break; 1572 case WAN_MAKE_INVISIBLE: 1573#ifdef INVISIBLE_OBJECTS 1574 obj->oinvis = TRUE; 1575 newsym(obj->ox,obj->oy); /* make object disappear */ 1576#endif 1577 break; 1578 case WAN_UNDEAD_TURNING: 1579 case SPE_TURN_UNDEAD: 1580 if (obj->otyp == EGG) 1581 revive_egg(obj); 1582 else 1583 res = !!revive(obj); 1584 break; 1585 case WAN_OPENING: 1586 case SPE_KNOCK: 1587 case WAN_LOCKING: 1588 case SPE_WIZARD_LOCK: 1589 if(Is_box(obj)) 1590 res = boxlock(obj, otmp); 1591 else 1592 res = 0; 1593 if (res /* && otmp->oclass == WAND_CLASS */) 1594 makeknown(otmp->otyp); 1595 break; 1596 case WAN_SLOW_MONSTER: /* no effect on objects */ 1597 case SPE_SLOW_MONSTER: 1598 case WAN_SPEED_MONSTER: 1599 case WAN_NOTHING: 1600 case SPE_HEALING: 1601 case SPE_EXTRA_HEALING: 1602 res = 0; 1603 break; 1604 case SPE_STONE_TO_FLESH: 1605 refresh_x = obj->ox; refresh_y = obj->oy; 1606 if (objects[obj->otyp].oc_material != MINERAL && 1607 objects[obj->otyp].oc_material != GEMSTONE) { 1608 res = 0; 1609 break; 1610 } 1611 /* add more if stone objects are added.. */ 1612 switch (objects[obj->otyp].oc_class) { 1613 case ROCK_CLASS: /* boulders and statues */ 1614 if (obj->otyp == BOULDER) { 1615 obj = poly_obj(obj, HUGE_CHUNK_OF_MEAT); 1616 goto smell; 1617 } else if (obj->otyp == STATUE) { 1618 xchar oox, ooy; 1619 1620 (void) get_obj_location(obj, &oox, &ooy, 0); 1621 refresh_x = oox; refresh_y = ooy; 1622 if (vegetarian(&mons[obj->corpsenm])) { 1623 /* Don't animate monsters that aren't flesh */ 1624 obj = poly_obj(obj, MEATBALL); 1625 goto smell; 1626 } 1627 if (!animate_statue(obj, oox, ooy, 1628 ANIMATE_SPELL, (int *)0)) { 1629 struct obj *item; 1630makecorpse: if (mons[obj->corpsenm].geno & 1631 (G_NOCORPSE|G_UNIQ)) { 1632 res = 0; 1633 break; 1634 } 1635 /* Unlikely to get here since genociding 1636 * monsters also sets the G_NOCORPSE flag. 1637 * Drop the contents, poly_obj looses them. 1638 */ 1639 while ((item = obj->cobj) != 0) { 1640 obj_extract_self(item); 1641 place_object(item, oox, ooy); 1642 } 1643 obj = poly_obj(obj, CORPSE); 1644 break; 1645 } 1646 } else { /* new rock class object... */ 1647 /* impossible? */ 1648 res = 0; 1649 } 1650 break; 1651 case TOOL_CLASS: /* figurine */ 1652 { 1653 struct monst *mon; 1654 xchar oox, ooy; 1655 1656 if (obj->otyp != FIGURINE) { 1657 res = 0; 1658 break; 1659 } 1660 if (vegetarian(&mons[obj->corpsenm])) { 1661 /* Don't animate monsters that aren't flesh */ 1662 obj = poly_obj(obj, MEATBALL); 1663 goto smell; 1664 } 1665 (void) get_obj_location(obj, &oox, &ooy, 0); 1666 refresh_x = oox; refresh_y = ooy; 1667 mon = makemon(&mons[obj->corpsenm], 1668 oox, ooy, NO_MM_FLAGS); 1669 if (mon) { 1670 delobj(obj); 1671 if (cansee(mon->mx, mon->my)) 1672 pline_The("figurine animates!"); 1673 break; 1674 } 1675 goto makecorpse; 1676 } 1677 /* maybe add weird things to become? */ 1678 case RING_CLASS: /* some of the rings are stone */ 1679 obj = poly_obj(obj, MEAT_RING); 1680 goto smell; 1681 case WAND_CLASS: /* marble wand */ 1682 obj = poly_obj(obj, MEAT_STICK); 1683 goto smell; 1684 case GEM_CLASS: /* rocks & gems */ 1685 obj = poly_obj(obj, MEATBALL); 1686smell: 1687 if (herbivorous(youmonst.data) && 1688 (!carnivorous(youmonst.data) || 1689 Role_if(PM_MONK) || !u.uconduct.unvegetarian)) 1690 Norep("You smell the odor of meat."); 1691 else 1692 Norep("You smell a delicious smell."); 1693 break; 1694 case WEAPON_CLASS: /* crysknife */ 1695 /* fall through */ 1696 default: 1697 res = 0; 1698 break; 1699 } 1700 newsym(refresh_x, refresh_y); 1701 break; 1702 default: 1703 impossible("What an interesting effect (%d)", otmp->otyp); 1704 break; 1705 } 1706 return res; 1707} 1708 1709/* returns nonzero if something was hit */ 1710int 1711bhitpile(obj,fhito,tx,ty) 1712 struct obj *obj; 1713 int FDECL((*fhito), (OBJ_P,OBJ_P)); 1714 int tx, ty; 1715{ 1716 int hitanything = 0; 1717 register struct obj *otmp, *next_obj; 1718 1719 if (obj->otyp == SPE_FORCE_BOLT || obj->otyp == WAN_STRIKING) { 1720 struct trap *t = t_at(tx, ty); 1721 1722 /* We can't settle for the default calling sequence of 1723 bhito(otmp) -> break_statue(otmp) -> activate_statue_trap(ox,oy) 1724 because that last call might end up operating on our `next_obj' 1725 (below), rather than on the current object, if it happens to 1726 encounter a statue which mustn't become animated. */ 1727 if (t && t->ttyp == STATUE_TRAP && 1728 activate_statue_trap(t, tx, ty, TRUE) && obj->otyp == WAN_STRIKING) 1729 makeknown(obj->otyp); 1730 } 1731 1732 poly_zapped = -1; 1733 for(otmp = level.objects[tx][ty]; otmp; otmp = next_obj) { 1734 /* Fix for polymorph bug, Tim Wright */ 1735 next_obj = otmp->nexthere; 1736 hitanything += (*fhito)(otmp, obj); 1737 } 1738 if(poly_zapped >= 0) 1739 create_polymon(level.objects[tx][ty], poly_zapped); 1740 1741 return hitanything; 1742} 1743#endif /*OVLB*/ 1744#ifdef OVL1 1745 1746/* 1747 * zappable - returns 1 if zap is available, 0 otherwise. 1748 * it removes a charge from the wand if zappable. 1749 * added by GAN 11/03/86 1750 */ 1751int 1752zappable(wand) 1753register struct obj *wand; 1754{ 1755 if(wand->spe < 0 || (wand->spe == 0 && rn2(121))) 1756 return 0; 1757 if(wand->spe == 0) 1758 You("wrest one last charge from the worn-out wand."); 1759 wand->spe--; 1760 return 1; 1761} 1762 1763/* 1764 * zapnodir - zaps a NODIR wand/spell. 1765 * added by GAN 11/03/86 1766 */ 1767void 1768zapnodir(obj) 1769register struct obj *obj; 1770{ 1771 boolean known = FALSE; 1772 1773 switch(obj->otyp) { 1774 case WAN_LIGHT: 1775 case SPE_LIGHT: 1776 litroom(TRUE,obj); 1777 if (!Blind) known = TRUE; 1778 break; 1779 case WAN_SECRET_DOOR_DETECTION: 1780 case SPE_DETECT_UNSEEN: 1781 if(!findit()) return; 1782 if (!Blind) known = TRUE; 1783 break; 1784 case WAN_CREATE_MONSTER: 1785 known = create_critters(rn2(23) ? 1 : rn1(7,2), 1786 (struct permonst *)0); 1787 break; 1788 case WAN_WISHING: 1789 known = TRUE; 1790 if(Luck + rn2(5) < 0) { 1791 pline("Unfortunately, nothing happens."); 1792 break; 1793 } 1794 makewish(); 1795 break; 1796 case WAN_ENLIGHTENMENT: 1797 known = TRUE; 1798 You_feel("self-knowledgeable..."); 1799 display_nhwindow(WIN_MESSAGE, FALSE); 1800 enlightenment(FALSE); 1801 pline_The("feeling subsides."); 1802 exercise(A_WIS, TRUE); 1803 break; 1804 } 1805 if (known && !objects[obj->otyp].oc_name_known) { 1806 makeknown(obj->otyp); 1807 more_experienced(0,10); 1808 } 1809} 1810#endif /*OVL1*/ 1811#ifdef OVL0 1812 1813STATIC_OVL void 1814backfire(otmp) 1815struct obj *otmp; 1816{ 1817 otmp->in_use = TRUE; /* in case losehp() is fatal */ 1818 pline("%s suddenly explodes!", The(xname(otmp))); 1819 losehp(d(otmp->spe+2,6), "exploding wand", KILLED_BY_AN); 1820 useup(otmp); 1821} 1822 1823static NEARDATA const char zap_syms[] = { WAND_CLASS, 0 }; 1824 1825int 1826dozap() 1827{ 1828 register struct obj *obj; 1829 int damage; 1830 1831 if(check_capacity((char *)0)) return(0); 1832 obj = getobj(zap_syms, "zap"); 1833 if(!obj) return(0); 1834 1835 check_unpaid(obj); 1836 1837 /* zappable addition done by GAN 11/03/86 */ 1838 if(!zappable(obj)) pline(nothing_happens); 1839 else if(obj->cursed && !rn2(100)) { 1840 backfire(obj); /* the wand blows up in your face! */ 1841 exercise(A_STR, FALSE); 1842 return(1); 1843 } else if(!(objects[obj->otyp].oc_dir == NODIR) && !getdir((char *)0)) { 1844 if (!Blind) 1845 pline("%s glows and fades.", The(xname(obj))); 1846 /* make him pay for knowing !NODIR */ 1847 } else if(!u.dx && !u.dy && !u.dz && !(objects[obj->otyp].oc_dir == NODIR)) { 1848 if ((damage = zapyourself(obj, TRUE)) != 0) { 1849 char buf[BUFSZ]; 1850 Sprintf(buf, "zapped %sself with a wand", uhim()); 1851 losehp(damage, buf, NO_KILLER_PREFIX); 1852 } 1853 } else { 1854 1855 /* Are we having fun yet? 1856 * weffects -> buzz(obj->otyp) -> zhitm (temple priest) -> 1857 * attack -> hitum -> known_hitum -> ghod_hitsu -> 1858 * buzz(AD_ELEC) -> destroy_item(WAND_CLASS) -> 1859 * useup -> obfree -> dealloc_obj -> free(obj) 1860 */ 1861 current_wand = obj; 1862 weffects(obj); 1863 obj = current_wand; 1864 current_wand = 0; 1865 } 1866 if (obj && obj->spe < 0) { 1867 pline("%s to dust.", Tobjnam(obj, "turn")); 1868 useup(obj); 1869 } 1870 update_inventory(); /* maybe used a charge */ 1871 return(1); 1872} 1873 1874int 1875zapyourself(obj, ordinary) 1876struct obj *obj; 1877boolean ordinary; 1878{ 1879 int damage = 0; 1880 char buf[BUFSZ]; 1881 1882 switch(obj->otyp) { 1883 case WAN_STRIKING: 1884 makeknown(WAN_STRIKING); 1885 case SPE_FORCE_BOLT: 1886 if(Antimagic) { 1887 shieldeff(u.ux, u.uy); 1888 pline("Boing!"); 1889 } else { 1890 if (ordinary) { 1891 You("bash yourself!"); 1892 damage = d(2,12); 1893 } else 1894 damage = d(1 + obj->spe,6); 1895 exercise(A_STR, FALSE); 1896 } 1897 break; 1898 1899 case WAN_LIGHTNING: 1900 makeknown(WAN_LIGHTNING); 1901 if (!Shock_resistance) { 1902 You("shock yourself!"); 1903 damage = d(12,6); 1904 exercise(A_CON, FALSE); 1905 } else { 1906 shieldeff(u.ux, u.uy); 1907 You("zap yourself, but seem unharmed."); 1908 ugolemeffects(AD_ELEC, d(12,6)); 1909 } 1910 destroy_item(WAND_CLASS, AD_ELEC); 1911 destroy_item(RING_CLASS, AD_ELEC); 1912 if (!resists_blnd(&youmonst)) { 1913 You(are_blinded_by_the_flash); 1914 make_blinded((long)rnd(100),FALSE); 1915 if (!Blind) Your(vision_clears); 1916 } 1917 break; 1918 1919 case SPE_FIREBALL: 1920 You("explode a fireball on top of yourself!"); 1921 explode(u.ux, u.uy, 11, d(6,6), WAND_CLASS, EXPL_FIERY); 1922 break; 1923 case WAN_FIRE: 1924 makeknown(WAN_FIRE); 1925 case FIRE_HORN: 1926 if (Fire_resistance) { 1927 shieldeff(u.ux, u.uy); 1928 You_feel("rather warm."); 1929 ugolemeffects(AD_FIRE, d(12,6)); 1930 } else { 1931 pline("You've set yourself afire!"); 1932 damage = d(12,6); 1933 } 1934 burn_away_slime(); 1935 (void) burnarmor(&youmonst); 1936 destroy_item(SCROLL_CLASS, AD_FIRE); 1937 destroy_item(POTION_CLASS, AD_FIRE); 1938 destroy_item(SPBOOK_CLASS, AD_FIRE); 1939 break; 1940 1941 case WAN_COLD: 1942 makeknown(WAN_COLD); 1943 case SPE_CONE_OF_COLD: 1944 case FROST_HORN: 1945 if (Cold_resistance) { 1946 shieldeff(u.ux, u.uy); 1947 You_feel("a little chill."); 1948 ugolemeffects(AD_COLD, d(12,6)); 1949 } else { 1950 You("imitate a popsicle!"); 1951 damage = d(12,6); 1952 } 1953 destroy_item(POTION_CLASS, AD_COLD); 1954 break; 1955 1956 case WAN_MAGIC_MISSILE: 1957 makeknown(WAN_MAGIC_MISSILE); 1958 case SPE_MAGIC_MISSILE: 1959 if(Antimagic) { 1960 shieldeff(u.ux, u.uy); 1961 pline_The("missiles bounce!"); 1962 } else { 1963 damage = d(4,6); 1964 pline("Idiot! You've shot yourself!"); 1965 } 1966 break; 1967 1968 case WAN_POLYMORPH: 1969 if (!Unchanging) 1970 makeknown(WAN_POLYMORPH); 1971 case SPE_POLYMORPH: 1972 if (!Unchanging) 1973 polyself(FALSE); 1974 break; 1975 1976 case WAN_CANCELLATION: 1977 case SPE_CANCELLATION: 1978 (void) cancel_monst(&youmonst, obj, TRUE, FALSE, TRUE); 1979 break; 1980 1981 case SPE_DRAIN_LIFE: 1982 if (!Drain_resistance) { 1983 losexp("life drainage"); 1984 makeknown(obj->otyp); 1985 } 1986 damage = 0; /* No additional damage */ 1987 break; 1988 1989 case WAN_MAKE_INVISIBLE: { 1990 /* have to test before changing HInvis but must change 1991 * HInvis before doing newsym(). 1992 */ 1993 int msg = !Invis && !Blind && !BInvis; 1994 1995 if (BInvis && uarmc->otyp == MUMMY_WRAPPING) { 1996 /* A mummy wrapping absorbs it and protects you */ 1997 You_feel("rather itchy under your %s.", xname(uarmc)); 1998 break; 1999 } 2000 if (ordinary || !rn2(10)) { /* permanent */ 2001 HInvis |= FROMOUTSIDE; 2002 } else { /* temporary */ 2003 incr_itimeout(&HInvis, d(obj->spe, 250)); 2004 } 2005 if (msg) { 2006 makeknown(WAN_MAKE_INVISIBLE); 2007 newsym(u.ux, u.uy); 2008 self_invis_message(); 2009 } 2010 break; 2011 } 2012 2013 case WAN_SPEED_MONSTER: 2014 if (!(HFast & INTRINSIC)) { 2015 if (!Fast) 2016 You("speed up."); 2017 else 2018 Your("quickness feels more natural."); 2019 makeknown(WAN_SPEED_MONSTER); 2020 exercise(A_DEX, TRUE); 2021 } 2022 HFast |= FROMOUTSIDE; 2023 break; 2024 2025 case WAN_SLEEP: 2026 makeknown(WAN_SLEEP); 2027 case SPE_SLEEP: 2028 if(Sleep_resistance) { 2029 shieldeff(u.ux, u.uy); 2030 You("don't feel sleepy!"); 2031 } else { 2032 pline_The("sleep ray hits you!"); 2033 fall_asleep(-rnd(50), TRUE); 2034 } 2035 break; 2036 2037 case WAN_SLOW_MONSTER: 2038 case SPE_SLOW_MONSTER: 2039 if(HFast & (TIMEOUT | INTRINSIC)) { 2040 u_slow_down(); 2041 makeknown(obj->otyp); 2042 } 2043 break; 2044 2045 case WAN_TELEPORTATION: 2046 case SPE_TELEPORT_AWAY: 2047 tele(); 2048 break; 2049 2050 case WAN_DEATH: 2051 case SPE_FINGER_OF_DEATH: 2052 if (nonliving(youmonst.data) || is_demon(youmonst.data)) { 2053 pline((obj->otyp == WAN_DEATH) ? 2054 "The wand shoots an apparently harmless beam at you." 2055 : "You seem no deader than before."); 2056 break; 2057 } 2058 Sprintf(buf, "shot %sself with a death ray", uhim()); 2059 killer = buf; 2060 killer_format = NO_KILLER_PREFIX; 2061 You("irradiate yourself with pure energy!"); 2062 You("die."); 2063 makeknown(obj->otyp); 2064 /* They might survive with an amulet of life saving */ 2065 done(DIED); 2066 break; 2067 case WAN_UNDEAD_TURNING: 2068 makeknown(WAN_UNDEAD_TURNING); 2069 case SPE_TURN_UNDEAD: 2070 (void) unturn_dead(&youmonst); 2071 if (is_undead(youmonst.data)) { 2072 You_feel("frightened and %sstunned.", 2073 Stunned ? "even more " : ""); 2074 make_stunned(HStun + rnd(30), FALSE); 2075 } else 2076 You("shudder in dread."); 2077 break; 2078 case SPE_HEALING: 2079 case SPE_EXTRA_HEALING: 2080 healup(d(6, obj->otyp == SPE_EXTRA_HEALING ? 8 : 4), 2081 0, FALSE, (obj->otyp == SPE_EXTRA_HEALING)); 2082 You_feel("%sbetter.", 2083 obj->otyp == SPE_EXTRA_HEALING ? "much " : ""); 2084 break; 2085 case WAN_LIGHT: /* (broken wand) */ 2086 /* assert( !ordinary ); */ 2087 damage = d(obj->spe, 25); 2088#ifdef TOURIST 2089 case EXPENSIVE_CAMERA: 2090#endif 2091 damage += rnd(25); 2092 if (!resists_blnd(&youmonst)) { 2093 You(are_blinded_by_the_flash); 2094 make_blinded((long)damage, FALSE); 2095 makeknown(obj->otyp); 2096 if (!Blind) Your(vision_clears); 2097 } 2098 damage = 0; /* reset */ 2099 break; 2100 case WAN_OPENING: 2101 if (Punished) makeknown(WAN_OPENING); 2102 case SPE_KNOCK: 2103 if (Punished) Your("chain quivers for a moment."); 2104 break; 2105 case WAN_DIGGING: 2106 case SPE_DIG: 2107 case SPE_DETECT_UNSEEN: 2108 case WAN_NOTHING: 2109 case WAN_LOCKING: 2110 case SPE_WIZARD_LOCK: 2111 break; 2112 case WAN_PROBING: 2113 for (obj = invent; obj; obj = obj->nobj) 2114 obj->dknown = 1; 2115 /* note: `obj' reused; doesn't point at wand anymore */ 2116 makeknown(WAN_PROBING); 2117 ustatusline(); 2118 break; 2119 case SPE_STONE_TO_FLESH: 2120 { 2121 struct obj *otemp, *onext; 2122 boolean didmerge; 2123 2124 if (u.umonnum == PM_STONE_GOLEM) 2125 (void) polymon(PM_FLESH_GOLEM); 2126 if (Stoned) fix_petrification(); /* saved! */ 2127 /* but at a cost.. */ 2128 for (otemp = invent; otemp; otemp = onext) { 2129 onext = otemp->nobj; 2130 (void) bhito(otemp, obj); 2131 } 2132 /* 2133 * It is possible that we can now merge some inventory. 2134 * Do a higly paranoid merge. Restart from the beginning 2135 * until no merges. 2136 */ 2137 do { 2138 didmerge = FALSE; 2139 for (otemp = invent; !didmerge && otemp; otemp = otemp->nobj) 2140 for (onext = otemp->nobj; onext; onext = onext->nobj) 2141 if (merged(&otemp, &onext)) { 2142 didmerge = TRUE; 2143 break; 2144 } 2145 } while (didmerge); 2146 } 2147 break; 2148 default: impossible("object %d used?",obj->otyp); 2149 break; 2150 } 2151 return(damage); 2152} 2153 2154#ifdef STEED 2155/* you've zapped a wand downwards while riding 2156 * Return TRUE if the steed was hit by the wand. 2157 * Return FALSE if the steed was not hit by the wand. 2158 */ 2159STATIC_OVL boolean 2160zap_steed(obj) 2161struct obj *obj; /* wand or spell */ 2162{ 2163 int steedhit = FALSE; 2164 2165 switch (obj->otyp) { 2166 2167 /* 2168 * Wands that are allowed to hit the steed 2169 * Carefully test the results of any that are 2170 * moved here from the bottom section. 2171 */ 2172 case WAN_PROBING: 2173 probe_monster(u.usteed); 2174 makeknown(WAN_PROBING); 2175 steedhit = TRUE; 2176 break; 2177 case WAN_TELEPORTATION: 2178 case SPE_TELEPORT_AWAY: 2179 /* you go together */ 2180 tele(); 2181 if(Teleport_control || !couldsee(u.ux0, u.uy0) || 2182 (distu(u.ux0, u.uy0) >= 16)) 2183 makeknown(obj->otyp); 2184 steedhit = TRUE; 2185 break; 2186 2187 /* Default processing via bhitm() for these */ 2188 case SPE_CURE_SICKNESS: 2189 case WAN_MAKE_INVISIBLE: 2190 case WAN_CANCELLATION: 2191 case SPE_CANCELLATION: 2192 case WAN_POLYMORPH: 2193 case SPE_POLYMORPH: 2194 case WAN_STRIKING: 2195 case SPE_FORCE_BOLT: 2196 case WAN_SLOW_MONSTER: 2197 case SPE_SLOW_MONSTER: 2198 case WAN_SPEED_MONSTER: 2199 case SPE_HEALING: 2200 case SPE_EXTRA_HEALING: 2201 case SPE_DRAIN_LIFE: 2202 case WAN_OPENING: 2203 case SPE_KNOCK: 2204 (void) bhitm(u.usteed, obj); 2205 steedhit = TRUE; 2206 break; 2207 2208 default: 2209 steedhit = FALSE; 2210 break; 2211 } 2212 return steedhit; 2213} 2214#endif 2215 2216#endif /*OVL0*/ 2217#ifdef OVL3 2218 2219/* 2220 * cancel a monster (possibly the hero). inventory is cancelled only 2221 * if the monster is zapping itself directly, since otherwise the 2222 * effect is too strong. currently non-hero monsters do not zap 2223 * themselves with cancellation. 2224 */ 2225boolean 2226cancel_monst(mdef, obj, youattack, allow_cancel_kill, self_cancel) 2227register struct monst *mdef; 2228register struct obj *obj; 2229boolean youattack, allow_cancel_kill, self_cancel; 2230{ 2231 boolean youdefend = (mdef == &youmonst); 2232 static const char writing_vanishes[] = 2233 "Some writing vanishes from %s head!"; 2234 static const char your[] = "your"; /* should be extern */ 2235 2236 if (youdefend ? (!youattack && Antimagic) 2237 : resist(mdef, obj->oclass, 0, NOTELL)) 2238 return FALSE; /* resisted cancellation */ 2239 2240 if (self_cancel) { /* 1st cancel inventory */ 2241 struct obj *otmp; 2242 2243 for (otmp = (youdefend ? invent : mdef->minvent); 2244 otmp; otmp = otmp->nobj) 2245 cancel_item(otmp); 2246 if (youdefend) { 2247 flags.botl = 1; /* potential AC change */ 2248 find_ac(); 2249 } 2250 } 2251 2252 /* now handle special cases */ 2253 if (youdefend) { 2254 if (Upolyd) { 2255 if ((u.umonnum == PM_CLAY_GOLEM) && !Blind) 2256 pline(writing_vanishes, your); 2257 2258 if (Unchanging) 2259 Your("amulet grows hot for a moment, then cools."); 2260 else 2261 rehumanize(); 2262 } 2263 } else { 2264 mdef->mcan = TRUE; 2265 2266 if (is_were(mdef->data) && mdef->data->mlet != S_HUMAN) 2267 were_change(mdef); 2268 2269 if (mdef->data == &mons[PM_CLAY_GOLEM]) { 2270 if (canseemon(mdef)) 2271 pline(writing_vanishes, s_suffix(mon_nam(mdef))); 2272 2273 if (allow_cancel_kill) { 2274 if (youattack) 2275 killed(mdef); 2276 else 2277 monkilled(mdef, "", AD_SPEL); 2278 } 2279 } 2280 } 2281 return TRUE; 2282} 2283 2284/* you've zapped an immediate type wand up or down */ 2285STATIC_OVL boolean 2286zap_updown(obj) 2287struct obj *obj; /* wand or spell */ 2288{ 2289 boolean striking = FALSE, disclose = FALSE; 2290 int x, y, xx, yy, ptmp; 2291 struct obj *otmp; 2292 struct engr *e; 2293 struct trap *ttmp; 2294 char buf[BUFSZ]; 2295 2296 /* some wands have special effects other than normal bhitpile */ 2297 /* drawbridge might change <u.ux,u.uy> */ 2298 x = xx = u.ux; /* <x,y> is zap location */ 2299 y = yy = u.uy; /* <xx,yy> is drawbridge (portcullis) position */ 2300 ttmp = t_at(x, y); /* trap if there is one */ 2301 2302 switch (obj->otyp) { 2303 case WAN_PROBING: 2304 ptmp = 0; 2305 if (u.dz < 0) { 2306 You("probe towards the %s.", ceiling(x,y)); 2307 } else { 2308 ptmp += bhitpile(obj, bhito, x, y); 2309 You("probe beneath the %s.", surface(x,y)); 2310 ptmp += display_binventory(x, y, TRUE); 2311 } 2312 if (!ptmp) Your("probe reveals nothing."); 2313 return TRUE; /* we've done our own bhitpile */ 2314 case WAN_OPENING: 2315 case SPE_KNOCK: 2316 /* up or down, but at closed portcullis only */ 2317 if (is_db_wall(x,y) && find_drawbridge(&xx, &yy)) { 2318 open_drawbridge(xx, yy); 2319 disclose = TRUE; 2320 } else if (u.dz > 0 && (x == xdnstair && y == ydnstair) && 2321 /* can't use the stairs down to quest level 2 until 2322 leader "unlocks" them; give feedback if you try */ 2323 on_level(&u.uz, &qstart_level) && !ok_to_quest()) { 2324 pline_The("stairs seem to ripple momentarily."); 2325 disclose = TRUE; 2326 } 2327 break; 2328 case WAN_STRIKING: 2329 case SPE_FORCE_BOLT: 2330 striking = TRUE; 2331 /*FALLTHRU*/ 2332 case WAN_LOCKING: 2333 case SPE_WIZARD_LOCK: 2334 /* down at open bridge or up or down at open portcullis */ 2335 if ((levl[x][y].typ == DRAWBRIDGE_DOWN) ? (u.dz > 0) : 2336 (is_drawbridge_wall(x,y) && !is_db_wall(x,y)) && 2337 find_drawbridge(&xx, &yy)) { 2338 if (!striking) 2339 close_drawbridge(xx, yy); 2340 else 2341 destroy_drawbridge(xx, yy); 2342 disclose = TRUE; 2343 } else if (striking && u.dz < 0 && rn2(3) && 2344 !Is_airlevel(&u.uz) && !Is_waterlevel(&u.uz) && 2345 !Underwater && !Is_qstart(&u.uz)) { 2346 /* similar to zap_dig() */ 2347 pline("A rock is dislodged from the %s and falls on your %s.", 2348 ceiling(x, y), body_part(HEAD)); 2349 losehp(rnd((uarmh && is_metallic(uarmh)) ? 2 : 6), 2350 "falling rock", KILLED_BY_AN); 2351 if ((otmp = mksobj_at(ROCK, x, y, FALSE, FALSE)) != 0) { 2352 (void)xname(otmp); /* set dknown, maybe bknown */ 2353 stackobj(otmp); 2354 } 2355 newsym(x, y); 2356 } else if (!striking && ttmp && ttmp->ttyp == TRAPDOOR && u.dz > 0) { 2357 if (!Blind) { 2358 if (ttmp->tseen) { 2359 pline("A trap door beneath you closes up then vanishes."); 2360 disclose = TRUE; 2361 } else { 2362 You("see a swirl of %s beneath you.", 2363 is_ice(x,y) ? "frost" : "dust"); 2364 } 2365 } else { 2366 You_hear("a twang followed by a thud."); 2367 } 2368 deltrap(ttmp); 2369 ttmp = (struct trap *)0; 2370 newsym(x, y); 2371 } 2372 break; 2373 case SPE_STONE_TO_FLESH: 2374 if (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz) || 2375 Underwater || (Is_qstart(&u.uz) && u.dz < 0)) { 2376 pline(nothing_happens); 2377 } else if (u.dz < 0) { /* we should do more... */ 2378 pline("Blood drips on your %s.", body_part(FACE)); 2379 } else if (u.dz > 0 && !OBJ_AT(u.ux, u.uy)) { 2380 /* 2381 Print this message only if there wasn't an engraving 2382 affected here. If water or ice, act like waterlevel case. 2383 */ 2384 e = engr_at(u.ux, u.uy); 2385 if (!(e && e->engr_type == ENGRAVE)) { 2386 if (is_pool(u.ux, u.uy) || is_ice(u.ux, u.uy)) 2387 pline(nothing_happens); 2388 else 2389 pline("Blood %ss %s your %s.", 2390 is_lava(u.ux, u.uy) ? "boil" : "pool", 2391 Levitation ? "beneath" : "at", 2392 makeplural(body_part(FOOT))); 2393 } 2394 } 2395 break; 2396 default: 2397 break; 2398 } 2399 2400 if (u.dz > 0) { 2401 /* zapping downward */ 2402 (void) bhitpile(obj, bhito, x, y); 2403 2404 /* subset of engraving effects; none sets `disclose' */ 2405 if ((e = engr_at(x, y)) != 0 && e->engr_type != HEADSTONE) { 2406 switch (obj->otyp) { 2407 case WAN_POLYMORPH: 2408 case SPE_POLYMORPH: 2409 del_engr(e); 2410 make_engr_at(x, y, random_engraving(buf), moves, (xchar)0); 2411 break; 2412 case WAN_CANCELLATION: 2413 case SPE_CANCELLATION: 2414 case WAN_MAKE_INVISIBLE: 2415 del_engr(e); 2416 break; 2417 case WAN_TELEPORTATION: 2418 case SPE_TELEPORT_AWAY: 2419 rloc_engr(e); 2420 break; 2421 case SPE_STONE_TO_FLESH: 2422 if (e->engr_type == ENGRAVE) { 2423 /* only affects things in stone */ 2424 pline_The(Hallucination ? 2425 "floor runs like butter!" : 2426 "edges on the floor get smoother."); 2427 wipe_engr_at(x, y, d(2,4)); 2428 } 2429 break; 2430 case WAN_STRIKING: 2431 case SPE_FORCE_BOLT: 2432 wipe_engr_at(x, y, d(2,4)); 2433 break; 2434 default: 2435 break; 2436 } 2437 } 2438 } 2439 2440 return disclose; 2441} 2442 2443#endif /*OVL3*/ 2444#ifdef OVLB 2445 2446/* called for various wand and spell effects - M. Stephenson */ 2447void 2448weffects(obj) 2449register struct obj *obj; 2450{ 2451 int otyp = obj->otyp; 2452 boolean disclose = FALSE, was_unkn = !objects[otyp].oc_name_known; 2453 2454 exercise(A_WIS, TRUE); 2455#ifdef STEED 2456 if (u.usteed && (objects[otyp].oc_dir != NODIR) && 2457 !u.dx && !u.dy && (u.dz > 0) && zap_steed(obj)) { 2458 disclose = TRUE; 2459 } else 2460#endif 2461 if (objects[otyp].oc_dir == IMMEDIATE) { 2462 obj_zapped = FALSE; 2463 2464 if (u.uswallow) { 2465 (void) bhitm(u.ustuck, obj); 2466 /* [how about `bhitpile(u.ustuck->minvent)' effect?] */ 2467 } else if (u.dz) { 2468 disclose = zap_updown(obj); 2469 } else { 2470 (void) bhit(u.dx,u.dy, rn1(8,6),ZAPPED_WAND, bhitm,bhito, obj); 2471 } 2472 /* give a clue if obj_zapped */ 2473 if (obj_zapped) 2474 You_feel("shuddering vibrations."); 2475 2476 } else if (objects[otyp].oc_dir == NODIR) { 2477 zapnodir(obj); 2478 2479 } else { 2480 /* neither immediate nor directionless */ 2481 2482 if (otyp == WAN_DIGGING || otyp == SPE_DIG) 2483 zap_dig(); 2484 else if (otyp >= SPE_MAGIC_MISSILE && otyp <= SPE_FINGER_OF_DEATH) 2485 buzz(otyp - SPE_MAGIC_MISSILE + 10, 2486 u.ulevel / 2 + 1, 2487 u.ux, u.uy, u.dx, u.dy); 2488 else if (otyp >= WAN_MAGIC_MISSILE && otyp <= WAN_LIGHTNING) 2489 buzz(otyp - WAN_MAGIC_MISSILE, 2490 (otyp == WAN_MAGIC_MISSILE) ? 2 : 6, 2491 u.ux, u.uy, u.dx, u.dy); 2492 else 2493 impossible("weffects: unexpected spell or wand"); 2494 disclose = TRUE; 2495 } 2496 if (disclose && was_unkn) { 2497 makeknown(otyp); 2498 more_experienced(0,10); 2499 } 2500 return; 2501} 2502#endif /*OVLB*/ 2503#ifdef OVL0 2504 2505/* 2506 * Generate the to damage bonus for a spell. Based on the hero's intelligence 2507 */ 2508int 2509spell_damage_bonus() 2510{ 2511 int tmp, intell = ACURR(A_INT); 2512 2513 /* Punish low intellegence before low level else low intellegence 2514 gets punished only when high level */ 2515 if (intell < 10) 2516 tmp = -3; 2517 else if (u.ulevel < 5) 2518 tmp = 0; 2519 else if (intell < 14) 2520 tmp = 0; 2521 else if (intell <= 18) 2522 tmp = 1; 2523 else /* helm of brilliance */ 2524 tmp = 2; 2525 2526 return tmp; 2527} 2528 2529/* 2530 * Generate the to hit bonus for a spell. Based on the hero's skill in 2531 * spell class and dexterity. 2532 */ 2533STATIC_OVL int 2534spell_hit_bonus(skill) 2535int skill; 2536{ 2537 int hit_bon = 0; 2538 int dex = ACURR(A_DEX); 2539 2540 switch (P_SKILL(spell_skilltype(skill))) { 2541 case P_ISRESTRICTED: 2542 case P_UNSKILLED: hit_bon = -4; break; 2543 case P_BASIC: hit_bon = 0; break; 2544 case P_SKILLED: hit_bon = 2; break; 2545 case P_EXPERT: hit_bon = 3; break; 2546 } 2547 2548 if (dex < 4) 2549 hit_bon -= 3; 2550 else if (dex < 6) 2551 hit_bon -= 2; 2552 else if (dex < 8) 2553 hit_bon -= 1; 2554 else if (dex < 14) 2555 hit_bon -= 0; /* Will change when print stuff below removed */ 2556 else 2557 hit_bon += dex - 14; /* Even increment for dextrous heroes (see weapon.c abon) */ 2558 2559 return hit_bon; 2560} 2561 2562const char * 2563exclam(force) 2564register int force; 2565{ 2566 /* force == 0 occurs e.g. with sleep ray */ 2567 /* note that large force is usual with wands so that !! would 2568 require information about hand/weapon/wand */ 2569 return (const char *)((force < 0) ? "?" : (force <= 4) ? "." : "!"); 2570} 2571 2572void 2573hit(str,mtmp,force) 2574register const char *str; 2575register struct monst *mtmp; 2576register const char *force; /* usually either "." or "!" */ 2577{ 2578 if((!cansee(bhitpos.x,bhitpos.y) && !canspotmon(mtmp) && 2579 !(u.uswallow && mtmp == u.ustuck)) 2580 || !flags.verbose) 2581 pline("%s %s it.", The(str), vtense(str, "hit")); 2582 else pline("%s %s %s%s", The(str), vtense(str, "hit"), 2583 mon_nam(mtmp), force); 2584} 2585 2586void 2587miss(str,mtmp) 2588register const char *str; 2589register struct monst *mtmp; 2590{ 2591 pline("%s %s %s.", The(str), vtense(str, "miss"), 2592 ((cansee(bhitpos.x,bhitpos.y) || canspotmon(mtmp)) 2593 && flags.verbose) ? 2594 mon_nam(mtmp) : "it"); 2595} 2596#endif /*OVL0*/ 2597#ifdef OVL1 2598 2599/* 2600 * Called for the following distance effects: 2601 * when a weapon is thrown (weapon == THROWN_WEAPON) 2602 * when an object is kicked (KICKED_WEAPON) 2603 * when an IMMEDIATE wand is zapped (ZAPPED_WAND) 2604 * when a light beam is flashed (FLASHED_LIGHT) 2605 * when a mirror is applied (INVIS_BEAM) 2606 * A thrown/kicked object falls down at the end of its range or when a monster 2607 * is hit. The variable 'bhitpos' is set to the final position of the weapon 2608 * thrown/zapped. The ray of a wand may affect (by calling a provided 2609 * function) several objects and monsters on its path. The return value 2610 * is the monster hit (weapon != ZAPPED_WAND), or a null monster pointer. 2611 * 2612 * Check !u.uswallow before calling bhit(). 2613 * This function reveals the absence of a remembered invisible monster in 2614 * necessary cases (throwing or kicking weapons). The presence of a real 2615 * one is revealed for a weapon, but if not a weapon is left up to fhitm(). 2616 */ 2617struct monst * 2618bhit(ddx,ddy,range,weapon,fhitm,fhito,obj) 2619register int ddx,ddy,range; /* direction and range */ 2620int weapon; /* see values in hack.h */ 2621int FDECL((*fhitm), (MONST_P, OBJ_P)), /* fns called when mon/obj hit */ 2622 FDECL((*fhito), (OBJ_P, OBJ_P)); 2623struct obj *obj; /* object tossed/used */ 2624{ 2625 struct monst *mtmp; 2626 uchar typ; 2627 boolean shopdoor = FALSE, point_blank = TRUE; 2628 2629 if (weapon == KICKED_WEAPON) { 2630 /* object starts one square in front of player */ 2631 bhitpos.x = u.ux + ddx; 2632 bhitpos.y = u.uy + ddy; 2633 range--; 2634 } else { 2635 bhitpos.x = u.ux; 2636 bhitpos.y = u.uy; 2637 } 2638 2639 if (weapon == FLASHED_LIGHT) { 2640 tmp_at(DISP_BEAM, cmap_to_glyph(S_flashbeam)); 2641 } else if (weapon != ZAPPED_WAND && weapon != INVIS_BEAM) 2642 tmp_at(DISP_FLASH, obj_to_glyph(obj)); 2643 2644 while(range-- > 0) { 2645 int x,y; 2646 2647 bhitpos.x += ddx; 2648 bhitpos.y += ddy; 2649 x = bhitpos.x; y = bhitpos.y; 2650 2651 if(!isok(x, y)) { 2652 bhitpos.x -= ddx; 2653 bhitpos.y -= ddy; 2654 break; 2655 } 2656 2657 if(is_pick(obj) && inside_shop(x, y) && 2658 (mtmp = shkcatch(obj, x, y))) { 2659 tmp_at(DISP_END, 0); 2660 return(mtmp); 2661 } 2662 2663 typ = levl[bhitpos.x][bhitpos.y].typ; 2664 2665 /* iron bars will block anything big enough */ 2666 if ((weapon == THROWN_WEAPON || weapon == KICKED_WEAPON) && 2667 typ == IRONBARS && 2668 hits_bars(&obj, x - ddx, y - ddy, 2669 point_blank ? 0 : !rn2(5), 1)) { 2670 /* caveat: obj might now be null... */ 2671 bhitpos.x -= ddx; 2672 bhitpos.y -= ddy; 2673 break; 2674 } 2675 2676 if (weapon == ZAPPED_WAND && find_drawbridge(&x,&y)) 2677 switch (obj->otyp) { 2678 case WAN_OPENING: 2679 case SPE_KNOCK: 2680 if (is_db_wall(bhitpos.x, bhitpos.y)) { 2681 if (cansee(x,y) || cansee(bhitpos.x,bhitpos.y)) 2682 makeknown(obj->otyp); 2683 open_drawbridge(x,y); 2684 } 2685 break; 2686 case WAN_LOCKING: 2687 case SPE_WIZARD_LOCK: 2688 if ((cansee(x,y) || cansee(bhitpos.x, bhitpos.y)) 2689 && levl[x][y].typ == DRAWBRIDGE_DOWN) 2690 makeknown(obj->otyp); 2691 close_drawbridge(x,y); 2692 break; 2693 case WAN_STRIKING: 2694 case SPE_FORCE_BOLT: 2695 if (typ != DRAWBRIDGE_UP) 2696 destroy_drawbridge(x,y); 2697 makeknown(obj->otyp); 2698 break; 2699 } 2700 2701 if ((mtmp = m_at(bhitpos.x, bhitpos.y)) != 0) { 2702 notonhead = (bhitpos.x != mtmp->mx || 2703 bhitpos.y != mtmp->my); 2704 if (weapon != FLASHED_LIGHT) { 2705 if(weapon != ZAPPED_WAND) { 2706 if(weapon != INVIS_BEAM) tmp_at(DISP_END, 0); 2707 if (cansee(bhitpos.x,bhitpos.y) && !canspotmon(mtmp)) { 2708 if (weapon != INVIS_BEAM) { 2709 map_invisible(bhitpos.x, bhitpos.y); 2710 return(mtmp); 2711 } 2712 } else 2713 return(mtmp); 2714 } 2715 if (weapon != INVIS_BEAM) { 2716 (*fhitm)(mtmp, obj); 2717 range -= 3; 2718 } 2719 } else { 2720 /* FLASHED_LIGHT hitting invisible monster 2721 should pass through instead of stop so 2722 we call flash_hits_mon() directly rather 2723 than returning mtmp back to caller. That 2724 allows the flash to keep on going. Note 2725 that we use mtmp->minvis not canspotmon() 2726 because it makes no difference whether 2727 the hero can see the monster or not.*/ 2728 if (mtmp->minvis) { 2729 obj->ox = u.ux, obj->oy = u.uy; 2730 (void) flash_hits_mon(mtmp, obj); 2731 } else { 2732 tmp_at(DISP_END, 0); 2733 return(mtmp); /* caller will call flash_hits_mon */ 2734 } 2735 } 2736 } else { 2737 if (weapon == ZAPPED_WAND && obj->otyp == WAN_PROBING && 2738 glyph_is_invisible(levl[bhitpos.x][bhitpos.y].glyph)) { 2739 unmap_object(bhitpos.x, bhitpos.y); 2740 newsym(x, y); 2741 } 2742 } 2743 if(fhito) { 2744 if(bhitpile(obj,fhito,bhitpos.x,bhitpos.y)) 2745 range--; 2746 } else { 2747 if(weapon == KICKED_WEAPON && 2748 ((obj->oclass == COIN_CLASS && 2749 OBJ_AT(bhitpos.x, bhitpos.y)) || 2750 ship_object(obj, bhitpos.x, bhitpos.y, 2751 costly_spot(bhitpos.x, bhitpos.y)))) { 2752 tmp_at(DISP_END, 0); 2753 return (struct monst *)0; 2754 } 2755 } 2756 if(weapon == ZAPPED_WAND && (IS_DOOR(typ) || typ == SDOOR)) { 2757 switch (obj->otyp) { 2758 case WAN_OPENING: 2759 case WAN_LOCKING: 2760 case WAN_STRIKING: 2761 case SPE_KNOCK: 2762 case SPE_WIZARD_LOCK: 2763 case SPE_FORCE_BOLT: 2764 if (doorlock(obj, bhitpos.x, bhitpos.y)) { 2765 if (cansee(bhitpos.x, bhitpos.y) || 2766 (obj->otyp == WAN_STRIKING)) 2767 makeknown(obj->otyp); 2768 if (levl[bhitpos.x][bhitpos.y].doormask == D_BROKEN 2769 && *in_rooms(bhitpos.x, bhitpos.y, SHOPBASE)) { 2770 shopdoor = TRUE; 2771 add_damage(bhitpos.x, bhitpos.y, 400L); 2772 } 2773 } 2774 break; 2775 } 2776 } 2777 if(!ZAP_POS(typ) || closed_door(bhitpos.x, bhitpos.y)) { 2778 bhitpos.x -= ddx; 2779 bhitpos.y -= ddy; 2780 break; 2781 } 2782 if(weapon != ZAPPED_WAND && weapon != INVIS_BEAM) { 2783 /* 'I' present but no monster: erase */ 2784 /* do this before the tmp_at() */ 2785 if (glyph_is_invisible(levl[bhitpos.x][bhitpos.y].glyph) 2786 && cansee(x, y)) { 2787 unmap_object(bhitpos.x, bhitpos.y); 2788 newsym(x, y); 2789 } 2790 tmp_at(bhitpos.x, bhitpos.y); 2791 delay_output(); 2792 /* kicked objects fall in pools */ 2793 if((weapon == KICKED_WEAPON) && 2794 (is_pool(bhitpos.x, bhitpos.y) || 2795 is_lava(bhitpos.x, bhitpos.y))) 2796 break; 2797#ifdef SINKS 2798 if(IS_SINK(typ) && weapon != FLASHED_LIGHT) 2799 break; /* physical objects fall onto sink */ 2800#endif 2801 } 2802 /* limit range of ball so hero won't make an invalid move */ 2803 if (weapon == THROWN_WEAPON && range > 0 && 2804 obj->otyp == HEAVY_IRON_BALL) { 2805 struct obj *bobj; 2806 struct trap *t; 2807 if ((bobj = sobj_at(BOULDER, x, y)) != 0) { 2808 if (cansee(x,y)) 2809 pline("%s hits %s.", 2810 The(distant_name(obj, xname)), an(xname(bobj))); 2811 range = 0; 2812 } else if (obj == uball) { 2813 if (!test_move(x - ddx, y - ddy, ddx, ddy, TEST_MOVE)) { 2814 /* nb: it didn't hit anything directly */ 2815 if (cansee(x,y)) 2816 pline("%s jerks to an abrupt halt.", 2817 The(distant_name(obj, xname))); /* lame */ 2818 range = 0; 2819 } else if (In_sokoban(&u.uz) && (t = t_at(x, y)) != 0 && 2820 (t->ttyp == PIT || t->ttyp == SPIKED_PIT || 2821 t->ttyp == HOLE || t->ttyp == TRAPDOOR)) { 2822 /* hero falls into the trap, so ball stops */ 2823 range = 0; 2824 } 2825 } 2826 } 2827 2828 /* thrown/kicked missile has moved away from its starting spot */ 2829 point_blank = FALSE; /* affects passing through iron bars */ 2830 } 2831 2832 if (weapon != ZAPPED_WAND && weapon != INVIS_BEAM) tmp_at(DISP_END, 0); 2833 2834 if(shopdoor) 2835 pay_for_damage("destroy", FALSE); 2836 2837 return (struct monst *)0; 2838} 2839 2840struct monst * 2841boomhit(dx, dy) 2842int dx, dy; 2843{ 2844 register int i, ct; 2845 int boom = S_boomleft; /* showsym[] index */ 2846 struct monst *mtmp; 2847 2848 bhitpos.x = u.ux; 2849 bhitpos.y = u.uy; 2850 2851 for (i = 0; i < 8; i++) if (xdir[i] == dx && ydir[i] == dy) break; 2852 tmp_at(DISP_FLASH, cmap_to_glyph(boom)); 2853 for (ct = 0; ct < 10; ct++) { 2854 if(i == 8) i = 0; 2855 boom = (boom == S_boomleft) ? S_boomright : S_boomleft; 2856 tmp_at(DISP_CHANGE, cmap_to_glyph(boom));/* change glyph */ 2857 dx = xdir[i]; 2858 dy = ydir[i]; 2859 bhitpos.x += dx; 2860 bhitpos.y += dy; 2861 if(MON_AT(bhitpos.x, bhitpos.y)) { 2862 mtmp = m_at(bhitpos.x,bhitpos.y); 2863 m_respond(mtmp); 2864 tmp_at(DISP_END, 0); 2865 return(mtmp); 2866 } 2867 if(!ZAP_POS(levl[bhitpos.x][bhitpos.y].typ) || 2868 closed_door(bhitpos.x, bhitpos.y)) { 2869 bhitpos.x -= dx; 2870 bhitpos.y -= dy; 2871 break; 2872 } 2873 if(bhitpos.x == u.ux && bhitpos.y == u.uy) { /* ct == 9 */ 2874 if(Fumbling || rn2(20) >= ACURR(A_DEX)) { 2875 /* we hit ourselves */ 2876 (void) thitu(10, rnd(10), (struct obj *)0, 2877 "boomerang"); 2878 break; 2879 } else { /* we catch it */ 2880 tmp_at(DISP_END, 0); 2881 You("skillfully catch the boomerang."); 2882 return(&youmonst); 2883 } 2884 } 2885 tmp_at(bhitpos.x, bhitpos.y); 2886 delay_output(); 2887 if(ct % 5 != 0) i++; 2888#ifdef SINKS 2889 if(IS_SINK(levl[bhitpos.x][bhitpos.y].typ)) 2890 break; /* boomerang falls on sink */ 2891#endif 2892 } 2893 tmp_at(DISP_END, 0); /* do not leave last symbol */ 2894 return (struct monst *)0; 2895} 2896 2897STATIC_OVL int 2898zhitm(mon, type, nd, ootmp) /* returns damage to mon */ 2899register struct monst *mon; 2900register int type, nd; 2901struct obj **ootmp; /* to return worn armor for caller to disintegrate */ 2902{ 2903 register int tmp = 0; 2904 register int abstype = abs(type) % 10; 2905 boolean sho_shieldeff = FALSE; 2906 boolean spellcaster = is_hero_spell(type); /* maybe get a bonus! */ 2907 2908 *ootmp = (struct obj *)0; 2909 switch(abstype) { 2910 case ZT_MAGIC_MISSILE: 2911 if (resists_magm(mon)) { 2912 sho_shieldeff = TRUE; 2913 break; 2914 } 2915 tmp = d(nd,6); 2916 if (spellcaster) 2917 tmp += spell_damage_bonus(); 2918#ifdef WIZ_PATCH_DEBUG 2919 if (spellcaster) 2920 pline("Damage = %d + %d", tmp-spell_damage_bonus(), 2921 spell_damage_bonus()); 2922#endif 2923 break; 2924 case ZT_FIRE: 2925 if (resists_fire(mon)) { 2926 sho_shieldeff = TRUE; 2927 break; 2928 } 2929 tmp = d(nd,6); 2930 if (resists_cold(mon)) tmp += 7; 2931 if (spellcaster) 2932 tmp += spell_damage_bonus(); 2933#ifdef WIZ_PATCH_DEBUG 2934 if (spellcaster) 2935 pline("Damage = %d + %d",tmp-spell_damage_bonus(), 2936 spell_damage_bonus()); 2937#endif 2938 if (burnarmor(mon)) { 2939 if (!rn2(3)) (void)destroy_mitem(mon, POTION_CLASS, AD_FIRE); 2940 if (!rn2(3)) (void)destroy_mitem(mon, SCROLL_CLASS, AD_FIRE); 2941 if (!rn2(5)) (void)destroy_mitem(mon, SPBOOK_CLASS, AD_FIRE); 2942 } 2943 break; 2944 case ZT_COLD: 2945 if (resists_cold(mon)) { 2946 sho_shieldeff = TRUE; 2947 break; 2948 } 2949 tmp = d(nd,6); 2950 if (resists_fire(mon)) tmp += d(nd, 3); 2951 if (spellcaster) 2952 tmp += spell_damage_bonus(); 2953#ifdef WIZ_PATCH_DEBUG 2954 if (spellcaster) 2955 pline("Damage = %d + %d", tmp-spell_damage_bonus(), 2956 spell_damage_bonus()); 2957#endif 2958 if (!rn2(3)) (void)destroy_mitem(mon, POTION_CLASS, AD_COLD); 2959 break; 2960 case ZT_SLEEP: 2961 tmp = 0; 2962 (void)sleep_monst(mon, d(nd, 25), 2963 type == ZT_WAND(ZT_SLEEP) ? WAND_CLASS : '\0'); 2964 break; 2965 case ZT_DEATH: /* death/disintegration */ 2966 if(abs(type) != ZT_BREATH(ZT_DEATH)) { /* death */ 2967 if(mon->data == &mons[PM_DEATH]) { 2968 mon->mhpmax += mon->mhpmax/2; 2969 if (mon->mhpmax >= MAGIC_COOKIE) 2970 mon->mhpmax = MAGIC_COOKIE - 1; 2971 mon->mhp = mon->mhpmax; 2972 tmp = 0; 2973 break; 2974 } 2975 if (nonliving(mon->data) || is_demon(mon->data) || 2976 resists_magm(mon)) { /* similar to player */ 2977 sho_shieldeff = TRUE; 2978 break; 2979 } 2980 type = -1; /* so they don't get saving throws */ 2981 } else { 2982 struct obj *otmp2; 2983 2984 if (resists_disint(mon)) { 2985 sho_shieldeff = TRUE; 2986 } else if (mon->misc_worn_check & W_ARMS) { 2987 /* destroy shield; victim survives */ 2988 *ootmp = which_armor(mon, W_ARMS); 2989 } else if (mon->misc_worn_check & W_ARM) { 2990 /* destroy body armor, also cloak if present */ 2991 *ootmp = which_armor(mon, W_ARM); 2992 if ((otmp2 = which_armor(mon, W_ARMC)) != 0) 2993 m_useup(mon, otmp2); 2994 } else { 2995 /* no body armor, victim dies; destroy cloak 2996 and shirt now in case target gets life-saved */ 2997 tmp = MAGIC_COOKIE; 2998 if ((otmp2 = which_armor(mon, W_ARMC)) != 0) 2999 m_useup(mon, otmp2); 3000#ifdef TOURIST 3001 if ((otmp2 = which_armor(mon, W_ARMU)) != 0) 3002 m_useup(mon, otmp2); 3003#endif 3004 } 3005 type = -1; /* no saving throw wanted */ 3006 break; /* not ordinary damage */ 3007 } 3008 tmp = mon->mhp+1; 3009 break; 3010 case ZT_LIGHTNING: 3011 if (resists_elec(mon)) { 3012 sho_shieldeff = TRUE; 3013 tmp = 0; 3014 /* can still blind the monster */ 3015 } else 3016 tmp = d(nd,6); 3017 if (spellcaster) 3018 tmp += spell_damage_bonus(); 3019#ifdef WIZ_PATCH_DEBUG 3020 if (spellcaster) 3021 pline("Damage = %d + %d", tmp-spell_damage_bonus(), 3022 spell_damage_bonus()); 3023#endif 3024 if (!resists_blnd(mon) && 3025 !(type > 0 && u.uswallow && mon == u.ustuck)) { 3026 register unsigned rnd_tmp = rnd(50); 3027 mon->mcansee = 0; 3028 if((mon->mblinded + rnd_tmp) > 127) 3029 mon->mblinded = 127; 3030 else mon->mblinded += rnd_tmp; 3031 } 3032 if (!rn2(3)) (void)destroy_mitem(mon, WAND_CLASS, AD_ELEC); 3033 /* not actually possible yet */ 3034 if (!rn2(3)) (void)destroy_mitem(mon, RING_CLASS, AD_ELEC); 3035 break; 3036 case ZT_POISON_GAS: 3037 if (resists_poison(mon)) { 3038 sho_shieldeff = TRUE; 3039 break; 3040 } 3041 tmp = d(nd,6); 3042 break; 3043 case ZT_ACID: 3044 if (resists_acid(mon)) { 3045 sho_shieldeff = TRUE; 3046 break; 3047 } 3048 tmp = d(nd,6); 3049 if (!rn2(6)) erode_obj(MON_WEP(mon), TRUE, TRUE); 3050 if (!rn2(6)) erode_armor(mon, TRUE); 3051 break; 3052 } 3053 if (sho_shieldeff) shieldeff(mon->mx, mon->my); 3054 if (is_hero_spell(type) && (Role_if(PM_KNIGHT) && u.uhave.questart)) 3055 tmp *= 2; 3056 if (tmp > 0 && type >= 0 && 3057 resist(mon, type < ZT_SPELL(0) ? WAND_CLASS : '\0', 0, NOTELL)) 3058 tmp /= 2; 3059 if (tmp < 0) tmp = 0; /* don't allow negative damage */ 3060#ifdef WIZ_PATCH_DEBUG 3061 pline("zapped monster hp = %d (= %d - %d)", mon->mhp-tmp,mon->mhp,tmp); 3062#endif 3063 mon->mhp -= tmp; 3064 return(tmp); 3065} 3066 3067STATIC_OVL void 3068zhitu(type, nd, fltxt, sx, sy) 3069int type, nd; 3070const char *fltxt; 3071xchar sx, sy; 3072{ 3073 int dam = 0; 3074 3075 switch (abs(type) % 10) { 3076 case ZT_MAGIC_MISSILE: 3077 if (Antimagic) { 3078 shieldeff(sx, sy); 3079 pline_The("missiles bounce off!"); 3080 } else { 3081 dam = d(nd,6); 3082 exercise(A_STR, FALSE); 3083 } 3084 break; 3085 case ZT_FIRE: 3086 if (Fire_resistance) { 3087 shieldeff(sx, sy); 3088 You("don't feel hot!"); 3089 ugolemeffects(AD_FIRE, d(nd, 6)); 3090 } else { 3091 dam = d(nd, 6); 3092 } 3093 burn_away_slime(); 3094 if (burnarmor(&youmonst)) { /* "body hit" */ 3095 if (!rn2(3)) destroy_item(POTION_CLASS, AD_FIRE); 3096 if (!rn2(3)) destroy_item(SCROLL_CLASS, AD_FIRE); 3097 if (!rn2(5)) destroy_item(SPBOOK_CLASS, AD_FIRE); 3098 } 3099 break; 3100 case ZT_COLD: 3101 if (Cold_resistance) { 3102 shieldeff(sx, sy); 3103 You("don't feel cold."); 3104 ugolemeffects(AD_COLD, d(nd, 6)); 3105 } else { 3106 dam = d(nd, 6); 3107 } 3108 if (!rn2(3)) destroy_item(POTION_CLASS, AD_COLD); 3109 break; 3110 case ZT_SLEEP: 3111 if (Sleep_resistance) { 3112 shieldeff(u.ux, u.uy); 3113 You("don't feel sleepy."); 3114 } else { 3115 fall_asleep(-d(nd,25), TRUE); /* sleep ray */ 3116 } 3117 break; 3118 case ZT_DEATH: 3119 if (abs(type) == ZT_BREATH(ZT_DEATH)) { 3120 if (Disint_resistance) { 3121 You("are not disintegrated."); 3122 break; 3123 } else if (uarms) { 3124 /* destroy shield; other possessions are safe */ 3125 (void) destroy_arm(uarms); 3126 break; 3127 } else if (uarm) { 3128 /* destroy suit; if present, cloak goes too */ 3129 if (uarmc) (void) destroy_arm(uarmc); 3130 (void) destroy_arm(uarm); 3131 break; 3132 } 3133 /* no shield or suit, you're dead; wipe out cloak 3134 and/or shirt in case of life-saving or bones */ 3135 if (uarmc) (void) destroy_arm(uarmc); 3136#ifdef TOURIST 3137 if (uarmu) (void) destroy_arm(uarmu); 3138#endif 3139 } else if (nonliving(youmonst.data) || is_demon(youmonst.data)) { 3140 shieldeff(sx, sy); 3141 You("seem unaffected."); 3142 break; 3143 } else if (Antimagic) { 3144 shieldeff(sx, sy); 3145 You("aren't affected."); 3146 break; 3147 } 3148 killer_format = KILLED_BY_AN; 3149 killer = fltxt; 3150 /* when killed by disintegration breath, don't leave corpse */ 3151 u.ugrave_arise = (type == -ZT_BREATH(ZT_DEATH)) ? -3 : NON_PM; 3152 done(DIED); 3153 return; /* lifesaved */ 3154 case ZT_LIGHTNING: 3155 if (Shock_resistance) { 3156 shieldeff(sx, sy); 3157 You("aren't affected."); 3158 ugolemeffects(AD_ELEC, d(nd, 6)); 3159 } else { 3160 dam = d(nd, 6); 3161 exercise(A_CON, FALSE); 3162 } 3163 if (!rn2(3)) destroy_item(WAND_CLASS, AD_ELEC); 3164 if (!rn2(3)) destroy_item(RING_CLASS, AD_ELEC); 3165 break; 3166 case ZT_POISON_GAS: 3167 poisoned("blast", A_DEX, "poisoned blast", 15); 3168 break; 3169 case ZT_ACID: 3170 if (Acid_resistance) { 3171 dam = 0; 3172 } else { 3173 pline_The("acid burns!"); 3174 dam = d(nd,6); 3175 exercise(A_STR, FALSE); 3176 } 3177 /* using two weapons at once makes both of them more vulnerable */ 3178 if (!rn2(u.twoweap ? 3 : 6)) erode_obj(uwep, TRUE, TRUE); 3179 if (u.twoweap && !rn2(3)) erode_obj(uswapwep, TRUE, TRUE); 3180 if (!rn2(6)) erode_armor(&youmonst, TRUE); 3181 break; 3182 } 3183 3184 if (Half_spell_damage && dam && 3185 type < 0 && (type > -20 || type < -29)) /* !Breath */ 3186 dam = (dam + 1) / 2; 3187 losehp(dam, fltxt, KILLED_BY_AN); 3188 return; 3189} 3190 3191#endif /*OVL1*/ 3192#ifdef OVLB 3193 3194/* 3195 * burn scrolls and spellbooks on floor at position x,y 3196 * return the number of scrolls and spellbooks burned 3197 */ 3198int 3199burn_floor_paper(x, y, give_feedback, u_caused) 3200int x, y; 3201boolean give_feedback; /* caller needs to decide about visibility checks */ 3202boolean u_caused; 3203{ 3204 struct obj *obj, *obj2; 3205 long i, scrquan, delquan; 3206 char buf1[BUFSZ], buf2[BUFSZ]; 3207 int cnt = 0; 3208 3209 for (obj = level.objects[x][y]; obj; obj = obj2) { 3210 obj2 = obj->nexthere; 3211 if (obj->oclass == SCROLL_CLASS || obj->oclass == SPBOOK_CLASS) { 3212 if (obj->otyp == SCR_FIRE || obj->otyp == SPE_FIREBALL || 3213 obj_resists(obj, 2, 100)) 3214 continue; 3215 scrquan = obj->quan; /* number present */ 3216 delquan = 0; /* number to destroy */ 3217 for (i = scrquan; i > 0; i--) 3218 if (!rn2(3)) delquan++; 3219 if (delquan) { 3220 /* save name before potential delobj() */ 3221 if (give_feedback) { 3222 obj->quan = 1; 3223 Strcpy(buf1, (x == u.ux && y == u.uy) ? 3224 xname(obj) : distant_name(obj, xname)); 3225 obj->quan = 2; 3226 Strcpy(buf2, (x == u.ux && y == u.uy) ? 3227 xname(obj) : distant_name(obj, xname)); 3228 obj->quan = scrquan; 3229 } 3230 /* useupf(), which charges, only if hero caused damage */ 3231 if (u_caused) useupf(obj, delquan); 3232 else if (delquan < scrquan) obj->quan -= delquan; 3233 else delobj(obj); 3234 cnt += delquan; 3235 if (give_feedback) { 3236 if (delquan > 1) 3237 pline("%ld %s burn.", delquan, buf2); 3238 else 3239 pline("%s burns.", An(buf1)); 3240 } 3241 } 3242 } 3243 } 3244 return cnt; 3245} 3246 3247/* will zap/spell/breath attack score a hit against armor class `ac'? */ 3248STATIC_OVL int 3249zap_hit(ac, type) 3250int ac; 3251int type; /* either hero cast spell type or 0 */ 3252{ 3253 int chance = rn2(20); 3254 int spell_bonus = type ? spell_hit_bonus(type) : 0; 3255 3256 /* small chance for naked target to avoid being hit */ 3257 if (!chance) return rnd(10) < ac+spell_bonus; 3258 3259 /* very high armor protection does not achieve invulnerability */ 3260 ac = AC_VALUE(ac); 3261 3262 return (3 - chance) < ac+spell_bonus; 3263} 3264 3265/* type == 0 to 9 : you shooting a wand */ 3266/* type == 10 to 19 : you casting a spell */ 3267/* type == 20 to 29 : you breathing as a monster */ 3268/* type == -10 to -19 : monster casting spell */ 3269/* type == -20 to -29 : monster breathing at you */ 3270/* type == -30 to -39 : monster shooting a wand */ 3271/* called with dx = dy = 0 with vertical bolts */ 3272void 3273buzz(type,nd,sx,sy,dx,dy) 3274register int type, nd; 3275register xchar sx,sy; 3276register int dx,dy; 3277{ 3278 int range, abstype = abs(type) % 10; 3279 struct rm *lev; 3280 register xchar lsx, lsy; 3281 struct monst *mon; 3282 coord save_bhitpos; 3283 boolean shopdamage = FALSE; 3284 register const char *fltxt; 3285 struct obj *otmp; 3286 int spell_type; 3287 3288 /* if its a Hero Spell then get its SPE_TYPE */ 3289 spell_type = is_hero_spell(type) ? SPE_MAGIC_MISSILE + abstype : 0; 3290 3291 fltxt = flash_types[(type <= -30) ? abstype : abs(type)]; 3292 if(u.uswallow) { 3293 register int tmp; 3294 3295 if(type < 0) return; 3296 tmp = zhitm(u.ustuck, type, nd, &otmp); 3297 if(!u.ustuck) u.uswallow = 0; 3298 else pline("%s rips into %s%s", 3299 The(fltxt), mon_nam(u.ustuck), exclam(tmp)); 3300 /* Using disintegration from the inside only makes a hole... */ 3301 if (tmp == MAGIC_COOKIE) 3302 u.ustuck->mhp = 0; 3303 if (u.ustuck->mhp < 1) 3304 killed(u.ustuck); 3305 return; 3306 } 3307 if(type < 0) newsym(u.ux,u.uy); 3308 range = rn1(7,7); 3309 if(dx == 0 && dy == 0) range = 1; 3310 save_bhitpos = bhitpos; 3311 3312 tmp_at(DISP_BEAM, zapdir_to_glyph(dx, dy, abstype)); 3313 while(range-- > 0) { 3314 lsx = sx; sx += dx; 3315 lsy = sy; sy += dy; 3316 if(isok(sx,sy) && (lev = &levl[sx][sy])->typ) { 3317 mon = m_at(sx, sy); 3318 if(cansee(sx,sy)) { 3319 /* reveal/unreveal invisible monsters before tmp_at() */ 3320 if (mon && !canspotmon(mon)) 3321 map_invisible(sx, sy); 3322 else if (!mon && glyph_is_invisible(levl[sx][sy].glyph)) { 3323 unmap_object(sx, sy); 3324 newsym(sx, sy); 3325 } 3326 if(ZAP_POS(lev->typ) || cansee(lsx,lsy)) 3327 tmp_at(sx,sy); 3328 delay_output(); /* wait a little */ 3329 } 3330 } else 3331 goto make_bounce; 3332 3333 /* hit() and miss() need bhitpos to match the target */ 3334 bhitpos.x = sx, bhitpos.y = sy; 3335 /* Fireballs only damage when they explode */ 3336 if (type != ZT_SPELL(ZT_FIRE)) 3337 range += zap_over_floor(sx, sy, type, &shopdamage); 3338 3339 if (mon) { 3340 if (type == ZT_SPELL(ZT_FIRE)) break; 3341 if (type >= 0) mon->mstrategy &= ~STRAT_WAITMASK; 3342#ifdef STEED 3343 buzzmonst: 3344#endif 3345 if (zap_hit(find_mac(mon), spell_type)) { 3346 if (mon_reflects(mon, (char *)0)) { 3347 if(cansee(mon->mx,mon->my)) { 3348 hit(fltxt, mon, exclam(0)); 3349 shieldeff(mon->mx, mon->my); 3350 (void) mon_reflects(mon, "But it reflects from %s %s!"); 3351 } 3352 dx = -dx; 3353 dy = -dy; 3354 } else { 3355 boolean mon_could_move = mon->mcanmove; 3356 int tmp = zhitm(mon, type, nd, &otmp); 3357 3358 if (is_rider(mon->data) && abs(type) == ZT_BREATH(ZT_DEATH)) { 3359 if (canseemon(mon)) { 3360 hit(fltxt, mon, "."); 3361 pline("%s disintegrates.", Monnam(mon)); 3362 pline("%s body reintegrates before your %s!", 3363 s_suffix(Monnam(mon)), 3364 (eyecount(youmonst.data) == 1) ? 3365 body_part(EYE) : makeplural(body_part(EYE))); 3366 pline("%s resurrects!", Monnam(mon)); 3367 } 3368 mon->mhp = mon->mhpmax; 3369 break; /* Out of while loop */ 3370 } 3371 if (mon->data == &mons[PM_DEATH] && abstype == ZT_DEATH) { 3372 if (canseemon(mon)) { 3373 hit(fltxt, mon, "."); 3374 pline("%s absorbs the deadly %s!", Monnam(mon), 3375 type == ZT_BREATH(ZT_DEATH) ? 3376 "blast" : "ray"); 3377 pline("It seems even stronger than before."); 3378 } 3379 break; /* Out of while loop */ 3380 } 3381 3382 if (tmp == MAGIC_COOKIE) { /* disintegration */ 3383 struct obj *otmp2, *m_amulet = mlifesaver(mon); 3384 3385 if (canseemon(mon)) { 3386 if (!m_amulet) 3387 pline("%s is disintegrated!", Monnam(mon)); 3388 else 3389 hit(fltxt, mon, "!"); 3390 } 3391#ifndef GOLDOBJ 3392 mon->mgold = 0L; 3393#endif 3394 3395/* note: worn amulet of life saving must be preserved in order to operate */ 3396#define oresist_disintegration(obj) \ 3397 (objects[obj->otyp].oc_oprop == DISINT_RES || \ 3398 obj_resists(obj, 5, 50) || is_quest_artifact(obj) || \ 3399 obj == m_amulet) 3400 3401 for (otmp = mon->minvent; otmp; otmp = otmp2) { 3402 otmp2 = otmp->nobj; 3403 if (!oresist_disintegration(otmp)) { 3404 obj_extract_self(otmp); 3405 obfree(otmp, (struct obj *)0); 3406 } 3407 } 3408 3409 if (type < 0) 3410 monkilled(mon, (char *)0, -AD_RBRE); 3411 else 3412 xkilled(mon, 2); 3413 } else if(mon->mhp < 1) { 3414 if(type < 0) 3415 monkilled(mon, fltxt, AD_RBRE); 3416 else 3417 killed(mon); 3418 } else { 3419 if (!otmp) { 3420 /* normal non-fatal hit */ 3421 hit(fltxt, mon, exclam(tmp)); 3422 } else { 3423 /* some armor was destroyed; no damage done */ 3424 if (canseemon(mon)) 3425 pline("%s %s is disintegrated!", 3426 s_suffix(Monnam(mon)), 3427 distant_name(otmp, xname)); 3428 m_useup(mon, otmp); 3429 } 3430 if (mon_could_move && !mon->mcanmove) /* ZT_SLEEP */ 3431 slept_monst(mon); 3432 } 3433 } 3434 range -= 2; 3435 } else { 3436 miss(fltxt,mon); 3437 } 3438 } else if (sx == u.ux && sy == u.uy && range >= 0) { 3439 nomul(0); 3440#ifdef STEED 3441 if (u.usteed && !rn2(3) && !mon_reflects(u.usteed, (char *)0)) { 3442 mon = u.usteed; 3443 goto buzzmonst; 3444 } else 3445#endif 3446 if (zap_hit((int) u.uac, 0)) { 3447 range -= 2; 3448 pline("%s hits you!", The(fltxt)); 3449 if (Reflecting) { 3450 if (!Blind) { 3451 (void) ureflects("But %s reflects from your %s!", "it"); 3452 } else 3453 pline("For some reason you are not affected."); 3454 dx = -dx; 3455 dy = -dy; 3456 shieldeff(sx, sy); 3457 } else { 3458 zhitu(type, nd, fltxt, sx, sy); 3459 } 3460 } else { 3461 pline("%s whizzes by you!", The(fltxt)); 3462 } 3463 if (abstype == ZT_LIGHTNING && !resists_blnd(&youmonst)) { 3464 You(are_blinded_by_the_flash); 3465 make_blinded((long)d(nd,50),FALSE); 3466 if (!Blind) Your(vision_clears); 3467 } 3468 stop_occupation(); 3469 nomul(0); 3470 } 3471 3472 if(!ZAP_POS(lev->typ) || (closed_door(sx, sy) && (range >= 0))) { 3473 int bounce; 3474 uchar rmn; 3475 3476 make_bounce: 3477 if (type == ZT_SPELL(ZT_FIRE)) { 3478 sx = lsx; 3479 sy = lsy; 3480 break; /* fireballs explode before the wall */ 3481 } 3482 bounce = 0; 3483 range--; 3484 if(range && isok(lsx, lsy) && cansee(lsx,lsy)) 3485 pline("%s bounces!", The(fltxt)); 3486 if(!dx || !dy || !rn2(20)) { 3487 dx = -dx; 3488 dy = -dy; 3489 } else { 3490 if(isok(sx,lsy) && ZAP_POS(rmn = levl[sx][lsy].typ) && 3491 !closed_door(sx,lsy) && 3492 (IS_ROOM(rmn) || (isok(sx+dx,lsy) && 3493 ZAP_POS(levl[sx+dx][lsy].typ)))) 3494 bounce = 1; 3495 if(isok(lsx,sy) && ZAP_POS(rmn = levl[lsx][sy].typ) && 3496 !closed_door(lsx,sy) && 3497 (IS_ROOM(rmn) || (isok(lsx,sy+dy) && 3498 ZAP_POS(levl[lsx][sy+dy].typ)))) 3499 if(!bounce || rn2(2)) 3500 bounce = 2; 3501 3502 switch(bounce) { 3503 case 0: dx = -dx; /* fall into... */ 3504 case 1: dy = -dy; break; 3505 case 2: dx = -dx; break; 3506 } 3507 tmp_at(DISP_CHANGE, zapdir_to_glyph(dx,dy,abstype)); 3508 } 3509 } 3510 } 3511 tmp_at(DISP_END,0); 3512 if (type == ZT_SPELL(ZT_FIRE)) 3513 explode(sx, sy, type, d(12,6), 0, EXPL_FIERY); 3514 if (shopdamage) 3515 pay_for_damage(abstype == ZT_FIRE ? "burn away" : 3516 abstype == ZT_COLD ? "shatter" : 3517 abstype == ZT_DEATH ? "disintegrate" : "destroy", FALSE); 3518 bhitpos = save_bhitpos; 3519} 3520#endif /*OVLB*/ 3521#ifdef OVL0 3522 3523void 3524melt_ice(x, y) 3525xchar x, y; 3526{ 3527 struct rm *lev = &levl[x][y]; 3528 struct obj *otmp; 3529 3530 if (lev->typ == DRAWBRIDGE_UP) 3531 lev->drawbridgemask &= ~DB_ICE; /* revert to DB_MOAT */ 3532 else { /* lev->typ == ICE */ 3533#ifdef STUPID 3534 if (lev->icedpool == ICED_POOL) lev->typ = POOL; 3535 else lev->typ = MOAT; 3536#else 3537 lev->typ = (lev->icedpool == ICED_POOL ? POOL : MOAT); 3538#endif 3539 lev->icedpool = 0; 3540 } 3541 obj_ice_effects(x, y, FALSE); 3542 unearth_objs(x, y); 3543 if (Underwater) vision_recalc(1); 3544 newsym(x,y); 3545 if (cansee(x,y)) Norep("The ice crackles and melts."); 3546 if ((otmp = sobj_at(BOULDER, x, y)) != 0) { 3547 if (cansee(x,y)) pline("%s settles...", An(xname(otmp))); 3548 do { 3549 obj_extract_self(otmp); /* boulder isn't being pushed */ 3550 if (!boulder_hits_pool(otmp, x, y, FALSE)) 3551 impossible("melt_ice: no pool?"); 3552 /* try again if there's another boulder and pool didn't fill */ 3553 } while (is_pool(x,y) && (otmp = sobj_at(BOULDER, x, y)) != 0); 3554 newsym(x,y); 3555 } 3556 if (x == u.ux && y == u.uy) 3557 spoteffects(TRUE); /* possibly drown, notice objects */ 3558} 3559 3560/* Burn floor scrolls, evaporate pools, etc... in a single square. Used 3561 * both for normal bolts of fire, cold, etc... and for fireballs. 3562 * Sets shopdamage to TRUE if a shop door is destroyed, and returns the 3563 * amount by which range is reduced (the latter is just ignored by fireballs) 3564 */ 3565int 3566zap_over_floor(x, y, type, shopdamage) 3567xchar x, y; 3568int type; 3569boolean *shopdamage; 3570{ 3571 struct monst *mon; 3572 int abstype = abs(type) % 10; 3573 struct rm *lev = &levl[x][y]; 3574 int rangemod = 0; 3575 3576 if(abstype == ZT_FIRE) { 3577 struct trap *t = t_at(x, y); 3578 3579 if (t && t->ttyp == WEB) { 3580 /* a burning web is too flimsy to notice if you can't see it */ 3581 if (cansee(x,y)) Norep("A web bursts into flames!"); 3582 (void) delfloortrap(t); 3583 if (cansee(x,y)) newsym(x,y); 3584 } 3585 if(is_ice(x, y)) { 3586 melt_ice(x, y); 3587 } else if(is_pool(x,y)) { 3588 const char *msgtxt = "You hear hissing gas."; 3589 if(lev->typ != POOL) { /* MOAT or DRAWBRIDGE_UP */ 3590 if (cansee(x,y)) msgtxt = "Some water evaporates."; 3591 } else { 3592 register struct trap *ttmp; 3593 3594 rangemod -= 3; 3595 lev->typ = ROOM; 3596 ttmp = maketrap(x, y, PIT); 3597 if (ttmp) ttmp->tseen = 1; 3598 if (cansee(x,y)) msgtxt = "The water evaporates."; 3599 } 3600 Norep(msgtxt); 3601 if (lev->typ == ROOM) newsym(x,y); 3602 } else if(IS_FOUNTAIN(lev->typ)) { 3603 if (cansee(x,y)) 3604 pline("Steam billows from the fountain."); 3605 rangemod -= 1; 3606 dryup(x, y, type > 0); 3607 } 3608 } 3609 else if(abstype == ZT_COLD && (is_pool(x,y) || is_lava(x,y))) { 3610 boolean lava = is_lava(x,y); 3611 boolean moat = (!lava && (lev->typ != POOL) && 3612 (lev->typ != WATER) && 3613 !Is_medusa_level(&u.uz) && 3614 !Is_waterlevel(&u.uz)); 3615 3616 if (lev->typ == WATER) { 3617 /* For now, don't let WATER freeze. */ 3618 if (cansee(x,y)) 3619 pline_The("water freezes for a moment."); 3620 else 3621 You_hear("a soft crackling."); 3622 rangemod -= 1000; /* stop */ 3623 } else { 3624 rangemod -= 3; 3625 if (lev->typ == DRAWBRIDGE_UP) { 3626 lev->drawbridgemask &= ~DB_UNDER; /* clear lava */ 3627 lev->drawbridgemask |= (lava ? DB_FLOOR : DB_ICE); 3628 } else { 3629 if (!lava) 3630 lev->icedpool = 3631 (lev->typ == POOL ? ICED_POOL : ICED_MOAT); 3632 lev->typ = (lava ? ROOM : ICE); 3633 } 3634 bury_objs(x,y); 3635 if(cansee(x,y)) { 3636 if(moat) 3637 Norep("The moat is bridged with ice!"); 3638 else if(lava) 3639 Norep("The lava cools and solidifies."); 3640 else 3641 Norep("The water freezes."); 3642 newsym(x,y); 3643 } else if(flags.soundok && !lava) 3644 You_hear("a crackling sound."); 3645 3646 if (x == u.ux && y == u.uy) { 3647 if (u.uinwater) { /* not just `if (Underwater)' */ 3648 /* leave the no longer existent water */ 3649 u.uinwater = 0; 3650 u.uundetected = 0; 3651 docrt(); 3652 vision_full_recalc = 1; 3653 } else if (u.utrap && u.utraptype == TT_LAVA) { 3654 if (Passes_walls) { 3655 You("pass through the now-solid rock."); 3656 } else { 3657 u.utrap = rn1(50,20); 3658 u.utraptype = TT_INFLOOR; 3659 You("are firmly stuck in the cooling rock."); 3660 } 3661 } 3662 } else if ((mon = m_at(x,y)) != 0) { 3663 /* probably ought to do some hefty damage to any 3664 non-ice creature caught in freezing water; 3665 at a minimum, eels are forced out of hiding */ 3666 if (is_swimmer(mon->data) && mon->mundetected) { 3667 mon->mundetected = 0; 3668 newsym(x,y); 3669 } 3670 } 3671 } 3672 obj_ice_effects(x,y,TRUE); 3673 } 3674 if(closed_door(x, y)) { 3675 int new_doormask = -1; 3676 const char *see_txt = 0, *sense_txt = 0, *hear_txt = 0; 3677 rangemod = -1000; 3678 switch(abstype) { 3679 case ZT_FIRE: 3680 new_doormask = D_NODOOR; 3681 see_txt = "The door is consumed in flames!"; 3682 sense_txt = "smell smoke."; 3683 break; 3684 case ZT_COLD: 3685 new_doormask = D_NODOOR; 3686 see_txt = "The door freezes and shatters!"; 3687 sense_txt = "feel cold."; 3688 break; 3689 case ZT_DEATH: 3690 /* death spells/wands don't disintegrate */ 3691 if(abs(type) != ZT_BREATH(ZT_DEATH)) 3692 goto def_case; 3693 new_doormask = D_NODOOR; 3694 see_txt = "The door disintegrates!"; 3695 hear_txt = "crashing wood."; 3696 break; 3697 case ZT_LIGHTNING: 3698 new_doormask = D_BROKEN; 3699 see_txt = "The door splinters!"; 3700 hear_txt = "crackling."; 3701 break; 3702 default: 3703 def_case: 3704 if(cansee(x,y)) { 3705 pline_The("door absorbs %s %s!", 3706 (type < 0) ? "the" : "your", 3707 abs(type) < ZT_SPELL(0) ? "bolt" : 3708 abs(type) < ZT_BREATH(0) ? "spell" : 3709 "blast"); 3710 } else You_feel("vibrations."); 3711 break; 3712 } 3713 if (new_doormask >= 0) { /* door gets broken */ 3714 if (*in_rooms(x, y, SHOPBASE)) { 3715 if (type >= 0) { 3716 add_damage(x, y, 400L); 3717 *shopdamage = TRUE; 3718 } else /* caused by monster */ 3719 add_damage(x, y, 0L); 3720 } 3721 lev->doormask = new_doormask; 3722 unblock_point(x, y); /* vision */ 3723 if (cansee(x, y)) { 3724 pline(see_txt); 3725 newsym(x, y); 3726 } else if (sense_txt) { 3727 You(sense_txt); 3728 } else if (hear_txt) { 3729 if (flags.soundok) You_hear(hear_txt); 3730 } 3731 if (picking_at(x, y)) { 3732 stop_occupation(); 3733 reset_pick(); 3734 } 3735 } 3736 } 3737 3738 if(OBJ_AT(x, y) && abstype == ZT_FIRE) 3739 if (burn_floor_paper(x, y, FALSE, type > 0) && couldsee(x, y)) { 3740 newsym(x,y); 3741 You("%s of smoke.", 3742 !Blind ? "see a puff" : "smell a whiff"); 3743 } 3744 if ((mon = m_at(x,y)) != 0) { 3745 /* Cannot use wakeup() which also angers the monster */ 3746 mon->msleeping = 0; 3747 if(mon->m_ap_type) seemimic(mon); 3748 if(type >= 0) { 3749 setmangry(mon); 3750 if(mon->ispriest && *in_rooms(mon->mx, mon->my, TEMPLE)) 3751 ghod_hitsu(mon); 3752 if(mon->isshk && !*u.ushops) 3753 hot_pursuit(mon); 3754 } 3755 } 3756 return rangemod; 3757} 3758 3759#endif /*OVL0*/ 3760#ifdef OVL3 3761 3762void 3763fracture_rock(obj) /* fractured by pick-axe or wand of striking */ 3764register struct obj *obj; /* no texts here! */ 3765{ 3766 /* A little Sokoban guilt... */ 3767 if (obj->otyp == BOULDER && In_sokoban(&u.uz) && !flags.mon_moving) 3768 change_luck(-1); 3769 3770 obj->otyp = ROCK; 3771 obj->quan = (long) rn1(60, 7); 3772 obj->owt = weight(obj); 3773 obj->oclass = GEM_CLASS; 3774 obj->known = FALSE; 3775 obj->onamelth = 0; /* no names */ 3776 obj->oxlth = 0; /* no extra data */ 3777 obj->oattached = OATTACHED_NOTHING; 3778 if (obj->where == OBJ_FLOOR) { 3779 obj_extract_self(obj); /* move rocks back on top */ 3780 place_object(obj, obj->ox, obj->oy); 3781 if(!does_block(obj->ox,obj->oy,&levl[obj->ox][obj->oy])) 3782 unblock_point(obj->ox,obj->oy); 3783 if(cansee(obj->ox,obj->oy)) 3784 newsym(obj->ox,obj->oy); 3785 } 3786} 3787 3788/* handle statue hit by striking/force bolt/pick-axe */ 3789boolean 3790break_statue(obj) 3791register struct obj *obj; 3792{ 3793 /* [obj is assumed to be on floor, so no get_obj_location() needed] */ 3794 struct trap *trap = t_at(obj->ox, obj->oy); 3795 struct obj *item; 3796 3797 if (trap && trap->ttyp == STATUE_TRAP && 3798 activate_statue_trap(trap, obj->ox, obj->oy, TRUE)) 3799 return FALSE; 3800 /* drop any objects contained inside the statue */ 3801 while ((item = obj->cobj) != 0) { 3802 obj_extract_self(item); 3803 place_object(item, obj->ox, obj->oy); 3804 } 3805 if (Role_if(PM_ARCHEOLOGIST) && !flags.mon_moving && (obj->spe & STATUE_HISTORIC)) { 3806 You_feel("guilty about damaging such a historic statue."); 3807 adjalign(-1); 3808 } 3809 obj->spe = 0; 3810 fracture_rock(obj); 3811 return TRUE; 3812} 3813 3814const char * const destroy_strings[] = { /* also used in trap.c */ 3815 "freezes and shatters", "freeze and shatter", "shattered potion", 3816 "boils and explodes", "boil and explode", "boiling potion", 3817 "catches fire and burns", "catch fire and burn", "burning scroll", 3818 "catches fire and burns", "catch fire and burn", "burning book", 3819 "turns to dust and vanishes", "turn to dust and vanish", "", 3820 "breaks apart and explodes", "break apart and explode", "exploding wand" 3821}; 3822 3823void 3824destroy_item(osym, dmgtyp) 3825register int osym, dmgtyp; 3826{ 3827 register struct obj *obj, *obj2; 3828 register int dmg, xresist, skip; 3829 register long i, cnt, quan; 3830 register int dindx; 3831 const char *mult; 3832 3833 for(obj = invent; obj; obj = obj2) { 3834 obj2 = obj->nobj; 3835 if(obj->oclass != osym) continue; /* test only objs of type osym */ 3836 if(obj->oartifact) continue; /* don't destroy artifacts */ 3837 if(obj->in_use && obj->quan == 1) continue; /* not available */ 3838 xresist = skip = 0; 3839#ifdef GCC_WARN 3840 dmg = dindx = 0; 3841 quan = 0L; 3842#endif 3843 switch(dmgtyp) { 3844 case AD_COLD: 3845 if(osym == POTION_CLASS && obj->otyp != POT_OIL) { 3846 quan = obj->quan; 3847 dindx = 0; 3848 dmg = rnd(4); 3849 } else skip++; 3850 break; 3851 case AD_FIRE: 3852 xresist = (Fire_resistance && obj->oclass != POTION_CLASS); 3853 3854 if (obj->otyp == SCR_FIRE || obj->otyp == SPE_FIREBALL) 3855 skip++; 3856 if (obj->otyp == SPE_BOOK_OF_THE_DEAD) { 3857 skip++; 3858 if (!Blind) 3859 pline("%s glows a strange %s, but remains intact.", 3860 The(xname(obj)), hcolor("dark red")); 3861 } 3862 quan = obj->quan; 3863 switch(osym) { 3864 case POTION_CLASS: 3865 dindx = 1; 3866 dmg = rnd(6); 3867 break; 3868 case SCROLL_CLASS: 3869 dindx = 2; 3870 dmg = 1; 3871 break; 3872 case SPBOOK_CLASS: 3873 dindx = 3; 3874 dmg = 1; 3875 break; 3876 default: 3877 skip++; 3878 break; 3879 } 3880 break; 3881 case AD_ELEC: 3882 xresist = (Shock_resistance && obj->oclass != RING_CLASS); 3883 quan = obj->quan; 3884 switch(osym) { 3885 case RING_CLASS: 3886 if(obj->otyp == RIN_SHOCK_RESISTANCE) 3887 { skip++; break; } 3888 dindx = 4; 3889 dmg = 0; 3890 break; 3891 case WAND_CLASS: 3892 if(obj->otyp == WAN_LIGHTNING) { skip++; break; } 3893#if 0 3894 if (obj == current_wand) { skip++; break; } 3895#endif 3896 dindx = 5; 3897 dmg = rnd(10); 3898 break; 3899 default: 3900 skip++; 3901 break; 3902 } 3903 break; 3904 default: 3905 skip++; 3906 break; 3907 } 3908 if(!skip) { 3909 if (obj->in_use) --quan; /* one will be used up elsewhere */ 3910 for(i = cnt = 0L; i < quan; i++) 3911 if(!rn2(3)) cnt++; 3912 3913 if(!cnt) continue; 3914 if(cnt == quan) mult = "Your"; 3915 else mult = (cnt == 1L) ? "One of your" : "Some of your"; 3916 pline("%s %s %s!", mult, xname(obj), 3917 (cnt > 1L) ? destroy_strings[dindx*3 + 1] 3918 : destroy_strings[dindx*3]); 3919 if(osym == POTION_CLASS && dmgtyp != AD_COLD) { 3920 if (!breathless(youmonst.data) || haseyes(youmonst.data)) 3921 potionbreathe(obj); 3922 } 3923 if (obj->owornmask) { 3924 if (obj->owornmask & W_RING) /* ring being worn */ 3925 Ring_gone(obj); 3926 else 3927 setnotworn(obj); 3928 } 3929 if (obj == current_wand) current_wand = 0; /* destroyed */ 3930 for (i = 0; i < cnt; i++) 3931 useup(obj); 3932 if(dmg) { 3933 if(xresist) You("aren't hurt!"); 3934 else { 3935 const char *how = destroy_strings[dindx * 3 + 2]; 3936 boolean one = (cnt == 1L); 3937 3938 losehp(dmg, one ? how : (const char *)makeplural(how), 3939 one ? KILLED_BY_AN : KILLED_BY); 3940 exercise(A_STR, FALSE); 3941 } 3942 } 3943 } 3944 } 3945 return; 3946} 3947 3948int 3949destroy_mitem(mtmp, osym, dmgtyp) 3950struct monst *mtmp; 3951int osym, dmgtyp; 3952{ 3953 struct obj *obj, *obj2; 3954 int skip, tmp = 0; 3955 long i, cnt, quan; 3956 int dindx; 3957 boolean vis; 3958 3959 if (mtmp == &youmonst) { /* this simplifies artifact_hit() */ 3960 destroy_item(osym, dmgtyp); 3961 return 0; /* arbitrary; value doesn't matter to artifact_hit() */ 3962 } 3963 3964 vis = canseemon(mtmp); 3965 for(obj = mtmp->minvent; obj; obj = obj2) { 3966 obj2 = obj->nobj; 3967 if(obj->oclass != osym) continue; /* test only objs of type osym */ 3968 skip = 0; 3969 quan = 0L; 3970 dindx = 0; 3971 3972 switch(dmgtyp) { 3973 case AD_COLD: 3974 if(osym == POTION_CLASS && obj->otyp != POT_OIL) { 3975 quan = obj->quan; 3976 dindx = 0; 3977 tmp++; 3978 } else skip++; 3979 break; 3980 case AD_FIRE: 3981 if (obj->otyp == SCR_FIRE || obj->otyp == SPE_FIREBALL) 3982 skip++; 3983 if (obj->otyp == SPE_BOOK_OF_THE_DEAD) { 3984 skip++; 3985 if (vis) 3986 pline("%s glows a strange %s, but remains intact.", 3987 The(distant_name(obj, xname)), 3988 hcolor("dark red")); 3989 } 3990 quan = obj->quan; 3991 switch(osym) { 3992 case POTION_CLASS: 3993 dindx = 1; 3994 tmp++; 3995 break; 3996 case SCROLL_CLASS: 3997 dindx = 2; 3998 tmp++; 3999 break; 4000 case SPBOOK_CLASS: 4001 dindx = 3; 4002 tmp++; 4003 break; 4004 default: 4005 skip++; 4006 break; 4007 } 4008 break; 4009 case AD_ELEC: 4010 quan = obj->quan; 4011 switch(osym) { 4012 case RING_CLASS: 4013 if(obj->otyp == RIN_SHOCK_RESISTANCE) 4014 { skip++; break; } 4015 dindx = 4; 4016 break; 4017 case WAND_CLASS: 4018 if(obj->otyp == WAN_LIGHTNING) { skip++; break; } 4019 dindx = 5; 4020 tmp++; 4021 break; 4022 default: 4023 skip++; 4024 break; 4025 } 4026 break; 4027 default: 4028 skip++; 4029 break; 4030 } 4031 if(!skip) { 4032 for(i = cnt = 0L; i < quan; i++) 4033 if(!rn2(3)) cnt++; 4034 4035 if(!cnt) continue; 4036 if (vis) pline("%s %s %s!", 4037 s_suffix(Monnam(mtmp)), xname(obj), 4038 (cnt > 1L) ? destroy_strings[dindx*3 + 1] 4039 : destroy_strings[dindx*3]); 4040 for(i = 0; i < cnt; i++) m_useup(mtmp, obj); 4041 } 4042 } 4043 return(tmp); 4044} 4045 4046#endif /*OVL3*/ 4047#ifdef OVL2 4048 4049int 4050resist(mtmp, oclass, damage, tell) 4051struct monst *mtmp; 4052char oclass; 4053int damage, tell; 4054{ 4055 int resisted; 4056 int alev, dlev; 4057 4058 /* attack level */ 4059 switch (oclass) { 4060 case WAND_CLASS: alev = 12; break; 4061 case TOOL_CLASS: alev = 10; break; /* instrument */ 4062 case WEAPON_CLASS: alev = 10; break; /* artifact */ 4063 case SCROLL_CLASS: alev = 9; break; 4064 case POTION_CLASS: alev = 6; break; 4065 case RING_CLASS: alev = 5; break; 4066 default: alev = u.ulevel; break; /* spell */ 4067 } 4068 /* defense level */ 4069 dlev = (int)mtmp->m_lev; 4070 if (dlev > 50) dlev = 50; 4071 else if (dlev < 1) dlev = is_mplayer(mtmp->data) ? u.ulevel : 1; 4072 4073 resisted = rn2(100 + alev - dlev) < mtmp->data->mr; 4074 if (resisted) { 4075 if (tell) { 4076 shieldeff(mtmp->mx, mtmp->my); 4077 pline("%s resists!", Monnam(mtmp)); 4078 } 4079 damage = (damage + 1) / 2; 4080 } 4081 4082 if (damage) { 4083 mtmp->mhp -= damage; 4084 if (mtmp->mhp < 1) { 4085 if(m_using) monkilled(mtmp, "", AD_RBRE); 4086 else killed(mtmp); 4087 } 4088 } 4089 return(resisted); 4090} 4091 4092void 4093makewish() 4094{ 4095 char buf[BUFSZ]; 4096 struct obj *otmp, nothing; 4097 int tries = 0; 4098 4099 nothing = zeroobj; /* lint suppression; only its address matters */ 4100 if (flags.verbose) You("may wish for an object."); 4101retry: 4102 getlin("For what do you wish?", buf); 4103 if(buf[0] == '\033') buf[0] = 0; 4104 /* 4105 * Note: if they wished for and got a non-object successfully, 4106 * otmp == &zeroobj. That includes gold, or an artifact that 4107 * has been denied. Wishing for "nothing" requires a separate 4108 * value to remain distinct. 4109 */ 4110 otmp = readobjnam(buf, ¬hing, TRUE); 4111 if (!otmp) { 4112 pline("Nothing fitting that description exists in the game."); 4113 if (++tries < 5) goto retry; 4114 pline(thats_enough_tries); 4115 otmp = readobjnam((char *)0, (struct obj *)0, TRUE); 4116 if (!otmp) return; /* for safety; should never happen */ 4117 } else if (otmp == ¬hing) { 4118 /* explicitly wished for "nothing", presumeably attempting 4119 to retain wishless conduct */ 4120 return; 4121 } 4122 4123 /* KMH, conduct */ 4124 u.uconduct.wishes++; 4125 4126 if (otmp != &zeroobj) { 4127 /* The(aobjnam()) is safe since otmp is unidentified -dlc */ 4128 (void) hold_another_object(otmp, u.uswallow ? 4129 "Oops! %s out of your reach!" : 4130 (Is_airlevel(&u.uz) || 4131 Is_waterlevel(&u.uz) || 4132 levl[u.ux][u.uy].typ < IRONBARS || 4133 levl[u.ux][u.uy].typ >= ICE) ? 4134 "Oops! %s away from you!" : 4135 "Oops! %s to the floor!", 4136 The(aobjnam(otmp, 4137 Is_airlevel(&u.uz) || u.uinwater ? 4138 "slip" : "drop")), 4139 (const char *)0); 4140 u.ublesscnt += rn1(100,50); /* the gods take notice */ 4141 } 4142} 4143 4144#endif /*OVL2*/ 4145 4146/*zap.c*/ 4147