1/* SCCS Id: @(#)do.c 3.4 2003/12/02 */ 2/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ 3/* NetHack may be freely redistributed. See license for details. */ 4 5/* Contains code for 'd', 'D' (drop), '>', '<' (up, down) */ 6 7#include "hack.h" 8#include "lev.h" 9 10#ifdef SINKS 11# ifdef OVLB 12STATIC_DCL void FDECL(trycall, (struct obj *)); 13# endif /* OVLB */ 14STATIC_DCL void FDECL(dosinkring, (struct obj *)); 15#endif /* SINKS */ 16 17STATIC_PTR int FDECL(drop, (struct obj *)); 18STATIC_PTR int NDECL(wipeoff); 19 20#ifdef OVL0 21STATIC_DCL int FDECL(menu_drop, (int)); 22#endif 23#ifdef OVL2 24STATIC_DCL int NDECL(currentlevel_rewrite); 25STATIC_DCL void NDECL(final_level); 26/* static boolean FDECL(badspot, (XCHAR_P,XCHAR_P)); */ 27#endif 28 29#ifdef OVLB 30 31static NEARDATA const char drop_types[] = 32 { ALLOW_COUNT, COIN_CLASS, ALL_CLASSES, 0 }; 33 34/* 'd' command: drop one inventory item */ 35int 36dodrop() 37{ 38#ifndef GOLDOBJ 39 int result, i = (invent || u.ugold) ? 0 : (SIZE(drop_types) - 1); 40#else 41 int result, i = (invent) ? 0 : (SIZE(drop_types) - 1); 42#endif 43 44 if (*u.ushops) sellobj_state(SELL_DELIBERATE); 45 result = drop(getobj(&drop_types[i], "drop")); 46 if (*u.ushops) sellobj_state(SELL_NORMAL); 47 reset_occupations(); 48 49 return result; 50} 51 52#endif /* OVLB */ 53#ifdef OVL0 54 55/* Called when a boulder is dropped, thrown, or pushed. If it ends up 56 * in a pool, it either fills the pool up or sinks away. In either case, 57 * it's gone for good... If the destination is not a pool, returns FALSE. 58 */ 59boolean 60boulder_hits_pool(otmp, rx, ry, pushing) 61struct obj *otmp; 62register int rx, ry; 63boolean pushing; 64{ 65 if (!otmp || otmp->otyp != BOULDER) 66 impossible("Not a boulder?"); 67 else if (!Is_waterlevel(&u.uz) && (is_pool(rx,ry) || is_lava(rx,ry))) { 68 boolean lava = is_lava(rx,ry), fills_up; 69 const char *what = waterbody_name(rx,ry); 70 schar ltyp = levl[rx][ry].typ; 71 int chance = rn2(10); /* water: 90%; lava: 10% */ 72 fills_up = lava ? chance == 0 : chance != 0; 73 74 if (fills_up) { 75 struct trap *ttmp = t_at(rx, ry); 76 77 if (ltyp == DRAWBRIDGE_UP) { 78 levl[rx][ry].drawbridgemask &= ~DB_UNDER; /* clear lava */ 79 levl[rx][ry].drawbridgemask |= DB_FLOOR; 80 } else 81 levl[rx][ry].typ = ROOM; 82 83 if (ttmp) (void) delfloortrap(ttmp); 84 bury_objs(rx, ry); 85 86 newsym(rx,ry); 87 if (pushing) { 88 You("push %s into the %s.", the(xname(otmp)), what); 89 if (flags.verbose && !Blind) 90 pline("Now you can cross it!"); 91 /* no splashing in this case */ 92 } 93 } 94 if (!fills_up || !pushing) { /* splashing occurs */ 95 if (!u.uinwater) { 96 if (pushing ? !Blind : cansee(rx,ry)) { 97 There("is a large splash as %s %s the %s.", 98 the(xname(otmp)), fills_up? "fills":"falls into", 99 what); 100 } else if (flags.soundok) 101 You_hear("a%s splash.", lava ? " sizzling" : ""); 102 wake_nearto(rx, ry, 40); 103 } 104 105 if (fills_up && u.uinwater && distu(rx,ry) == 0) { 106 u.uinwater = 0; 107 docrt(); 108 vision_full_recalc = 1; 109 You("find yourself on dry land again!"); 110 } else if (lava && distu(rx,ry) <= 2) { 111 You("are hit by molten lava%c", 112 Fire_resistance ? '.' : '!'); 113 burn_away_slime(); 114 losehp(d((Fire_resistance ? 1 : 3), 6), 115 "molten lava", KILLED_BY); 116 } else if (!fills_up && flags.verbose && 117 (pushing ? !Blind : cansee(rx,ry))) 118 pline("It sinks without a trace!"); 119 } 120 121 /* boulder is now gone */ 122 if (pushing) delobj(otmp); 123 else obfree(otmp, (struct obj *)0); 124 return TRUE; 125 } 126 return FALSE; 127} 128 129/* Used for objects which sometimes do special things when dropped; must be 130 * called with the object not in any chain. Returns TRUE if the object goes 131 * away. 132 */ 133boolean 134flooreffects(obj,x,y,verb) 135struct obj *obj; 136int x,y; 137const char *verb; 138{ 139 struct trap *t; 140 struct monst *mtmp; 141 142 if (obj->where != OBJ_FREE) 143 panic("flooreffects: obj not free"); 144 145 /* make sure things like water_damage() have no pointers to follow */ 146 obj->nobj = obj->nexthere = (struct obj *)0; 147 148 if (obj->otyp == BOULDER && boulder_hits_pool(obj, x, y, FALSE)) 149 return TRUE; 150 else if (obj->otyp == BOULDER && (t = t_at(x,y)) != 0 && 151 (t->ttyp==PIT || t->ttyp==SPIKED_PIT 152 || t->ttyp==TRAPDOOR || t->ttyp==HOLE)) { 153 if (((mtmp = m_at(x, y)) && mtmp->mtrapped) || 154 (u.utrap && u.ux == x && u.uy == y)) { 155 if (*verb) 156 pline_The("boulder %s into the pit%s.", 157 vtense((const char *)0, verb), 158 (mtmp) ? "" : " with you"); 159 if (mtmp) { 160 if (!passes_walls(mtmp->data) && 161 !throws_rocks(mtmp->data)) { 162 if (hmon(mtmp, obj, TRUE) && !is_whirly(mtmp->data)) 163 return FALSE; /* still alive */ 164 } 165 mtmp->mtrapped = 0; 166 } else { 167 if (!Passes_walls && !throws_rocks(youmonst.data)) { 168 losehp(rnd(15), "squished under a boulder", 169 NO_KILLER_PREFIX); 170 return FALSE; /* player remains trapped */ 171 } else u.utrap = 0; 172 } 173 } 174 if (*verb) { 175 if (Blind) { 176 if ((x == u.ux) && (y == u.uy)) 177 You_hear("a CRASH! beneath you."); 178 else 179 You_hear("the boulder %s.", verb); 180 } else if (cansee(x, y)) { 181 pline_The("boulder %s%s.", 182 t->tseen ? "" : "triggers and ", 183 t->ttyp == TRAPDOOR ? "plugs a trap door" : 184 t->ttyp == HOLE ? "plugs a hole" : 185 "fills a pit"); 186 } 187 } 188 deltrap(t); 189 obfree(obj, (struct obj *)0); 190 bury_objs(x, y); 191 newsym(x,y); 192 return TRUE; 193 } else if (is_lava(x, y)) { 194 return fire_damage(obj, FALSE, FALSE, x, y); 195 } else if (is_pool(x, y)) { 196 /* Reasonably bulky objects (arbitrary) splash when dropped. 197 * If you're floating above the water even small things make noise. 198 * Stuff dropped near fountains always misses */ 199 if ((Blind || (Levitation || Flying)) && flags.soundok && 200 ((x == u.ux) && (y == u.uy))) { 201 if (!Underwater) { 202 if (weight(obj) > 9) { 203 pline("Splash!"); 204 } else if (Levitation || Flying) { 205 pline("Plop!"); 206 } 207 } 208 map_background(x, y, 0); 209 newsym(x, y); 210 } 211 water_damage(obj, FALSE, FALSE); 212 } else if (u.ux == x && u.uy == y && 213 (!u.utrap || u.utraptype != TT_PIT) && 214 (t = t_at(x,y)) != 0 && t->tseen && 215 (t->ttyp==PIT || t->ttyp==SPIKED_PIT)) { 216 /* you escaped a pit and are standing on the precipice */ 217 if (Blind && flags.soundok) 218 You_hear("%s %s downwards.", 219 The(xname(obj)), otense(obj, "tumble")); 220 else 221 pline("%s %s into %s pit.", 222 The(xname(obj)), otense(obj, "tumble"), 223 the_your[t->madeby_u]); 224 } 225 return FALSE; 226} 227 228#endif /* OVL0 */ 229#ifdef OVLB 230 231void 232doaltarobj(obj) /* obj is an object dropped on an altar */ 233 register struct obj *obj; 234{ 235 if (Blind) 236 return; 237 238 /* KMH, conduct */ 239 u.uconduct.gnostic++; 240 241 if ((obj->blessed || obj->cursed) && obj->oclass != COIN_CLASS) { 242 There("is %s flash as %s %s the altar.", 243 an(hcolor(obj->blessed ? NH_AMBER : NH_BLACK)), 244 doname(obj), otense(obj, "hit")); 245 if (!Hallucination) obj->bknown = 1; 246 } else { 247 pline("%s %s on the altar.", Doname2(obj), 248 otense(obj, "land")); 249 obj->bknown = 1; 250 } 251} 252 253#ifdef SINKS 254STATIC_OVL 255void 256trycall(obj) 257register struct obj *obj; 258{ 259 if(!objects[obj->otyp].oc_name_known && 260 !objects[obj->otyp].oc_uname) 261 docall(obj); 262} 263 264STATIC_OVL 265void 266dosinkring(obj) /* obj is a ring being dropped over a kitchen sink */ 267register struct obj *obj; 268{ 269 register struct obj *otmp,*otmp2; 270 register boolean ideed = TRUE; 271 272 You("drop %s down the drain.", doname(obj)); 273 obj->in_use = TRUE; /* block free identification via interrupt */ 274 switch(obj->otyp) { /* effects that can be noticed without eyes */ 275 case RIN_SEARCHING: 276 You("thought your %s got lost in the sink, but there it is!", 277 xname(obj)); 278 goto giveback; 279 case RIN_SLOW_DIGESTION: 280 pline_The("ring is regurgitated!"); 281giveback: 282 obj->in_use = FALSE; 283 dropx(obj); 284 trycall(obj); 285 return; 286 case RIN_LEVITATION: 287 pline_The("sink quivers upward for a moment."); 288 break; 289 case RIN_POISON_RESISTANCE: 290 You("smell rotten %s.", makeplural(fruitname(FALSE))); 291 break; 292 case RIN_AGGRAVATE_MONSTER: 293 pline("Several flies buzz angrily around the sink."); 294 break; 295 case RIN_SHOCK_RESISTANCE: 296 pline("Static electricity surrounds the sink."); 297 break; 298 case RIN_CONFLICT: 299 You_hear("loud noises coming from the drain."); 300 break; 301 case RIN_SUSTAIN_ABILITY: /* KMH */ 302 pline_The("water flow seems fixed."); 303 break; 304 case RIN_GAIN_STRENGTH: 305 pline_The("water flow seems %ser now.", 306 (obj->spe<0) ? "weak" : "strong"); 307 break; 308 case RIN_GAIN_CONSTITUTION: 309 pline_The("water flow seems %ser now.", 310 (obj->spe<0) ? "less" : "great"); 311 break; 312 case RIN_INCREASE_ACCURACY: /* KMH */ 313 pline_The("water flow %s the drain.", 314 (obj->spe<0) ? "misses" : "hits"); 315 break; 316 case RIN_INCREASE_DAMAGE: 317 pline_The("water's force seems %ser now.", 318 (obj->spe<0) ? "small" : "great"); 319 break; 320 case RIN_HUNGER: 321 ideed = FALSE; 322 for(otmp = level.objects[u.ux][u.uy]; otmp; otmp = otmp2) { 323 otmp2 = otmp->nexthere; 324 if (otmp != uball && otmp != uchain && 325 !obj_resists(otmp, 1, 99)) { 326 if (!Blind) { 327 pline("Suddenly, %s %s from the sink!", 328 doname(otmp), otense(otmp, "vanish")); 329 ideed = TRUE; 330 } 331 delobj(otmp); 332 } 333 } 334 break; 335 case MEAT_RING: 336 /* Not the same as aggravate monster; besides, it's obvious. */ 337 pline("Several flies buzz around the sink."); 338 break; 339 default: 340 ideed = FALSE; 341 break; 342 } 343 if(!Blind && !ideed && obj->otyp != RIN_HUNGER) { 344 ideed = TRUE; 345 switch(obj->otyp) { /* effects that need eyes */ 346 case RIN_ADORNMENT: 347 pline_The("faucets flash brightly for a moment."); 348 break; 349 case RIN_REGENERATION: 350 pline_The("sink looks as good as new."); 351 break; 352 case RIN_INVISIBILITY: 353 You("don't see anything happen to the sink."); 354 break; 355 case RIN_FREE_ACTION: 356 You("see the ring slide right down the drain!"); 357 break; 358 case RIN_SEE_INVISIBLE: 359 You("see some air in the sink."); 360 break; 361 case RIN_STEALTH: 362 pline_The("sink seems to blend into the floor for a moment."); 363 break; 364 case RIN_FIRE_RESISTANCE: 365 pline_The("hot water faucet flashes brightly for a moment."); 366 break; 367 case RIN_COLD_RESISTANCE: 368 pline_The("cold water faucet flashes brightly for a moment."); 369 break; 370 case RIN_PROTECTION_FROM_SHAPE_CHAN: 371 pline_The("sink looks nothing like a fountain."); 372 break; 373 case RIN_PROTECTION: 374 pline_The("sink glows %s for a moment.", 375 hcolor((obj->spe<0) ? NH_BLACK : NH_SILVER)); 376 break; 377 case RIN_WARNING: 378 pline_The("sink glows %s for a moment.", hcolor(NH_WHITE)); 379 break; 380 case RIN_TELEPORTATION: 381 pline_The("sink momentarily vanishes."); 382 break; 383 case RIN_TELEPORT_CONTROL: 384 pline_The("sink looks like it is being beamed aboard somewhere."); 385 break; 386 case RIN_POLYMORPH: 387 pline_The("sink momentarily looks like a fountain."); 388 break; 389 case RIN_POLYMORPH_CONTROL: 390 pline_The("sink momentarily looks like a regularly erupting geyser."); 391 break; 392 } 393 } 394 if(ideed) 395 trycall(obj); 396 else 397 You_hear("the ring bouncing down the drainpipe."); 398 if (!rn2(20)) { 399 pline_The("sink backs up, leaving %s.", doname(obj)); 400 obj->in_use = FALSE; 401 dropx(obj); 402 } else 403 useup(obj); 404} 405#endif 406 407#endif /* OVLB */ 408#ifdef OVL0 409 410/* some common tests when trying to drop or throw items */ 411boolean 412canletgo(obj,word) 413register struct obj *obj; 414register const char *word; 415{ 416 if(obj->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL)){ 417 if (*word) 418 Norep("You cannot %s %s you are wearing.",word, 419 something); 420 return(FALSE); 421 } 422 if (obj->otyp == LOADSTONE && obj->cursed) { 423 /* getobj() kludge sets corpsenm to user's specified count 424 when refusing to split a stack of cursed loadstones */ 425 if (*word) { 426 /* getobj() ignores a count for throwing since that is 427 implicitly forced to be 1; replicate its kludge... */ 428 if (!strcmp(word, "throw") && obj->quan > 1L) 429 obj->corpsenm = 1; 430 pline("For some reason, you cannot %s%s the stone%s!", 431 word, obj->corpsenm ? " any of" : "", 432 plur(obj->quan)); 433 } 434 obj->corpsenm = 0; /* reset */ 435 obj->bknown = 1; 436 return(FALSE); 437 } 438 if (obj->otyp == LEASH && obj->leashmon != 0) { 439 if (*word) 440 pline_The("leash is tied around your %s.", 441 body_part(HAND)); 442 return(FALSE); 443 } 444#ifdef STEED 445 if (obj->owornmask & W_SADDLE) { 446 if (*word) 447 You("cannot %s %s you are sitting on.", word, 448 something); 449 return (FALSE); 450 } 451#endif 452 return(TRUE); 453} 454 455STATIC_PTR 456int 457drop(obj) 458register struct obj *obj; 459{ 460 if(!obj) return(0); 461 if(!canletgo(obj,"drop")) 462 return(0); 463 if(obj == uwep) { 464 if(welded(uwep)) { 465 weldmsg(obj); 466 return(0); 467 } 468 setuwep((struct obj *)0); 469 } 470 if(obj == uquiver) { 471 setuqwep((struct obj *)0); 472 } 473 if (obj == uswapwep) { 474 setuswapwep((struct obj *)0); 475 } 476 477 if (u.uswallow) { 478 /* barrier between you and the floor */ 479 if(flags.verbose) 480 { 481 char buf[BUFSZ]; 482 483 /* doname can call s_suffix, reusing its buffer */ 484 Strcpy(buf, s_suffix(mon_nam(u.ustuck))); 485 You("drop %s into %s %s.", doname(obj), buf, 486 mbodypart(u.ustuck, STOMACH)); 487 } 488 } else { 489#ifdef SINKS 490 if((obj->oclass == RING_CLASS || obj->otyp == MEAT_RING) && 491 IS_SINK(levl[u.ux][u.uy].typ)) { 492 dosinkring(obj); 493 return(1); 494 } 495#endif 496 if (!can_reach_floor()) { 497 if(flags.verbose) You("drop %s.", doname(obj)); 498#ifndef GOLDOBJ 499 if (obj->oclass != COIN_CLASS || obj == invent) freeinv(obj); 500#else 501 /* Ensure update when we drop gold objects */ 502 if (obj->oclass == COIN_CLASS) flags.botl = 1; 503 freeinv(obj); 504#endif 505 hitfloor(obj); 506 return(1); 507 } 508 if (!IS_ALTAR(levl[u.ux][u.uy].typ) && flags.verbose) 509 You("drop %s.", doname(obj)); 510 } 511 dropx(obj); 512 return(1); 513} 514 515/* Called in several places - may produce output */ 516/* eg ship_object() and dropy() -> sellobj() both produce output */ 517void 518dropx(obj) 519register struct obj *obj; 520{ 521#ifndef GOLDOBJ 522 if (obj->oclass != COIN_CLASS || obj == invent) freeinv(obj); 523#else 524 /* Ensure update when we drop gold objects */ 525 if (obj->oclass == COIN_CLASS) flags.botl = 1; 526 freeinv(obj); 527#endif 528 if (!u.uswallow) { 529 if (ship_object(obj, u.ux, u.uy, FALSE)) return; 530 if (IS_ALTAR(levl[u.ux][u.uy].typ)) 531 doaltarobj(obj); /* set bknown */ 532 } 533 dropy(obj); 534} 535 536void 537dropy(obj) 538register struct obj *obj; 539{ 540 if (obj == uwep) setuwep((struct obj *)0); 541 if (obj == uquiver) setuqwep((struct obj *)0); 542 if (obj == uswapwep) setuswapwep((struct obj *)0); 543 544 if (!u.uswallow && flooreffects(obj,u.ux,u.uy,"drop")) return; 545 /* uswallow check done by GAN 01/29/87 */ 546 if(u.uswallow) { 547 boolean could_petrify = FALSE; 548 boolean could_poly = FALSE; 549 boolean could_slime = FALSE; 550 boolean could_grow = FALSE; 551 boolean could_heal = FALSE; 552 553 if (obj != uball) { /* mon doesn't pick up ball */ 554 if (obj->otyp == CORPSE) { 555 could_petrify = touch_petrifies(&mons[obj->corpsenm]); 556 could_poly = polyfodder(obj); 557 could_slime = (obj->corpsenm == PM_GREEN_SLIME); 558 could_grow = (obj->corpsenm == PM_WRAITH); 559 could_heal = (obj->corpsenm == PM_NURSE); 560 } 561 (void) mpickobj(u.ustuck,obj); 562 if (is_animal(u.ustuck->data)) { 563 if (could_poly || could_slime) { 564 (void) newcham(u.ustuck, 565 could_poly ? (struct permonst *)0 : 566 &mons[PM_GREEN_SLIME], 567 FALSE, could_slime); 568 delobj(obj); /* corpse is digested */ 569 } else if (could_petrify) { 570 minstapetrify(u.ustuck, TRUE); 571 /* Don't leave a cockatrice corpse in a statue */ 572 if (!u.uswallow) delobj(obj); 573 } else if (could_grow) { 574 (void) grow_up(u.ustuck, (struct monst *)0); 575 delobj(obj); /* corpse is digested */ 576 } else if (could_heal) { 577 u.ustuck->mhp = u.ustuck->mhpmax; 578 delobj(obj); /* corpse is digested */ 579 } 580 } 581 } 582 } else { 583 place_object(obj, u.ux, u.uy); 584 if (obj == uball) 585 drop_ball(u.ux,u.uy); 586 else 587 sellobj(obj, u.ux, u.uy); 588 stackobj(obj); 589 if(Blind && Levitation) 590 map_object(obj, 0); 591 newsym(u.ux,u.uy); /* remap location under self */ 592 } 593} 594 595/* things that must change when not held; recurse into containers. 596 Called for both player and monsters */ 597void 598obj_no_longer_held(obj) 599struct obj *obj; 600{ 601 if (!obj) { 602 return; 603 } else if ((Is_container(obj) || obj->otyp == STATUE) && obj->cobj) { 604 struct obj *contents; 605 for(contents=obj->cobj; contents; contents=contents->nobj) 606 obj_no_longer_held(contents); 607 } 608 switch(obj->otyp) { 609 case CRYSKNIFE: 610 /* KMH -- Fixed crysknives have only 10% chance of reverting */ 611 /* only changes when not held by player or monster */ 612 if (!obj->oerodeproof || !rn2(10)) { 613 obj->otyp = WORM_TOOTH; 614 obj->oerodeproof = 0; 615 } 616 break; 617 } 618} 619 620/* 'D' command: drop several things */ 621int 622doddrop() 623{ 624 int result = 0; 625 626 add_valid_menu_class(0); /* clear any classes already there */ 627 if (*u.ushops) sellobj_state(SELL_DELIBERATE); 628 if (flags.menu_style != MENU_TRADITIONAL || 629 (result = ggetobj("drop", drop, 0, FALSE, (unsigned *)0)) < -1) 630 result = menu_drop(result); 631 if (*u.ushops) sellobj_state(SELL_NORMAL); 632 reset_occupations(); 633 634 return result; 635} 636 637/* Drop things from the hero's inventory, using a menu. */ 638STATIC_OVL int 639menu_drop(retry) 640int retry; 641{ 642 int n, i, n_dropped = 0; 643 long cnt; 644 struct obj *otmp, *otmp2; 645#ifndef GOLDOBJ 646 struct obj *u_gold = 0; 647#endif 648 menu_item *pick_list; 649 boolean all_categories = TRUE; 650 boolean drop_everything = FALSE; 651 652#ifndef GOLDOBJ 653 if (u.ugold) { 654 /* Hack: gold is not in the inventory, so make a gold object 655 and put it at the head of the inventory list. */ 656 u_gold = mkgoldobj(u.ugold); /* removes from u.ugold */ 657 u_gold->in_use = TRUE; 658 u.ugold = u_gold->quan; /* put the gold back */ 659 assigninvlet(u_gold); /* might end up as NOINVSYM */ 660 u_gold->nobj = invent; 661 invent = u_gold; 662 } 663#endif 664 if (retry) { 665 all_categories = (retry == -2); 666 } else if (flags.menu_style == MENU_FULL) { 667 all_categories = FALSE; 668 n = query_category("Drop what type of items?", 669 invent, 670 UNPAID_TYPES | ALL_TYPES | CHOOSE_ALL | 671 BUC_BLESSED | BUC_CURSED | BUC_UNCURSED | BUC_UNKNOWN, 672 &pick_list, PICK_ANY); 673 if (!n) goto drop_done; 674 for (i = 0; i < n; i++) { 675 if (pick_list[i].item.a_int == ALL_TYPES_SELECTED) 676 all_categories = TRUE; 677 else if (pick_list[i].item.a_int == 'A') 678 drop_everything = TRUE; 679 else 680 add_valid_menu_class(pick_list[i].item.a_int); 681 } 682 free((genericptr_t) pick_list); 683 } else if (flags.menu_style == MENU_COMBINATION) { 684 unsigned ggoresults = 0; 685 all_categories = FALSE; 686 /* Gather valid classes via traditional NetHack method */ 687 i = ggetobj("drop", drop, 0, TRUE, &ggoresults); 688 if (i == -2) all_categories = TRUE; 689 if (ggoresults & ALL_FINISHED) { 690 n_dropped = i; 691 goto drop_done; 692 } 693 } 694 695 if (drop_everything) { 696 for(otmp = invent; otmp; otmp = otmp2) { 697 otmp2 = otmp->nobj; 698 n_dropped += drop(otmp); 699 } 700 } else { 701 /* should coordinate with perm invent, maybe not show worn items */ 702 n = query_objlist("What would you like to drop?", invent, 703 USE_INVLET|INVORDER_SORT, &pick_list, 704 PICK_ANY, all_categories ? allow_all : allow_category); 705 if (n > 0) { 706 for (i = 0; i < n; i++) { 707 otmp = pick_list[i].item.a_obj; 708 cnt = pick_list[i].count; 709 if (cnt < otmp->quan) { 710 if (welded(otmp)) { 711 ; /* don't split */ 712 } else if (otmp->otyp == LOADSTONE && otmp->cursed) { 713 /* same kludge as getobj(), for canletgo()'s use */ 714 otmp->corpsenm = (int) cnt; /* don't split */ 715 } else { 716#ifndef GOLDOBJ 717 if (otmp->oclass == COIN_CLASS) 718 (void) splitobj(otmp, otmp->quan - cnt); 719 else 720#endif 721 otmp = splitobj(otmp, cnt); 722 } 723 } 724 n_dropped += drop(otmp); 725 } 726 free((genericptr_t) pick_list); 727 } 728 } 729 730 drop_done: 731#ifndef GOLDOBJ 732 if (u_gold && invent && invent->oclass == COIN_CLASS) { 733 /* didn't drop [all of] it */ 734 u_gold = invent; 735 invent = u_gold->nobj; 736 u_gold->in_use = FALSE; 737 dealloc_obj(u_gold); 738 update_inventory(); 739 } 740#endif 741 return n_dropped; 742} 743 744#endif /* OVL0 */ 745#ifdef OVL2 746 747/* on a ladder, used in goto_level */ 748static NEARDATA boolean at_ladder = FALSE; 749 750int 751dodown() 752{ 753 struct trap *trap = 0; 754 boolean stairs_down = ((u.ux == xdnstair && u.uy == ydnstair) || 755 (u.ux == sstairs.sx && u.uy == sstairs.sy && !sstairs.up)), 756 ladder_down = (u.ux == xdnladder && u.uy == ydnladder); 757 758#ifdef STEED 759 if (u.usteed && !u.usteed->mcanmove) { 760 pline("%s won't move!", Monnam(u.usteed)); 761 return(0); 762 } else if (u.usteed && u.usteed->meating) { 763 pline("%s is still eating.", Monnam(u.usteed)); 764 return(0); 765 } else 766#endif 767 if (Levitation) { 768 if ((HLevitation & I_SPECIAL) || (ELevitation & W_ARTI)) { 769 /* end controlled levitation */ 770 if (ELevitation & W_ARTI) { 771 struct obj *obj; 772 773 for(obj = invent; obj; obj = obj->nobj) { 774 if (obj->oartifact && 775 artifact_has_invprop(obj,LEVITATION)) { 776 if (obj->age < monstermoves) 777 obj->age = monstermoves + rnz(100); 778 else 779 obj->age += rnz(100); 780 } 781 } 782 } 783 if (float_down(I_SPECIAL|TIMEOUT, W_ARTI)) 784 return (1); /* came down, so moved */ 785 } 786 floating_above(stairs_down ? "stairs" : ladder_down ? 787 "ladder" : surface(u.ux, u.uy)); 788 return (0); /* didn't move */ 789 } 790 if (!stairs_down && !ladder_down) { 791 if (!(trap = t_at(u.ux,u.uy)) || 792 (trap->ttyp != TRAPDOOR && trap->ttyp != HOLE) 793 || !Can_fall_thru(&u.uz) || !trap->tseen) { 794 795 if (flags.autodig && !flags.nopick && 796 uwep && is_pick(uwep)) { 797 return use_pick_axe2(uwep); 798 } else { 799 You_cant("go down here."); 800 return(0); 801 } 802 } 803 } 804 if(u.ustuck) { 805 You("are %s, and cannot go down.", 806 !u.uswallow ? "being held" : is_animal(u.ustuck->data) ? 807 "swallowed" : "engulfed"); 808 return(1); 809 } 810 if (on_level(&valley_level, &u.uz) && !u.uevent.gehennom_entered) { 811 You("are standing at the gate to Gehennom."); 812 pline("Unspeakable cruelty and harm lurk down there."); 813 if (yn("Are you sure you want to enter?") != 'y') 814 return(0); 815 else pline("So be it."); 816 u.uevent.gehennom_entered = 1; /* don't ask again */ 817 } 818 819 if(!next_to_u()) { 820 You("are held back by your pet!"); 821 return(0); 822 } 823 824 if (trap) 825 You("%s %s.", locomotion(youmonst.data, "jump"), 826 trap->ttyp == HOLE ? "down the hole" : "through the trap door"); 827 828 if (trap && Is_stronghold(&u.uz)) { 829 goto_hell(FALSE, TRUE); 830 } else { 831 at_ladder = (boolean) (levl[u.ux][u.uy].typ == LADDER); 832 next_level(!trap); 833 at_ladder = FALSE; 834 } 835 return(1); 836} 837 838int 839doup() 840{ 841 if( (u.ux != xupstair || u.uy != yupstair) 842 && (!xupladder || u.ux != xupladder || u.uy != yupladder) 843 && (!sstairs.sx || u.ux != sstairs.sx || u.uy != sstairs.sy 844 || !sstairs.up) 845 ) { 846 You_cant("go up here."); 847 return(0); 848 } 849#ifdef STEED 850 if (u.usteed && !u.usteed->mcanmove) { 851 pline("%s won't move!", Monnam(u.usteed)); 852 return(0); 853 } else if (u.usteed && u.usteed->meating) { 854 pline("%s is still eating.", Monnam(u.usteed)); 855 return(0); 856 } else 857#endif 858 if(u.ustuck) { 859 You("are %s, and cannot go up.", 860 !u.uswallow ? "being held" : is_animal(u.ustuck->data) ? 861 "swallowed" : "engulfed"); 862 return(1); 863 } 864 if(near_capacity() > SLT_ENCUMBER) { 865 /* No levitation check; inv_weight() already allows for it */ 866 Your("load is too heavy to climb the %s.", 867 levl[u.ux][u.uy].typ == STAIRS ? "stairs" : "ladder"); 868 return(1); 869 } 870 if(ledger_no(&u.uz) == 1) { 871 if (yn("Beware, there will be no return! Still climb?") != 'y') 872 return(0); 873 } 874 if(!next_to_u()) { 875 You("are held back by your pet!"); 876 return(0); 877 } 878 at_ladder = (boolean) (levl[u.ux][u.uy].typ == LADDER); 879 prev_level(TRUE); 880 at_ladder = FALSE; 881 return(1); 882} 883 884d_level save_dlevel = {0, 0}; 885 886/* check that we can write out the current level */ 887STATIC_OVL int 888currentlevel_rewrite() 889{ 890 register int fd; 891 char whynot[BUFSZ]; 892 893 /* since level change might be a bit slow, flush any buffered screen 894 * output (like "you fall through a trap door") */ 895 mark_synch(); 896 897 fd = create_levelfile(ledger_no(&u.uz), whynot); 898 if (fd < 0) { 899 /* 900 * This is not quite impossible: e.g., we may have 901 * exceeded our quota. If that is the case then we 902 * cannot leave this level, and cannot save either. 903 * Another possibility is that the directory was not 904 * writable. 905 */ 906 pline("%s", whynot); 907 return -1; 908 } 909 910#ifdef MFLOPPY 911 if (!savelev(fd, ledger_no(&u.uz), COUNT_SAVE)) { 912 (void) close(fd); 913 delete_levelfile(ledger_no(&u.uz)); 914 pline("NetHack is out of disk space for making levels!"); 915 You("can save, quit, or continue playing."); 916 return -1; 917 } 918#endif 919 return fd; 920} 921 922#ifdef INSURANCE 923void 924save_currentstate() 925{ 926 int fd; 927 928 if (flags.ins_chkpt) { 929 /* write out just-attained level, with pets and everything */ 930 fd = currentlevel_rewrite(); 931 if(fd < 0) return; 932 bufon(fd); 933 savelev(fd,ledger_no(&u.uz), WRITE_SAVE); 934 bclose(fd); 935 } 936 937 /* write out non-level state */ 938 savestateinlock(); 939} 940#endif 941 942/* 943static boolean 944badspot(x, y) 945register xchar x, y; 946{ 947 return((levl[x][y].typ != ROOM && levl[x][y].typ != AIR && 948 levl[x][y].typ != CORR) || MON_AT(x, y)); 949} 950*/ 951 952void 953goto_level(newlevel, at_stairs, falling, portal) 954d_level *newlevel; 955boolean at_stairs, falling, portal; 956{ 957 int fd, l_idx; 958 xchar new_ledger; 959 boolean cant_go_back, 960 up = (depth(newlevel) < depth(&u.uz)), 961 newdungeon = (u.uz.dnum != newlevel->dnum), 962 was_in_W_tower = In_W_tower(u.ux, u.uy, &u.uz), 963 familiar = FALSE; 964 boolean new = FALSE; /* made a new level? */ 965 struct monst *mtmp; 966 char whynot[BUFSZ]; 967 968 if (dunlev(newlevel) > dunlevs_in_dungeon(newlevel)) 969 newlevel->dlevel = dunlevs_in_dungeon(newlevel); 970 if (newdungeon && In_endgame(newlevel)) { /* 1st Endgame Level !!! */ 971 if (u.uhave.amulet) 972 assign_level(newlevel, &earth_level); 973 else return; 974 } 975 new_ledger = ledger_no(newlevel); 976 if (new_ledger <= 0) 977 done(ESCAPED); /* in fact < 0 is impossible */ 978 979 /* If you have the amulet and are trying to get out of Gehennom, going 980 * up a set of stairs sometimes does some very strange things! 981 * Biased against law and towards chaos, but not nearly as strongly 982 * as it used to be (prior to 3.2.0). 983 * Odds: old new 984 * "up" L N C "up" L N C 985 * +1 75.0 75.0 75.0 +1 75.0 75.0 75.0 986 * 0 0.0 12.5 25.0 0 6.25 8.33 12.5 987 * -1 8.33 4.17 0.0 -1 6.25 8.33 12.5 988 * -2 8.33 4.17 0.0 -2 6.25 8.33 0.0 989 * -3 8.33 4.17 0.0 -3 6.25 0.0 0.0 990 */ 991 if (Inhell && up && u.uhave.amulet && !newdungeon && !portal && 992 (dunlev(&u.uz) < dunlevs_in_dungeon(&u.uz)-3)) { 993 if (!rn2(4)) { 994 int odds = 3 + (int)u.ualign.type, /* 2..4 */ 995 diff = odds <= 1 ? 0 : rn2(odds); /* paranoia */ 996 997 if (diff != 0) { 998 assign_rnd_level(newlevel, &u.uz, diff); 999 /* if inside the tower, stay inside */ 1000 if (was_in_W_tower && 1001 !On_W_tower_level(newlevel)) diff = 0; 1002 } 1003 if (diff == 0) 1004 assign_level(newlevel, &u.uz); 1005 1006 new_ledger = ledger_no(newlevel); 1007 1008 pline("A mysterious force momentarily surrounds you..."); 1009 if (on_level(newlevel, &u.uz)) { 1010 (void) safe_teleds(FALSE); 1011 (void) next_to_u(); 1012 return; 1013 } else 1014 at_stairs = at_ladder = FALSE; 1015 } 1016 } 1017 1018 /* Prevent the player from going past the first quest level unless 1019 * (s)he has been given the go-ahead by the leader. 1020 */ 1021 if (on_level(&u.uz, &qstart_level) && !newdungeon && !ok_to_quest()) { 1022 pline("A mysterious force prevents you from descending."); 1023 return; 1024 } 1025 1026 if (on_level(newlevel, &u.uz)) return; /* this can happen */ 1027 1028 fd = currentlevel_rewrite(); 1029 if (fd < 0) return; 1030 1031 if (falling) /* assuming this is only trap door or hole */ 1032 impact_drop((struct obj *)0, u.ux, u.uy, newlevel->dlevel); 1033 1034 check_special_room(TRUE); /* probably was a trap door */ 1035 if (Punished) unplacebc(); 1036 u.utrap = 0; /* needed in level_tele */ 1037 fill_pit(u.ux, u.uy); 1038 u.ustuck = 0; /* idem */ 1039 u.uinwater = 0; 1040 u.uundetected = 0; /* not hidden, even if means are available */ 1041 keepdogs(FALSE); 1042 if (u.uswallow) /* idem */ 1043 u.uswldtim = u.uswallow = 0; 1044 /* 1045 * We no longer see anything on the level. Make sure that this 1046 * follows u.uswallow set to null since uswallow overrides all 1047 * normal vision. 1048 */ 1049 vision_recalc(2); 1050 1051 /* 1052 * Save the level we're leaving. If we're entering the endgame, 1053 * we can get rid of all existing levels because they cannot be 1054 * reached any more. We still need to use savelev()'s cleanup 1055 * for the level being left, to recover dynamic memory in use and 1056 * to avoid dangling timers and light sources. 1057 */ 1058 cant_go_back = (newdungeon && In_endgame(newlevel)); 1059 if (!cant_go_back) { 1060 update_mlstmv(); /* current monsters are becoming inactive */ 1061 bufon(fd); /* use buffered output */ 1062 } 1063 savelev(fd, ledger_no(&u.uz), 1064 cant_go_back ? FREE_SAVE : (WRITE_SAVE | FREE_SAVE)); 1065 bclose(fd); 1066 if (cant_go_back) { 1067 /* discard unreachable levels; keep #0 */ 1068 for (l_idx = maxledgerno(); l_idx > 0; --l_idx) 1069 delete_levelfile(l_idx); 1070 } 1071 1072#ifdef REINCARNATION 1073 if (Is_rogue_level(newlevel) || Is_rogue_level(&u.uz)) 1074 assign_rogue_graphics(Is_rogue_level(newlevel)); 1075#endif 1076#ifdef USE_TILES 1077 substitute_tiles(newlevel); 1078#endif 1079 assign_level(&u.uz0, &u.uz); 1080 assign_level(&u.uz, newlevel); 1081 assign_level(&u.utolev, newlevel); 1082 u.utotype = 0; 1083 if (dunlev_reached(&u.uz) < dunlev(&u.uz)) 1084 dunlev_reached(&u.uz) = dunlev(&u.uz); 1085 reset_rndmonst(NON_PM); /* u.uz change affects monster generation */ 1086 1087 /* set default level change destination areas */ 1088 /* the special level code may override these */ 1089 (void) memset((genericptr_t) &updest, 0, sizeof updest); 1090 (void) memset((genericptr_t) &dndest, 0, sizeof dndest); 1091 1092 if (!(level_info[new_ledger].flags & LFILE_EXISTS)) { 1093 /* entering this level for first time; make it now */ 1094 if (level_info[new_ledger].flags & (FORGOTTEN|VISITED)) { 1095 impossible("goto_level: returning to discarded level?"); 1096 level_info[new_ledger].flags &= ~(FORGOTTEN|VISITED); 1097 } 1098 mklev(); 1099 new = TRUE; /* made the level */ 1100 } else { 1101 /* returning to previously visited level; reload it */ 1102 fd = open_levelfile(new_ledger, whynot); 1103 if (fd < 0) { 1104 pline("%s", whynot); 1105 pline("Probably someone removed it."); 1106 killer = whynot; 1107 done(TRICKED); 1108 /* we'll reach here if running in wizard mode */ 1109 error("Cannot continue this game."); 1110 } 1111 minit(); /* ZEROCOMP */ 1112 getlev(fd, hackpid, new_ledger, FALSE); 1113 (void) close(fd); 1114 } 1115 /* do this prior to level-change pline messages */ 1116 vision_reset(); /* clear old level's line-of-sight */ 1117 vision_full_recalc = 0; /* don't let that reenable vision yet */ 1118 flush_screen(-1); /* ensure all map flushes are postponed */ 1119 1120 if (portal && !In_endgame(&u.uz)) { 1121 /* find the portal on the new level */ 1122 register struct trap *ttrap; 1123 1124 for (ttrap = ftrap; ttrap; ttrap = ttrap->ntrap) 1125 if (ttrap->ttyp == MAGIC_PORTAL) break; 1126 1127 if (!ttrap) panic("goto_level: no corresponding portal!"); 1128 seetrap(ttrap); 1129 u_on_newpos(ttrap->tx, ttrap->ty); 1130 } else if (at_stairs && !In_endgame(&u.uz)) { 1131 if (up) { 1132 if (at_ladder) { 1133 u_on_newpos(xdnladder, ydnladder); 1134 } else { 1135 if (newdungeon) { 1136 if (Is_stronghold(&u.uz)) { 1137 register xchar x, y; 1138 1139 do { 1140 x = (COLNO - 2 - rnd(5)); 1141 y = rn1(ROWNO - 4, 3); 1142 } while(occupied(x, y) || 1143 IS_WALL(levl[x][y].typ)); 1144 u_on_newpos(x, y); 1145 } else u_on_sstairs(); 1146 } else u_on_dnstairs(); 1147 } 1148 /* Remove bug which crashes with levitation/punishment KAA */ 1149 if (Punished && !Levitation) { 1150 pline("With great effort you climb the %s.", 1151 at_ladder ? "ladder" : "stairs"); 1152 } else if (at_ladder) 1153 You("climb up the ladder."); 1154 } else { /* down */ 1155 if (at_ladder) { 1156 u_on_newpos(xupladder, yupladder); 1157 } else { 1158 if (newdungeon) u_on_sstairs(); 1159 else u_on_upstairs(); 1160 } 1161 if (u.dz && Flying) 1162 You("fly down along the %s.", 1163 at_ladder ? "ladder" : "stairs"); 1164 else if (u.dz && 1165 (near_capacity() > UNENCUMBERED || Punished || Fumbling)) { 1166 You("fall down the %s.", at_ladder ? "ladder" : "stairs"); 1167 if (Punished) { 1168 drag_down(); 1169 if (carried(uball)) { 1170 if (uwep == uball) 1171 setuwep((struct obj *)0); 1172 if (uswapwep == uball) 1173 setuswapwep((struct obj *)0); 1174 if (uquiver == uball) 1175 setuqwep((struct obj *)0); 1176 freeinv(uball); 1177 } 1178 } 1179#ifdef STEED 1180 /* falling off steed has its own losehp() call */ 1181 if (u.usteed) 1182 dismount_steed(DISMOUNT_FELL); 1183 else 1184#endif 1185 losehp(rnd(3), "falling downstairs", KILLED_BY); 1186 selftouch("Falling, you"); 1187 } else if (u.dz && at_ladder) 1188 You("climb down the ladder."); 1189 } 1190 } else { /* trap door or level_tele or In_endgame */ 1191 if (was_in_W_tower && On_W_tower_level(&u.uz)) 1192 /* Stay inside the Wizard's tower when feasible. */ 1193 /* Note: up vs down doesn't really matter in this case. */ 1194 place_lregion(dndest.nlx, dndest.nly, 1195 dndest.nhx, dndest.nhy, 1196 0,0, 0,0, LR_DOWNTELE, (d_level *) 0); 1197 else if (up) 1198 place_lregion(updest.lx, updest.ly, 1199 updest.hx, updest.hy, 1200 updest.nlx, updest.nly, 1201 updest.nhx, updest.nhy, 1202 LR_UPTELE, (d_level *) 0); 1203 else 1204 place_lregion(dndest.lx, dndest.ly, 1205 dndest.hx, dndest.hy, 1206 dndest.nlx, dndest.nly, 1207 dndest.nhx, dndest.nhy, 1208 LR_DOWNTELE, (d_level *) 0); 1209 if (falling) { 1210 if (Punished) ballfall(); 1211 selftouch("Falling, you"); 1212 } 1213 } 1214 1215 if (Punished) placebc(); 1216 obj_delivery(); /* before killing geno'd monsters' eggs */ 1217 losedogs(); 1218 kill_genocided_monsters(); /* for those wiped out while in limbo */ 1219 /* 1220 * Expire all timers that have gone off while away. Must be 1221 * after migrating monsters and objects are delivered 1222 * (losedogs and obj_delivery). 1223 */ 1224 run_timers(); 1225 1226 initrack(); 1227 1228 if ((mtmp = m_at(u.ux, u.uy)) != 0 1229#ifdef STEED 1230 && mtmp != u.usteed 1231#endif 1232 ) { 1233 /* There's a monster at your target destination; it might be one 1234 which accompanied you--see mon_arrive(dogmove.c)--or perhaps 1235 it was already here. Randomly move you to an adjacent spot 1236 or else the monster to any nearby location. Prior to 3.3.0 1237 the latter was done unconditionally. */ 1238 coord cc; 1239 1240 if (!rn2(2) && 1241 enexto(&cc, u.ux, u.uy, youmonst.data) && 1242 distu(cc.x, cc.y) <= 2) 1243 u_on_newpos(cc.x, cc.y); /*[maybe give message here?]*/ 1244 else 1245 mnexto(mtmp); 1246 1247 if ((mtmp = m_at(u.ux, u.uy)) != 0) { 1248 impossible("mnexto failed (do.c)?"); 1249 (void) rloc(mtmp, FALSE); 1250 } 1251 } 1252 1253 /* initial movement of bubbles just before vision_recalc */ 1254 if (Is_waterlevel(&u.uz)) 1255 movebubbles(); 1256 1257 if (level_info[new_ledger].flags & FORGOTTEN) { 1258 forget_map(ALL_MAP); /* forget the map */ 1259 forget_traps(); /* forget all traps too */ 1260 familiar = TRUE; 1261 level_info[new_ledger].flags &= ~FORGOTTEN; 1262 } 1263 1264 /* Reset the screen. */ 1265 vision_reset(); /* reset the blockages */ 1266 docrt(); /* does a full vision recalc */ 1267 flush_screen(-1); 1268 1269 /* 1270 * Move all plines beyond the screen reset. 1271 */ 1272 1273 /* give room entrance message, if any */ 1274 check_special_room(FALSE); 1275 1276 /* Check whether we just entered Gehennom. */ 1277 if (!In_hell(&u.uz0) && Inhell) { 1278 if (Is_valley(&u.uz)) { 1279 You("arrive at the Valley of the Dead..."); 1280 pline_The("odor of burnt flesh and decay pervades the air."); 1281#ifdef MICRO 1282 display_nhwindow(WIN_MESSAGE, FALSE); 1283#endif 1284 You_hear("groans and moans everywhere."); 1285 } else pline("It is hot here. You smell smoke..."); 1286 } 1287 1288 if (familiar) { 1289 static const char * const fam_msgs[4] = { 1290 "You have a sense of deja vu.", 1291 "You feel like you've been here before.", 1292 "This place %s familiar...", 1293 0 /* no message */ 1294 }; 1295 static const char * const halu_fam_msgs[4] = { 1296 "Whoa! Everything %s different.", 1297 "You are surrounded by twisty little passages, all alike.", 1298 "Gee, this %s like uncle Conan's place...", 1299 0 /* no message */ 1300 }; 1301 const char *mesg; 1302 char buf[BUFSZ]; 1303 int which = rn2(4); 1304 1305 if (Hallucination) 1306 mesg = halu_fam_msgs[which]; 1307 else 1308 mesg = fam_msgs[which]; 1309 if (mesg && index(mesg, '%')) { 1310 Sprintf(buf, mesg, !Blind ? "looks" : "seems"); 1311 mesg = buf; 1312 } 1313 if (mesg) pline(mesg); 1314 } 1315 1316#ifdef REINCARNATION 1317 if (new && Is_rogue_level(&u.uz)) 1318 You("enter what seems to be an older, more primitive world."); 1319#endif 1320 /* Final confrontation */ 1321 if (In_endgame(&u.uz) && newdungeon && u.uhave.amulet) 1322 resurrect(); 1323 if (newdungeon && In_V_tower(&u.uz) && In_hell(&u.uz0)) 1324 pline_The("heat and smoke are gone."); 1325 1326 /* the message from your quest leader */ 1327 if (!In_quest(&u.uz0) && at_dgn_entrance("The Quest") && 1328 !(u.uevent.qexpelled || u.uevent.qcompleted || quest_status.leader_is_dead)) { 1329 1330 if (u.uevent.qcalled) { 1331 com_pager(Role_if(PM_ROGUE) ? 4 : 3); 1332 } else { 1333 com_pager(2); 1334 u.uevent.qcalled = TRUE; 1335 } 1336 } 1337 1338 /* once Croesus is dead, his alarm doesn't work any more */ 1339 if (Is_knox(&u.uz) && (new || !mvitals[PM_CROESUS].died)) { 1340 You("penetrated a high security area!"); 1341 pline("An alarm sounds!"); 1342 for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) 1343 if (!DEADMONSTER(mtmp) && mtmp->msleeping) mtmp->msleeping = 0; 1344 } 1345 1346 if (on_level(&u.uz, &astral_level)) 1347 final_level(); 1348 else 1349 onquest(); 1350 assign_level(&u.uz0, &u.uz); /* reset u.uz0 */ 1351 1352#ifdef INSURANCE 1353 save_currentstate(); 1354#endif 1355 1356 /* assume this will always return TRUE when changing level */ 1357 (void) in_out_region(u.ux, u.uy); 1358 (void) pickup(1); 1359} 1360 1361STATIC_OVL void 1362final_level() 1363{ 1364 struct monst *mtmp; 1365 struct obj *otmp; 1366 coord mm; 1367 int i; 1368 1369 /* reset monster hostility relative to player */ 1370 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) 1371 if (!DEADMONSTER(mtmp)) reset_hostility(mtmp); 1372 1373 /* create some player-monsters */ 1374 create_mplayers(rn1(4, 3), TRUE); 1375 1376 /* create a guardian angel next to player, if worthy */ 1377 if (Conflict) { 1378 pline( 1379 "A voice booms: \"Thy desire for conflict shall be fulfilled!\""); 1380 for (i = rnd(4); i > 0; --i) { 1381 mm.x = u.ux; 1382 mm.y = u.uy; 1383 if (enexto(&mm, mm.x, mm.y, &mons[PM_ANGEL])) 1384 (void) mk_roamer(&mons[PM_ANGEL], u.ualign.type, 1385 mm.x, mm.y, FALSE); 1386 } 1387 1388 } else if (u.ualign.record > 8) { /* fervent */ 1389 pline("A voice whispers: \"Thou hast been worthy of me!\""); 1390 mm.x = u.ux; 1391 mm.y = u.uy; 1392 if (enexto(&mm, mm.x, mm.y, &mons[PM_ANGEL])) { 1393 if ((mtmp = mk_roamer(&mons[PM_ANGEL], u.ualign.type, 1394 mm.x, mm.y, TRUE)) != 0) { 1395 if (!Blind) 1396 pline("An angel appears near you."); 1397 else 1398 You_feel("the presence of a friendly angel near you."); 1399 /* guardian angel -- the one case mtame doesn't 1400 * imply an edog structure, so we don't want to 1401 * call tamedog(). 1402 */ 1403 mtmp->mtame = 10; 1404 /* make him strong enough vs. endgame foes */ 1405 mtmp->m_lev = rn1(8,15); 1406 mtmp->mhp = mtmp->mhpmax = 1407 d((int)mtmp->m_lev,10) + 30 + rnd(30); 1408 if ((otmp = select_hwep(mtmp)) == 0) { 1409 otmp = mksobj(SILVER_SABER, FALSE, FALSE); 1410 if (mpickobj(mtmp, otmp)) 1411 panic("merged weapon?"); 1412 } 1413 bless(otmp); 1414 if (otmp->spe < 4) otmp->spe += rnd(4); 1415 if ((otmp = which_armor(mtmp, W_ARMS)) == 0 || 1416 otmp->otyp != SHIELD_OF_REFLECTION) { 1417 (void) mongets(mtmp, AMULET_OF_REFLECTION); 1418 m_dowear(mtmp, TRUE); 1419 } 1420 } 1421 } 1422 } 1423} 1424 1425static char *dfr_pre_msg = 0, /* pline() before level change */ 1426 *dfr_post_msg = 0; /* pline() after level change */ 1427 1428/* change levels at the end of this turn, after monsters finish moving */ 1429void 1430schedule_goto(tolev, at_stairs, falling, portal_flag, pre_msg, post_msg) 1431d_level *tolev; 1432boolean at_stairs, falling; 1433int portal_flag; 1434const char *pre_msg, *post_msg; 1435{ 1436 int typmask = 0100; /* non-zero triggers `deferred_goto' */ 1437 1438 /* destination flags (`goto_level' args) */ 1439 if (at_stairs) typmask |= 1; 1440 if (falling) typmask |= 2; 1441 if (portal_flag) typmask |= 4; 1442 if (portal_flag < 0) typmask |= 0200; /* flag for portal removal */ 1443 u.utotype = typmask; 1444 /* destination level */ 1445 assign_level(&u.utolev, tolev); 1446 1447 if (pre_msg) 1448 dfr_pre_msg = strcpy((char *)alloc(strlen(pre_msg) + 1), pre_msg); 1449 if (post_msg) 1450 dfr_post_msg = strcpy((char *)alloc(strlen(post_msg)+1), post_msg); 1451} 1452 1453/* handle something like portal ejection */ 1454void 1455deferred_goto() 1456{ 1457 if (!on_level(&u.uz, &u.utolev)) { 1458 d_level dest; 1459 int typmask = u.utotype; /* save it; goto_level zeroes u.utotype */ 1460 1461 assign_level(&dest, &u.utolev); 1462 if (dfr_pre_msg) pline(dfr_pre_msg); 1463 goto_level(&dest, !!(typmask&1), !!(typmask&2), !!(typmask&4)); 1464 if (typmask & 0200) { /* remove portal */ 1465 struct trap *t = t_at(u.ux, u.uy); 1466 1467 if (t) { 1468 deltrap(t); 1469 newsym(u.ux, u.uy); 1470 } 1471 } 1472 if (dfr_post_msg) pline(dfr_post_msg); 1473 } 1474 u.utotype = 0; /* our caller keys off of this */ 1475 if (dfr_pre_msg) 1476 free((genericptr_t)dfr_pre_msg), dfr_pre_msg = 0; 1477 if (dfr_post_msg) 1478 free((genericptr_t)dfr_post_msg), dfr_post_msg = 0; 1479} 1480 1481#endif /* OVL2 */ 1482#ifdef OVL3 1483 1484/* 1485 * Return TRUE if we created a monster for the corpse. If successful, the 1486 * corpse is gone. 1487 */ 1488boolean 1489revive_corpse(corpse) 1490struct obj *corpse; 1491{ 1492 struct monst *mtmp, *mcarry; 1493 boolean is_uwep, chewed; 1494 xchar where; 1495 char *cname, cname_buf[BUFSZ]; 1496 struct obj *container = (struct obj *)0; 1497 int container_where = 0; 1498 1499 where = corpse->where; 1500 is_uwep = corpse == uwep; 1501 cname = eos(strcpy(cname_buf, "bite-covered ")); 1502 Strcpy(cname, corpse_xname(corpse, TRUE)); 1503 mcarry = (where == OBJ_MINVENT) ? corpse->ocarry : 0; 1504 1505 if (where == OBJ_CONTAINED) { 1506 struct monst *mtmp2 = (struct monst *)0; 1507 container = corpse->ocontainer; 1508 mtmp2 = get_container_location(container, &container_where, (int *)0); 1509 /* container_where is the outermost container's location even if nested */ 1510 if (container_where == OBJ_MINVENT && mtmp2) mcarry = mtmp2; 1511 } 1512 mtmp = revive(corpse); /* corpse is gone if successful */ 1513 1514 if (mtmp) { 1515 chewed = (mtmp->mhp < mtmp->mhpmax); 1516 if (chewed) cname = cname_buf; /* include "bite-covered" prefix */ 1517 switch (where) { 1518 case OBJ_INVENT: 1519 if (is_uwep) 1520 pline_The("%s writhes out of your grasp!", cname); 1521 else 1522 You_feel("squirming in your backpack!"); 1523 break; 1524 1525 case OBJ_FLOOR: 1526 if (cansee(mtmp->mx, mtmp->my)) 1527 pline("%s rises from the dead!", chewed ? 1528 Adjmonnam(mtmp, "bite-covered") : Monnam(mtmp)); 1529 break; 1530 1531 case OBJ_MINVENT: /* probably a nymph's */ 1532 if (cansee(mtmp->mx, mtmp->my)) { 1533 if (canseemon(mcarry)) 1534 pline("Startled, %s drops %s as it revives!", 1535 mon_nam(mcarry), an(cname)); 1536 else 1537 pline("%s suddenly appears!", chewed ? 1538 Adjmonnam(mtmp, "bite-covered") : Monnam(mtmp)); 1539 } 1540 break; 1541 case OBJ_CONTAINED: 1542 if (container_where == OBJ_MINVENT && cansee(mtmp->mx, mtmp->my) && 1543 mcarry && canseemon(mcarry) && container) { 1544 char sackname[BUFSZ]; 1545 Sprintf(sackname, "%s %s", s_suffix(mon_nam(mcarry)), 1546 xname(container)); 1547 pline("%s writhes out of %s!", Amonnam(mtmp), sackname); 1548 } else if (container_where == OBJ_INVENT && container) { 1549 char sackname[BUFSZ]; 1550 Strcpy(sackname, an(xname(container))); 1551 pline("%s %s out of %s in your pack!", 1552 Blind ? Something : Amonnam(mtmp), 1553 locomotion(mtmp->data,"writhes"), 1554 sackname); 1555 } else if (container_where == OBJ_FLOOR && container && 1556 cansee(mtmp->mx, mtmp->my)) { 1557 char sackname[BUFSZ]; 1558 Strcpy(sackname, an(xname(container))); 1559 pline("%s escapes from %s!", Amonnam(mtmp), sackname); 1560 } 1561 break; 1562 default: 1563 /* we should be able to handle the other cases... */ 1564 impossible("revive_corpse: lost corpse @ %d", where); 1565 break; 1566 } 1567 return TRUE; 1568 } 1569 return FALSE; 1570} 1571 1572/* Revive the corpse via a timeout. */ 1573/*ARGSUSED*/ 1574void 1575revive_mon(arg, timeout) 1576genericptr_t arg; 1577long timeout; 1578{ 1579 struct obj *body = (struct obj *) arg; 1580 1581 /* if we succeed, the corpse is gone, otherwise, rot it away */ 1582 if (!revive_corpse(body)) { 1583 if (is_rider(&mons[body->corpsenm])) 1584 You_feel("less hassled."); 1585 (void) start_timer(250L - (monstermoves-body->age), 1586 TIMER_OBJECT, ROT_CORPSE, arg); 1587 } 1588} 1589 1590int 1591donull() 1592{ 1593 return(1); /* Do nothing, but let other things happen */ 1594} 1595 1596#endif /* OVL3 */ 1597#ifdef OVLB 1598 1599STATIC_PTR int 1600wipeoff() 1601{ 1602 if(u.ucreamed < 4) u.ucreamed = 0; 1603 else u.ucreamed -= 4; 1604 if (Blinded < 4) Blinded = 0; 1605 else Blinded -= 4; 1606 if (!Blinded) { 1607 pline("You've got the glop off."); 1608 u.ucreamed = 0; 1609 Blinded = 1; 1610 make_blinded(0L,TRUE); 1611 return(0); 1612 } else if (!u.ucreamed) { 1613 Your("%s feels clean now.", body_part(FACE)); 1614 return(0); 1615 } 1616 return(1); /* still busy */ 1617} 1618 1619int 1620dowipe() 1621{ 1622 if(u.ucreamed) { 1623 static NEARDATA char buf[39]; 1624 1625 Sprintf(buf, "wiping off your %s", body_part(FACE)); 1626 set_occupation(wipeoff, buf, 0); 1627 /* Not totally correct; what if they change back after now 1628 * but before they're finished wiping? 1629 */ 1630 return(1); 1631 } 1632 Your("%s is already clean.", body_part(FACE)); 1633 return(1); 1634} 1635 1636void 1637set_wounded_legs(side, timex) 1638register long side; 1639register int timex; 1640{ 1641 /* KMH -- STEED 1642 * If you are riding, your steed gets the wounded legs instead. 1643 * You still call this function, but don't lose hp. 1644 * Caller is also responsible for adjusting messages. 1645 */ 1646 1647 if(!Wounded_legs) { 1648 ATEMP(A_DEX)--; 1649 flags.botl = 1; 1650 } 1651 1652 if(!Wounded_legs || (HWounded_legs & TIMEOUT)) 1653 HWounded_legs = timex; 1654 EWounded_legs = side; 1655 (void)encumber_msg(); 1656} 1657 1658void 1659heal_legs() 1660{ 1661 if(Wounded_legs) { 1662 if (ATEMP(A_DEX) < 0) { 1663 ATEMP(A_DEX)++; 1664 flags.botl = 1; 1665 } 1666 1667#ifdef STEED 1668 if (!u.usteed) 1669#endif 1670 { 1671 /* KMH, intrinsics patch */ 1672 if((EWounded_legs & BOTH_SIDES) == BOTH_SIDES) { 1673 Your("%s feel somewhat better.", 1674 makeplural(body_part(LEG))); 1675 } else { 1676 Your("%s feels somewhat better.", 1677 body_part(LEG)); 1678 } 1679 } 1680 HWounded_legs = EWounded_legs = 0; 1681 } 1682 (void)encumber_msg(); 1683} 1684 1685#endif /* OVLB */ 1686 1687/*do.c*/ 1688