OSDN Git Service

no E-word
[nethackexpress/trunk.git] / src / do.c
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
12 STATIC_DCL void FDECL(trycall, (struct obj *));
13 # endif /* OVLB */
14 STATIC_DCL void FDECL(dosinkring, (struct obj *));
15 #endif /* SINKS */
16
17 STATIC_PTR int FDECL(drop, (struct obj *));
18 STATIC_PTR int NDECL(wipeoff);
19
20 #ifdef OVL0
21 STATIC_DCL int FDECL(menu_drop, (int));
22 #endif
23 #ifdef OVL2
24 STATIC_DCL int NDECL(currentlevel_rewrite);
25 STATIC_DCL void NDECL(final_level);
26 /* static boolean FDECL(badspot, (XCHAR_P,XCHAR_P)); */
27 #endif
28
29 #ifdef OVLB
30
31 static NEARDATA const char drop_types[] =
32         { ALLOW_COUNT, COIN_CLASS, ALL_CLASSES, 0 };
33
34 /* 'd' command: drop one inventory item */
35 int
36 dodrop()
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  */
59 boolean
60 boulder_hits_pool(otmp, rx, ry, pushing)
61 struct obj *otmp;
62 register int rx, ry;
63 boolean 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  */
133 boolean
134 flooreffects(obj,x,y,verb)
135 struct obj *obj;
136 int x,y;
137 const 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
231 void
232 doaltarobj(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
254 STATIC_OVL
255 void
256 trycall(obj)
257 register struct obj *obj;
258 {
259         if(!objects[obj->otyp].oc_name_known &&
260            !objects[obj->otyp].oc_uname)
261            docall(obj);
262 }
263
264 STATIC_OVL
265 void
266 dosinkring(obj)  /* obj is a ring being dropped over a kitchen sink */
267 register 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!");
281 giveback:
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 */
411 boolean
412 canletgo(obj,word)
413 register struct obj *obj;
414 register 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
455 STATIC_PTR
456 int
457 drop(obj)
458 register 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 */
517 void
518 dropx(obj)
519 register 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
536 void
537 dropy(obj)
538 register 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 */
597 void
598 obj_no_longer_held(obj)
599 struct 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 */
621 int
622 doddrop()
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. */
638 STATIC_OVL int
639 menu_drop(retry)
640 int 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 */
748 static NEARDATA boolean at_ladder = FALSE;
749
750 int
751 dodown()
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
838 int
839 doup()
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
884 d_level save_dlevel = {0, 0};
885
886 /* check that we can write out the current level */
887 STATIC_OVL int
888 currentlevel_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
923 void
924 save_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 /*
943 static boolean
944 badspot(x, y)
945 register 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
952 void
953 goto_level(newlevel, at_stairs, falling, portal)
954 d_level *newlevel;
955 boolean 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
1361 STATIC_OVL void
1362 final_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
1425 static 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 */
1429 void
1430 schedule_goto(tolev, at_stairs, falling, portal_flag, pre_msg, post_msg)
1431 d_level *tolev;
1432 boolean at_stairs, falling;
1433 int portal_flag;
1434 const 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 */
1454 void
1455 deferred_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  */
1488 boolean
1489 revive_corpse(corpse)
1490 struct 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*/
1574 void
1575 revive_mon(arg, timeout)
1576 genericptr_t arg;
1577 long 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
1590 int
1591 donull()
1592 {
1593         return(1);      /* Do nothing, but let other things happen */
1594 }
1595
1596 #endif /* OVL3 */
1597 #ifdef OVLB
1598
1599 STATIC_PTR int
1600 wipeoff()
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
1619 int
1620 dowipe()
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
1636 void
1637 set_wounded_legs(side, timex)
1638 register long side;
1639 register 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
1658 void
1659 heal_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*/