1/* SCCS Id: @(#)trap.c 3.4 2003/10/20 */ 2/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ 3/* NetHack may be freely redistributed. See license for details. */ 4 5#include "hack.h" 6 7extern const char * const destroy_strings[]; /* from zap.c */ 8 9STATIC_DCL void FDECL(dofiretrap, (struct obj *)); 10STATIC_DCL void NDECL(domagictrap); 11STATIC_DCL boolean FDECL(emergency_disrobe,(boolean *)); 12STATIC_DCL int FDECL(untrap_prob, (struct trap *ttmp)); 13STATIC_DCL void FDECL(cnv_trap_obj, (int, int, struct trap *)); 14STATIC_DCL void FDECL(move_into_trap, (struct trap *)); 15STATIC_DCL int FDECL(try_disarm, (struct trap *,BOOLEAN_P)); 16STATIC_DCL void FDECL(reward_untrap, (struct trap *, struct monst *)); 17STATIC_DCL int FDECL(disarm_holdingtrap, (struct trap *)); 18STATIC_DCL int FDECL(disarm_landmine, (struct trap *)); 19STATIC_DCL int FDECL(disarm_squeaky_board, (struct trap *)); 20STATIC_DCL int FDECL(disarm_shooting_trap, (struct trap *, int)); 21STATIC_DCL int FDECL(try_lift, (struct monst *, struct trap *, int, BOOLEAN_P)); 22STATIC_DCL int FDECL(help_monster_out, (struct monst *, struct trap *)); 23STATIC_DCL boolean FDECL(thitm, (int,struct monst *,struct obj *,int,BOOLEAN_P)); 24STATIC_DCL int FDECL(mkroll_launch, 25 (struct trap *,XCHAR_P,XCHAR_P,SHORT_P,long)); 26STATIC_DCL boolean FDECL(isclearpath,(coord *, int, SCHAR_P, SCHAR_P)); 27#ifdef STEED 28STATIC_OVL int FDECL(steedintrap, (struct trap *, struct obj *)); 29STATIC_OVL boolean FDECL(keep_saddle_with_steedcorpse, 30 (unsigned, struct obj *, struct obj *)); 31#endif 32 33#ifndef OVLB 34STATIC_VAR const char *a_your[2]; 35STATIC_VAR const char *A_Your[2]; 36STATIC_VAR const char tower_of_flame[]; 37STATIC_VAR const char *A_gush_of_water_hits; 38STATIC_VAR const char * const blindgas[6]; 39 40#else 41 42STATIC_VAR const char * const a_your[2] = { "a", "your" }; 43STATIC_VAR const char * const A_Your[2] = { "A", "Your" }; 44STATIC_VAR const char tower_of_flame[] = "tower of flame"; 45STATIC_VAR const char * const A_gush_of_water_hits = "A gush of water hits"; 46STATIC_VAR const char * const blindgas[6] = 47 {"humid", "odorless", "pungent", "chilling", "acrid", "biting"}; 48 49#endif /* OVLB */ 50 51#ifdef OVLB 52 53/* called when you're hit by fire (dofiretrap,buzz,zapyourself,explode) */ 54boolean /* returns TRUE if hit on torso */ 55burnarmor(victim) 56struct monst *victim; 57{ 58 struct obj *item; 59 char buf[BUFSZ]; 60 int mat_idx; 61 62 if (!victim) return 0; 63#define burn_dmg(obj,descr) rust_dmg(obj, descr, 0, FALSE, victim) 64 while (1) { 65 switch (rn2(5)) { 66 case 0: 67 item = (victim == &youmonst) ? uarmh : which_armor(victim, W_ARMH); 68 if (item) { 69 mat_idx = objects[item->otyp].oc_material; 70 Sprintf(buf,"%s helmet", materialnm[mat_idx] ); 71 } 72 if (!burn_dmg(item, item ? buf : "helmet")) continue; 73 break; 74 case 1: 75 item = (victim == &youmonst) ? uarmc : which_armor(victim, W_ARMC); 76 if (item) { 77 (void) burn_dmg(item, cloak_simple_name(item)); 78 return TRUE; 79 } 80 item = (victim == &youmonst) ? uarm : which_armor(victim, W_ARM); 81 if (item) { 82 (void) burn_dmg(item, xname(item)); 83 return TRUE; 84 } 85#ifdef TOURIST 86 item = (victim == &youmonst) ? uarmu : which_armor(victim, W_ARMU); 87 if (item) 88 (void) burn_dmg(item, "shirt"); 89#endif 90 return TRUE; 91 case 2: 92 item = (victim == &youmonst) ? uarms : which_armor(victim, W_ARMS); 93 if (!burn_dmg(item, "wooden shield")) continue; 94 break; 95 case 3: 96 item = (victim == &youmonst) ? uarmg : which_armor(victim, W_ARMG); 97 if (!burn_dmg(item, "gloves")) continue; 98 break; 99 case 4: 100 item = (victim == &youmonst) ? uarmf : which_armor(victim, W_ARMF); 101 if (!burn_dmg(item, "boots")) continue; 102 break; 103 } 104 break; /* Out of while loop */ 105 } 106 return FALSE; 107#undef burn_dmg 108} 109 110/* Generic rust-armor function. Returns TRUE if a message was printed; 111 * "print", if set, means to print a message (and thus to return TRUE) even 112 * if the item could not be rusted; otherwise a message is printed and TRUE is 113 * returned only for rustable items. 114 */ 115boolean 116rust_dmg(otmp, ostr, type, print, victim) 117register struct obj *otmp; 118register const char *ostr; 119int type; 120boolean print; 121struct monst *victim; 122{ 123 static NEARDATA const char * const action[] = { "smoulder", "rust", "rot", "corrode" }; 124 static NEARDATA const char * const msg[] = { "burnt", "rusted", "rotten", "corroded" }; 125 boolean vulnerable = FALSE; 126 boolean grprot = FALSE; 127 boolean is_primary = TRUE; 128 boolean vismon = (victim != &youmonst) && canseemon(victim); 129 int erosion; 130 131 if (!otmp) return(FALSE); 132 switch(type) { 133 case 0: vulnerable = is_flammable(otmp); 134 break; 135 case 1: vulnerable = is_rustprone(otmp); 136 grprot = TRUE; 137 break; 138 case 2: vulnerable = is_rottable(otmp); 139 is_primary = FALSE; 140 break; 141 case 3: vulnerable = is_corrodeable(otmp); 142 grprot = TRUE; 143 is_primary = FALSE; 144 break; 145 } 146 erosion = is_primary ? otmp->oeroded : otmp->oeroded2; 147 148 if (!print && (!vulnerable || otmp->oerodeproof || erosion == MAX_ERODE)) 149 return FALSE; 150 151 if (!vulnerable) { 152 if (flags.verbose) { 153 if (victim == &youmonst) 154 Your("%s %s not affected.", ostr, vtense(ostr, "are")); 155 else if (vismon) 156 pline("%s's %s %s not affected.", Monnam(victim), ostr, 157 vtense(ostr, "are")); 158 } 159 } else if (erosion < MAX_ERODE) { 160 if (grprot && otmp->greased) { 161 grease_protect(otmp,ostr,victim); 162 } else if (otmp->oerodeproof || (otmp->blessed && !rnl(4))) { 163 if (flags.verbose) { 164 if (victim == &youmonst) 165 pline("Somehow, your %s %s not affected.", 166 ostr, vtense(ostr, "are")); 167 else if (vismon) 168 pline("Somehow, %s's %s %s not affected.", 169 mon_nam(victim), ostr, vtense(ostr, "are")); 170 } 171 } else { 172 if (victim == &youmonst) 173 Your("%s %s%s!", ostr, 174 vtense(ostr, action[type]), 175 erosion+1 == MAX_ERODE ? " completely" : 176 erosion ? " further" : ""); 177 else if (vismon) 178 pline("%s's %s %s%s!", Monnam(victim), ostr, 179 vtense(ostr, action[type]), 180 erosion+1 == MAX_ERODE ? " completely" : 181 erosion ? " further" : ""); 182 if (is_primary) 183 otmp->oeroded++; 184 else 185 otmp->oeroded2++; 186 update_inventory(); 187 } 188 } else { 189 if (flags.verbose) { 190 if (victim == &youmonst) 191 Your("%s %s completely %s.", ostr, 192 vtense(ostr, Blind ? "feel" : "look"), 193 msg[type]); 194 else if (vismon) 195 pline("%s's %s %s completely %s.", 196 Monnam(victim), ostr, 197 vtense(ostr, "look"), msg[type]); 198 } 199 } 200 return(TRUE); 201} 202 203void 204grease_protect(otmp,ostr,victim) 205register struct obj *otmp; 206register const char *ostr; 207struct monst *victim; 208{ 209 static const char txt[] = "protected by the layer of grease!"; 210 boolean vismon = victim && (victim != &youmonst) && canseemon(victim); 211 212 if (ostr) { 213 if (victim == &youmonst) 214 Your("%s %s %s", ostr, vtense(ostr, "are"), txt); 215 else if (vismon) 216 pline("%s's %s %s %s", Monnam(victim), 217 ostr, vtense(ostr, "are"), txt); 218 } else { 219 if (victim == &youmonst) 220 Your("%s %s",aobjnam(otmp,"are"), txt); 221 else if (vismon) 222 pline("%s's %s %s", Monnam(victim), aobjnam(otmp,"are"), txt); 223 } 224 if (!rn2(2)) { 225 otmp->greased = 0; 226 if (carried(otmp)) { 227 pline_The("grease dissolves."); 228 update_inventory(); 229 } 230 } 231} 232 233struct trap * 234maketrap(x,y,typ) 235register int x, y, typ; 236{ 237 register struct trap *ttmp; 238 register struct rm *lev; 239 register boolean oldplace; 240 241 if ((ttmp = t_at(x,y)) != 0) { 242 if (ttmp->ttyp == MAGIC_PORTAL) return (struct trap *)0; 243 oldplace = TRUE; 244 if (u.utrap && (x == u.ux) && (y == u.uy) && 245 ((u.utraptype == TT_BEARTRAP && typ != BEAR_TRAP) || 246 (u.utraptype == TT_WEB && typ != WEB) || 247 (u.utraptype == TT_PIT && typ != PIT && typ != SPIKED_PIT))) 248 u.utrap = 0; 249 } else { 250 oldplace = FALSE; 251 ttmp = newtrap(); 252 ttmp->tx = x; 253 ttmp->ty = y; 254 ttmp->launch.x = -1; /* force error if used before set */ 255 ttmp->launch.y = -1; 256 } 257 ttmp->ttyp = typ; 258 switch(typ) { 259 case STATUE_TRAP: /* create a "living" statue */ 260 { struct monst *mtmp; 261 struct obj *otmp, *statue; 262 263 statue = mkcorpstat(STATUE, (struct monst *)0, 264 &mons[rndmonnum()], x, y, FALSE); 265 mtmp = makemon(&mons[statue->corpsenm], 0, 0, NO_MM_FLAGS); 266 if (!mtmp) break; /* should never happen */ 267 while(mtmp->minvent) { 268 otmp = mtmp->minvent; 269 otmp->owornmask = 0; 270 obj_extract_self(otmp); 271 (void) add_to_container(statue, otmp); 272 } 273 statue->owt = weight(statue); 274 mongone(mtmp); 275 break; 276 } 277 case ROLLING_BOULDER_TRAP: /* boulder will roll towards trigger */ 278 (void) mkroll_launch(ttmp, x, y, BOULDER, 1L); 279 break; 280 case HOLE: 281 case PIT: 282 case SPIKED_PIT: 283 case TRAPDOOR: 284 lev = &levl[x][y]; 285 if (*in_rooms(x, y, SHOPBASE) && 286 ((typ == HOLE || typ == TRAPDOOR) || 287 IS_DOOR(lev->typ) || IS_WALL(lev->typ))) 288 add_damage(x, y, /* schedule repair */ 289 ((IS_DOOR(lev->typ) || IS_WALL(lev->typ)) 290 && !flags.mon_moving) ? 200L : 0L); 291 lev->doormask = 0; /* subsumes altarmask, icedpool... */ 292 if (IS_ROOM(lev->typ)) /* && !IS_AIR(lev->typ) */ 293 lev->typ = ROOM; 294 295 /* 296 * some cases which can happen when digging 297 * down while phazing thru solid areas 298 */ 299 else if (lev->typ == STONE || lev->typ == SCORR) 300 lev->typ = CORR; 301 else if (IS_WALL(lev->typ) || lev->typ == SDOOR) 302 lev->typ = level.flags.is_maze_lev ? ROOM : 303 level.flags.is_cavernous_lev ? CORR : DOOR; 304 305 unearth_objs(x, y); 306 break; 307 } 308 if (ttmp->ttyp == HOLE) ttmp->tseen = 1; /* You can't hide a hole */ 309 else ttmp->tseen = 0; 310 ttmp->once = 0; 311 ttmp->madeby_u = 0; 312 ttmp->dst.dnum = -1; 313 ttmp->dst.dlevel = -1; 314 if (!oldplace) { 315 ttmp->ntrap = ftrap; 316 ftrap = ttmp; 317 } 318 return(ttmp); 319} 320 321void 322fall_through(td) 323boolean td; /* td == TRUE : trap door or hole */ 324{ 325 d_level dtmp; 326 char msgbuf[BUFSZ]; 327 const char *dont_fall = 0; 328 register int newlevel = dunlev(&u.uz); 329 330 /* KMH -- You can't escape the Sokoban level traps */ 331 if(Blind && Levitation && !In_sokoban(&u.uz)) return; 332 333 do { 334 newlevel++; 335 } while(!rn2(4) && newlevel < dunlevs_in_dungeon(&u.uz)); 336 337 if(td) { 338 struct trap *t=t_at(u.ux,u.uy); 339 seetrap(t); 340 if (!In_sokoban(&u.uz)) { 341 if (t->ttyp == TRAPDOOR) 342 pline("A trap door opens up under you!"); 343 else 344 pline("There's a gaping hole under you!"); 345 } 346 } else pline_The("%s opens up under you!", surface(u.ux,u.uy)); 347 348 if (In_sokoban(&u.uz) && Can_fall_thru(&u.uz)) 349 ; /* KMH -- You can't escape the Sokoban level traps */ 350 else if(Levitation || u.ustuck || !Can_fall_thru(&u.uz) 351 || Flying || is_clinger(youmonst.data) 352 || (Inhell && !u.uevent.invoked && 353 newlevel == dunlevs_in_dungeon(&u.uz)) 354 ) { 355 dont_fall = "don't fall in."; 356 } else if (youmonst.data->msize >= MZ_HUGE) { 357 dont_fall = "don't fit through."; 358 } else if (!next_to_u()) { 359 dont_fall = "are jerked back by your pet!"; 360 } 361 if (dont_fall) { 362 You(dont_fall); 363 /* hero didn't fall through, but any objects here might */ 364 impact_drop((struct obj *)0, u.ux, u.uy, 0); 365 if (!td) { 366 display_nhwindow(WIN_MESSAGE, FALSE); 367 pline_The("opening under you closes up."); 368 } 369 return; 370 } 371 372 if(*u.ushops) shopdig(1); 373 if (Is_stronghold(&u.uz)) { 374 find_hell(&dtmp); 375 } else { 376 dtmp.dnum = u.uz.dnum; 377 dtmp.dlevel = newlevel; 378 } 379 if (!td) 380 Sprintf(msgbuf, "The hole in the %s above you closes up.", 381 ceiling(u.ux,u.uy)); 382 schedule_goto(&dtmp, FALSE, TRUE, 0, 383 (char *)0, !td ? msgbuf : (char *)0); 384} 385 386/* 387 * Animate the given statue. May have been via shatter attempt, trap, 388 * or stone to flesh spell. Return a monster if successfully animated. 389 * If the monster is animated, the object is deleted. If fail_reason 390 * is non-null, then fill in the reason for failure (or success). 391 * 392 * The cause of animation is: 393 * 394 * ANIMATE_NORMAL - hero "finds" the monster 395 * ANIMATE_SHATTER - hero tries to destroy the statue 396 * ANIMATE_SPELL - stone to flesh spell hits the statue 397 * 398 * Perhaps x, y is not needed if we can use get_obj_location() to find 399 * the statue's location... ??? 400 */ 401struct monst * 402animate_statue(statue, x, y, cause, fail_reason) 403struct obj *statue; 404xchar x, y; 405int cause; 406int *fail_reason; 407{ 408 struct permonst *mptr; 409 struct monst *mon = 0; 410 struct obj *item; 411 coord cc; 412 boolean historic = (Role_if(PM_ARCHEOLOGIST) && !flags.mon_moving && (statue->spe & STATUE_HISTORIC)); 413 char statuename[BUFSZ]; 414 415 Strcpy(statuename,the(xname(statue))); 416 417 if (statue->oxlth && statue->oattached == OATTACHED_MONST) { 418 cc.x = x, cc.y = y; 419 mon = montraits(statue, &cc); 420 if (mon && mon->mtame && !mon->isminion) 421 wary_dog(mon, TRUE); 422 } else { 423 /* statue of any golem hit with stone-to-flesh becomes flesh golem */ 424 if (is_golem(&mons[statue->corpsenm]) && cause == ANIMATE_SPELL) 425 mptr = &mons[PM_FLESH_GOLEM]; 426 else 427 mptr = &mons[statue->corpsenm]; 428 /* 429 * Guard against someone wishing for a statue of a unique monster 430 * (which is allowed in normal play) and then tossing it onto the 431 * [detected or guessed] location of a statue trap. Normally the 432 * uppermost statue is the one which would be activated. 433 */ 434 if ((mptr->geno & G_UNIQ) && cause != ANIMATE_SPELL) { 435 if (fail_reason) *fail_reason = AS_MON_IS_UNIQUE; 436 return (struct monst *)0; 437 } 438 if (cause == ANIMATE_SPELL && 439 ((mptr->geno & G_UNIQ) || mptr->msound == MS_GUARDIAN)) { 440 /* Statues of quest guardians or unique monsters 441 * will not stone-to-flesh as the real thing. 442 */ 443 mon = makemon(&mons[PM_DOPPELGANGER], x, y, 444 NO_MINVENT|MM_NOCOUNTBIRTH|MM_ADJACENTOK); 445 if (mon) { 446 /* makemon() will set mon->cham to 447 * CHAM_ORDINARY if hero is wearing 448 * ring of protection from shape changers 449 * when makemon() is called, so we have to 450 * check the field before calling newcham(). 451 */ 452 if (mon->cham == CHAM_DOPPELGANGER) 453 (void) newcham(mon, mptr, FALSE, FALSE); 454 } 455 } else 456 mon = makemon(mptr, x, y, (cause == ANIMATE_SPELL) ? 457 (NO_MINVENT | MM_ADJACENTOK) : NO_MINVENT); 458 } 459 460 if (!mon) { 461 if (fail_reason) *fail_reason = AS_NO_MON; 462 return (struct monst *)0; 463 } 464 465 /* in case statue is wielded and hero zaps stone-to-flesh at self */ 466 if (statue->owornmask) remove_worn_item(statue, TRUE); 467 468 /* allow statues to be of a specific gender */ 469 if (statue->spe & STATUE_MALE) 470 mon->female = FALSE; 471 else if (statue->spe & STATUE_FEMALE) 472 mon->female = TRUE; 473 /* if statue has been named, give same name to the monster */ 474 if (statue->onamelth) 475 mon = christen_monst(mon, ONAME(statue)); 476 /* transfer any statue contents to monster's inventory */ 477 while ((item = statue->cobj) != 0) { 478 obj_extract_self(item); 479 (void) add_to_minv(mon, item); 480 } 481 m_dowear(mon, TRUE); 482 delobj(statue); 483 484 /* mimic statue becomes seen mimic; other hiders won't be hidden */ 485 if (mon->m_ap_type) seemimic(mon); 486 else mon->mundetected = FALSE; 487 if ((x == u.ux && y == u.uy) || cause == ANIMATE_SPELL) { 488 const char *comes_to_life = nonliving(mon->data) ? 489 "moves" : "comes to life"; 490 if (cause == ANIMATE_SPELL) 491 pline("%s %s!", upstart(statuename), 492 canspotmon(mon) ? comes_to_life : "disappears"); 493 else 494 pline_The("statue %s!", 495 canspotmon(mon) ? comes_to_life : "disappears"); 496 if (historic) { 497 You_feel("guilty that the historic statue is now gone."); 498 adjalign(-1); 499 } 500 } else if (cause == ANIMATE_SHATTER) 501 pline("Instead of shattering, the statue suddenly %s!", 502 canspotmon(mon) ? "comes to life" : "disappears"); 503 else { /* cause == ANIMATE_NORMAL */ 504 You("find %s posing as a statue.", 505 canspotmon(mon) ? a_monnam(mon) : something); 506 stop_occupation(); 507 } 508 /* avoid hiding under nothing */ 509 if (x == u.ux && y == u.uy && 510 Upolyd && hides_under(youmonst.data) && !OBJ_AT(x, y)) 511 u.uundetected = 0; 512 513 if (fail_reason) *fail_reason = AS_OK; 514 return mon; 515} 516 517/* 518 * You've either stepped onto a statue trap's location or you've triggered a 519 * statue trap by searching next to it or by trying to break it with a wand 520 * or pick-axe. 521 */ 522struct monst * 523activate_statue_trap(trap, x, y, shatter) 524struct trap *trap; 525xchar x, y; 526boolean shatter; 527{ 528 struct monst *mtmp = (struct monst *)0; 529 struct obj *otmp = sobj_at(STATUE, x, y); 530 int fail_reason; 531 532 /* 533 * Try to animate the first valid statue. Stop the loop when we 534 * actually create something or the failure cause is not because 535 * the mon was unique. 536 */ 537 deltrap(trap); 538 while (otmp) { 539 mtmp = animate_statue(otmp, x, y, 540 shatter ? ANIMATE_SHATTER : ANIMATE_NORMAL, &fail_reason); 541 if (mtmp || fail_reason != AS_MON_IS_UNIQUE) break; 542 543 while ((otmp = otmp->nexthere) != 0) 544 if (otmp->otyp == STATUE) break; 545 } 546 547 if (Blind) feel_location(x, y); 548 else newsym(x, y); 549 return mtmp; 550} 551 552#ifdef STEED 553STATIC_OVL boolean 554keep_saddle_with_steedcorpse(steed_mid, objchn, saddle) 555unsigned steed_mid; 556struct obj *objchn, *saddle; 557{ 558 if (!saddle) return FALSE; 559 while(objchn) { 560 if(objchn->otyp == CORPSE && 561 objchn->oattached == OATTACHED_MONST && objchn->oxlth) { 562 struct monst *mtmp = (struct monst *)objchn->oextra; 563 if (mtmp->m_id == steed_mid) { 564 /* move saddle */ 565 xchar x,y; 566 if (get_obj_location(objchn, &x, &y, 0)) { 567 obj_extract_self(saddle); 568 place_object(saddle, x, y); 569 stackobj(saddle); 570 } 571 return TRUE; 572 } 573 } 574 if (Has_contents(objchn) && 575 keep_saddle_with_steedcorpse(steed_mid, objchn->cobj, saddle)) 576 return TRUE; 577 objchn = objchn->nobj; 578 } 579 return FALSE; 580} 581#endif /*STEED*/ 582 583void 584dotrap(trap, trflags) 585register struct trap *trap; 586unsigned trflags; 587{ 588 register int ttype = trap->ttyp; 589 register struct obj *otmp; 590 boolean already_seen = trap->tseen; 591 boolean webmsgok = (!(trflags & NOWEBMSG)); 592 boolean forcebungle = (trflags & FORCEBUNGLE); 593 594 nomul(0); 595 596 /* KMH -- You can't escape the Sokoban level traps */ 597 if (In_sokoban(&u.uz) && 598 (ttype == PIT || ttype == SPIKED_PIT || ttype == HOLE || 599 ttype == TRAPDOOR)) { 600 /* The "air currents" message is still appropriate -- even when 601 * the hero isn't flying or levitating -- because it conveys the 602 * reason why the player cannot escape the trap with a dexterity 603 * check, clinging to the ceiling, etc. 604 */ 605 pline("Air currents pull you down into %s %s!", 606 a_your[trap->madeby_u], 607 defsyms[trap_to_defsym(ttype)].explanation); 608 /* then proceed to normal trap effect */ 609 } else if (already_seen) { 610 if ((Levitation || Flying) && 611 (ttype == PIT || ttype == SPIKED_PIT || ttype == HOLE || 612 ttype == BEAR_TRAP)) { 613 You("%s over %s %s.", 614 Levitation ? "float" : "fly", 615 a_your[trap->madeby_u], 616 defsyms[trap_to_defsym(ttype)].explanation); 617 return; 618 } 619 if(!Fumbling && ttype != MAGIC_PORTAL && 620 ttype != ANTI_MAGIC && !forcebungle && 621 (!rn2(5) || 622 ((ttype == PIT || ttype == SPIKED_PIT) && is_clinger(youmonst.data)))) { 623 You("escape %s %s.", 624 (ttype == ARROW_TRAP && !trap->madeby_u) ? "an" : 625 a_your[trap->madeby_u], 626 defsyms[trap_to_defsym(ttype)].explanation); 627 return; 628 } 629 } 630 631#ifdef STEED 632 if (u.usteed) u.usteed->mtrapseen |= (1 << (ttype-1)); 633#endif 634 635 switch(ttype) { 636 case ARROW_TRAP: 637 if (trap->once && trap->tseen && !rn2(15)) { 638 You_hear("a loud click!"); 639 deltrap(trap); 640 newsym(u.ux,u.uy); 641 break; 642 } 643 trap->once = 1; 644 seetrap(trap); 645 pline("An arrow shoots out at you!"); 646 otmp = mksobj(ARROW, TRUE, FALSE); 647 otmp->quan = 1L; 648 otmp->owt = weight(otmp); 649 otmp->opoisoned = 0; 650#ifdef STEED 651 if (u.usteed && !rn2(2) && steedintrap(trap, otmp)) /* nothing */; 652 else 653#endif 654 if (thitu(8, dmgval(otmp, &youmonst), otmp, "arrow")) { 655 obfree(otmp, (struct obj *)0); 656 } else { 657 place_object(otmp, u.ux, u.uy); 658 if (!Blind) otmp->dknown = 1; 659 stackobj(otmp); 660 newsym(u.ux, u.uy); 661 } 662 break; 663 case DART_TRAP: 664 if (trap->once && trap->tseen && !rn2(15)) { 665 You_hear("a soft click."); 666 deltrap(trap); 667 newsym(u.ux,u.uy); 668 break; 669 } 670 trap->once = 1; 671 seetrap(trap); 672 pline("A little dart shoots out at you!"); 673 otmp = mksobj(DART, TRUE, FALSE); 674 otmp->quan = 1L; 675 otmp->owt = weight(otmp); 676 if (!rn2(6)) otmp->opoisoned = 1; 677#ifdef STEED 678 if (u.usteed && !rn2(2) && steedintrap(trap, otmp)) /* nothing */; 679 else 680#endif 681 if (thitu(7, dmgval(otmp, &youmonst), otmp, "little dart")) { 682 if (otmp->opoisoned) 683 poisoned("dart", A_CON, "little dart", -10); 684 obfree(otmp, (struct obj *)0); 685 } else { 686 place_object(otmp, u.ux, u.uy); 687 if (!Blind) otmp->dknown = 1; 688 stackobj(otmp); 689 newsym(u.ux, u.uy); 690 } 691 break; 692 case ROCKTRAP: 693 if (trap->once && trap->tseen && !rn2(15)) { 694 pline("A trap door in %s opens, but nothing falls out!", 695 the(ceiling(u.ux,u.uy))); 696 deltrap(trap); 697 newsym(u.ux,u.uy); 698 } else { 699 int dmg = d(2,6); /* should be std ROCK dmg? */ 700 701 trap->once = 1; 702 seetrap(trap); 703 otmp = mksobj_at(ROCK, u.ux, u.uy, TRUE, FALSE); 704 otmp->quan = 1L; 705 otmp->owt = weight(otmp); 706 707 pline("A trap door in %s opens and %s falls on your %s!", 708 the(ceiling(u.ux,u.uy)), 709 an(xname(otmp)), 710 body_part(HEAD)); 711 712 if (uarmh) { 713 if(is_metallic(uarmh)) { 714 pline("Fortunately, you are wearing a hard helmet."); 715 dmg = 2; 716 } else if (flags.verbose) { 717 Your("%s does not protect you.", xname(uarmh)); 718 } 719 } 720 721 if (!Blind) otmp->dknown = 1; 722 stackobj(otmp); 723 newsym(u.ux,u.uy); /* map the rock */ 724 725 losehp(dmg, "falling rock", KILLED_BY_AN); 726 exercise(A_STR, FALSE); 727 } 728 break; 729 730 case SQKY_BOARD: /* stepped on a squeaky board */ 731 if (Levitation || Flying) { 732 if (!Blind) { 733 seetrap(trap); 734 if (Hallucination) 735 You("notice a crease in the linoleum."); 736 else 737 You("notice a loose board below you."); 738 } 739 } else { 740 seetrap(trap); 741 pline("A board beneath you squeaks loudly."); 742 wake_nearby(); 743 } 744 break; 745 746 case BEAR_TRAP: 747 if(Levitation || Flying) break; 748 seetrap(trap); 749 if(amorphous(youmonst.data) || is_whirly(youmonst.data) || 750 unsolid(youmonst.data)) { 751 pline("%s bear trap closes harmlessly through you.", 752 A_Your[trap->madeby_u]); 753 break; 754 } 755 if( 756#ifdef STEED 757 !u.usteed && 758#endif 759 youmonst.data->msize <= MZ_SMALL) { 760 pline("%s bear trap closes harmlessly over you.", 761 A_Your[trap->madeby_u]); 762 break; 763 } 764 u.utrap = rn1(4, 4); 765 u.utraptype = TT_BEARTRAP; 766#ifdef STEED 767 if (u.usteed) { 768 pline("%s bear trap closes on %s %s!", 769 A_Your[trap->madeby_u], s_suffix(mon_nam(u.usteed)), 770 mbodypart(u.usteed, FOOT)); 771 } else 772#endif 773 { 774 pline("%s bear trap closes on your %s!", 775 A_Your[trap->madeby_u], body_part(FOOT)); 776 if(u.umonnum == PM_OWLBEAR || u.umonnum == PM_BUGBEAR) 777 You("howl in anger!"); 778 } 779 exercise(A_DEX, FALSE); 780 break; 781 782 case SLP_GAS_TRAP: 783 seetrap(trap); 784 if(Sleep_resistance || breathless(youmonst.data)) { 785 You("are enveloped in a cloud of gas!"); 786 break; 787 } 788 pline("A cloud of gas puts you to sleep!"); 789 fall_asleep(-rnd(25), TRUE); 790#ifdef STEED 791 (void) steedintrap(trap, (struct obj *)0); 792#endif 793 break; 794 795 case RUST_TRAP: 796 seetrap(trap); 797 if (u.umonnum == PM_IRON_GOLEM) { 798 int dam = u.mhmax; 799 800 pline("%s you!", A_gush_of_water_hits); 801 You("are covered with rust!"); 802 if (Half_physical_damage) dam = (dam+1) / 2; 803 losehp(dam, "rusting away", KILLED_BY); 804 break; 805 } else if (u.umonnum == PM_GREMLIN && rn2(3)) { 806 pline("%s you!", A_gush_of_water_hits); 807 (void)split_mon(&youmonst, (struct monst *)0); 808 break; 809 } 810 811 /* Unlike monsters, traps cannot aim their rust attacks at 812 * you, so instead of looping through and taking either the 813 * first rustable one or the body, we take whatever we get, 814 * even if it is not rustable. 815 */ 816 switch (rn2(5)) { 817 case 0: 818 pline("%s you on the %s!", A_gush_of_water_hits, 819 body_part(HEAD)); 820 (void) rust_dmg(uarmh, "helmet", 1, TRUE, &youmonst); 821 break; 822 case 1: 823 pline("%s your left %s!", A_gush_of_water_hits, 824 body_part(ARM)); 825 if (rust_dmg(uarms, "shield", 1, TRUE, &youmonst)) 826 break; 827 if (u.twoweap || (uwep && bimanual(uwep))) 828 erode_obj(u.twoweap ? uswapwep : uwep, FALSE, TRUE); 829glovecheck: (void) rust_dmg(uarmg, "gauntlets", 1, TRUE, &youmonst); 830 /* Not "metal gauntlets" since it gets called 831 * even if it's leather for the message 832 */ 833 break; 834 case 2: 835 pline("%s your right %s!", A_gush_of_water_hits, 836 body_part(ARM)); 837 erode_obj(uwep, FALSE, TRUE); 838 goto glovecheck; 839 default: 840 pline("%s you!", A_gush_of_water_hits); 841 for (otmp=invent; otmp; otmp = otmp->nobj) 842 (void) snuff_lit(otmp); 843 if (uarmc) 844 (void) rust_dmg(uarmc, cloak_simple_name(uarmc), 845 1, TRUE, &youmonst); 846 else if (uarm) 847 (void) rust_dmg(uarm, "armor", 1, TRUE, &youmonst); 848#ifdef TOURIST 849 else if (uarmu) 850 (void) rust_dmg(uarmu, "shirt", 1, TRUE, &youmonst); 851#endif 852 } 853 update_inventory(); 854 break; 855 856 case FIRE_TRAP: 857 seetrap(trap); 858 dofiretrap((struct obj *)0); 859 break; 860 861 case PIT: 862 case SPIKED_PIT: 863 /* KMH -- You can't escape the Sokoban level traps */ 864 if (!In_sokoban(&u.uz) && (Levitation || Flying)) break; 865 seetrap(trap); 866 if (!In_sokoban(&u.uz) && is_clinger(youmonst.data)) { 867 if(trap->tseen) { 868 You("see %s %spit below you.", a_your[trap->madeby_u], 869 ttype == SPIKED_PIT ? "spiked " : ""); 870 } else { 871 pline("%s pit %sopens up under you!", 872 A_Your[trap->madeby_u], 873 ttype == SPIKED_PIT ? "full of spikes " : ""); 874 You("don't fall in!"); 875 } 876 break; 877 } 878 if (!In_sokoban(&u.uz)) { 879 char verbbuf[BUFSZ]; 880#ifdef STEED 881 if (u.usteed) { 882 if ((trflags & RECURSIVETRAP) != 0) 883 Sprintf(verbbuf, "and %s fall", 884 x_monnam(u.usteed, 885 u.usteed->mnamelth ? ARTICLE_NONE : ARTICLE_THE, 886 (char *)0, SUPPRESS_SADDLE, FALSE)); 887 else 888 Sprintf(verbbuf,"lead %s", 889 x_monnam(u.usteed, 890 u.usteed->mnamelth ? ARTICLE_NONE : ARTICLE_THE, 891 "poor", SUPPRESS_SADDLE, FALSE)); 892 } else 893#endif 894 Strcpy(verbbuf,"fall"); 895 You("%s into %s pit!", verbbuf, a_your[trap->madeby_u]); 896 } 897 /* wumpus reference */ 898 if (Role_if(PM_RANGER) && !trap->madeby_u && !trap->once && 899 In_quest(&u.uz) && Is_qlocate(&u.uz)) { 900 pline("Fortunately it has a bottom after all..."); 901 trap->once = 1; 902 } else if (u.umonnum == PM_PIT_VIPER || 903 u.umonnum == PM_PIT_FIEND) 904 pline("How pitiful. Isn't that the pits?"); 905 if (ttype == SPIKED_PIT) { 906 const char *predicament = "on a set of sharp iron spikes"; 907#ifdef STEED 908 if (u.usteed) { 909 pline("%s lands %s!", 910 upstart(x_monnam(u.usteed, 911 u.usteed->mnamelth ? ARTICLE_NONE : ARTICLE_THE, 912 "poor", SUPPRESS_SADDLE, FALSE)), 913 predicament); 914 } else 915#endif 916 You("land %s!", predicament); 917 } 918 if (!Passes_walls) 919 u.utrap = rn1(6,2); 920 u.utraptype = TT_PIT; 921#ifdef STEED 922 if (!steedintrap(trap, (struct obj *)0)) { 923#endif 924 if (ttype == SPIKED_PIT) { 925 losehp(rnd(10),"fell into a pit of iron spikes", 926 NO_KILLER_PREFIX); 927 if (!rn2(6)) 928 poisoned("spikes", A_STR, "fall onto poison spikes", 8); 929 } else 930 losehp(rnd(6),"fell into a pit", NO_KILLER_PREFIX); 931 if (Punished && !carried(uball)) { 932 unplacebc(); 933 ballfall(); 934 placebc(); 935 } 936 selftouch("Falling, you"); 937 vision_full_recalc = 1; /* vision limits change */ 938 exercise(A_STR, FALSE); 939 exercise(A_DEX, FALSE); 940#ifdef STEED 941 } 942#endif 943 break; 944 case HOLE: 945 case TRAPDOOR: 946 if (!Can_fall_thru(&u.uz)) { 947 seetrap(trap); /* normally done in fall_through */ 948 impossible("dotrap: %ss cannot exist on this level.", 949 defsyms[trap_to_defsym(ttype)].explanation); 950 break; /* don't activate it after all */ 951 } 952 fall_through(TRUE); 953 break; 954 955 case TELEP_TRAP: 956 seetrap(trap); 957 tele_trap(trap); 958 break; 959 case LEVEL_TELEP: 960 seetrap(trap); 961 level_tele_trap(trap); 962 break; 963 964 case WEB: /* Our luckless player has stumbled into a web. */ 965 seetrap(trap); 966 if (amorphous(youmonst.data) || is_whirly(youmonst.data) || 967 unsolid(youmonst.data)) { 968 if (acidic(youmonst.data) || u.umonnum == PM_GELATINOUS_CUBE || 969 u.umonnum == PM_FIRE_ELEMENTAL) { 970 if (webmsgok) 971 You("%s %s spider web!", 972 (u.umonnum == PM_FIRE_ELEMENTAL) ? "burn" : "dissolve", 973 a_your[trap->madeby_u]); 974 deltrap(trap); 975 newsym(u.ux,u.uy); 976 break; 977 } 978 if (webmsgok) You("flow through %s spider web.", 979 a_your[trap->madeby_u]); 980 break; 981 } 982 if (webmaker(youmonst.data)) { 983 if (webmsgok) 984 pline(trap->madeby_u ? "You take a walk on your web." 985 : "There is a spider web here."); 986 break; 987 } 988 if (webmsgok) { 989 char verbbuf[BUFSZ]; 990 verbbuf[0] = '\0'; 991#ifdef STEED 992 if (u.usteed) 993 Sprintf(verbbuf,"lead %s", 994 x_monnam(u.usteed, 995 u.usteed->mnamelth ? ARTICLE_NONE : ARTICLE_THE, 996 "poor", SUPPRESS_SADDLE, FALSE)); 997 else 998#endif 999 1000 Sprintf(verbbuf, "%s", Levitation ? (const char *)"float" : 1001 locomotion(youmonst.data, "stumble")); 1002 You("%s into %s spider web!", 1003 verbbuf, a_your[trap->madeby_u]); 1004 } 1005 u.utraptype = TT_WEB; 1006 1007 /* Time stuck in the web depends on your/steed strength. */ 1008 { 1009 register int str = ACURR(A_STR); 1010 1011#ifdef STEED 1012 /* If mounted, the steed gets trapped. Use mintrap 1013 * to do all the work. If mtrapped is set as a result, 1014 * unset it and set utrap instead. In the case of a 1015 * strongmonst and mintrap said it's trapped, use a 1016 * short but non-zero trap time. Otherwise, monsters 1017 * have no specific strength, so use player strength. 1018 * This gets skipped for webmsgok, which implies that 1019 * the steed isn't a factor. 1020 */ 1021 if (u.usteed && webmsgok) { 1022 /* mtmp location might not be up to date */ 1023 u.usteed->mx = u.ux; 1024 u.usteed->my = u.uy; 1025 1026 /* mintrap currently does not return 2(died) for webs */ 1027 if (mintrap(u.usteed)) { 1028 u.usteed->mtrapped = 0; 1029 if (strongmonst(u.usteed->data)) str = 17; 1030 } else { 1031 break; 1032 } 1033 1034 webmsgok = FALSE; /* mintrap printed the messages */ 1035 } 1036#endif 1037 if (str <= 3) u.utrap = rn1(6,6); 1038 else if (str < 6) u.utrap = rn1(6,4); 1039 else if (str < 9) u.utrap = rn1(4,4); 1040 else if (str < 12) u.utrap = rn1(4,2); 1041 else if (str < 15) u.utrap = rn1(2,2); 1042 else if (str < 18) u.utrap = rnd(2); 1043 else if (str < 69) u.utrap = 1; 1044 else { 1045 u.utrap = 0; 1046 if (webmsgok) 1047 You("tear through %s web!", a_your[trap->madeby_u]); 1048 deltrap(trap); 1049 newsym(u.ux,u.uy); /* get rid of trap symbol */ 1050 } 1051 } 1052 break; 1053 1054 case STATUE_TRAP: 1055 (void) activate_statue_trap(trap, u.ux, u.uy, FALSE); 1056 break; 1057 1058 case MAGIC_TRAP: /* A magic trap. */ 1059 seetrap(trap); 1060 if (!rn2(30)) { 1061 deltrap(trap); 1062 newsym(u.ux,u.uy); /* update position */ 1063 You("are caught in a magical explosion!"); 1064 losehp(rnd(10), "magical explosion", KILLED_BY_AN); 1065 Your("body absorbs some of the magical energy!"); 1066 u.uen = (u.uenmax += 2); 1067 } else domagictrap(); 1068#ifdef STEED 1069 (void) steedintrap(trap, (struct obj *)0); 1070#endif 1071 break; 1072 1073 case ANTI_MAGIC: 1074 seetrap(trap); 1075 if(Antimagic) { 1076 shieldeff(u.ux, u.uy); 1077 You_feel("momentarily lethargic."); 1078 } else drain_en(rnd(u.ulevel) + 1); 1079 break; 1080 1081 case POLY_TRAP: { 1082 char verbbuf[BUFSZ]; 1083 seetrap(trap); 1084#ifdef STEED 1085 if (u.usteed) 1086 Sprintf(verbbuf, "lead %s", 1087 x_monnam(u.usteed, 1088 u.usteed->mnamelth ? ARTICLE_NONE : ARTICLE_THE, 1089 (char *)0, SUPPRESS_SADDLE, FALSE)); 1090 else 1091#endif 1092 Sprintf(verbbuf,"%s", 1093 Levitation ? (const char *)"float" : 1094 locomotion(youmonst.data, "step")); 1095 You("%s onto a polymorph trap!", verbbuf); 1096 if(Antimagic || Unchanging) { 1097 shieldeff(u.ux, u.uy); 1098 You_feel("momentarily different."); 1099 /* Trap did nothing; don't remove it --KAA */ 1100 } else { 1101#ifdef STEED 1102 (void) steedintrap(trap, (struct obj *)0); 1103#endif 1104 deltrap(trap); /* delete trap before polymorph */ 1105 newsym(u.ux,u.uy); /* get rid of trap symbol */ 1106 You_feel("a change coming over you."); 1107 polyself(FALSE); 1108 } 1109 break; 1110 } 1111 case LANDMINE: { 1112#ifdef STEED 1113 unsigned steed_mid = 0; 1114 struct obj *saddle = 0; 1115#endif 1116 if (Levitation || Flying) { 1117 if (!already_seen && rn2(3)) break; 1118 seetrap(trap); 1119 pline("%s %s in a pile of soil below you.", 1120 already_seen ? "There is" : "You discover", 1121 trap->madeby_u ? "the trigger of your mine" : 1122 "a trigger"); 1123 if (already_seen && rn2(3)) break; 1124 pline("KAABLAMM!!! %s %s%s off!", 1125 forcebungle ? "Your inept attempt sets" : 1126 "The air currents set", 1127 already_seen ? a_your[trap->madeby_u] : "", 1128 already_seen ? " land mine" : "it"); 1129 } else { 1130#ifdef STEED 1131 /* prevent landmine from killing steed, throwing you to 1132 * the ground, and you being affected again by the same 1133 * mine because it hasn't been deleted yet 1134 */ 1135 static boolean recursive_mine = FALSE; 1136 1137 if (recursive_mine) break; 1138#endif 1139 seetrap(trap); 1140 pline("KAABLAMM!!! You triggered %s land mine!", 1141 a_your[trap->madeby_u]); 1142#ifdef STEED 1143 if (u.usteed) steed_mid = u.usteed->m_id; 1144 recursive_mine = TRUE; 1145 (void) steedintrap(trap, (struct obj *)0); 1146 recursive_mine = FALSE; 1147 saddle = sobj_at(SADDLE,u.ux, u.uy); 1148#endif 1149 set_wounded_legs(LEFT_SIDE, rn1(35, 41)); 1150 set_wounded_legs(RIGHT_SIDE, rn1(35, 41)); 1151 exercise(A_DEX, FALSE); 1152 } 1153 blow_up_landmine(trap); 1154#ifdef STEED 1155 if (steed_mid && saddle && !u.usteed) 1156 (void)keep_saddle_with_steedcorpse(steed_mid, fobj, saddle); 1157#endif 1158 newsym(u.ux,u.uy); /* update trap symbol */ 1159 losehp(rnd(16), "land mine", KILLED_BY_AN); 1160 /* fall recursively into the pit... */ 1161 if ((trap = t_at(u.ux, u.uy)) != 0) dotrap(trap, RECURSIVETRAP); 1162 fill_pit(u.ux, u.uy); 1163 break; 1164 } 1165 case ROLLING_BOULDER_TRAP: { 1166 int style = ROLL | (trap->tseen ? LAUNCH_KNOWN : 0); 1167 1168 seetrap(trap); 1169 pline("Click! You trigger a rolling boulder trap!"); 1170 if(!launch_obj(BOULDER, trap->launch.x, trap->launch.y, 1171 trap->launch2.x, trap->launch2.y, style)) { 1172 deltrap(trap); 1173 newsym(u.ux,u.uy); /* get rid of trap symbol */ 1174 pline("Fortunately for you, no boulder was released."); 1175 } 1176 break; 1177 } 1178 case MAGIC_PORTAL: 1179 seetrap(trap); 1180 domagicportal(trap); 1181 break; 1182 1183 default: 1184 seetrap(trap); 1185 impossible("You hit a trap of type %u", trap->ttyp); 1186 } 1187} 1188 1189#ifdef STEED 1190STATIC_OVL int 1191steedintrap(trap, otmp) 1192struct trap *trap; 1193struct obj *otmp; 1194{ 1195 struct monst *mtmp = u.usteed; 1196 struct permonst *mptr; 1197 int tt; 1198 boolean in_sight; 1199 boolean trapkilled = FALSE; 1200 boolean steedhit = FALSE; 1201 1202 if (!u.usteed || !trap) return 0; 1203 mptr = mtmp->data; 1204 tt = trap->ttyp; 1205 mtmp->mx = u.ux; 1206 mtmp->my = u.uy; 1207 1208 in_sight = !Blind; 1209 switch (tt) { 1210 case ARROW_TRAP: 1211 if(!otmp) { 1212 impossible("steed hit by non-existant arrow?"); 1213 return 0; 1214 } 1215 if (thitm(8, mtmp, otmp, 0, FALSE)) trapkilled = TRUE; 1216 steedhit = TRUE; 1217 break; 1218 case DART_TRAP: 1219 if(!otmp) { 1220 impossible("steed hit by non-existant dart?"); 1221 return 0; 1222 } 1223 if (thitm(7, mtmp, otmp, 0, FALSE)) trapkilled = TRUE; 1224 steedhit = TRUE; 1225 break; 1226 case SLP_GAS_TRAP: 1227 if (!resists_sleep(mtmp) && !breathless(mptr) && 1228 !mtmp->msleeping && mtmp->mcanmove) { 1229 mtmp->mcanmove = 0; 1230 mtmp->mfrozen = rnd(25); 1231 if (in_sight) { 1232 pline("%s suddenly falls asleep!", 1233 Monnam(mtmp)); 1234 } 1235 } 1236 steedhit = TRUE; 1237 break; 1238 case LANDMINE: 1239 if (thitm(0, mtmp, (struct obj *)0, rnd(16), FALSE)) 1240 trapkilled = TRUE; 1241 steedhit = TRUE; 1242 break; 1243 case PIT: 1244 case SPIKED_PIT: 1245 if (mtmp->mhp <= 0 || 1246 thitm(0, mtmp, (struct obj *)0, 1247 rnd((tt == PIT) ? 6 : 10), FALSE)) 1248 trapkilled = TRUE; 1249 steedhit = TRUE; 1250 break; 1251 case POLY_TRAP: 1252 if (!resists_magm(mtmp)) { 1253 if (!resist(mtmp, WAND_CLASS, 0, NOTELL)) { 1254 (void) newcham(mtmp, (struct permonst *)0, 1255 FALSE, FALSE); 1256 if (!can_saddle(mtmp) || !can_ride(mtmp)) { 1257 dismount_steed(DISMOUNT_POLY); 1258 } else { 1259 You("have to adjust yourself in the saddle on %s.", 1260 x_monnam(mtmp, 1261 mtmp->mnamelth ? ARTICLE_NONE : ARTICLE_A, 1262 (char *)0, SUPPRESS_SADDLE, FALSE)); 1263 } 1264 1265 } 1266 steedhit = TRUE; 1267 break; 1268 default: 1269 return 0; 1270 } 1271 } 1272 if(trapkilled) { 1273 dismount_steed(DISMOUNT_POLY); 1274 return 2; 1275 } 1276 else if(steedhit) return 1; 1277 else return 0; 1278} 1279#endif /*STEED*/ 1280 1281/* some actions common to both player and monsters for triggered landmine */ 1282void 1283blow_up_landmine(trap) 1284struct trap *trap; 1285{ 1286 (void)scatter(trap->tx, trap->ty, 4, 1287 MAY_DESTROY | MAY_HIT | MAY_FRACTURE | VIS_EFFECTS, 1288 (struct obj *)0); 1289 del_engr_at(trap->tx, trap->ty); 1290 wake_nearto(trap->tx, trap->ty, 400); 1291 if (IS_DOOR(levl[trap->tx][trap->ty].typ)) 1292 levl[trap->tx][trap->ty].doormask = D_BROKEN; 1293 /* TODO: destroy drawbridge if present */ 1294 /* caller may subsequently fill pit, e.g. with a boulder */ 1295 trap->ttyp = PIT; /* explosion creates a pit */ 1296 trap->madeby_u = FALSE; /* resulting pit isn't yours */ 1297 seetrap(trap); /* and it isn't concealed */ 1298} 1299 1300#endif /* OVLB */ 1301#ifdef OVL3 1302 1303/* 1304 * Move obj from (x1,y1) to (x2,y2) 1305 * 1306 * Return 0 if no object was launched. 1307 * 1 if an object was launched and placed somewhere. 1308 * 2 if an object was launched, but used up. 1309 */ 1310int 1311launch_obj(otyp, x1, y1, x2, y2, style) 1312short otyp; 1313register int x1,y1,x2,y2; 1314int style; 1315{ 1316 register struct monst *mtmp; 1317 register struct obj *otmp, *otmp2; 1318 register int dx,dy; 1319 struct obj *singleobj; 1320 boolean used_up = FALSE; 1321 boolean otherside = FALSE; 1322 int dist; 1323 int tmp; 1324 int delaycnt = 0; 1325 1326 otmp = sobj_at(otyp, x1, y1); 1327 /* Try the other side too, for rolling boulder traps */ 1328 if (!otmp && otyp == BOULDER) { 1329 otherside = TRUE; 1330 otmp = sobj_at(otyp, x2, y2); 1331 } 1332 if (!otmp) return 0; 1333 if (otherside) { /* swap 'em */ 1334 int tx, ty; 1335 1336 tx = x1; ty = y1; 1337 x1 = x2; y1 = y2; 1338 x2 = tx; y2 = ty; 1339 } 1340 1341 if (otmp->quan == 1L) { 1342 obj_extract_self(otmp); 1343 singleobj = otmp; 1344 otmp = (struct obj *) 0; 1345 } else { 1346 singleobj = splitobj(otmp, 1L); 1347 obj_extract_self(singleobj); 1348 } 1349 newsym(x1,y1); 1350 /* in case you're using a pick-axe to chop the boulder that's being 1351 launched (perhaps a monster triggered it), destroy context so that 1352 next dig attempt never thinks you're resuming previous effort */ 1353 if ((otyp == BOULDER || otyp == STATUE) && 1354 singleobj->ox == digging.pos.x && singleobj->oy == digging.pos.y) 1355 (void) memset((genericptr_t)&digging, 0, sizeof digging); 1356 1357 dist = distmin(x1,y1,x2,y2); 1358 bhitpos.x = x1; 1359 bhitpos.y = y1; 1360 dx = sgn(x2 - x1); 1361 dy = sgn(y2 - y1); 1362 switch (style) { 1363 case ROLL|LAUNCH_UNSEEN: 1364 if (otyp == BOULDER) { 1365 You_hear(Hallucination ? 1366 "someone bowling." : 1367 "rumbling in the distance."); 1368 } 1369 style &= ~LAUNCH_UNSEEN; 1370 goto roll; 1371 case ROLL|LAUNCH_KNOWN: 1372 /* use otrapped as a flag to ohitmon */ 1373 singleobj->otrapped = 1; 1374 style &= ~LAUNCH_KNOWN; 1375 /* fall through */ 1376 roll: 1377 case ROLL: 1378 delaycnt = 2; 1379 /* fall through */ 1380 default: 1381 if (!delaycnt) delaycnt = 1; 1382 if (!cansee(bhitpos.x,bhitpos.y)) curs_on_u(); 1383 tmp_at(DISP_FLASH, obj_to_glyph(singleobj)); 1384 tmp_at(bhitpos.x, bhitpos.y); 1385 } 1386 1387 /* Set the object in motion */ 1388 while(dist-- > 0 && !used_up) { 1389 struct trap *t; 1390 tmp_at(bhitpos.x, bhitpos.y); 1391 tmp = delaycnt; 1392 1393 /* dstage@u.washington.edu -- Delay only if hero sees it */ 1394 if (cansee(bhitpos.x, bhitpos.y)) 1395 while (tmp-- > 0) delay_output(); 1396 1397 bhitpos.x += dx; 1398 bhitpos.y += dy; 1399 t = t_at(bhitpos.x, bhitpos.y); 1400 1401 if ((mtmp = m_at(bhitpos.x, bhitpos.y)) != 0) { 1402 if (otyp == BOULDER && throws_rocks(mtmp->data)) { 1403 if (rn2(3)) { 1404 pline("%s snatches the boulder.", 1405 Monnam(mtmp)); 1406 singleobj->otrapped = 0; 1407 (void) mpickobj(mtmp, singleobj); 1408 used_up = TRUE; 1409 break; 1410 } 1411 } 1412 if (ohitmon(mtmp,singleobj, 1413 (style==ROLL) ? -1 : dist, FALSE)) { 1414 used_up = TRUE; 1415 break; 1416 } 1417 } else if (bhitpos.x == u.ux && bhitpos.y == u.uy) { 1418 if (multi) nomul(0); 1419 if (thitu(9 + singleobj->spe, 1420 dmgval(singleobj, &youmonst), 1421 singleobj, (char *)0)) 1422 stop_occupation(); 1423 } 1424 if (style == ROLL) { 1425 if (down_gate(bhitpos.x, bhitpos.y) != -1) { 1426 if(ship_object(singleobj, bhitpos.x, bhitpos.y, FALSE)){ 1427 used_up = TRUE; 1428 break; 1429 } 1430 } 1431 if (t && otyp == BOULDER) { 1432 switch(t->ttyp) { 1433 case LANDMINE: 1434 if (rn2(10) > 2) { 1435 pline( 1436 "KAABLAMM!!!%s", 1437 cansee(bhitpos.x, bhitpos.y) ? 1438 " The rolling boulder triggers a land mine." : ""); 1439 deltrap(t); 1440 del_engr_at(bhitpos.x,bhitpos.y); 1441 place_object(singleobj, bhitpos.x, bhitpos.y); 1442 singleobj->otrapped = 0; 1443 fracture_rock(singleobj); 1444 (void)scatter(bhitpos.x,bhitpos.y, 4, 1445 MAY_DESTROY|MAY_HIT|MAY_FRACTURE|VIS_EFFECTS, 1446 (struct obj *)0); 1447 if (cansee(bhitpos.x,bhitpos.y)) 1448 newsym(bhitpos.x,bhitpos.y); 1449 used_up = TRUE; 1450 } 1451 break; 1452 case LEVEL_TELEP: 1453 case TELEP_TRAP: 1454 if (cansee(bhitpos.x, bhitpos.y)) 1455 pline("Suddenly the rolling boulder disappears!"); 1456 else 1457 You_hear("a rumbling stop abruptly."); 1458 singleobj->otrapped = 0; 1459 if (t->ttyp == TELEP_TRAP) 1460 rloco(singleobj); 1461 else { 1462 int newlev = random_teleport_level(); 1463 d_level dest; 1464 1465 if (newlev == depth(&u.uz) || In_endgame(&u.uz)) 1466 continue; 1467 add_to_migration(singleobj); 1468 get_level(&dest, newlev); 1469 singleobj->ox = dest.dnum; 1470 singleobj->oy = dest.dlevel; 1471 singleobj->owornmask = (long)MIGR_RANDOM; 1472 } 1473 seetrap(t); 1474 used_up = TRUE; 1475 break; 1476 case PIT: 1477 case SPIKED_PIT: 1478 case HOLE: 1479 case TRAPDOOR: 1480 /* the boulder won't be used up if there is a 1481 monster in the trap; stop rolling anyway */ 1482 x2 = bhitpos.x, y2 = bhitpos.y; /* stops here */ 1483 if (flooreffects(singleobj, x2, y2, "fall")) 1484 used_up = TRUE; 1485 dist = -1; /* stop rolling immediately */ 1486 break; 1487 } 1488 if (used_up || dist == -1) break; 1489 } 1490 if (flooreffects(singleobj, bhitpos.x, bhitpos.y, "fall")) { 1491 used_up = TRUE; 1492 break; 1493 } 1494 if (otyp == BOULDER && 1495 (otmp2 = sobj_at(BOULDER, bhitpos.x, bhitpos.y)) != 0) { 1496 const char *bmsg = 1497 " as one boulder sets another in motion"; 1498 1499 if (!isok(bhitpos.x + dx, bhitpos.y + dy) || !dist || 1500 IS_ROCK(levl[bhitpos.x + dx][bhitpos.y + dy].typ)) 1501 bmsg = " as one boulder hits another"; 1502 1503 You_hear("a loud crash%s!", 1504 cansee(bhitpos.x, bhitpos.y) ? bmsg : ""); 1505 obj_extract_self(otmp2); 1506 /* pass off the otrapped flag to the next boulder */ 1507 otmp2->otrapped = singleobj->otrapped; 1508 singleobj->otrapped = 0; 1509 place_object(singleobj, bhitpos.x, bhitpos.y); 1510 singleobj = otmp2; 1511 otmp2 = (struct obj *)0; 1512 wake_nearto(bhitpos.x, bhitpos.y, 10*10); 1513 } 1514 } 1515 if (otyp == BOULDER && closed_door(bhitpos.x,bhitpos.y)) { 1516 if (cansee(bhitpos.x, bhitpos.y)) 1517 pline_The("boulder crashes through a door."); 1518 levl[bhitpos.x][bhitpos.y].doormask = D_BROKEN; 1519 if (dist) unblock_point(bhitpos.x, bhitpos.y); 1520 } 1521 1522 /* if about to hit iron bars, do so now */ 1523 if (dist > 0 && isok(bhitpos.x + dx,bhitpos.y + dy) && 1524 levl[bhitpos.x + dx][bhitpos.y + dy].typ == IRONBARS) { 1525 x2 = bhitpos.x, y2 = bhitpos.y; /* object stops here */ 1526 if (hits_bars(&singleobj, x2, y2, !rn2(20), 0)) { 1527 if (!singleobj) used_up = TRUE; 1528 break; 1529 } 1530 } 1531 } 1532 tmp_at(DISP_END, 0); 1533 if (!used_up) { 1534 singleobj->otrapped = 0; 1535 place_object(singleobj, x2,y2); 1536 newsym(x2,y2); 1537 return 1; 1538 } else 1539 return 2; 1540} 1541 1542#endif /* OVL3 */ 1543#ifdef OVLB 1544 1545void 1546seetrap(trap) 1547 register struct trap *trap; 1548{ 1549 if(!trap->tseen) { 1550 trap->tseen = 1; 1551 newsym(trap->tx, trap->ty); 1552 } 1553} 1554 1555#endif /* OVLB */ 1556#ifdef OVL3 1557 1558STATIC_OVL int 1559mkroll_launch(ttmp, x, y, otyp, ocount) 1560struct trap *ttmp; 1561xchar x,y; 1562short otyp; 1563long ocount; 1564{ 1565 struct obj *otmp; 1566 register int tmp; 1567 schar dx,dy; 1568 int distance; 1569 coord cc; 1570 coord bcc; 1571 int trycount = 0; 1572 boolean success = FALSE; 1573 int mindist = 4; 1574 1575 if (ttmp->ttyp == ROLLING_BOULDER_TRAP) mindist = 2; 1576 distance = rn1(5,4); /* 4..8 away */ 1577 tmp = rn2(8); /* randomly pick a direction to try first */ 1578 while (distance >= mindist) { 1579 dx = xdir[tmp]; 1580 dy = ydir[tmp]; 1581 cc.x = x; cc.y = y; 1582 /* Prevent boulder from being placed on water */ 1583 if (ttmp->ttyp == ROLLING_BOULDER_TRAP 1584 && is_pool(x+distance*dx,y+distance*dy)) 1585 success = FALSE; 1586 else success = isclearpath(&cc, distance, dx, dy); 1587 if (ttmp->ttyp == ROLLING_BOULDER_TRAP) { 1588 boolean success_otherway; 1589 bcc.x = x; bcc.y = y; 1590 success_otherway = isclearpath(&bcc, distance, 1591 -(dx), -(dy)); 1592 if (!success_otherway) success = FALSE; 1593 } 1594 if (success) break; 1595 if (++tmp > 7) tmp = 0; 1596 if ((++trycount % 8) == 0) --distance; 1597 } 1598 if (!success) { 1599 /* create the trap without any ammo, launch pt at trap location */ 1600 cc.x = bcc.x = x; 1601 cc.y = bcc.y = y; 1602 } else { 1603 otmp = mksobj(otyp, TRUE, FALSE); 1604 otmp->quan = ocount; 1605 otmp->owt = weight(otmp); 1606 place_object(otmp, cc.x, cc.y); 1607 stackobj(otmp); 1608 } 1609 ttmp->launch.x = cc.x; 1610 ttmp->launch.y = cc.y; 1611 if (ttmp->ttyp == ROLLING_BOULDER_TRAP) { 1612 ttmp->launch2.x = bcc.x; 1613 ttmp->launch2.y = bcc.y; 1614 } else 1615 ttmp->launch_otyp = otyp; 1616 newsym(ttmp->launch.x, ttmp->launch.y); 1617 return 1; 1618} 1619 1620STATIC_OVL boolean 1621isclearpath(cc,distance,dx,dy) 1622coord *cc; 1623int distance; 1624schar dx,dy; 1625{ 1626 uchar typ; 1627 xchar x, y; 1628 1629 x = cc->x; 1630 y = cc->y; 1631 while (distance-- > 0) { 1632 x += dx; 1633 y += dy; 1634 typ = levl[x][y].typ; 1635 if (!isok(x,y) || !ZAP_POS(typ) || closed_door(x,y)) 1636 return FALSE; 1637 } 1638 cc->x = x; 1639 cc->y = y; 1640 return TRUE; 1641} 1642#endif /* OVL3 */ 1643#ifdef OVL1 1644 1645int 1646mintrap(mtmp) 1647register struct monst *mtmp; 1648{ 1649 register struct trap *trap = t_at(mtmp->mx, mtmp->my); 1650 boolean trapkilled = FALSE; 1651 struct permonst *mptr = mtmp->data; 1652 struct obj *otmp; 1653 1654 if (!trap) { 1655 mtmp->mtrapped = 0; /* perhaps teleported? */ 1656 } else if (mtmp->mtrapped) { /* is currently in the trap */ 1657 if (!trap->tseen && 1658 cansee(mtmp->mx, mtmp->my) && canseemon(mtmp) && 1659 (trap->ttyp == SPIKED_PIT || trap->ttyp == BEAR_TRAP || 1660 trap->ttyp == HOLE || trap->ttyp == PIT || 1661 trap->ttyp == WEB)) { 1662 /* If you come upon an obviously trapped monster, then 1663 * you must be able to see the trap it's in too. 1664 */ 1665 seetrap(trap); 1666 } 1667 1668 if (!rn2(40)) { 1669 if (sobj_at(BOULDER, mtmp->mx, mtmp->my) && 1670 (trap->ttyp == PIT || trap->ttyp == SPIKED_PIT)) { 1671 if (!rn2(2)) { 1672 mtmp->mtrapped = 0; 1673 if (canseemon(mtmp)) 1674 pline("%s pulls free...", Monnam(mtmp)); 1675 fill_pit(mtmp->mx, mtmp->my); 1676 } 1677 } else { 1678 mtmp->mtrapped = 0; 1679 } 1680 } else if (metallivorous(mptr)) { 1681 if (trap->ttyp == BEAR_TRAP) { 1682 if (canseemon(mtmp)) 1683 pline("%s eats a bear trap!", Monnam(mtmp)); 1684 deltrap(trap); 1685 mtmp->meating = 5; 1686 mtmp->mtrapped = 0; 1687 } else if (trap->ttyp == SPIKED_PIT) { 1688 if (canseemon(mtmp)) 1689 pline("%s munches on some spikes!", Monnam(mtmp)); 1690 trap->ttyp = PIT; 1691 mtmp->meating = 5; 1692 } 1693 } 1694 } else { 1695 register int tt = trap->ttyp; 1696 boolean in_sight, tear_web, see_it, 1697 inescapable = ((tt == HOLE || tt == PIT) && 1698 In_sokoban(&u.uz) && !trap->madeby_u); 1699 const char *fallverb; 1700 1701#ifdef STEED 1702 /* true when called from dotrap, inescapable is not an option */ 1703 if (mtmp == u.usteed) inescapable = TRUE; 1704#endif 1705 if (!inescapable && 1706 ((mtmp->mtrapseen & (1 << (tt-1))) != 0 || 1707 (tt == HOLE && !mindless(mtmp->data)))) { 1708 /* it has been in such a trap - perhaps it escapes */ 1709 if(rn2(4)) return(0); 1710 } else { 1711 mtmp->mtrapseen |= (1 << (tt-1)); 1712 } 1713 /* Monster is aggravated by being trapped by you. 1714 Recognizing who made the trap isn't completely 1715 unreasonable; everybody has their own style. */ 1716 if (trap->madeby_u && rnl(5)) setmangry(mtmp); 1717 1718 in_sight = canseemon(mtmp); 1719 see_it = cansee(mtmp->mx, mtmp->my); 1720#ifdef STEED 1721 /* assume hero can tell what's going on for the steed */ 1722 if (mtmp == u.usteed) in_sight = TRUE; 1723#endif 1724 switch (tt) { 1725 case ARROW_TRAP: 1726 if (trap->once && trap->tseen && !rn2(15)) { 1727 if (in_sight && see_it) 1728 pline("%s triggers a trap but nothing happens.", 1729 Monnam(mtmp)); 1730 deltrap(trap); 1731 newsym(mtmp->mx, mtmp->my); 1732 break; 1733 } 1734 trap->once = 1; 1735 otmp = mksobj(ARROW, TRUE, FALSE); 1736 otmp->quan = 1L; 1737 otmp->owt = weight(otmp); 1738 otmp->opoisoned = 0; 1739 if (in_sight) seetrap(trap); 1740 if (thitm(8, mtmp, otmp, 0, FALSE)) trapkilled = TRUE; 1741 break; 1742 case DART_TRAP: 1743 if (trap->once && trap->tseen && !rn2(15)) { 1744 if (in_sight && see_it) 1745 pline("%s triggers a trap but nothing happens.", 1746 Monnam(mtmp)); 1747 deltrap(trap); 1748 newsym(mtmp->mx, mtmp->my); 1749 break; 1750 } 1751 trap->once = 1; 1752 otmp = mksobj(DART, TRUE, FALSE); 1753 otmp->quan = 1L; 1754 otmp->owt = weight(otmp); 1755 if (!rn2(6)) otmp->opoisoned = 1; 1756 if (in_sight) seetrap(trap); 1757 if (thitm(7, mtmp, otmp, 0, FALSE)) trapkilled = TRUE; 1758 break; 1759 case ROCKTRAP: 1760 if (trap->once && trap->tseen && !rn2(15)) { 1761 if (in_sight && see_it) 1762 pline("A trap door above %s opens, but nothing falls out!", 1763 mon_nam(mtmp)); 1764 deltrap(trap); 1765 newsym(mtmp->mx, mtmp->my); 1766 break; 1767 } 1768 trap->once = 1; 1769 otmp = mksobj(ROCK, TRUE, FALSE); 1770 otmp->quan = 1L; 1771 otmp->owt = weight(otmp); 1772 if (in_sight) seetrap(trap); 1773 if (thitm(0, mtmp, otmp, d(2, 6), FALSE)) 1774 trapkilled = TRUE; 1775 break; 1776 1777 case SQKY_BOARD: 1778 if(is_flyer(mptr)) break; 1779 /* stepped on a squeaky board */ 1780 if (in_sight) { 1781 pline("A board beneath %s squeaks loudly.", mon_nam(mtmp)); 1782 seetrap(trap); 1783 } else 1784 You_hear("a distant squeak."); 1785 /* wake up nearby monsters */ 1786 wake_nearto(mtmp->mx, mtmp->my, 40); 1787 break; 1788 1789 case BEAR_TRAP: 1790 if(mptr->msize > MZ_SMALL && 1791 !amorphous(mptr) && !is_flyer(mptr) && 1792 !is_whirly(mptr) && !unsolid(mptr)) { 1793 mtmp->mtrapped = 1; 1794 if(in_sight) { 1795 pline("%s is caught in %s bear trap!", 1796 Monnam(mtmp), a_your[trap->madeby_u]); 1797 seetrap(trap); 1798 } else { 1799 if((mptr == &mons[PM_OWLBEAR] 1800 || mptr == &mons[PM_BUGBEAR]) 1801 && flags.soundok) 1802 You_hear("the roaring of an angry bear!"); 1803 } 1804 } 1805 break; 1806 1807 case SLP_GAS_TRAP: 1808 if (!resists_sleep(mtmp) && !breathless(mptr) && 1809 !mtmp->msleeping && mtmp->mcanmove) { 1810 mtmp->mcanmove = 0; 1811 mtmp->mfrozen = rnd(25); 1812 if (in_sight) { 1813 pline("%s suddenly falls asleep!", 1814 Monnam(mtmp)); 1815 seetrap(trap); 1816 } 1817 } 1818 break; 1819 1820 case RUST_TRAP: 1821 { 1822 struct obj *target; 1823 1824 if (in_sight) 1825 seetrap(trap); 1826 switch (rn2(5)) { 1827 case 0: 1828 if (in_sight) 1829 pline("%s %s on the %s!", A_gush_of_water_hits, 1830 mon_nam(mtmp), mbodypart(mtmp, HEAD)); 1831 target = which_armor(mtmp, W_ARMH); 1832 (void) rust_dmg(target, "helmet", 1, TRUE, mtmp); 1833 break; 1834 case 1: 1835 if (in_sight) 1836 pline("%s %s's left %s!", A_gush_of_water_hits, 1837 mon_nam(mtmp), mbodypart(mtmp, ARM)); 1838 target = which_armor(mtmp, W_ARMS); 1839 if (rust_dmg(target, "shield", 1, TRUE, mtmp)) 1840 break; 1841 target = MON_WEP(mtmp); 1842 if (target && bimanual(target)) 1843 erode_obj(target, FALSE, TRUE); 1844glovecheck: target = which_armor(mtmp, W_ARMG); 1845 (void) rust_dmg(target, "gauntlets", 1, TRUE, mtmp); 1846 break; 1847 case 2: 1848 if (in_sight) 1849 pline("%s %s's right %s!", A_gush_of_water_hits, 1850 mon_nam(mtmp), mbodypart(mtmp, ARM)); 1851 erode_obj(MON_WEP(mtmp), FALSE, TRUE); 1852 goto glovecheck; 1853 default: 1854 if (in_sight) 1855 pline("%s %s!", A_gush_of_water_hits, 1856 mon_nam(mtmp)); 1857 for (otmp=mtmp->minvent; otmp; otmp = otmp->nobj) 1858 (void) snuff_lit(otmp); 1859 target = which_armor(mtmp, W_ARMC); 1860 if (target) 1861 (void) rust_dmg(target, cloak_simple_name(target), 1862 1, TRUE, mtmp); 1863 else { 1864 target = which_armor(mtmp, W_ARM); 1865 if (target) 1866 (void) rust_dmg(target, "armor", 1, TRUE, mtmp); 1867#ifdef TOURIST 1868 else { 1869 target = which_armor(mtmp, W_ARMU); 1870 (void) rust_dmg(target, "shirt", 1, TRUE, mtmp); 1871 } 1872#endif 1873 } 1874 } 1875 if (mptr == &mons[PM_IRON_GOLEM]) { 1876 if (in_sight) 1877 pline("%s falls to pieces!", Monnam(mtmp)); 1878 else if(mtmp->mtame) 1879 pline("May %s rust in peace.", 1880 mon_nam(mtmp)); 1881 mondied(mtmp); 1882 if (mtmp->mhp <= 0) 1883 trapkilled = TRUE; 1884 } else if (mptr == &mons[PM_GREMLIN] && rn2(3)) { 1885 (void)split_mon(mtmp, (struct monst *)0); 1886 } 1887 break; 1888 } 1889 case FIRE_TRAP: 1890 mfiretrap: 1891 if (in_sight) 1892 pline("A %s erupts from the %s under %s!", 1893 tower_of_flame, 1894 surface(mtmp->mx,mtmp->my), mon_nam(mtmp)); 1895 else if (see_it) /* evidently `mtmp' is invisible */ 1896 You("see a %s erupt from the %s!", 1897 tower_of_flame, surface(mtmp->mx,mtmp->my)); 1898 1899 if (resists_fire(mtmp)) { 1900 if (in_sight) { 1901 shieldeff(mtmp->mx,mtmp->my); 1902 pline("%s is uninjured.", Monnam(mtmp)); 1903 } 1904 } else { 1905 int num = d(2,4), alt; 1906 boolean immolate = FALSE; 1907 1908 /* paper burns very fast, assume straw is tightly 1909 * packed and burns a bit slower */ 1910 switch (monsndx(mtmp->data)) { 1911 case PM_PAPER_GOLEM: immolate = TRUE; 1912 alt = mtmp->mhpmax; break; 1913 case PM_STRAW_GOLEM: alt = mtmp->mhpmax / 2; break; 1914 case PM_WOOD_GOLEM: alt = mtmp->mhpmax / 4; break; 1915 case PM_LEATHER_GOLEM: alt = mtmp->mhpmax / 8; break; 1916 default: alt = 0; break; 1917 } 1918 if (alt > num) num = alt; 1919 1920 if (thitm(0, mtmp, (struct obj *)0, num, immolate)) 1921 trapkilled = TRUE; 1922 else 1923 /* we know mhp is at least `num' below mhpmax, 1924 so no (mhp > mhpmax) check is needed here */ 1925 mtmp->mhpmax -= rn2(num + 1); 1926 } 1927 if (burnarmor(mtmp) || rn2(3)) { 1928 (void) destroy_mitem(mtmp, SCROLL_CLASS, AD_FIRE); 1929 (void) destroy_mitem(mtmp, SPBOOK_CLASS, AD_FIRE); 1930 (void) destroy_mitem(mtmp, POTION_CLASS, AD_FIRE); 1931 } 1932 if (burn_floor_paper(mtmp->mx, mtmp->my, see_it, FALSE) && 1933 !see_it && distu(mtmp->mx, mtmp->my) <= 3*3) 1934 You("smell smoke."); 1935 if (is_ice(mtmp->mx,mtmp->my)) 1936 melt_ice(mtmp->mx,mtmp->my); 1937 if (see_it) seetrap(trap); 1938 break; 1939 1940 case PIT: 1941 case SPIKED_PIT: 1942 fallverb = "falls"; 1943 if (is_flyer(mptr) || is_floater(mptr) || 1944 (mtmp->wormno && count_wsegs(mtmp) > 5) || 1945 is_clinger(mptr)) { 1946 if (!inescapable) break; /* avoids trap */ 1947 fallverb = "is dragged"; /* sokoban pit */ 1948 } 1949 if (!passes_walls(mptr)) 1950 mtmp->mtrapped = 1; 1951 if (in_sight) { 1952 pline("%s %s into %s pit!", 1953 Monnam(mtmp), fallverb, 1954 a_your[trap->madeby_u]); 1955 if (mptr == &mons[PM_PIT_VIPER] || mptr == &mons[PM_PIT_FIEND]) 1956 pline("How pitiful. Isn't that the pits?"); 1957 seetrap(trap); 1958 } 1959 mselftouch(mtmp, "Falling, ", FALSE); 1960 if (mtmp->mhp <= 0 || 1961 thitm(0, mtmp, (struct obj *)0, 1962 rnd((tt == PIT) ? 6 : 10), FALSE)) 1963 trapkilled = TRUE; 1964 break; 1965 case HOLE: 1966 case TRAPDOOR: 1967 if (!Can_fall_thru(&u.uz)) { 1968 impossible("mintrap: %ss cannot exist on this level.", 1969 defsyms[trap_to_defsym(tt)].explanation); 1970 break; /* don't activate it after all */ 1971 } 1972 if (is_flyer(mptr) || is_floater(mptr) || 1973 mptr == &mons[PM_WUMPUS] || 1974 (mtmp->wormno && count_wsegs(mtmp) > 5) || 1975 mptr->msize >= MZ_HUGE) { 1976 if (inescapable) { /* sokoban hole */ 1977 if (in_sight) { 1978 pline("%s seems to be yanked down!", 1979 Monnam(mtmp)); 1980 /* suppress message in mlevel_tele_trap() */ 1981 in_sight = FALSE; 1982 seetrap(trap); 1983 } 1984 } else 1985 break; 1986 } 1987 /* Fall through */ 1988 case LEVEL_TELEP: 1989 case MAGIC_PORTAL: 1990 { 1991 int mlev_res; 1992 mlev_res = mlevel_tele_trap(mtmp, trap, 1993 inescapable, in_sight); 1994 if (mlev_res) return(mlev_res); 1995 } 1996 break; 1997 1998 case TELEP_TRAP: 1999 mtele_trap(mtmp, trap, in_sight); 2000 break; 2001 2002 case WEB: 2003 /* Monster in a web. */ 2004 if (webmaker(mptr)) break; 2005 if (amorphous(mptr) || is_whirly(mptr) || unsolid(mptr)){ 2006 if(acidic(mptr) || 2007 mptr == &mons[PM_GELATINOUS_CUBE] || 2008 mptr == &mons[PM_FIRE_ELEMENTAL]) { 2009 if (in_sight) 2010 pline("%s %s %s spider web!", 2011 Monnam(mtmp), 2012 (mptr == &mons[PM_FIRE_ELEMENTAL]) ? 2013 "burns" : "dissolves", 2014 a_your[trap->madeby_u]); 2015 deltrap(trap); 2016 newsym(mtmp->mx, mtmp->my); 2017 break; 2018 } 2019 if (in_sight) { 2020 pline("%s flows through %s spider web.", 2021 Monnam(mtmp), 2022 a_your[trap->madeby_u]); 2023 seetrap(trap); 2024 } 2025 break; 2026 } 2027 tear_web = FALSE; 2028 switch (monsndx(mptr)) { 2029 case PM_OWLBEAR: /* Eric Backus */ 2030 case PM_BUGBEAR: 2031 if (!in_sight) { 2032 You_hear("the roaring of a confused bear!"); 2033 mtmp->mtrapped = 1; 2034 break; 2035 } 2036 /* fall though */ 2037 default: 2038 if (mptr->mlet == S_GIANT || 2039 (mptr->mlet == S_DRAGON && 2040 extra_nasty(mptr)) || /* excl. babies */ 2041 (mtmp->wormno && count_wsegs(mtmp) > 5)) { 2042 tear_web = TRUE; 2043 } else if (in_sight) { 2044 pline("%s is caught in %s spider web.", 2045 Monnam(mtmp), 2046 a_your[trap->madeby_u]); 2047 seetrap(trap); 2048 } 2049 mtmp->mtrapped = tear_web ? 0 : 1; 2050 break; 2051 /* this list is fairly arbitrary; it deliberately 2052 excludes wumpus & giant/ettin zombies/mummies */ 2053 case PM_TITANOTHERE: 2054 case PM_BALUCHITHERIUM: 2055 case PM_PURPLE_WORM: 2056 case PM_JABBERWOCK: 2057 case PM_IRON_GOLEM: 2058 case PM_BALROG: 2059 case PM_KRAKEN: 2060 case PM_MASTODON: 2061 tear_web = TRUE; 2062 break; 2063 } 2064 if (tear_web) { 2065 if (in_sight) 2066 pline("%s tears through %s spider web!", 2067 Monnam(mtmp), a_your[trap->madeby_u]); 2068 deltrap(trap); 2069 newsym(mtmp->mx, mtmp->my); 2070 } 2071 break; 2072 2073 case STATUE_TRAP: 2074 break; 2075 2076 case MAGIC_TRAP: 2077 /* A magic trap. Monsters usually immune. */ 2078 if (!rn2(21)) goto mfiretrap; 2079 break; 2080 case ANTI_MAGIC: 2081 break; 2082 2083 case LANDMINE: 2084 if(rn2(3)) 2085 break; /* monsters usually don't set it off */ 2086 if(is_flyer(mptr)) { 2087 boolean already_seen = trap->tseen; 2088 if (in_sight && !already_seen) { 2089 pline("A trigger appears in a pile of soil below %s.", mon_nam(mtmp)); 2090 seetrap(trap); 2091 } 2092 if (rn2(3)) break; 2093 if (in_sight) { 2094 newsym(mtmp->mx, mtmp->my); 2095 pline_The("air currents set %s off!", 2096 already_seen ? "a land mine" : "it"); 2097 } 2098 } else if(in_sight) { 2099 newsym(mtmp->mx, mtmp->my); 2100 pline("KAABLAMM!!! %s triggers %s land mine!", 2101 Monnam(mtmp), a_your[trap->madeby_u]); 2102 } 2103 if (!in_sight) 2104 pline("Kaablamm! You hear an explosion in the distance!"); 2105 blow_up_landmine(trap); 2106 if (thitm(0, mtmp, (struct obj *)0, rnd(16), FALSE)) 2107 trapkilled = TRUE; 2108 else { 2109 /* monsters recursively fall into new pit */ 2110 if (mintrap(mtmp) == 2) trapkilled=TRUE; 2111 } 2112 /* a boulder may fill the new pit, crushing monster */ 2113 fill_pit(trap->tx, trap->ty); 2114 if (mtmp->mhp <= 0) trapkilled = TRUE; 2115 if (unconscious()) { 2116 multi = -1; 2117 nomovemsg="The explosion awakens you!"; 2118 } 2119 break; 2120 2121 case POLY_TRAP: 2122 if (resists_magm(mtmp)) { 2123 shieldeff(mtmp->mx, mtmp->my); 2124 } else if (!resist(mtmp, WAND_CLASS, 0, NOTELL)) { 2125 (void) newcham(mtmp, (struct permonst *)0, 2126 FALSE, FALSE); 2127 if (in_sight) seetrap(trap); 2128 } 2129 break; 2130 2131 case ROLLING_BOULDER_TRAP: 2132 if (!is_flyer(mptr)) { 2133 int style = ROLL | (in_sight ? 0 : LAUNCH_UNSEEN); 2134 2135 newsym(mtmp->mx,mtmp->my); 2136 if (in_sight) 2137 pline("Click! %s triggers %s.", Monnam(mtmp), 2138 trap->tseen ? 2139 "a rolling boulder trap" : 2140 something); 2141 if (launch_obj(BOULDER, trap->launch.x, trap->launch.y, 2142 trap->launch2.x, trap->launch2.y, style)) { 2143 if (in_sight) trap->tseen = TRUE; 2144 if (mtmp->mhp <= 0) trapkilled = TRUE; 2145 } else { 2146 deltrap(trap); 2147 newsym(mtmp->mx,mtmp->my); 2148 } 2149 } 2150 break; 2151 2152 default: 2153 impossible("Some monster encountered a strange trap of type %d.", tt); 2154 } 2155 } 2156 if(trapkilled) return 2; 2157 return mtmp->mtrapped; 2158} 2159 2160#endif /* OVL1 */ 2161#ifdef OVLB 2162 2163/* Combine cockatrice checks into single functions to avoid repeating code. */ 2164void 2165instapetrify(str) 2166const char *str; 2167{ 2168 if (Stone_resistance) return; 2169 if (poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM)) 2170 return; 2171 You("turn to stone..."); 2172 killer_format = KILLED_BY; 2173 killer = str; 2174 done(STONING); 2175} 2176 2177void 2178minstapetrify(mon,byplayer) 2179struct monst *mon; 2180boolean byplayer; 2181{ 2182 if (resists_ston(mon)) return; 2183 if (poly_when_stoned(mon->data)) { 2184 mon_to_stone(mon); 2185 return; 2186 } 2187 2188 /* give a "<mon> is slowing down" message and also remove 2189 intrinsic speed (comparable to similar effect on the hero) */ 2190 mon_adjust_speed(mon, -3, (struct obj *)0); 2191 2192 if (cansee(mon->mx, mon->my)) 2193 pline("%s turns to stone.", Monnam(mon)); 2194 if (byplayer) { 2195 stoned = TRUE; 2196 xkilled(mon,0); 2197 } else monstone(mon); 2198} 2199 2200void 2201selftouch(arg) 2202const char *arg; 2203{ 2204 char kbuf[BUFSZ]; 2205 2206 if(uwep && uwep->otyp == CORPSE && touch_petrifies(&mons[uwep->corpsenm]) 2207 && !Stone_resistance) { 2208 pline("%s touch the %s corpse.", arg, 2209 mons[uwep->corpsenm].mname); 2210 Sprintf(kbuf, "%s corpse", an(mons[uwep->corpsenm].mname)); 2211 instapetrify(kbuf); 2212 } 2213 /* Or your secondary weapon, if wielded */ 2214 if(u.twoweap && uswapwep && uswapwep->otyp == CORPSE && 2215 touch_petrifies(&mons[uswapwep->corpsenm]) && !Stone_resistance){ 2216 pline("%s touch the %s corpse.", arg, 2217 mons[uswapwep->corpsenm].mname); 2218 Sprintf(kbuf, "%s corpse", an(mons[uswapwep->corpsenm].mname)); 2219 instapetrify(kbuf); 2220 } 2221} 2222 2223void 2224mselftouch(mon,arg,byplayer) 2225struct monst *mon; 2226const char *arg; 2227boolean byplayer; 2228{ 2229 struct obj *mwep = MON_WEP(mon); 2230 2231 if (mwep && mwep->otyp == CORPSE && touch_petrifies(&mons[mwep->corpsenm])) { 2232 if (cansee(mon->mx, mon->my)) { 2233 pline("%s%s touches the %s corpse.", 2234 arg ? arg : "", arg ? mon_nam(mon) : Monnam(mon), 2235 mons[mwep->corpsenm].mname); 2236 } 2237 minstapetrify(mon, byplayer); 2238 } 2239} 2240 2241void 2242float_up() 2243{ 2244 if(u.utrap) { 2245 if(u.utraptype == TT_PIT) { 2246 u.utrap = 0; 2247 You("float up, out of the pit!"); 2248 vision_full_recalc = 1; /* vision limits change */ 2249 fill_pit(u.ux, u.uy); 2250 } else if (u.utraptype == TT_INFLOOR) { 2251 Your("body pulls upward, but your %s are still stuck.", 2252 makeplural(body_part(LEG))); 2253 } else { 2254 You("float up, only your %s is still stuck.", 2255 body_part(LEG)); 2256 } 2257 } 2258 else if(Is_waterlevel(&u.uz)) 2259 pline("It feels as though you've lost some weight."); 2260 else if(u.uinwater) 2261 spoteffects(TRUE); 2262 else if(u.uswallow) 2263 You(is_animal(u.ustuck->data) ? 2264 "float away from the %s." : 2265 "spiral up into %s.", 2266 is_animal(u.ustuck->data) ? 2267 surface(u.ux, u.uy) : 2268 mon_nam(u.ustuck)); 2269 else if (Hallucination) 2270 pline("Up, up, and awaaaay! You're walking on air!"); 2271 else if(Is_airlevel(&u.uz)) 2272 You("gain control over your movements."); 2273 else 2274 You("start to float in the air!"); 2275#ifdef STEED 2276 if (u.usteed && !is_floater(u.usteed->data) && 2277 !is_flyer(u.usteed->data)) { 2278 if (Lev_at_will) 2279 pline("%s magically floats up!", Monnam(u.usteed)); 2280 else { 2281 You("cannot stay on %s.", mon_nam(u.usteed)); 2282 dismount_steed(DISMOUNT_GENERIC); 2283 } 2284 } 2285#endif 2286 return; 2287} 2288 2289void 2290fill_pit(x, y) 2291int x, y; 2292{ 2293 struct obj *otmp; 2294 struct trap *t; 2295 2296 if ((t = t_at(x, y)) && 2297 ((t->ttyp == PIT) || (t->ttyp == SPIKED_PIT)) && 2298 (otmp = sobj_at(BOULDER, x, y))) { 2299 obj_extract_self(otmp); 2300 (void) flooreffects(otmp, x, y, "settle"); 2301 } 2302} 2303 2304int 2305float_down(hmask, emask) 2306long hmask, emask; /* might cancel timeout */ 2307{ 2308 register struct trap *trap = (struct trap *)0; 2309 d_level current_dungeon_level; 2310 boolean no_msg = FALSE; 2311 2312 HLevitation &= ~hmask; 2313 ELevitation &= ~emask; 2314 if(Levitation) return(0); /* maybe another ring/potion/boots */ 2315 if(u.uswallow) { 2316 You("float down, but you are still %s.", 2317 is_animal(u.ustuck->data) ? "swallowed" : "engulfed"); 2318 return(1); 2319 } 2320 2321 if (Punished && !carried(uball) && 2322 (is_pool(uball->ox, uball->oy) || 2323 ((trap = t_at(uball->ox, uball->oy)) && 2324 ((trap->ttyp == PIT) || (trap->ttyp == SPIKED_PIT) || 2325 (trap->ttyp == TRAPDOOR) || (trap->ttyp == HOLE))))) { 2326 u.ux0 = u.ux; 2327 u.uy0 = u.uy; 2328 u.ux = uball->ox; 2329 u.uy = uball->oy; 2330 movobj(uchain, uball->ox, uball->oy); 2331 newsym(u.ux0, u.uy0); 2332 vision_full_recalc = 1; /* in case the hero moved. */ 2333 } 2334 /* check for falling into pool - added by GAN 10/20/86 */ 2335 if(!Flying) { 2336 if (!u.uswallow && u.ustuck) { 2337 if (sticks(youmonst.data)) 2338 You("aren't able to maintain your hold on %s.", 2339 mon_nam(u.ustuck)); 2340 else 2341 pline("Startled, %s can no longer hold you!", 2342 mon_nam(u.ustuck)); 2343 u.ustuck = 0; 2344 } 2345 /* kludge alert: 2346 * drown() and lava_effects() print various messages almost 2347 * every time they're called which conflict with the "fall 2348 * into" message below. Thus, we want to avoid printing 2349 * confusing, duplicate or out-of-order messages. 2350 * Use knowledge of the two routines as a hack -- this 2351 * should really be handled differently -dlc 2352 */ 2353 if(is_pool(u.ux,u.uy) && !Wwalking && !Swimming && !u.uinwater) 2354 no_msg = drown(); 2355 2356 if(is_lava(u.ux,u.uy)) { 2357 (void) lava_effects(); 2358 no_msg = TRUE; 2359 } 2360 } 2361 if (!trap) { 2362 trap = t_at(u.ux,u.uy); 2363 if(Is_airlevel(&u.uz)) 2364 You("begin to tumble in place."); 2365 else if (Is_waterlevel(&u.uz) && !no_msg) 2366 You_feel("heavier."); 2367 /* u.uinwater msgs already in spoteffects()/drown() */ 2368 else if (!u.uinwater && !no_msg) { 2369#ifdef STEED 2370 if (!(emask & W_SADDLE)) 2371#endif 2372 { 2373 boolean sokoban_trap = (In_sokoban(&u.uz) && trap); 2374 if (Hallucination) 2375 pline("Bummer! You've %s.", 2376 is_pool(u.ux,u.uy) ? 2377 "splashed down" : sokoban_trap ? "crashed" : 2378 "hit the ground"); 2379 else { 2380 if (!sokoban_trap) 2381 You("float gently to the %s.", 2382 surface(u.ux, u.uy)); 2383 else { 2384 /* Justification elsewhere for Sokoban traps 2385 * is based on air currents. This is 2386 * consistent with that. 2387 * The unexpected additional force of the 2388 * air currents once leviation 2389 * ceases knocks you off your feet. 2390 */ 2391 You("fall over."); 2392 losehp(rnd(2), "dangerous winds", KILLED_BY); 2393#ifdef STEED 2394 if (u.usteed) dismount_steed(DISMOUNT_FELL); 2395#endif 2396 selftouch("As you fall, you"); 2397 } 2398 } 2399 } 2400 } 2401 } 2402 2403 /* can't rely on u.uz0 for detecting trap door-induced level change; 2404 it gets changed to reflect the new level before we can check it */ 2405 assign_level(¤t_dungeon_level, &u.uz); 2406 2407 if(trap) 2408 switch(trap->ttyp) { 2409 case STATUE_TRAP: 2410 break; 2411 case HOLE: 2412 case TRAPDOOR: 2413 if(!Can_fall_thru(&u.uz) || u.ustuck) 2414 break; 2415 /* fall into next case */ 2416 default: 2417 if (!u.utrap) /* not already in the trap */ 2418 dotrap(trap, 0); 2419 } 2420 2421 if (!Is_airlevel(&u.uz) && !Is_waterlevel(&u.uz) && !u.uswallow && 2422 /* falling through trap door calls goto_level, 2423 and goto_level does its own pickup() call */ 2424 on_level(&u.uz, ¤t_dungeon_level)) 2425 (void) pickup(1); 2426 return 1; 2427} 2428 2429STATIC_OVL void 2430dofiretrap(box) 2431struct obj *box; /* null for floor trap */ 2432{ 2433 boolean see_it = !Blind; 2434 int num, alt; 2435 2436/* Bug: for box case, the equivalent of burn_floor_paper() ought 2437 * to be done upon its contents. 2438 */ 2439 2440 if ((box && !carried(box)) ? is_pool(box->ox, box->oy) : Underwater) { 2441 pline("A cascade of steamy bubbles erupts from %s!", 2442 the(box ? xname(box) : surface(u.ux,u.uy))); 2443 if (Fire_resistance) You("are uninjured."); 2444 else losehp(rnd(3), "boiling water", KILLED_BY); 2445 return; 2446 } 2447 pline("A %s %s from %s!", tower_of_flame, 2448 box ? "bursts" : "erupts", 2449 the(box ? xname(box) : surface(u.ux,u.uy))); 2450 if (Fire_resistance) { 2451 shieldeff(u.ux, u.uy); 2452 num = rn2(2); 2453 } else if (Upolyd) { 2454 num = d(2,4); 2455 switch (u.umonnum) { 2456 case PM_PAPER_GOLEM: alt = u.mhmax; break; 2457 case PM_STRAW_GOLEM: alt = u.mhmax / 2; break; 2458 case PM_WOOD_GOLEM: alt = u.mhmax / 4; break; 2459 case PM_LEATHER_GOLEM: alt = u.mhmax / 8; break; 2460 default: alt = 0; break; 2461 } 2462 if (alt > num) num = alt; 2463 if (u.mhmax > mons[u.umonnum].mlevel) 2464 u.mhmax -= rn2(min(u.mhmax,num + 1)), flags.botl = 1; 2465 } else { 2466 num = d(2,4); 2467 if (u.uhpmax > u.ulevel) 2468 u.uhpmax -= rn2(min(u.uhpmax,num + 1)), flags.botl = 1; 2469 } 2470 if (!num) 2471 You("are uninjured."); 2472 else 2473 losehp(num, tower_of_flame, KILLED_BY_AN); 2474 burn_away_slime(); 2475 2476 if (burnarmor(&youmonst) || rn2(3)) { 2477 destroy_item(SCROLL_CLASS, AD_FIRE); 2478 destroy_item(SPBOOK_CLASS, AD_FIRE); 2479 destroy_item(POTION_CLASS, AD_FIRE); 2480 } 2481 if (!box && burn_floor_paper(u.ux, u.uy, see_it, TRUE) && !see_it) 2482 You("smell paper burning."); 2483 if (is_ice(u.ux, u.uy)) 2484 melt_ice(u.ux, u.uy); 2485} 2486 2487STATIC_OVL void 2488domagictrap() 2489{ 2490 register int fate = rnd(20); 2491 2492 /* What happened to the poor sucker? */ 2493 2494 if (fate < 10) { 2495 /* Most of the time, it creates some monsters. */ 2496 register int cnt = rnd(4); 2497 2498 if (!resists_blnd(&youmonst)) { 2499 You("are momentarily blinded by a flash of light!"); 2500 make_blinded((long)rn1(5,10),FALSE); 2501 if (!Blind) Your(vision_clears); 2502 } else if (!Blind) { 2503 You("see a flash of light!"); 2504 } else 2505 You_hear("a deafening roar!"); 2506 while(cnt--) 2507 (void) makemon((struct permonst *) 0, u.ux, u.uy, NO_MM_FLAGS); 2508 } 2509 else 2510 switch (fate) { 2511 2512 case 10: 2513 case 11: 2514 /* sometimes nothing happens */ 2515 break; 2516 case 12: /* a flash of fire */ 2517 dofiretrap((struct obj *)0); 2518 break; 2519 2520 /* odd feelings */ 2521 case 13: pline("A shiver runs up and down your %s!", 2522 body_part(SPINE)); 2523 break; 2524 case 14: You_hear(Hallucination ? 2525 "the moon howling at you." : 2526 "distant howling."); 2527 break; 2528 case 15: if (on_level(&u.uz, &qstart_level)) 2529 You_feel("%slike the prodigal son.", 2530 (flags.female || (Upolyd && is_neuter(youmonst.data))) ? 2531 "oddly " : ""); 2532 else 2533 You("suddenly yearn for %s.", 2534 Hallucination ? "Cleveland" : 2535 (In_quest(&u.uz) || at_dgn_entrance("The Quest")) ? 2536 "your nearby homeland" : 2537 "your distant homeland"); 2538 break; 2539 case 16: Your("pack shakes violently!"); 2540 break; 2541 case 17: You(Hallucination ? 2542 "smell hamburgers." : 2543 "smell charred flesh."); 2544 break; 2545 case 18: You_feel("tired."); 2546 break; 2547 2548 /* very occasionally something nice happens. */ 2549 2550 case 19: 2551 /* tame nearby monsters */ 2552 { register int i,j; 2553 register struct monst *mtmp; 2554 2555 (void) adjattrib(A_CHA,1,FALSE); 2556 for(i = -1; i <= 1; i++) for(j = -1; j <= 1; j++) { 2557 if(!isok(u.ux+i, u.uy+j)) continue; 2558 mtmp = m_at(u.ux+i, u.uy+j); 2559 if(mtmp) 2560 (void) tamedog(mtmp, (struct obj *)0); 2561 } 2562 break; 2563 } 2564 2565 case 20: 2566 /* uncurse stuff */ 2567 { struct obj pseudo; 2568 long save_conf = HConfusion; 2569 2570 pseudo = zeroobj; /* neither cursed nor blessed */ 2571 pseudo.otyp = SCR_REMOVE_CURSE; 2572 HConfusion = 0L; 2573 (void) seffects(&pseudo); 2574 HConfusion = save_conf; 2575 break; 2576 } 2577 default: break; 2578 } 2579} 2580 2581/* 2582 * Scrolls, spellbooks, potions, and flammable items 2583 * may get affected by the fire. 2584 * 2585 * Return number of objects destroyed. --ALI 2586 */ 2587int 2588fire_damage(chain, force, here, x, y) 2589struct obj *chain; 2590boolean force, here; 2591xchar x, y; 2592{ 2593 int chance; 2594 struct obj *obj, *otmp, *nobj, *ncobj; 2595 int retval = 0; 2596 int in_sight = !Blind && couldsee(x, y); /* Don't care if it's lit */ 2597 int dindx; 2598 2599 for (obj = chain; obj; obj = nobj) { 2600 nobj = here ? obj->nexthere : obj->nobj; 2601 2602 /* object might light in a controlled manner */ 2603 if (catch_lit(obj)) 2604 continue; 2605 2606 if (Is_container(obj)) { 2607 switch (obj->otyp) { 2608 case ICE_BOX: 2609 continue; /* Immune */ 2610 /*NOTREACHED*/ 2611 break; 2612 case CHEST: 2613 chance = 40; 2614 break; 2615 case LARGE_BOX: 2616 chance = 30; 2617 break; 2618 default: 2619 chance = 20; 2620 break; 2621 } 2622 if (!force && (Luck + 5) > rn2(chance)) 2623 continue; 2624 /* Container is burnt up - dump contents out */ 2625 if (in_sight) pline("%s catches fire and burns.", Yname2(obj)); 2626 if (Has_contents(obj)) { 2627 if (in_sight) pline("Its contents fall out."); 2628 for (otmp = obj->cobj; otmp; otmp = ncobj) { 2629 ncobj = otmp->nobj; 2630 obj_extract_self(otmp); 2631 if (!flooreffects(otmp, x, y, "")) 2632 place_object(otmp, x, y); 2633 } 2634 } 2635 delobj(obj); 2636 retval++; 2637 } else if (!force && (Luck + 5) > rn2(20)) { 2638 /* chance per item of sustaining damage: 2639 * max luck (full moon): 5% 2640 * max luck (elsewhen): 10% 2641 * avg luck (Luck==0): 75% 2642 * awful luck (Luck<-4): 100% 2643 */ 2644 continue; 2645 } else if (obj->oclass == SCROLL_CLASS || obj->oclass == SPBOOK_CLASS) { 2646 if (obj->otyp == SCR_FIRE || obj->otyp == SPE_FIREBALL) 2647 continue; 2648 if (obj->otyp == SPE_BOOK_OF_THE_DEAD) { 2649 if (in_sight) pline("Smoke rises from %s.", the(xname(obj))); 2650 continue; 2651 } 2652 dindx = (obj->oclass == SCROLL_CLASS) ? 2 : 3; 2653 if (in_sight) 2654 pline("%s %s.", Yname2(obj), (obj->quan > 1) ? 2655 destroy_strings[dindx*3 + 1] : destroy_strings[dindx*3]); 2656 delobj(obj); 2657 retval++; 2658 } else if (obj->oclass == POTION_CLASS) { 2659 dindx = 1; 2660 if (in_sight) 2661 pline("%s %s.", Yname2(obj), (obj->quan > 1) ? 2662 destroy_strings[dindx*3 + 1] : destroy_strings[dindx*3]); 2663 delobj(obj); 2664 retval++; 2665 } else if (is_flammable(obj) && obj->oeroded < MAX_ERODE && 2666 !(obj->oerodeproof || (obj->blessed && !rnl(4)))) { 2667 if (in_sight) { 2668 pline("%s %s%s.", Yname2(obj), otense(obj, "burn"), 2669 obj->oeroded+1 == MAX_ERODE ? " completely" : 2670 obj->oeroded ? " further" : ""); 2671 } 2672 obj->oeroded++; 2673 } 2674 } 2675 2676 if (retval && !in_sight) 2677 You("smell smoke."); 2678 return retval; 2679} 2680 2681void 2682water_damage(obj, force, here) 2683register struct obj *obj; 2684register boolean force, here; 2685{ 2686 struct obj *otmp; 2687 2688 /* Scrolls, spellbooks, potions, weapons and 2689 pieces of armor may get affected by the water */ 2690 for (; obj; obj = otmp) { 2691 otmp = here ? obj->nexthere : obj->nobj; 2692 2693 (void) snuff_lit(obj); 2694 2695 if(obj->otyp == CAN_OF_GREASE && obj->spe > 0) { 2696 continue; 2697 } else if(obj->greased) { 2698 if (force || !rn2(2)) obj->greased = 0; 2699 } else if(Is_container(obj) && !Is_box(obj) && 2700 (obj->otyp != OILSKIN_SACK || (obj->cursed && !rn2(3)))) { 2701 water_damage(obj->cobj, force, FALSE); 2702 } else if (!force && (Luck + 5) > rn2(20)) { 2703 /* chance per item of sustaining damage: 2704 * max luck (full moon): 5% 2705 * max luck (elsewhen): 10% 2706 * avg luck (Luck==0): 75% 2707 * awful luck (Luck<-4): 100% 2708 */ 2709 continue; 2710 } else if (obj->oclass == SCROLL_CLASS) { 2711#ifdef MAIL 2712 if (obj->otyp != SCR_MAIL) 2713#endif 2714 { 2715 obj->otyp = SCR_BLANK_PAPER; 2716 obj->spe = 0; 2717 } 2718 } else if (obj->oclass == SPBOOK_CLASS) { 2719 if (obj->otyp == SPE_BOOK_OF_THE_DEAD) 2720 pline("Steam rises from %s.", the(xname(obj))); 2721 else obj->otyp = SPE_BLANK_PAPER; 2722 } else if (obj->oclass == POTION_CLASS) { 2723 if (obj->otyp == POT_ACID) { 2724 /* damage player/monster? */ 2725 pline("A potion explodes!"); 2726 delobj(obj); 2727 continue; 2728 } else if (obj->odiluted) { 2729 obj->otyp = POT_WATER; 2730 obj->blessed = obj->cursed = 0; 2731 obj->odiluted = 0; 2732 } else if (obj->otyp != POT_WATER) 2733 obj->odiluted++; 2734 } else if (is_rustprone(obj) && obj->oeroded < MAX_ERODE && 2735 !(obj->oerodeproof || (obj->blessed && !rnl(4)))) { 2736 /* all metal stuff and armor except (body armor 2737 protected by oilskin cloak) */ 2738 if(obj->oclass != ARMOR_CLASS || obj != uarm || 2739 !uarmc || uarmc->otyp != OILSKIN_CLOAK || 2740 (uarmc->cursed && !rn2(3))) 2741 obj->oeroded++; 2742 } 2743 } 2744} 2745 2746/* 2747 * This function is potentially expensive - rolling 2748 * inventory list multiple times. Luckily it's seldom needed. 2749 * Returns TRUE if disrobing made player unencumbered enough to 2750 * crawl out of the current predicament. 2751 */ 2752STATIC_OVL boolean 2753emergency_disrobe(lostsome) 2754boolean *lostsome; 2755{ 2756 int invc = inv_cnt(); 2757 2758 while (near_capacity() > (Punished ? UNENCUMBERED : SLT_ENCUMBER)) { 2759 register struct obj *obj, *otmp = (struct obj *)0; 2760 register int i; 2761 2762 /* Pick a random object */ 2763 if (invc > 0) { 2764 i = rn2(invc); 2765 for (obj = invent; obj; obj = obj->nobj) { 2766 /* 2767 * Undroppables are: body armor, boots, gloves, 2768 * amulets, and rings because of the time and effort 2769 * in removing them + loadstone and other cursed stuff 2770 * for obvious reasons. 2771 */ 2772 if (!((obj->otyp == LOADSTONE && obj->cursed) || 2773 obj == uamul || obj == uleft || obj == uright || 2774 obj == ublindf || obj == uarm || obj == uarmc || 2775 obj == uarmg || obj == uarmf || 2776#ifdef TOURIST 2777 obj == uarmu || 2778#endif 2779 (obj->cursed && (obj == uarmh || obj == uarms)) || 2780 welded(obj))) 2781 otmp = obj; 2782 /* reached the mark and found some stuff to drop? */ 2783 if (--i < 0 && otmp) break; 2784 2785 /* else continue */ 2786 } 2787 } 2788#ifndef GOLDOBJ 2789 if (!otmp) { 2790 /* Nothing available left to drop; try gold */ 2791 if (u.ugold) { 2792 pline("In desperation, you drop your purse."); 2793 /* Hack: gold is not in the inventory, so make a gold object 2794 * and put it at the head of the inventory list. 2795 */ 2796 obj = mkgoldobj(u.ugold); /* removes from u.ugold */ 2797 obj->in_use = TRUE; 2798 u.ugold = obj->quan; /* put the gold back */ 2799 assigninvlet(obj); /* might end up as NOINVSYM */ 2800 obj->nobj = invent; 2801 invent = obj; 2802 *lostsome = TRUE; 2803 dropx(obj); 2804 continue; /* Try again */ 2805 } 2806 /* We can't even drop gold! */ 2807 return (FALSE); 2808 } 2809#else 2810 if (!otmp) return (FALSE); /* nothing to drop! */ 2811#endif 2812 if (otmp->owornmask) remove_worn_item(otmp, FALSE); 2813 *lostsome = TRUE; 2814 dropx(otmp); 2815 invc--; 2816 } 2817 return(TRUE); 2818} 2819 2820/* 2821 * return(TRUE) == player relocated 2822 */ 2823boolean 2824drown() 2825{ 2826 boolean inpool_ok = FALSE, crawl_ok; 2827 int i, x, y; 2828 2829 /* happily wading in the same contiguous pool */ 2830 if (u.uinwater && is_pool(u.ux-u.dx,u.uy-u.dy) && 2831 (Swimming || Amphibious)) { 2832 /* water effects on objects every now and then */ 2833 if (!rn2(5)) inpool_ok = TRUE; 2834 else return(FALSE); 2835 } 2836 2837 if (!u.uinwater) { 2838 You("%s into the water%c", 2839 Is_waterlevel(&u.uz) ? "plunge" : "fall", 2840 Amphibious || Swimming ? '.' : '!'); 2841 if (!Swimming && !Is_waterlevel(&u.uz)) 2842 You("sink like %s.", 2843 Hallucination ? "the Titanic" : "a rock"); 2844 } 2845 2846 water_damage(invent, FALSE, FALSE); 2847 2848 if (u.umonnum == PM_GREMLIN && rn2(3)) 2849 (void)split_mon(&youmonst, (struct monst *)0); 2850 else if (u.umonnum == PM_IRON_GOLEM) { 2851 You("rust!"); 2852 i = d(2,6); 2853 if (u.mhmax > i) u.mhmax -= i; 2854 losehp(i, "rusting away", KILLED_BY); 2855 } 2856 if (inpool_ok) return(FALSE); 2857 2858 if ((i = number_leashed()) > 0) { 2859 pline_The("leash%s slip%s loose.", 2860 (i > 1) ? "es" : "", 2861 (i > 1) ? "" : "s"); 2862 unleash_all(); 2863 } 2864 2865 if (Amphibious || Swimming) { 2866 if (Amphibious) { 2867 if (flags.verbose) 2868 pline("But you aren't drowning."); 2869 if (!Is_waterlevel(&u.uz)) { 2870 if (Hallucination) 2871 Your("keel hits the bottom."); 2872 else 2873 You("touch bottom."); 2874 } 2875 } 2876 if (Punished) { 2877 unplacebc(); 2878 placebc(); 2879 } 2880 vision_recalc(2); /* unsee old position */ 2881 u.uinwater = 1; 2882 under_water(1); 2883 vision_full_recalc = 1; 2884 return(FALSE); 2885 } 2886 if ((Teleportation || can_teleport(youmonst.data)) && 2887 !u.usleep && (Teleport_control || rn2(3) < Luck+2)) { 2888 You("attempt a teleport spell."); /* utcsri!carroll */ 2889 if (!level.flags.noteleport) { 2890 (void) dotele(); 2891 if(!is_pool(u.ux,u.uy)) 2892 return(TRUE); 2893 } else pline_The("attempted teleport spell fails."); 2894 } 2895#ifdef STEED 2896 if (u.usteed) { 2897 dismount_steed(DISMOUNT_GENERIC); 2898 if(!is_pool(u.ux,u.uy)) 2899 return(TRUE); 2900 } 2901#endif 2902 crawl_ok = FALSE; 2903 x = y = 0; /* lint suppression */ 2904 /* if sleeping, wake up now so that we don't crawl out of water 2905 while still asleep; we can't do that the same way that waking 2906 due to combat is handled; note unmul() clears u.usleep */ 2907 if (u.usleep) unmul("Suddenly you wake up!"); 2908 /* can't crawl if unable to move (crawl_ok flag stays false) */ 2909 if (multi < 0 || (Upolyd && !youmonst.data->mmove)) goto crawl; 2910 /* look around for a place to crawl to */ 2911 for (i = 0; i < 100; i++) { 2912 x = rn1(3,u.ux - 1); 2913 y = rn1(3,u.uy - 1); 2914 if (goodpos(x, y, &youmonst, 0)) { 2915 crawl_ok = TRUE; 2916 goto crawl; 2917 } 2918 } 2919 /* one more scan */ 2920 for (x = u.ux - 1; x <= u.ux + 1; x++) 2921 for (y = u.uy - 1; y <= u.uy + 1; y++) 2922 if (goodpos(x, y, &youmonst, 0)) { 2923 crawl_ok = TRUE; 2924 goto crawl; 2925 } 2926 crawl: 2927 if (crawl_ok) { 2928 boolean lost = FALSE; 2929 /* time to do some strip-tease... */ 2930 boolean succ = Is_waterlevel(&u.uz) ? TRUE : 2931 emergency_disrobe(&lost); 2932 2933 You("try to crawl out of the water."); 2934 if (lost) 2935 You("dump some of your gear to lose weight..."); 2936 if (succ) { 2937 pline("Pheew! That was close."); 2938 teleds(x,y,TRUE); 2939 return(TRUE); 2940 } 2941 /* still too much weight */ 2942 pline("But in vain."); 2943 } 2944 u.uinwater = 1; 2945 You("drown."); 2946 killer_format = KILLED_BY_AN; 2947 killer = (levl[u.ux][u.uy].typ == POOL || Is_medusa_level(&u.uz)) ? 2948 "pool of water" : "moat"; 2949 done(DROWNING); 2950 /* oops, we're still alive. better get out of the water. */ 2951 while (!safe_teleds(TRUE)) { 2952 pline("You're still drowning."); 2953 done(DROWNING); 2954 } 2955 if (u.uinwater) { 2956 u.uinwater = 0; 2957 You("find yourself back %s.", Is_waterlevel(&u.uz) ? 2958 "in an air bubble" : "on land"); 2959 } 2960 return(TRUE); 2961} 2962 2963void 2964drain_en(n) 2965register int n; 2966{ 2967 if (!u.uenmax) return; 2968 You_feel("your magical energy drain away!"); 2969 u.uen -= n; 2970 if(u.uen < 0) { 2971 u.uenmax += u.uen; 2972 if(u.uenmax < 0) u.uenmax = 0; 2973 u.uen = 0; 2974 } 2975 flags.botl = 1; 2976} 2977 2978int 2979dountrap() /* disarm a trap */ 2980{ 2981 if (near_capacity() >= HVY_ENCUMBER) { 2982 pline("You're too strained to do that."); 2983 return 0; 2984 } 2985 if ((nohands(youmonst.data) && !webmaker(youmonst.data)) || !youmonst.data->mmove) { 2986 pline("And just how do you expect to do that?"); 2987 return 0; 2988 } else if (u.ustuck && sticks(youmonst.data)) { 2989 pline("You'll have to let go of %s first.", mon_nam(u.ustuck)); 2990 return 0; 2991 } 2992 if (u.ustuck || (welded(uwep) && bimanual(uwep))) { 2993 Your("%s seem to be too busy for that.", 2994 makeplural(body_part(HAND))); 2995 return 0; 2996 } 2997 return untrap(FALSE); 2998} 2999#endif /* OVLB */ 3000#ifdef OVL2 3001 3002/* Probability of disabling a trap. Helge Hafting */ 3003STATIC_OVL int 3004untrap_prob(ttmp) 3005struct trap *ttmp; 3006{ 3007 int chance = 3; 3008 3009 /* Only spiders know how to deal with webs reliably */ 3010 if (ttmp->ttyp == WEB && !webmaker(youmonst.data)) 3011 chance = 30; 3012 if (Confusion || Hallucination) chance++; 3013 if (Blind) chance++; 3014 if (Stunned) chance += 2; 3015 if (Fumbling) chance *= 2; 3016 /* Your own traps are better known than others. */ 3017 if (ttmp && ttmp->madeby_u) chance--; 3018 if (Role_if(PM_ROGUE)) { 3019 if (rn2(2 * MAXULEV) < u.ulevel) chance--; 3020 if (u.uhave.questart && chance > 1) chance--; 3021 } else if (Role_if(PM_RANGER) && chance > 1) chance--; 3022 return rn2(chance); 3023} 3024 3025/* Replace trap with object(s). Helge Hafting */ 3026STATIC_OVL void 3027cnv_trap_obj(otyp, cnt, ttmp) 3028int otyp; 3029int cnt; 3030struct trap *ttmp; 3031{ 3032 struct obj *otmp = mksobj(otyp, TRUE, FALSE); 3033 otmp->quan=cnt; 3034 otmp->owt = weight(otmp); 3035 /* Only dart traps are capable of being poisonous */ 3036 if (otyp != DART) 3037 otmp->opoisoned = 0; 3038 place_object(otmp, ttmp->tx, ttmp->ty); 3039 /* Sell your own traps only... */ 3040 if (ttmp->madeby_u) sellobj(otmp, ttmp->tx, ttmp->ty); 3041 stackobj(otmp); 3042 newsym(ttmp->tx, ttmp->ty); 3043 deltrap(ttmp); 3044} 3045 3046/* while attempting to disarm an adjacent trap, we've fallen into it */ 3047STATIC_OVL void 3048move_into_trap(ttmp) 3049struct trap *ttmp; 3050{ 3051 int bc; 3052 xchar x = ttmp->tx, y = ttmp->ty, bx, by, cx, cy; 3053 boolean unused; 3054 3055 /* we know there's no monster in the way, and we're not trapped */ 3056 if (!Punished || drag_ball(x, y, &bc, &bx, &by, &cx, &cy, &unused, 3057 TRUE)) { 3058 u.ux0 = u.ux, u.uy0 = u.uy; 3059 u.ux = x, u.uy = y; 3060 u.umoved = TRUE; 3061 newsym(u.ux0, u.uy0); 3062 vision_recalc(1); 3063 check_leash(u.ux0, u.uy0); 3064 if (Punished) move_bc(0, bc, bx, by, cx, cy); 3065 spoteffects(FALSE); /* dotrap() */ 3066 exercise(A_WIS, FALSE); 3067 } 3068} 3069 3070/* 0: doesn't even try 3071 * 1: tries and fails 3072 * 2: succeeds 3073 */ 3074STATIC_OVL int 3075try_disarm(ttmp, force_failure) 3076struct trap *ttmp; 3077boolean force_failure; 3078{ 3079 struct monst *mtmp = m_at(ttmp->tx,ttmp->ty); 3080 int ttype = ttmp->ttyp; 3081 boolean under_u = (!u.dx && !u.dy); 3082 boolean holdingtrap = (ttype == BEAR_TRAP || ttype == WEB); 3083 3084 /* Test for monster first, monsters are displayed instead of trap. */ 3085 if (mtmp && (!mtmp->mtrapped || !holdingtrap)) { 3086 pline("%s is in the way.", Monnam(mtmp)); 3087 return 0; 3088 } 3089 /* We might be forced to move onto the trap's location. */ 3090 if (sobj_at(BOULDER, ttmp->tx, ttmp->ty) 3091 && !Passes_walls && !under_u) { 3092 There("is a boulder in your way."); 3093 return 0; 3094 } 3095 /* duplicate tight-space checks from test_move */ 3096 if (u.dx && u.dy && 3097 bad_rock(youmonst.data,u.ux,ttmp->ty) && 3098 bad_rock(youmonst.data,ttmp->tx,u.uy)) { 3099 if ((invent && (inv_weight() + weight_cap() > 600)) || 3100 bigmonst(youmonst.data)) { 3101 /* don't allow untrap if they can't get thru to it */ 3102 You("are unable to reach the %s!", 3103 defsyms[trap_to_defsym(ttype)].explanation); 3104 return 0; 3105 } 3106 } 3107 /* untrappable traps are located on the ground. */ 3108 if (!can_reach_floor()) { 3109#ifdef STEED 3110 if (u.usteed && P_SKILL(P_RIDING) < P_BASIC) 3111 You("aren't skilled enough to reach from %s.", 3112 mon_nam(u.usteed)); 3113 else 3114#endif 3115 You("are unable to reach the %s!", 3116 defsyms[trap_to_defsym(ttype)].explanation); 3117 return 0; 3118 } 3119 3120 /* Will our hero succeed? */ 3121 if (force_failure || untrap_prob(ttmp)) { 3122 if (rnl(5)) { 3123 pline("Whoops..."); 3124 if (mtmp) { /* must be a trap that holds monsters */ 3125 if (ttype == BEAR_TRAP) { 3126 if (mtmp->mtame) abuse_dog(mtmp); 3127 if ((mtmp->mhp -= rnd(4)) <= 0) killed(mtmp); 3128 } else if (ttype == WEB) { 3129 if (!webmaker(youmonst.data)) { 3130 struct trap *ttmp2 = maketrap(u.ux, u.uy, WEB); 3131 if (ttmp2) { 3132 pline_The("webbing sticks to you. You're caught too!"); 3133 dotrap(ttmp2, NOWEBMSG); 3134#ifdef STEED 3135 if (u.usteed && u.utrap) { 3136 /* you, not steed, are trapped */ 3137 dismount_steed(DISMOUNT_FELL); 3138 } 3139#endif 3140 } 3141 } else 3142 pline("%s remains entangled.", Monnam(mtmp)); 3143 } 3144 } else if (under_u) { 3145 dotrap(ttmp, 0); 3146 } else { 3147 move_into_trap(ttmp); 3148 } 3149 } else { 3150 pline("%s %s is difficult to %s.", 3151 ttmp->madeby_u ? "Your" : under_u ? "This" : "That", 3152 defsyms[trap_to_defsym(ttype)].explanation, 3153 (ttype == WEB) ? "remove" : "disarm"); 3154 } 3155 return 1; 3156 } 3157 return 2; 3158} 3159 3160STATIC_OVL void 3161reward_untrap(ttmp, mtmp) 3162struct trap *ttmp; 3163struct monst *mtmp; 3164{ 3165 if (!ttmp->madeby_u) { 3166 if (rnl(10) < 8 && !mtmp->mpeaceful && 3167 !mtmp->msleeping && !mtmp->mfrozen && 3168 !mindless(mtmp->data) && 3169 mtmp->data->mlet != S_HUMAN) { 3170 mtmp->mpeaceful = 1; 3171 set_malign(mtmp); /* reset alignment */ 3172 pline("%s is grateful.", Monnam(mtmp)); 3173 } 3174 /* Helping someone out of a trap is a nice thing to do, 3175 * A lawful may be rewarded, but not too often. */ 3176 if (!rn2(3) && !rnl(8) && u.ualign.type == A_LAWFUL) { 3177 adjalign(1); 3178 You_feel("that you did the right thing."); 3179 } 3180 } 3181} 3182 3183STATIC_OVL int 3184disarm_holdingtrap(ttmp) /* Helge Hafting */ 3185struct trap *ttmp; 3186{ 3187 struct monst *mtmp; 3188 int fails = try_disarm(ttmp, FALSE); 3189 3190 if (fails < 2) return fails; 3191 3192 /* ok, disarm it. */ 3193 3194 /* untrap the monster, if any. 3195 There's no need for a cockatrice test, only the trap is touched */ 3196 if ((mtmp = m_at(ttmp->tx,ttmp->ty)) != 0) { 3197 mtmp->mtrapped = 0; 3198 You("remove %s %s from %s.", the_your[ttmp->madeby_u], 3199 (ttmp->ttyp == BEAR_TRAP) ? "bear trap" : "webbing", 3200 mon_nam(mtmp)); 3201 reward_untrap(ttmp, mtmp); 3202 } else { 3203 if (ttmp->ttyp == BEAR_TRAP) { 3204 You("disarm %s bear trap.", the_your[ttmp->madeby_u]); 3205 cnv_trap_obj(BEARTRAP, 1, ttmp); 3206 } else /* if (ttmp->ttyp == WEB) */ { 3207 You("succeed in removing %s web.", the_your[ttmp->madeby_u]); 3208 deltrap(ttmp); 3209 } 3210 } 3211 newsym(u.ux + u.dx, u.uy + u.dy); 3212 return 1; 3213} 3214 3215STATIC_OVL int 3216disarm_landmine(ttmp) /* Helge Hafting */ 3217struct trap *ttmp; 3218{ 3219 int fails = try_disarm(ttmp, FALSE); 3220 3221 if (fails < 2) return fails; 3222 You("disarm %s land mine.", the_your[ttmp->madeby_u]); 3223 cnv_trap_obj(LAND_MINE, 1, ttmp); 3224 return 1; 3225} 3226 3227/* getobj will filter down to cans of grease and known potions of oil */ 3228static NEARDATA const char oil[] = { ALL_CLASSES, TOOL_CLASS, POTION_CLASS, 0 }; 3229 3230/* it may not make much sense to use grease on floor boards, but so what? */ 3231STATIC_OVL int 3232disarm_squeaky_board(ttmp) 3233struct trap *ttmp; 3234{ 3235 struct obj *obj; 3236 boolean bad_tool; 3237 int fails; 3238 3239 obj = getobj(oil, "untrap with"); 3240 if (!obj) return 0; 3241 3242 bad_tool = (obj->cursed || 3243 ((obj->otyp != POT_OIL || obj->lamplit) && 3244 (obj->otyp != CAN_OF_GREASE || !obj->spe))); 3245 3246 fails = try_disarm(ttmp, bad_tool); 3247 if (fails < 2) return fails; 3248 3249 /* successfully used oil or grease to fix squeaky board */ 3250 if (obj->otyp == CAN_OF_GREASE) { 3251 consume_obj_charge(obj, TRUE); 3252 } else { 3253 useup(obj); /* oil */ 3254 makeknown(POT_OIL); 3255 } 3256 You("repair the squeaky board."); /* no madeby_u */ 3257 deltrap(ttmp); 3258 newsym(u.ux + u.dx, u.uy + u.dy); 3259 more_experienced(1, 5); 3260 newexplevel(); 3261 return 1; 3262} 3263 3264/* removes traps that shoot arrows, darts, etc. */ 3265STATIC_OVL int 3266disarm_shooting_trap(ttmp, otyp) 3267struct trap *ttmp; 3268int otyp; 3269{ 3270 int fails = try_disarm(ttmp, FALSE); 3271 3272 if (fails < 2) return fails; 3273 You("disarm %s trap.", the_your[ttmp->madeby_u]); 3274 cnv_trap_obj(otyp, 50-rnl(50), ttmp); 3275 return 1; 3276} 3277 3278/* Is the weight too heavy? 3279 * Formula as in near_capacity() & check_capacity() */ 3280STATIC_OVL int 3281try_lift(mtmp, ttmp, wt, stuff) 3282struct monst *mtmp; 3283struct trap *ttmp; 3284int wt; 3285boolean stuff; 3286{ 3287 int wc = weight_cap(); 3288 3289 if (((wt * 2) / wc) >= HVY_ENCUMBER) { 3290 pline("%s is %s for you to lift.", Monnam(mtmp), 3291 stuff ? "carrying too much" : "too heavy"); 3292 if (!ttmp->madeby_u && !mtmp->mpeaceful && mtmp->mcanmove && 3293 !mindless(mtmp->data) && 3294 mtmp->data->mlet != S_HUMAN && rnl(10) < 3) { 3295 mtmp->mpeaceful = 1; 3296 set_malign(mtmp); /* reset alignment */ 3297 pline("%s thinks it was nice of you to try.", Monnam(mtmp)); 3298 } 3299 return 0; 3300 } 3301 return 1; 3302} 3303 3304/* Help trapped monster (out of a (spiked) pit) */ 3305STATIC_OVL int 3306help_monster_out(mtmp, ttmp) 3307struct monst *mtmp; 3308struct trap *ttmp; 3309{ 3310 int wt; 3311 struct obj *otmp; 3312 boolean uprob; 3313 3314 /* 3315 * This works when levitating too -- consistent with the ability 3316 * to hit monsters while levitating. 3317 * 3318 * Should perhaps check that our hero has arms/hands at the 3319 * moment. Helping can also be done by engulfing... 3320 * 3321 * Test the monster first - monsters are displayed before traps. 3322 */ 3323 if (!mtmp->mtrapped) { 3324 pline("%s isn't trapped.", Monnam(mtmp)); 3325 return 0; 3326 } 3327 /* Do you have the necessary capacity to lift anything? */ 3328 if (check_capacity((char *)0)) return 1; 3329 3330 /* Will our hero succeed? */ 3331 if ((uprob = untrap_prob(ttmp)) && !mtmp->msleeping && mtmp->mcanmove) { 3332 You("try to reach out your %s, but %s backs away skeptically.", 3333 makeplural(body_part(ARM)), 3334 mon_nam(mtmp)); 3335 return 1; 3336 } 3337 3338 3339 /* is it a cockatrice?... */ 3340 if (touch_petrifies(mtmp->data) && !uarmg && !Stone_resistance) { 3341 You("grab the trapped %s using your bare %s.", 3342 mtmp->data->mname, makeplural(body_part(HAND))); 3343 3344 if (poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM)) 3345 display_nhwindow(WIN_MESSAGE, FALSE); 3346 else { 3347 char kbuf[BUFSZ]; 3348 3349 Sprintf(kbuf, "trying to help %s out of a pit", 3350 an(mtmp->data->mname)); 3351 instapetrify(kbuf); 3352 return 1; 3353 } 3354 } 3355 /* need to do cockatrice check first if sleeping or paralyzed */ 3356 if (uprob) { 3357 You("try to grab %s, but cannot get a firm grasp.", 3358 mon_nam(mtmp)); 3359 if (mtmp->msleeping) { 3360 mtmp->msleeping = 0; 3361 pline("%s awakens.", Monnam(mtmp)); 3362 } 3363 return 1; 3364 } 3365 3366 You("reach out your %s and grab %s.", 3367 makeplural(body_part(ARM)), mon_nam(mtmp)); 3368 3369 if (mtmp->msleeping) { 3370 mtmp->msleeping = 0; 3371 pline("%s awakens.", Monnam(mtmp)); 3372 } else if (mtmp->mfrozen && !rn2(mtmp->mfrozen)) { 3373 /* After such manhandling, perhaps the effect wears off */ 3374 mtmp->mcanmove = 1; 3375 mtmp->mfrozen = 0; 3376 pline("%s stirs.", Monnam(mtmp)); 3377 } 3378 3379 /* is the monster too heavy? */ 3380 wt = inv_weight() + mtmp->data->cwt; 3381 if (!try_lift(mtmp, ttmp, wt, FALSE)) return 1; 3382 3383 /* is the monster with inventory too heavy? */ 3384 for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj) 3385 wt += otmp->owt; 3386 if (!try_lift(mtmp, ttmp, wt, TRUE)) return 1; 3387 3388 You("pull %s out of the pit.", mon_nam(mtmp)); 3389 mtmp->mtrapped = 0; 3390 fill_pit(mtmp->mx, mtmp->my); 3391 reward_untrap(ttmp, mtmp); 3392 return 1; 3393} 3394 3395int 3396untrap(force) 3397boolean force; 3398{ 3399 register struct obj *otmp; 3400 register boolean confused = (Confusion > 0 || Hallucination > 0); 3401 register int x,y; 3402 int ch; 3403 struct trap *ttmp; 3404 struct monst *mtmp; 3405 boolean trap_skipped = FALSE; 3406 boolean box_here = FALSE; 3407 boolean deal_with_floor_trap = FALSE; 3408 char the_trap[BUFSZ], qbuf[QBUFSZ]; 3409 int containercnt = 0; 3410 3411 if(!getdir((char *)0)) return(0); 3412 x = u.ux + u.dx; 3413 y = u.uy + u.dy; 3414 3415 for(otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere) { 3416 if(Is_box(otmp) && !u.dx && !u.dy) { 3417 box_here = TRUE; 3418 containercnt++; 3419 if (containercnt > 1) break; 3420 } 3421 } 3422 3423 if ((ttmp = t_at(x,y)) && ttmp->tseen) { 3424 deal_with_floor_trap = TRUE; 3425 Strcpy(the_trap, the(defsyms[trap_to_defsym(ttmp->ttyp)].explanation)); 3426 if (box_here) { 3427 if (ttmp->ttyp == PIT || ttmp->ttyp == SPIKED_PIT) { 3428 You_cant("do much about %s%s.", 3429 the_trap, u.utrap ? 3430 " that you're stuck in" : 3431 " while standing on the edge of it"); 3432 trap_skipped = TRUE; 3433 deal_with_floor_trap = FALSE; 3434 } else { 3435 Sprintf(qbuf, "There %s and %s here. %s %s?", 3436 (containercnt == 1) ? "is a container" : "are containers", 3437 an(defsyms[trap_to_defsym(ttmp->ttyp)].explanation), 3438 ttmp->ttyp == WEB ? "Remove" : "Disarm", the_trap); 3439 switch (ynq(qbuf)) { 3440 case 'q': return(0); 3441 case 'n': trap_skipped = TRUE; 3442 deal_with_floor_trap = FALSE; 3443 break; 3444 } 3445 } 3446 } 3447 if (deal_with_floor_trap) { 3448 if (u.utrap) { 3449 You("cannot deal with %s while trapped%s!", the_trap, 3450 (x == u.ux && y == u.uy) ? " in it" : ""); 3451 return 1; 3452 } 3453 switch(ttmp->ttyp) { 3454 case BEAR_TRAP: 3455 case WEB: 3456 return disarm_holdingtrap(ttmp); 3457 case LANDMINE: 3458 return disarm_landmine(ttmp); 3459 case SQKY_BOARD: 3460 return disarm_squeaky_board(ttmp); 3461 case DART_TRAP: 3462 return disarm_shooting_trap(ttmp, DART); 3463 case ARROW_TRAP: 3464 return disarm_shooting_trap(ttmp, ARROW); 3465 case PIT: 3466 case SPIKED_PIT: 3467 if (!u.dx && !u.dy) { 3468 You("are already on the edge of the pit."); 3469 return 0; 3470 } 3471 if (!(mtmp = m_at(x,y))) { 3472 pline("Try filling the pit instead."); 3473 return 0; 3474 } 3475 return help_monster_out(mtmp, ttmp); 3476 default: 3477 You("cannot disable %s trap.", (u.dx || u.dy) ? "that" : "this"); 3478 return 0; 3479 } 3480 } 3481 } /* end if */ 3482 3483 if(!u.dx && !u.dy) { 3484 for(otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere) 3485 if(Is_box(otmp)) { 3486 Sprintf(qbuf, "There is %s here. Check it for traps?", 3487 safe_qbuf("", sizeof("There is here. Check it for traps?"), 3488 doname(otmp), an(simple_typename(otmp->otyp)), "a box")); 3489 switch (ynq(qbuf)) { 3490 case 'q': return(0); 3491 case 'n': continue; 3492 } 3493#ifdef STEED 3494 if (u.usteed && P_SKILL(P_RIDING) < P_BASIC) { 3495 You("aren't skilled enough to reach from %s.", 3496 mon_nam(u.usteed)); 3497 return(0); 3498 } 3499#endif 3500 if((otmp->otrapped && (force || (!confused 3501 && rn2(MAXULEV + 1 - u.ulevel) < 10))) 3502 || (!force && confused && !rn2(3))) { 3503 You("find a trap on %s!", the(xname(otmp))); 3504 if (!confused) exercise(A_WIS, TRUE); 3505 3506 switch (ynq("Disarm it?")) { 3507 case 'q': return(1); 3508 case 'n': trap_skipped = TRUE; continue; 3509 } 3510 3511 if(otmp->otrapped) { 3512 exercise(A_DEX, TRUE); 3513 ch = ACURR(A_DEX) + u.ulevel; 3514 if (Role_if(PM_ROGUE)) ch *= 2; 3515 if(!force && (confused || Fumbling || 3516 rnd(75+level_difficulty()/2) > ch)) { 3517 (void) chest_trap(otmp, FINGER, TRUE); 3518 } else { 3519 You("disarm it!"); 3520 otmp->otrapped = 0; 3521 } 3522 } else pline("That %s was not trapped.", xname(otmp)); 3523 return(1); 3524 } else { 3525 You("find no traps on %s.", the(xname(otmp))); 3526 return(1); 3527 } 3528 } 3529 3530 You(trap_skipped ? "find no other traps here." 3531 : "know of no traps here."); 3532 return(0); 3533 } 3534 3535 if ((mtmp = m_at(x,y)) && 3536 mtmp->m_ap_type == M_AP_FURNITURE && 3537 (mtmp->mappearance == S_hcdoor || 3538 mtmp->mappearance == S_vcdoor) && 3539 !Protection_from_shape_changers) { 3540 3541 stumble_onto_mimic(mtmp); 3542 return(1); 3543 } 3544 3545 if (!IS_DOOR(levl[x][y].typ)) { 3546 if ((ttmp = t_at(x,y)) && ttmp->tseen) 3547 You("cannot disable that trap."); 3548 else 3549 You("know of no traps there."); 3550 return(0); 3551 } 3552 3553 switch (levl[x][y].doormask) { 3554 case D_NODOOR: 3555 You("%s no door there.", Blind ? "feel" : "see"); 3556 return(0); 3557 case D_ISOPEN: 3558 pline("This door is safely open."); 3559 return(0); 3560 case D_BROKEN: 3561 pline("This door is broken."); 3562 return(0); 3563 } 3564 3565 if ((levl[x][y].doormask & D_TRAPPED 3566 && (force || 3567 (!confused && rn2(MAXULEV - u.ulevel + 11) < 10))) 3568 || (!force && confused && !rn2(3))) { 3569 You("find a trap on the door!"); 3570 exercise(A_WIS, TRUE); 3571 if (ynq("Disarm it?") != 'y') return(1); 3572 if (levl[x][y].doormask & D_TRAPPED) { 3573 ch = 15 + (Role_if(PM_ROGUE) ? u.ulevel*3 : u.ulevel); 3574 exercise(A_DEX, TRUE); 3575 if(!force && (confused || Fumbling || 3576 rnd(75+level_difficulty()/2) > ch)) { 3577 You("set it off!"); 3578 b_trapped("door", FINGER); 3579 levl[x][y].doormask = D_NODOOR; 3580 unblock_point(x, y); 3581 newsym(x, y); 3582 /* (probably ought to charge for this damage...) */ 3583 if (*in_rooms(x, y, SHOPBASE)) add_damage(x, y, 0L); 3584 } else { 3585 You("disarm it!"); 3586 levl[x][y].doormask &= ~D_TRAPPED; 3587 } 3588 } else pline("This door was not trapped."); 3589 return(1); 3590 } else { 3591 You("find no traps on the door."); 3592 return(1); 3593 } 3594} 3595#endif /* OVL2 */ 3596#ifdef OVLB 3597 3598/* only called when the player is doing something to the chest directly */ 3599boolean 3600chest_trap(obj, bodypart, disarm) 3601register struct obj *obj; 3602register int bodypart; 3603boolean disarm; 3604{ 3605 register struct obj *otmp = obj, *otmp2; 3606 char buf[80]; 3607 const char *msg; 3608 coord cc; 3609 3610 if (get_obj_location(obj, &cc.x, &cc.y, 0)) /* might be carried */ 3611 obj->ox = cc.x, obj->oy = cc.y; 3612 3613 otmp->otrapped = 0; /* trap is one-shot; clear flag first in case 3614 chest kills you and ends up in bones file */ 3615 You(disarm ? "set it off!" : "trigger a trap!"); 3616 display_nhwindow(WIN_MESSAGE, FALSE); 3617 if (Luck > -13 && rn2(13+Luck) > 7) { /* saved by luck */ 3618 /* trap went off, but good luck prevents damage */ 3619 switch (rn2(13)) { 3620 case 12: 3621 case 11: msg = "explosive charge is a dud"; break; 3622 case 10: 3623 case 9: msg = "electric charge is grounded"; break; 3624 case 8: 3625 case 7: msg = "flame fizzles out"; break; 3626 case 6: 3627 case 5: 3628 case 4: msg = "poisoned needle misses"; break; 3629 case 3: 3630 case 2: 3631 case 1: 3632 case 0: msg = "gas cloud blows away"; break; 3633 default: impossible("chest disarm bug"); msg = (char *)0; 3634 break; 3635 } 3636 if (msg) pline("But luckily the %s!", msg); 3637 } else { 3638 switch(rn2(20) ? ((Luck >= 13) ? 0 : rn2(13-Luck)) : rn2(26)) { 3639 case 25: 3640 case 24: 3641 case 23: 3642 case 22: 3643 case 21: { 3644 struct monst *shkp = 0; 3645 long loss = 0L; 3646 boolean costly, insider; 3647 register xchar ox = obj->ox, oy = obj->oy; 3648 3649 /* the obj location need not be that of player */ 3650 costly = (costly_spot(ox, oy) && 3651 (shkp = shop_keeper(*in_rooms(ox, oy, 3652 SHOPBASE))) != (struct monst *)0); 3653 insider = (*u.ushops && inside_shop(u.ux, u.uy) && 3654 *in_rooms(ox, oy, SHOPBASE) == *u.ushops); 3655 3656 pline("%s!", Tobjnam(obj, "explode")); 3657 Sprintf(buf, "exploding %s", xname(obj)); 3658 3659 if(costly) 3660 loss += stolen_value(obj, ox, oy, 3661 (boolean)shkp->mpeaceful, TRUE); 3662 delete_contents(obj); 3663 /* we're about to delete all things at this location, 3664 * which could include the ball & chain. 3665 * If we attempt to call unpunish() in the 3666 * for-loop below we can end up with otmp2 3667 * being invalid once the chain is gone. 3668 * Deal with ball & chain right now instead. 3669 */ 3670 if (Punished && !carried(uball) && 3671 ((uchain->ox == u.ux && uchain->oy == u.uy) || 3672 (uball->ox == u.ux && uball->oy == u.uy))) 3673 unpunish(); 3674 3675 for(otmp = level.objects[u.ux][u.uy]; 3676 otmp; otmp = otmp2) { 3677 otmp2 = otmp->nexthere; 3678 if(costly) 3679 loss += stolen_value(otmp, otmp->ox, 3680 otmp->oy, (boolean)shkp->mpeaceful, 3681 TRUE); 3682 delobj(otmp); 3683 } 3684 wake_nearby(); 3685 losehp(d(6,6), buf, KILLED_BY_AN); 3686 exercise(A_STR, FALSE); 3687 if(costly && loss) { 3688 if(insider) 3689 You("owe %ld %s for objects destroyed.", 3690 loss, currency(loss)); 3691 else { 3692 You("caused %ld %s worth of damage!", 3693 loss, currency(loss)); 3694 make_angry_shk(shkp, ox, oy); 3695 } 3696 } 3697 return TRUE; 3698 } 3699 case 20: 3700 case 19: 3701 case 18: 3702 case 17: 3703 pline("A cloud of noxious gas billows from %s.", 3704 the(xname(obj))); 3705 poisoned("gas cloud", A_STR, "cloud of poison gas",15); 3706 exercise(A_CON, FALSE); 3707 break; 3708 case 16: 3709 case 15: 3710 case 14: 3711 case 13: 3712 You_feel("a needle prick your %s.",body_part(bodypart)); 3713 poisoned("needle", A_CON, "poisoned needle",10); 3714 exercise(A_CON, FALSE); 3715 break; 3716 case 12: 3717 case 11: 3718 case 10: 3719 case 9: 3720 dofiretrap(obj); 3721 break; 3722 case 8: 3723 case 7: 3724 case 6: { 3725 int dmg; 3726 3727 You("are jolted by a surge of electricity!"); 3728 if(Shock_resistance) { 3729 shieldeff(u.ux, u.uy); 3730 You("don't seem to be affected."); 3731 dmg = 0; 3732 } else 3733 dmg = d(4, 4); 3734 destroy_item(RING_CLASS, AD_ELEC); 3735 destroy_item(WAND_CLASS, AD_ELEC); 3736 if (dmg) losehp(dmg, "electric shock", KILLED_BY_AN); 3737 break; 3738 } 3739 case 5: 3740 case 4: 3741 case 3: 3742 if (!Free_action) { 3743 pline("Suddenly you are frozen in place!"); 3744 nomul(-d(5, 6)); 3745 exercise(A_DEX, FALSE); 3746 nomovemsg = You_can_move_again; 3747 } else You("momentarily stiffen."); 3748 break; 3749 case 2: 3750 case 1: 3751 case 0: 3752 pline("A cloud of %s gas billows from %s.", 3753 Blind ? blindgas[rn2(SIZE(blindgas))] : 3754 rndcolor(), the(xname(obj))); 3755 if(!Stunned) { 3756 if (Hallucination) 3757 pline("What a groovy feeling!"); 3758 else if (Blind) 3759 You("%s and get dizzy...", 3760 stagger(youmonst.data, "stagger")); 3761 else 3762 You("%s and your vision blurs...", 3763 stagger(youmonst.data, "stagger")); 3764 } 3765 make_stunned(HStun + rn1(7, 16),FALSE); 3766 (void) make_hallucinated(HHallucination + rn1(5, 16),FALSE,0L); 3767 break; 3768 default: impossible("bad chest trap"); 3769 break; 3770 } 3771 bot(); /* to get immediate botl re-display */ 3772 } 3773 3774 return FALSE; 3775} 3776 3777#endif /* OVLB */ 3778#ifdef OVL0 3779 3780struct trap * 3781t_at(x,y) 3782register int x, y; 3783{ 3784 register struct trap *trap = ftrap; 3785 while(trap) { 3786 if(trap->tx == x && trap->ty == y) return(trap); 3787 trap = trap->ntrap; 3788 } 3789 return((struct trap *)0); 3790} 3791 3792#endif /* OVL0 */ 3793#ifdef OVLB 3794 3795void 3796deltrap(trap) 3797register struct trap *trap; 3798{ 3799 register struct trap *ttmp; 3800 3801 if(trap == ftrap) 3802 ftrap = ftrap->ntrap; 3803 else { 3804 for(ttmp = ftrap; ttmp->ntrap != trap; ttmp = ttmp->ntrap) ; 3805 ttmp->ntrap = trap->ntrap; 3806 } 3807 dealloc_trap(trap); 3808} 3809 3810boolean 3811delfloortrap(ttmp) 3812register struct trap *ttmp; 3813{ 3814 /* Destroy a trap that emanates from the floor. */ 3815 /* some of these are arbitrary -dlc */ 3816 if (ttmp && ((ttmp->ttyp == SQKY_BOARD) || 3817 (ttmp->ttyp == BEAR_TRAP) || 3818 (ttmp->ttyp == LANDMINE) || 3819 (ttmp->ttyp == FIRE_TRAP) || 3820 (ttmp->ttyp == PIT) || 3821 (ttmp->ttyp == SPIKED_PIT) || 3822 (ttmp->ttyp == HOLE) || 3823 (ttmp->ttyp == TRAPDOOR) || 3824 (ttmp->ttyp == TELEP_TRAP) || 3825 (ttmp->ttyp == LEVEL_TELEP) || 3826 (ttmp->ttyp == WEB) || 3827 (ttmp->ttyp == MAGIC_TRAP) || 3828 (ttmp->ttyp == ANTI_MAGIC))) { 3829 register struct monst *mtmp; 3830 3831 if (ttmp->tx == u.ux && ttmp->ty == u.uy) { 3832 u.utrap = 0; 3833 u.utraptype = 0; 3834 } else if ((mtmp = m_at(ttmp->tx, ttmp->ty)) != 0) { 3835 mtmp->mtrapped = 0; 3836 } 3837 deltrap(ttmp); 3838 return TRUE; 3839 } else 3840 return FALSE; 3841} 3842 3843/* used for doors (also tins). can be used for anything else that opens. */ 3844void 3845b_trapped(item, bodypart) 3846register const char *item; 3847register int bodypart; 3848{ 3849 register int lvl = level_difficulty(); 3850 int dmg = rnd(5 + (lvl < 5 ? lvl : 2+lvl/2)); 3851 3852 pline("KABOOM!! %s was booby-trapped!", The(item)); 3853 wake_nearby(); 3854 losehp(dmg, "explosion", KILLED_BY_AN); 3855 exercise(A_STR, FALSE); 3856 if (bodypart) exercise(A_CON, FALSE); 3857 make_stunned(HStun + dmg, TRUE); 3858} 3859 3860/* Monster is hit by trap. */ 3861/* Note: doesn't work if both obj and d_override are null */ 3862STATIC_OVL boolean 3863thitm(tlev, mon, obj, d_override, nocorpse) 3864int tlev; 3865struct monst *mon; 3866struct obj *obj; 3867int d_override; 3868boolean nocorpse; 3869{ 3870 int strike; 3871 boolean trapkilled = FALSE; 3872 3873 if (d_override) strike = 1; 3874 else if (obj) strike = (find_mac(mon) + tlev + obj->spe <= rnd(20)); 3875 else strike = (find_mac(mon) + tlev <= rnd(20)); 3876 3877 /* Actually more accurate than thitu, which doesn't take 3878 * obj->spe into account. 3879 */ 3880 if(!strike) { 3881 if (obj && cansee(mon->mx, mon->my)) 3882 pline("%s is almost hit by %s!", Monnam(mon), doname(obj)); 3883 } else { 3884 int dam = 1; 3885 3886 if (obj && cansee(mon->mx, mon->my)) 3887 pline("%s is hit by %s!", Monnam(mon), doname(obj)); 3888 if (d_override) dam = d_override; 3889 else if (obj) { 3890 dam = dmgval(obj, mon); 3891 if (dam < 1) dam = 1; 3892 } 3893 if ((mon->mhp -= dam) <= 0) { 3894 int xx = mon->mx; 3895 int yy = mon->my; 3896 3897 monkilled(mon, "", nocorpse ? -AD_RBRE : AD_PHYS); 3898 if (mon->mhp <= 0) { 3899 newsym(xx, yy); 3900 trapkilled = TRUE; 3901 } 3902 } 3903 } 3904 if (obj && (!strike || d_override)) { 3905 place_object(obj, mon->mx, mon->my); 3906 stackobj(obj); 3907 } else if (obj) dealloc_obj(obj); 3908 3909 return trapkilled; 3910} 3911 3912boolean 3913unconscious() 3914{ 3915 return((boolean)(multi < 0 && (!nomovemsg || 3916 u.usleep || 3917 !strncmp(nomovemsg,"You regain con", 14) || 3918 !strncmp(nomovemsg,"You are consci", 14)))); 3919} 3920 3921static const char lava_killer[] = "molten lava"; 3922 3923boolean 3924lava_effects() 3925{ 3926 register struct obj *obj, *obj2; 3927 int dmg; 3928 boolean usurvive; 3929 3930 burn_away_slime(); 3931 if (likes_lava(youmonst.data)) return FALSE; 3932 3933 if (!Fire_resistance) { 3934 if(Wwalking) { 3935 dmg = d(6,6); 3936 pline_The("lava here burns you!"); 3937 if(dmg < u.uhp) { 3938 losehp(dmg, lava_killer, KILLED_BY); 3939 goto burn_stuff; 3940 } 3941 } else 3942 You("fall into the lava!"); 3943 3944 usurvive = Lifesaved || discover; 3945#ifdef WIZARD 3946 if (wizard) usurvive = TRUE; 3947#endif 3948 for(obj = invent; obj; obj = obj2) { 3949 obj2 = obj->nobj; 3950 if(is_organic(obj) && !obj->oerodeproof) { 3951 if(obj->owornmask) { 3952 if (usurvive) 3953 Your("%s into flame!", aobjnam(obj, "burst")); 3954 3955 if(obj == uarm) (void) Armor_gone(); 3956 else if(obj == uarmc) (void) Cloak_off(); 3957 else if(obj == uarmh) (void) Helmet_off(); 3958 else if(obj == uarms) (void) Shield_off(); 3959 else if(obj == uarmg) (void) Gloves_off(); 3960 else if(obj == uarmf) (void) Boots_off(); 3961#ifdef TOURIST 3962 else if(obj == uarmu) setnotworn(obj); 3963#endif 3964 else if(obj == uleft) Ring_gone(obj); 3965 else if(obj == uright) Ring_gone(obj); 3966 else if(obj == ublindf) Blindf_off(obj); 3967 else if(obj == uamul) Amulet_off(); 3968 else if(obj == uwep) uwepgone(); 3969 else if (obj == uquiver) uqwepgone(); 3970 else if (obj == uswapwep) uswapwepgone(); 3971 } 3972 useupall(obj); 3973 } 3974 } 3975 3976 /* s/he died... */ 3977 u.uhp = -1; 3978 killer_format = KILLED_BY; 3979 killer = lava_killer; 3980 You("burn to a crisp..."); 3981 done(BURNING); 3982 while (!safe_teleds(TRUE)) { 3983 pline("You're still burning."); 3984 done(BURNING); 3985 } 3986 You("find yourself back on solid %s.", surface(u.ux, u.uy)); 3987 return(TRUE); 3988 } 3989 3990 if (!Wwalking) { 3991 u.utrap = rn1(4, 4) + (rn1(4, 12) << 8); 3992 u.utraptype = TT_LAVA; 3993 You("sink into the lava, but it only burns slightly!"); 3994 if (u.uhp > 1) 3995 losehp(1, lava_killer, KILLED_BY); 3996 } 3997 /* just want to burn boots, not all armor; destroy_item doesn't work on 3998 armor anyway */ 3999burn_stuff: 4000 if(uarmf && !uarmf->oerodeproof && is_organic(uarmf)) { 4001 /* save uarmf value because Boots_off() sets uarmf to null */ 4002 obj = uarmf; 4003 Your("%s bursts into flame!", xname(obj)); 4004 (void) Boots_off(); 4005 useup(obj); 4006 } 4007 destroy_item(SCROLL_CLASS, AD_FIRE); 4008 destroy_item(SPBOOK_CLASS, AD_FIRE); 4009 destroy_item(POTION_CLASS, AD_FIRE); 4010 return(FALSE); 4011} 4012 4013#endif /* OVLB */ 4014 4015/*trap.c*/ 4016