1 /* NetHack 3.6	do.c	$NHDT-Date: 1576638499 2019/12/18 03:08:19 $  $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.198 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /*-Copyright (c) Derek S. Ray, 2015. */
4 /* NetHack may be freely redistributed.  See license for details. */
5 
6 /* Contains code for 'd', 'D' (drop), '>', '<' (up, down) */
7 
8 #include "hack.h"
9 #include "lev.h"
10 
11 STATIC_DCL void FDECL(trycall, (struct obj *));
12 STATIC_DCL void NDECL(polymorph_sink);
13 STATIC_DCL boolean NDECL(teleport_sink);
14 STATIC_DCL void FDECL(dosinkring, (struct obj *));
15 STATIC_PTR int FDECL(drop, (struct obj *));
16 STATIC_PTR int NDECL(wipeoff);
17 STATIC_DCL int FDECL(menu_drop, (int));
18 STATIC_DCL int NDECL(currentlevel_rewrite);
19 STATIC_DCL void NDECL(final_level);
20 /* static boolean FDECL(badspot, (XCHAR_P,XCHAR_P)); */
21 
22 extern int n_dgns; /* number of dungeons, from dungeon.c */
23 
24 static NEARDATA const char drop_types[] = { ALLOW_COUNT, COIN_CLASS,
25                                             ALL_CLASSES, 0 };
26 
27 /* 'd' command: drop one inventory item */
28 int
dodrop()29 dodrop()
30 {
31     int result, i = (invent) ? 0 : (SIZE(drop_types) - 1);
32 
33     if (*u.ushops)
34         sellobj_state(SELL_DELIBERATE);
35     result = drop(getobj(&drop_types[i], "drop"));
36     if (*u.ushops)
37         sellobj_state(SELL_NORMAL);
38     if (result)
39         reset_occupations();
40 
41     return result;
42 }
43 
44 /* Called when a boulder is dropped, thrown, or pushed.  If it ends up
45  * in a pool, it either fills the pool up or sinks away.  In either case,
46  * it's gone for good...  If the destination is not a pool, returns FALSE.
47  */
48 boolean
boulder_hits_pool(otmp,rx,ry,pushing)49 boulder_hits_pool(otmp, rx, ry, pushing)
50 struct obj *otmp;
51 register int rx, ry;
52 boolean pushing;
53 {
54     if (!otmp || otmp->otyp != BOULDER) {
55         impossible("Not a boulder?");
56     } else if (!Is_waterlevel(&u.uz) && is_pool_or_lava(rx, ry)) {
57         boolean lava = is_lava(rx, ry), fills_up;
58         const char *what = waterbody_name(rx, ry);
59         schar ltyp = levl[rx][ry].typ;
60         int chance = rn2(10); /* water: 90%; lava: 10% */
61         fills_up = lava ? chance == 0 : chance != 0;
62 
63         if (fills_up) {
64             struct trap *ttmp = t_at(rx, ry);
65 
66             if (ltyp == DRAWBRIDGE_UP) {
67                 levl[rx][ry].drawbridgemask &= ~DB_UNDER; /* clear lava */
68                 levl[rx][ry].drawbridgemask |= DB_FLOOR;
69             } else
70                 levl[rx][ry].typ = ROOM, levl[rx][ry].flags = 0;
71 
72             if (ttmp)
73                 (void) delfloortrap(ttmp);
74             bury_objs(rx, ry);
75 
76             newsym(rx, ry);
77             if (pushing) {
78                 char whobuf[BUFSZ];
79 
80                 Strcpy(whobuf, "you");
81                 if (u.usteed)
82                     Strcpy(whobuf, y_monnam(u.usteed));
83                 pline("%s %s %s into the %s.", upstart(whobuf),
84                       vtense(whobuf, "push"), the(xname(otmp)), what);
85                 if (flags.verbose && !Blind)
86                     pline("Now you can cross it!");
87                 /* no splashing in this case */
88             }
89         }
90         if (!fills_up || !pushing) { /* splashing occurs */
91             if (!u.uinwater) {
92                 if (pushing ? !Blind : cansee(rx, ry)) {
93                     There("is a large splash as %s %s the %s.",
94                           the(xname(otmp)), fills_up ? "fills" : "falls into",
95                           what);
96                 } else if (!Deaf)
97                     You_hear("a%s splash.", lava ? " sizzling" : "");
98                 wake_nearto(rx, ry, 40);
99             }
100 
101             if (fills_up && u.uinwater && distu(rx, ry) == 0) {
102                 u.uinwater = 0;
103                 docrt();
104                 vision_full_recalc = 1;
105                 You("find yourself on dry land again!");
106             } else if (lava && distu(rx, ry) <= 2) {
107                 int dmg;
108                 You("are hit by molten %s%c",
109                     hliquid("lava"), Fire_resistance ? '.' : '!');
110                 burn_away_slime();
111                 dmg = d((Fire_resistance ? 1 : 3), 6);
112                 losehp(Maybe_Half_Phys(dmg), /* lava damage */
113                        "molten lava", KILLED_BY);
114             } else if (!fills_up && flags.verbose
115                        && (pushing ? !Blind : cansee(rx, ry)))
116                 pline("It sinks without a trace!");
117         }
118 
119         /* boulder is now gone */
120         if (pushing)
121             delobj(otmp);
122         else
123             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
flooreffects(obj,x,y,verb)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     struct obj *otmp;
142     boolean tseen;
143     int ttyp = NO_TRAP;
144 
145     if (obj->where != OBJ_FREE)
146         panic("flooreffects: obj not free");
147 
148     /* make sure things like water_damage() have no pointers to follow */
149     obj->nobj = obj->nexthere = (struct obj *) 0;
150 
151     if (obj->otyp == BOULDER && boulder_hits_pool(obj, x, y, FALSE)) {
152         return TRUE;
153     } else if (obj->otyp == BOULDER && (t = t_at(x, y)) != 0
154                && (is_pit(t->ttyp) || is_hole(t->ttyp))) {
155         ttyp = t->ttyp;
156         tseen = t->tseen ? TRUE : FALSE;
157         if (((mtmp = m_at(x, y)) && mtmp->mtrapped)
158             || (u.utrap && u.ux == x && u.uy == y)) {
159             if (*verb && (cansee(x, y) || distu(x, y) == 0))
160                 pline("%s boulder %s into the pit%s.",
161                       Blind ? "A" : "The",
162                       vtense((const char *) 0, verb),
163                       mtmp ? "" : " with you");
164             if (mtmp) {
165                 if (!passes_walls(mtmp->data) && !throws_rocks(mtmp->data)) {
166                     /* dieroll was rnd(20); 1: maximum chance to hit
167                        since trapped target is a sitting duck */
168                     int damage, dieroll = 1;
169 
170                     /* As of 3.6.2: this was calling hmon() unconditionally
171                        so always credited/blamed the hero but the boulder
172                        might have been thrown by a giant or launched by
173                        a rolling boulder trap triggered by a monster or
174                        dropped by a scroll of earth read by a monster */
175                     if (context.mon_moving) {
176                         /* normally we'd use ohitmon() but it can call
177                            drop_throw() which calls flooreffects() */
178                         damage = dmgval(obj, mtmp);
179                         mtmp->mhp -= damage;
180                         if (DEADMONSTER(mtmp)) {
181                             if (canspotmon(mtmp))
182                                 pline("%s is %s!", Monnam(mtmp),
183                                       (nonliving(mtmp->data)
184                                        || is_vampshifter(mtmp))
185                                       ? "destroyed" : "killed");
186                             mondied(mtmp);
187                         }
188                     } else {
189                         (void) hmon(mtmp, obj, HMON_THROWN, dieroll);
190                     }
191                     if (!DEADMONSTER(mtmp) && !is_whirly(mtmp->data))
192                         return FALSE; /* still alive */
193                 }
194                 mtmp->mtrapped = 0;
195             } else {
196                 if (!Passes_walls && !throws_rocks(youmonst.data)) {
197                     losehp(Maybe_Half_Phys(rnd(15)),
198                            "squished under a boulder", NO_KILLER_PREFIX);
199                     return FALSE; /* player remains trapped */
200                 } else
201                     reset_utrap(TRUE);
202             }
203         }
204         if (*verb) {
205             if (Blind && (x == u.ux) && (y == u.uy)) {
206                 You_hear("a CRASH! beneath you.");
207             } else if (!Blind && cansee(x, y)) {
208                 pline_The("boulder %s%s.",
209                           (ttyp == TRAPDOOR && !tseen)
210                               ? "triggers and " : "",
211                           (ttyp == TRAPDOOR)
212                               ? "plugs a trap door"
213                               : (ttyp == HOLE) ? "plugs a hole"
214                                                : "fills a pit");
215             } else {
216                 You_hear("a boulder %s.", verb);
217             }
218         }
219         /*
220          * Note:  trap might have gone away via ((hmon -> killed -> xkilled)
221          *  || mondied) -> mondead -> m_detach -> fill_pit.
222          */
223         if ((t = t_at(x, y)) != 0)
224             deltrap(t);
225         useupf(obj, 1L);
226         bury_objs(x, y);
227         newsym(x, y);
228         return TRUE;
229     } else if (is_lava(x, y)) {
230         return lava_damage(obj, x, y);
231     } else if (is_pool(x, y)) {
232         /* Reasonably bulky objects (arbitrary) splash when dropped.
233          * If you're floating above the water even small things make
234          * noise.  Stuff dropped near fountains always misses */
235         if ((Blind || (Levitation || Flying)) && !Deaf
236             && ((x == u.ux) && (y == u.uy))) {
237             if (!Underwater) {
238                 if (weight(obj) > 9) {
239                     pline("Splash!");
240                 } else if (Levitation || Flying) {
241                     pline("Plop!");
242                 }
243             }
244             map_background(x, y, 0);
245             newsym(x, y);
246         }
247         return water_damage(obj, NULL, FALSE) == ER_DESTROYED;
248     } else if (u.ux == x && u.uy == y && (t = t_at(x, y)) != 0
249                && (uteetering_at_seen_pit(t) || uescaped_shaft(t))) {
250         if (Blind && !Deaf)
251             You_hear("%s tumble downwards.", the(xname(obj)));
252         else
253             pline("%s %s into %s %s.", The(xname(obj)),
254                   otense(obj, "tumble"), the_your[t->madeby_u],
255                   is_pit(t->ttyp) ? "pit" : "hole");
256     } else if (obj->globby) {
257         /* Globby things like puddings might stick together */
258         while (obj && (otmp = obj_nexto_xy(obj, x, y, TRUE)) != 0) {
259             pudding_merge_message(obj, otmp);
260             /* intentionally not getting the melded object; obj_meld may set
261              * obj to null. */
262             (void) obj_meld(&obj, &otmp);
263         }
264         return (boolean) !obj;
265     }
266     return FALSE;
267 }
268 
269 /* obj is an object dropped on an altar */
270 void
doaltarobj(obj)271 doaltarobj(obj)
272 register struct obj *obj;
273 {
274     if (Blind)
275         return;
276 
277     if (obj->oclass != COIN_CLASS) {
278         /* KMH, conduct */
279         u.uconduct.gnostic++;
280     } else {
281         /* coins don't have bless/curse status */
282         obj->blessed = obj->cursed = 0;
283     }
284 
285     if (obj->blessed || obj->cursed) {
286         There("is %s flash as %s %s the altar.",
287               an(hcolor(obj->blessed ? NH_AMBER : NH_BLACK)), doname(obj),
288               otense(obj, "hit"));
289         if (!Hallucination)
290             obj->bknown = 1; /* ok to bypass set_bknown() */
291     } else {
292         pline("%s %s on the altar.", Doname2(obj), otense(obj, "land"));
293         if (obj->oclass != COIN_CLASS)
294             obj->bknown = 1; /* ok to bypass set_bknown() */
295     }
296 }
297 
298 STATIC_OVL void
trycall(obj)299 trycall(obj)
300 register struct obj *obj;
301 {
302     if (!objects[obj->otyp].oc_name_known && !objects[obj->otyp].oc_uname)
303         docall(obj);
304 }
305 
306 /* Transforms the sink at the player's position into
307    a fountain, throne, altar or grave. */
308 STATIC_DCL void
polymorph_sink()309 polymorph_sink()
310 {
311     uchar sym = S_sink;
312     boolean sinklooted;
313     int algn;
314 
315     if (levl[u.ux][u.uy].typ != SINK)
316         return;
317 
318     sinklooted = levl[u.ux][u.uy].looted != 0;
319     level.flags.nsinks--;
320     levl[u.ux][u.uy].doormask = 0; /* levl[][].flags */
321     switch (rn2(4)) {
322     default:
323     case 0:
324         sym = S_fountain;
325         levl[u.ux][u.uy].typ = FOUNTAIN;
326         levl[u.ux][u.uy].blessedftn = 0;
327         if (sinklooted)
328             SET_FOUNTAIN_LOOTED(u.ux, u.uy);
329         level.flags.nfountains++;
330         break;
331     case 1:
332         sym = S_throne;
333         levl[u.ux][u.uy].typ = THRONE;
334         if (sinklooted)
335             levl[u.ux][u.uy].looted = T_LOOTED;
336         break;
337     case 2:
338         sym = S_altar;
339         levl[u.ux][u.uy].typ = ALTAR;
340         /* 3.6.3: this used to pass 'rn2(A_LAWFUL + 2) - 1' to
341            Align2amask() but that evaluates its argument more than once */
342         algn = rn2(3) - 1; /* -1 (A_Cha) or 0 (A_Neu) or +1 (A_Law) */
343         levl[u.ux][u.uy].altarmask = ((Inhell && rn2(3)) ? AM_NONE
344                                       : Align2amask(algn));
345         break;
346     case 3:
347         sym = S_room;
348         levl[u.ux][u.uy].typ = ROOM;
349         make_grave(u.ux, u.uy, (char *) 0);
350         if (levl[u.ux][u.uy].typ == GRAVE)
351             sym = S_grave;
352         break;
353     }
354     /* give message even if blind; we know we're not levitating,
355        so can feel the outcome even if we can't directly see it */
356     if (levl[u.ux][u.uy].typ != ROOM)
357         pline_The("sink transforms into %s!", an(defsyms[sym].explanation));
358     else
359         pline_The("sink vanishes.");
360     newsym(u.ux, u.uy);
361 }
362 
363 /* Teleports the sink at the player's position;
364    return True if sink teleported. */
365 STATIC_DCL boolean
teleport_sink()366 teleport_sink()
367 {
368     int cx, cy;
369     int cnt = 0;
370     struct trap *trp;
371     struct engr *eng;
372 
373     do {
374         cx = rnd(COLNO - 1);
375         cy = rn2(ROWNO);
376         trp = t_at(cx, cy);
377         eng = engr_at(cx, cy);
378     } while ((levl[cx][cy].typ != ROOM || trp || eng || cansee(cx, cy))
379              && cnt++ < 200);
380 
381     if (levl[cx][cy].typ == ROOM && !trp && !eng) {
382         /* create sink at new position */
383         levl[cx][cy].typ = SINK;
384         levl[cx][cy].looted = levl[u.ux][u.uy].looted;
385         newsym(cx, cy);
386         /* remove old sink */
387         levl[u.ux][u.uy].typ = ROOM;
388         levl[u.ux][u.uy].looted = 0;
389         newsym(u.ux, u.uy);
390         return TRUE;
391     }
392     return FALSE;
393 }
394 
395 /* obj is a ring being dropped over a kitchen sink */
396 STATIC_OVL void
dosinkring(obj)397 dosinkring(obj)
398 register struct obj *obj;
399 {
400     struct obj *otmp, *otmp2;
401     boolean ideed = TRUE;
402     boolean nosink = FALSE;
403 
404     You("drop %s down the drain.", doname(obj));
405     obj->in_use = TRUE;  /* block free identification via interrupt */
406     switch (obj->otyp) { /* effects that can be noticed without eyes */
407     case RIN_SEARCHING:
408         You("thought %s got lost in the sink, but there it is!", yname(obj));
409         goto giveback;
410     case RIN_SLOW_DIGESTION:
411         pline_The("ring is regurgitated!");
412  giveback:
413         obj->in_use = FALSE;
414         dropx(obj);
415         trycall(obj);
416         return;
417     case RIN_LEVITATION:
418         pline_The("sink quivers upward for a moment.");
419         break;
420     case RIN_POISON_RESISTANCE:
421         You("smell rotten %s.", makeplural(fruitname(FALSE)));
422         break;
423     case RIN_AGGRAVATE_MONSTER:
424         pline("Several %s buzz angrily around the sink.",
425               Hallucination ? makeplural(rndmonnam(NULL)) : "flies");
426         break;
427     case RIN_SHOCK_RESISTANCE:
428         pline("Static electricity surrounds the sink.");
429         break;
430     case RIN_CONFLICT:
431         You_hear("loud noises coming from the drain.");
432         break;
433     case RIN_SUSTAIN_ABILITY: /* KMH */
434         pline_The("%s flow seems fixed.", hliquid("water"));
435         break;
436     case RIN_GAIN_STRENGTH:
437         pline_The("%s flow seems %ser now.",
438                   hliquid("water"),
439                   (obj->spe < 0) ? "weak" : "strong");
440         break;
441     case RIN_GAIN_CONSTITUTION:
442         pline_The("%s flow seems %ser now.",
443                   hliquid("water"),
444                   (obj->spe < 0) ? "less" : "great");
445         break;
446     case RIN_INCREASE_ACCURACY: /* KMH */
447         pline_The("%s flow %s the drain.",
448                   hliquid("water"),
449                   (obj->spe < 0) ? "misses" : "hits");
450         break;
451     case RIN_INCREASE_DAMAGE:
452         pline_The("water's force seems %ser now.",
453                   (obj->spe < 0) ? "small" : "great");
454         break;
455     case RIN_HUNGER:
456         ideed = FALSE;
457         for (otmp = level.objects[u.ux][u.uy]; otmp; otmp = otmp2) {
458             otmp2 = otmp->nexthere;
459             if (otmp != uball && otmp != uchain
460                 && !obj_resists(otmp, 1, 99)) {
461                 if (!Blind) {
462                     pline("Suddenly, %s %s from the sink!", doname(otmp),
463                           otense(otmp, "vanish"));
464                     ideed = TRUE;
465                 }
466                 delobj(otmp);
467             }
468         }
469         break;
470     case MEAT_RING:
471         /* Not the same as aggravate monster; besides, it's obvious. */
472         pline("Several flies buzz around the sink.");
473         break;
474     case RIN_TELEPORTATION:
475         nosink = teleport_sink();
476         /* give message even if blind; we know we're not levitating,
477            so can feel the outcome even if we can't directly see it */
478         pline_The("sink %svanishes.", nosink ? "" : "momentarily ");
479         ideed = FALSE;
480         break;
481     case RIN_POLYMORPH:
482         polymorph_sink();
483         nosink = TRUE;
484         /* for S_room case, same message as for teleportation is given */
485         ideed = (levl[u.ux][u.uy].typ != ROOM);
486         break;
487     default:
488         ideed = FALSE;
489         break;
490     }
491     if (!Blind && !ideed) {
492         ideed = TRUE;
493         switch (obj->otyp) { /* effects that need eyes */
494         case RIN_ADORNMENT:
495             pline_The("faucets flash brightly for a moment.");
496             break;
497         case RIN_REGENERATION:
498             pline_The("sink looks as good as new.");
499             break;
500         case RIN_INVISIBILITY:
501             You("don't see anything happen to the sink.");
502             break;
503         case RIN_FREE_ACTION:
504             You_see("the ring slide right down the drain!");
505             break;
506         case RIN_SEE_INVISIBLE:
507             You_see("some %s in the sink.",
508                     Hallucination ? "oxygen molecules" : "air");
509             break;
510         case RIN_STEALTH:
511             pline_The("sink seems to blend into the floor for a moment.");
512             break;
513         case RIN_FIRE_RESISTANCE:
514             pline_The("hot %s faucet flashes brightly for a moment.",
515                       hliquid("water"));
516             break;
517         case RIN_COLD_RESISTANCE:
518             pline_The("cold %s faucet flashes brightly for a moment.",
519                       hliquid("water"));
520             break;
521         case RIN_PROTECTION_FROM_SHAPE_CHAN:
522             pline_The("sink looks nothing like a fountain.");
523             break;
524         case RIN_PROTECTION:
525             pline_The("sink glows %s for a moment.",
526                       hcolor((obj->spe < 0) ? NH_BLACK : NH_SILVER));
527             break;
528         case RIN_WARNING:
529             pline_The("sink glows %s for a moment.", hcolor(NH_WHITE));
530             break;
531         case RIN_TELEPORT_CONTROL:
532             pline_The("sink looks like it is being beamed aboard somewhere.");
533             break;
534         case RIN_POLYMORPH_CONTROL:
535             pline_The(
536                   "sink momentarily looks like a regularly erupting geyser.");
537             break;
538         default:
539             break;
540         }
541     }
542     if (ideed)
543         trycall(obj);
544     else if (!nosink)
545         You_hear("the ring bouncing down the drainpipe.");
546 
547     if (!rn2(20) && !nosink) {
548         pline_The("sink backs up, leaving %s.", doname(obj));
549         obj->in_use = FALSE;
550         dropx(obj);
551     } else if (!rn2(5)) {
552         freeinv(obj);
553         obj->in_use = FALSE;
554         obj->ox = u.ux;
555         obj->oy = u.uy;
556         add_to_buried(obj);
557     } else
558         useup(obj);
559 }
560 
561 /* some common tests when trying to drop or throw items */
562 boolean
canletgo(obj,word)563 canletgo(obj, word)
564 struct obj *obj;
565 const char *word;
566 {
567     if (obj->owornmask & (W_ARMOR | W_ACCESSORY)) {
568         if (*word)
569             Norep("You cannot %s %s you are wearing.", word, something);
570         return FALSE;
571     }
572     if (obj->otyp == LOADSTONE && obj->cursed) {
573         /* getobj() kludge sets corpsenm to user's specified count
574            when refusing to split a stack of cursed loadstones */
575         if (*word) {
576             /* getobj() ignores a count for throwing since that is
577                implicitly forced to be 1; replicate its kludge... */
578             if (!strcmp(word, "throw") && obj->quan > 1L)
579                 obj->corpsenm = 1;
580             pline("For some reason, you cannot %s%s the stone%s!", word,
581                   obj->corpsenm ? " any of" : "", plur(obj->quan));
582         }
583         obj->corpsenm = 0; /* reset */
584         set_bknown(obj, 1);
585         return FALSE;
586     }
587     if (obj->otyp == LEASH && obj->leashmon != 0) {
588         if (*word)
589             pline_The("leash is tied around your %s.", body_part(HAND));
590         return FALSE;
591     }
592     if (obj->owornmask & W_SADDLE) {
593         if (*word)
594             You("cannot %s %s you are sitting on.", word, something);
595         return FALSE;
596     }
597     return TRUE;
598 }
599 
600 STATIC_PTR int
drop(obj)601 drop(obj)
602 register struct obj *obj;
603 {
604     if (!obj)
605         return 0;
606     if (!canletgo(obj, "drop"))
607         return 0;
608     if (obj == uwep) {
609         if (welded(uwep)) {
610             weldmsg(obj);
611             return 0;
612         }
613         setuwep((struct obj *) 0);
614     }
615     if (obj == uquiver) {
616         setuqwep((struct obj *) 0);
617     }
618     if (obj == uswapwep) {
619         setuswapwep((struct obj *) 0);
620     }
621 
622     if (u.uswallow) {
623         /* barrier between you and the floor */
624         if (flags.verbose) {
625             char *onam_p, monbuf[BUFSZ];
626 
627             /* doname can call s_suffix, reusing its buffer */
628             Strcpy(monbuf, s_suffix(mon_nam(u.ustuck)));
629             onam_p = is_unpaid(obj) ? yobjnam(obj, (char *) 0) : doname(obj);
630             You("drop %s into %s %s.", onam_p, monbuf,
631                 mbodypart(u.ustuck, STOMACH));
632         }
633     } else {
634         if ((obj->oclass == RING_CLASS || obj->otyp == MEAT_RING)
635             && IS_SINK(levl[u.ux][u.uy].typ)) {
636             dosinkring(obj);
637             return 1;
638         }
639         if (!can_reach_floor(TRUE)) {
640             /* we might be levitating due to #invoke Heart of Ahriman;
641                if so, levitation would end during call to freeinv()
642                and we want hitfloor() to happen before float_down() */
643             boolean levhack = finesse_ahriman(obj);
644 
645             if (levhack)
646                 ELevitation = W_ART; /* other than W_ARTI */
647             if (flags.verbose)
648                 You("drop %s.", doname(obj));
649             /* Ensure update when we drop gold objects */
650             if (obj->oclass == COIN_CLASS)
651                 context.botl = 1;
652             freeinv(obj);
653             hitfloor(obj, TRUE);
654             if (levhack)
655                 float_down(I_SPECIAL | TIMEOUT, W_ARTI | W_ART);
656             return 1;
657         }
658         if (!IS_ALTAR(levl[u.ux][u.uy].typ) && flags.verbose)
659             You("drop %s.", doname(obj));
660     }
661     dropx(obj);
662     return 1;
663 }
664 
665 /* dropx - take dropped item out of inventory;
666    called in several places - may produce output
667    (eg ship_object() and dropy() -> sellobj() both produce output) */
668 void
dropx(obj)669 dropx(obj)
670 register struct obj *obj;
671 {
672     /* Ensure update when we drop gold objects */
673     if (obj->oclass == COIN_CLASS)
674         context.botl = 1;
675     freeinv(obj);
676     if (!u.uswallow) {
677         if (ship_object(obj, u.ux, u.uy, FALSE))
678             return;
679         if (IS_ALTAR(levl[u.ux][u.uy].typ))
680             doaltarobj(obj); /* set bknown */
681     }
682     dropy(obj);
683 }
684 
685 /* dropy - put dropped object at destination; called from lots of places */
686 void
dropy(obj)687 dropy(obj)
688 struct obj *obj;
689 {
690     dropz(obj, FALSE);
691 }
692 
693 /* dropz - really put dropped object at its destination... */
694 void
dropz(obj,with_impact)695 dropz(obj, with_impact)
696 struct obj *obj;
697 boolean with_impact;
698 {
699     if (obj == uwep)
700         setuwep((struct obj *) 0);
701     if (obj == uquiver)
702         setuqwep((struct obj *) 0);
703     if (obj == uswapwep)
704         setuswapwep((struct obj *) 0);
705 
706     if (!u.uswallow && flooreffects(obj, u.ux, u.uy, "drop"))
707         return;
708     /* uswallow check done by GAN 01/29/87 */
709     if (u.uswallow) {
710         boolean could_petrify = FALSE;
711         boolean could_poly = FALSE;
712         boolean could_slime = FALSE;
713         boolean could_grow = FALSE;
714         boolean could_heal = FALSE;
715 
716         if (obj != uball) { /* mon doesn't pick up ball */
717             if (obj->otyp == CORPSE) {
718                 could_petrify = touch_petrifies(&mons[obj->corpsenm]);
719                 could_poly = polyfodder(obj);
720                 could_slime = (obj->corpsenm == PM_GREEN_SLIME);
721                 could_grow = (obj->corpsenm == PM_WRAITH);
722                 could_heal = (obj->corpsenm == PM_NURSE);
723             }
724             if (is_unpaid(obj))
725                 (void) stolen_value(obj, u.ux, u.uy, TRUE, FALSE);
726             (void) mpickobj(u.ustuck, obj);
727             if (is_animal(u.ustuck->data)) {
728                 if (could_poly || could_slime) {
729                     (void) newcham(u.ustuck,
730                                    could_poly ? (struct permonst *) 0
731                                               : &mons[PM_GREEN_SLIME],
732                                    FALSE, could_slime);
733                     delobj(obj); /* corpse is digested */
734                 } else if (could_petrify) {
735                     minstapetrify(u.ustuck, TRUE);
736                     /* Don't leave a cockatrice corpse in a statue */
737                     if (!u.uswallow)
738                         delobj(obj);
739                 } else if (could_grow) {
740                     (void) grow_up(u.ustuck, (struct monst *) 0);
741                     delobj(obj); /* corpse is digested */
742                 } else if (could_heal) {
743                     u.ustuck->mhp = u.ustuck->mhpmax;
744                     delobj(obj); /* corpse is digested */
745                 }
746             }
747         }
748     } else {
749         place_object(obj, u.ux, u.uy);
750         if (with_impact)
751             container_impact_dmg(obj, u.ux, u.uy);
752         if (obj == uball)
753             drop_ball(u.ux, u.uy);
754         else if (level.flags.has_shop)
755             sellobj(obj, u.ux, u.uy);
756         stackobj(obj);
757         if (Blind && Levitation)
758             map_object(obj, 0);
759         newsym(u.ux, u.uy); /* remap location under self */
760     }
761 }
762 
763 /* things that must change when not held; recurse into containers.
764    Called for both player and monsters */
765 void
obj_no_longer_held(obj)766 obj_no_longer_held(obj)
767 struct obj *obj;
768 {
769     if (!obj) {
770         return;
771     } else if (Has_contents(obj)) {
772         struct obj *contents;
773 
774         for (contents = obj->cobj; contents; contents = contents->nobj)
775             obj_no_longer_held(contents);
776     }
777     switch (obj->otyp) {
778     case CRYSKNIFE:
779         /* Normal crysknife reverts to worm tooth when not held by hero
780          * or monster; fixed crysknife has only 10% chance of reverting.
781          * When a stack of the latter is involved, it could be worthwhile
782          * to give each individual crysknife its own separate 10% chance,
783          * but we aren't in any position to handle stack splitting here.
784          */
785         if (!obj->oerodeproof || !rn2(10)) {
786             /* if monsters aren't moving, assume player is responsible */
787             if (!context.mon_moving && !program_state.gameover)
788                 costly_alteration(obj, COST_DEGRD);
789             obj->otyp = WORM_TOOTH;
790             obj->oerodeproof = 0;
791         }
792         break;
793     }
794 }
795 
796 /* 'D' command: drop several things */
797 int
doddrop()798 doddrop()
799 {
800     int result = 0;
801 
802     if (!invent) {
803         You("have nothing to drop.");
804         return 0;
805     }
806     add_valid_menu_class(0); /* clear any classes already there */
807     if (*u.ushops)
808         sellobj_state(SELL_DELIBERATE);
809     if (flags.menu_style != MENU_TRADITIONAL
810         || (result = ggetobj("drop", drop, 0, FALSE, (unsigned *) 0)) < -1)
811         result = menu_drop(result);
812     if (*u.ushops)
813         sellobj_state(SELL_NORMAL);
814     if (result)
815         reset_occupations();
816 
817     return result;
818 }
819 
820 /* Drop things from the hero's inventory, using a menu. */
821 STATIC_OVL int
menu_drop(retry)822 menu_drop(retry)
823 int retry;
824 {
825     int n, i, n_dropped = 0;
826     long cnt;
827     struct obj *otmp, *otmp2;
828     menu_item *pick_list;
829     boolean all_categories = TRUE;
830     boolean drop_everything = FALSE;
831 
832     if (retry) {
833         all_categories = (retry == -2);
834     } else if (flags.menu_style == MENU_FULL) {
835         all_categories = FALSE;
836         n = query_category("Drop what type of items?", invent,
837                            UNPAID_TYPES | ALL_TYPES | CHOOSE_ALL | BUC_BLESSED
838                                | BUC_CURSED | BUC_UNCURSED | BUC_UNKNOWN,
839                            &pick_list, PICK_ANY);
840         if (!n)
841             goto drop_done;
842         for (i = 0; i < n; i++) {
843             if (pick_list[i].item.a_int == ALL_TYPES_SELECTED)
844                 all_categories = TRUE;
845             else if (pick_list[i].item.a_int == 'A')
846                 drop_everything = TRUE;
847             else
848                 add_valid_menu_class(pick_list[i].item.a_int);
849         }
850         free((genericptr_t) pick_list);
851     } else if (flags.menu_style == MENU_COMBINATION) {
852         unsigned ggoresults = 0;
853 
854         all_categories = FALSE;
855         /* Gather valid classes via traditional NetHack method */
856         i = ggetobj("drop", drop, 0, TRUE, &ggoresults);
857         if (i == -2)
858             all_categories = TRUE;
859         if (ggoresults & ALL_FINISHED) {
860             n_dropped = i;
861             goto drop_done;
862         }
863     }
864 
865     if (drop_everything) {
866         /*
867          * Dropping a burning potion of oil while levitating can cause
868          * an explosion which might destroy some of hero's inventory,
869          * so the old code
870          *      for (otmp = invent; otmp; otmp = otmp2) {
871          *          otmp2 = otmp->nobj;
872          *          n_dropped += drop(otmp);
873          *      }
874          * was unreliable and could lead to an "object lost" panic.
875          *
876          * Use the bypass bit to mark items already processed (hence
877          * not droppable) and rescan inventory until no unbypassed
878          * items remain.
879          */
880         bypass_objlist(invent, FALSE); /* clear bypass bit for invent */
881         while ((otmp = nxt_unbypassed_obj(invent)) != 0)
882             n_dropped += drop(otmp);
883         /* we might not have dropped everything (worn armor, welded weapon,
884            cursed loadstones), so reset any remaining inventory to normal */
885         bypass_objlist(invent, FALSE);
886     } else {
887         /* should coordinate with perm invent, maybe not show worn items */
888         n = query_objlist("What would you like to drop?", &invent,
889                           (USE_INVLET | INVORDER_SORT), &pick_list, PICK_ANY,
890                           all_categories ? allow_all : allow_category);
891         if (n > 0) {
892             /*
893              * picklist[] contains a set of pointers into inventory, but
894              * as soon as something gets dropped, they might become stale
895              * (see the drop_everything code above for an explanation).
896              * Just checking to see whether one is still in the invent
897              * chain is not sufficient validation since destroyed items
898              * will be freed and items we've split here might have already
899              * reused that memory and put the same pointer value back into
900              * invent.  Ditto for using invlet to validate.  So we start
901              * by setting bypass on all of invent, then check each pointer
902              * to verify that it is in invent and has that bit set.
903              */
904             bypass_objlist(invent, TRUE);
905             for (i = 0; i < n; i++) {
906                 otmp = pick_list[i].item.a_obj;
907                 for (otmp2 = invent; otmp2; otmp2 = otmp2->nobj)
908                     if (otmp2 == otmp)
909                         break;
910                 if (!otmp2 || !otmp2->bypass)
911                     continue;
912                 /* found next selected invent item */
913                 cnt = pick_list[i].count;
914                 if (cnt < otmp->quan) {
915                     if (welded(otmp)) {
916                         ; /* don't split */
917                     } else if (otmp->otyp == LOADSTONE && otmp->cursed) {
918                         /* same kludge as getobj(), for canletgo()'s use */
919                         otmp->corpsenm = (int) cnt; /* don't split */
920                     } else {
921                         otmp = splitobj(otmp, cnt);
922                     }
923                 }
924                 n_dropped += drop(otmp);
925             }
926             bypass_objlist(invent, FALSE); /* reset invent to normal */
927             free((genericptr_t) pick_list);
928         }
929     }
930 
931  drop_done:
932     return n_dropped;
933 }
934 
935 /* on a ladder, used in goto_level */
936 static NEARDATA boolean at_ladder = FALSE;
937 
938 /* the '>' command */
939 int
dodown()940 dodown()
941 {
942     struct trap *trap = 0;
943     boolean stairs_down = ((u.ux == xdnstair && u.uy == ydnstair)
944                            || (u.ux == sstairs.sx && u.uy == sstairs.sy
945                                && !sstairs.up)),
946             ladder_down = (u.ux == xdnladder && u.uy == ydnladder);
947 
948     if (u_rooted())
949         return 1;
950 
951     if (stucksteed(TRUE)) {
952         return 0;
953     }
954     /* Levitation might be blocked, but player can still use '>' to
955        turn off controlled levitation */
956     if (HLevitation || ELevitation) {
957         if ((HLevitation & I_SPECIAL) || (ELevitation & W_ARTI)) {
958             /* end controlled levitation */
959             if (ELevitation & W_ARTI) {
960                 struct obj *obj;
961 
962                 for (obj = invent; obj; obj = obj->nobj) {
963                     if (obj->oartifact
964                         && artifact_has_invprop(obj, LEVITATION)) {
965                         if (obj->age < monstermoves)
966                             obj->age = monstermoves;
967                         obj->age += rnz(100);
968                     }
969                 }
970             }
971             if (float_down(I_SPECIAL | TIMEOUT, W_ARTI)) {
972                 return 1; /* came down, so moved */
973             } else if (!HLevitation && !ELevitation) {
974                 Your("latent levitation ceases.");
975                 return 1; /* did something, effectively moved */
976             }
977         }
978         if (BLevitation) {
979             ; /* weren't actually floating after all */
980         } else if (Blind) {
981             /* Avoid alerting player to an unknown stair or ladder.
982              * Changes the message for a covered, known staircase
983              * too; staircase knowledge is not stored anywhere.
984              */
985             if (stairs_down)
986                 stairs_down =
987                     (glyph_to_cmap(levl[u.ux][u.uy].glyph) == S_dnstair);
988             else if (ladder_down)
989                 ladder_down =
990                     (glyph_to_cmap(levl[u.ux][u.uy].glyph) == S_dnladder);
991         }
992         if (Is_airlevel(&u.uz))
993             You("are floating in the %s.", surface(u.ux, u.uy));
994         else if (Is_waterlevel(&u.uz))
995             You("are floating in %s.",
996                 is_pool(u.ux, u.uy) ? "the water" : "a bubble of air");
997         else
998             floating_above(stairs_down ? "stairs" : ladder_down
999                                                     ? "ladder"
1000                                                     : surface(u.ux, u.uy));
1001         return 0; /* didn't move */
1002     }
1003 
1004     if (Upolyd && ceiling_hider(&mons[u.umonnum]) && u.uundetected) {
1005         u.uundetected = 0;
1006         if (Flying) { /* lurker above */
1007             You("fly out of hiding.");
1008         } else { /* piercer */
1009             You("drop to the %s.", surface(u.ux, u.uy));
1010             if (is_pool_or_lava(u.ux, u.uy)) {
1011                 pooleffects(FALSE);
1012             } else {
1013                 (void) pickup(1);
1014                 if ((trap = t_at(u.ux, u.uy)) != 0)
1015                     dotrap(trap, TOOKPLUNGE);
1016             }
1017         }
1018         return 1; /* came out of hiding; might need '>' again to go down */
1019     }
1020 
1021     if (!stairs_down && !ladder_down) {
1022         trap = t_at(u.ux, u.uy);
1023         if (trap && (uteetering_at_seen_pit(trap) || uescaped_shaft(trap))) {
1024             dotrap(trap, TOOKPLUNGE);
1025             return 1;
1026         } else if (!trap || !is_hole(trap->ttyp)
1027                    || !Can_fall_thru(&u.uz) || !trap->tseen) {
1028             if (flags.autodig && !context.nopick && uwep && is_pick(uwep)) {
1029                 return use_pick_axe2(uwep);
1030             } else {
1031                 You_cant("go down here.");
1032                 return 0;
1033             }
1034         }
1035     }
1036     if (u.ustuck) {
1037         You("are %s, and cannot go down.",
1038             !u.uswallow ? "being held" : is_animal(u.ustuck->data)
1039                                              ? "swallowed"
1040                                              : "engulfed");
1041         return 1;
1042     }
1043     if (on_level(&valley_level, &u.uz) && !u.uevent.gehennom_entered) {
1044         You("are standing at the gate to Gehennom.");
1045         pline("Unspeakable cruelty and harm lurk down there.");
1046         if (yn("Are you sure you want to enter?") != 'y')
1047             return 0;
1048         else
1049             pline("So be it.");
1050         u.uevent.gehennom_entered = 1; /* don't ask again */
1051     }
1052 
1053     if (!next_to_u()) {
1054         You("are held back by your pet!");
1055         return 0;
1056     }
1057 
1058     if (trap) {
1059         const char *down_or_thru = trap->ttyp == HOLE ? "down" : "through";
1060         const char *actn = Flying ? "fly" : locomotion(youmonst.data, "jump");
1061 
1062         if (youmonst.data->msize >= MZ_HUGE) {
1063             char qbuf[QBUFSZ];
1064 
1065             You("don't fit %s easily.", down_or_thru);
1066             Sprintf(qbuf, "Try to squeeze %s?", down_or_thru);
1067             if (yn(qbuf) == 'y') {
1068                 if (!rn2(3)) {
1069                     actn = "manage to squeeze";
1070                     losehp(Maybe_Half_Phys(rnd(4)),
1071                            "contusion from a small passage", KILLED_BY);
1072                 } else {
1073                     You("were unable to fit %s.", down_or_thru);
1074                     return 0;
1075                 }
1076             } else {
1077                 return 0;
1078             }
1079         }
1080         You("%s %s the %s.", actn, down_or_thru,
1081             trap->ttyp == HOLE ? "hole" : "trap door");
1082     }
1083     if (trap && Is_stronghold(&u.uz)) {
1084         goto_hell(FALSE, TRUE);
1085     } else {
1086         at_ladder = (boolean) (levl[u.ux][u.uy].typ == LADDER);
1087         next_level(!trap);
1088         at_ladder = FALSE;
1089     }
1090     return 1;
1091 }
1092 
1093 /* the '<' command */
1094 int
doup()1095 doup()
1096 {
1097     if (u_rooted())
1098         return 1;
1099 
1100     /* "up" to get out of a pit... */
1101     if (u.utrap && u.utraptype == TT_PIT) {
1102         climb_pit();
1103         return 1;
1104     }
1105 
1106     if ((u.ux != xupstair || u.uy != yupstair)
1107         && (!xupladder || u.ux != xupladder || u.uy != yupladder)
1108         && (!sstairs.sx || u.ux != sstairs.sx || u.uy != sstairs.sy
1109             || !sstairs.up)) {
1110         You_cant("go up here.");
1111         return 0;
1112     }
1113     if (stucksteed(TRUE)) {
1114         return 0;
1115     }
1116     if (u.ustuck) {
1117         You("are %s, and cannot go up.",
1118             !u.uswallow ? "being held" : is_animal(u.ustuck->data)
1119                                              ? "swallowed"
1120                                              : "engulfed");
1121         return 1;
1122     }
1123     if (near_capacity() > SLT_ENCUMBER) {
1124         /* No levitation check; inv_weight() already allows for it */
1125         Your("load is too heavy to climb the %s.",
1126              levl[u.ux][u.uy].typ == STAIRS ? "stairs" : "ladder");
1127         return 1;
1128     }
1129     if (ledger_no(&u.uz) == 1) {
1130         if (iflags.debug_fuzzer)
1131             return 0;
1132         if (yn("Beware, there will be no return!  Still climb?") != 'y')
1133             return 0;
1134     }
1135     if (!next_to_u()) {
1136         You("are held back by your pet!");
1137         return 0;
1138     }
1139     at_ladder = (boolean) (levl[u.ux][u.uy].typ == LADDER);
1140     prev_level(TRUE);
1141     at_ladder = FALSE;
1142     return 1;
1143 }
1144 
1145 d_level save_dlevel = { 0, 0 };
1146 
1147 /* check that we can write out the current level */
1148 STATIC_OVL int
currentlevel_rewrite()1149 currentlevel_rewrite()
1150 {
1151     register int fd;
1152     char whynot[BUFSZ];
1153 
1154     /* since level change might be a bit slow, flush any buffered screen
1155      *  output (like "you fall through a trap door") */
1156     mark_synch();
1157 
1158     fd = create_levelfile(ledger_no(&u.uz), whynot);
1159     if (fd < 0) {
1160         /*
1161          * This is not quite impossible: e.g., we may have
1162          * exceeded our quota. If that is the case then we
1163          * cannot leave this level, and cannot save either.
1164          * Another possibility is that the directory was not
1165          * writable.
1166          */
1167         pline1(whynot);
1168         return -1;
1169     }
1170 
1171 #ifdef MFLOPPY
1172     if (!savelev(fd, ledger_no(&u.uz), COUNT_SAVE)) {
1173         (void) nhclose(fd);
1174         delete_levelfile(ledger_no(&u.uz));
1175         pline("NetHack is out of disk space for making levels!");
1176         You("can save, quit, or continue playing.");
1177         return -1;
1178     }
1179 #endif
1180     return fd;
1181 }
1182 
1183 #ifdef INSURANCE
1184 void
save_currentstate()1185 save_currentstate()
1186 {
1187     int fd;
1188 
1189     if (flags.ins_chkpt) {
1190         /* write out just-attained level, with pets and everything */
1191         fd = currentlevel_rewrite();
1192         if (fd < 0)
1193             return;
1194         bufon(fd);
1195         savelev(fd, ledger_no(&u.uz), WRITE_SAVE);
1196         bclose(fd);
1197     }
1198 
1199     /* write out non-level state */
1200     savestateinlock();
1201 }
1202 #endif
1203 
1204 /*
1205 static boolean
1206 badspot(x, y)
1207 register xchar x, y;
1208 {
1209     return (boolean) ((levl[x][y].typ != ROOM
1210                        && levl[x][y].typ != AIR
1211                        && levl[x][y].typ != CORR)
1212                       || MON_AT(x, y));
1213 }
1214 */
1215 
1216 /* when arriving on a level, if hero and a monster are trying to share same
1217    spot, move one; extracted from goto_level(); also used by wiz_makemap() */
1218 void
u_collide_m(mtmp)1219 u_collide_m(mtmp)
1220 struct monst *mtmp;
1221 {
1222     coord cc;
1223 
1224     if (!mtmp || mtmp == u.usteed || mtmp != m_at(u.ux, u.uy)) {
1225         impossible("level arrival collision: %s?",
1226                    !mtmp ? "no monster"
1227                      : (mtmp == u.usteed) ? "steed is on map"
1228                        : "monster not co-located");
1229         return;
1230     }
1231 
1232     /* There's a monster at your target destination; it might be one
1233        which accompanied you--see mon_arrive(dogmove.c)--or perhaps
1234        it was already here.  Randomly move you to an adjacent spot
1235        or else the monster to any nearby location.  Prior to 3.3.0
1236        the latter was done unconditionally. */
1237     if (!rn2(2) && enexto(&cc, u.ux, u.uy, youmonst.data)
1238         && distu(cc.x, cc.y) <= 2)
1239         u_on_newpos(cc.x, cc.y); /*[maybe give message here?]*/
1240     else
1241         mnexto(mtmp);
1242 
1243     if ((mtmp = m_at(u.ux, u.uy)) != 0) {
1244         /* there was an unconditional impossible("mnexto failed")
1245            here, but it's not impossible and we're prepared to cope
1246            with the situation, so only say something when debugging */
1247         if (wizard)
1248             pline("(monster in hero's way)");
1249         if (!rloc(mtmp, TRUE) || (mtmp = m_at(u.ux, u.uy)) != 0)
1250             /* no room to move it; send it away, to return later */
1251             m_into_limbo(mtmp);
1252     }
1253 }
1254 
1255 void
goto_level(newlevel,at_stairs,falling,portal)1256 goto_level(newlevel, at_stairs, falling, portal)
1257 d_level *newlevel;
1258 boolean at_stairs, falling, portal;
1259 {
1260     int fd, l_idx;
1261     xchar new_ledger;
1262     boolean cant_go_back, great_effort,
1263             up = (depth(newlevel) < depth(&u.uz)),
1264             newdungeon = (u.uz.dnum != newlevel->dnum),
1265             was_in_W_tower = In_W_tower(u.ux, u.uy, &u.uz),
1266             familiar = FALSE,
1267             new = FALSE; /* made a new level? */
1268     struct monst *mtmp;
1269     char whynot[BUFSZ];
1270     char *annotation;
1271 
1272     if (dunlev(newlevel) > dunlevs_in_dungeon(newlevel))
1273         newlevel->dlevel = dunlevs_in_dungeon(newlevel);
1274     if (newdungeon && In_endgame(newlevel)) { /* 1st Endgame Level !!! */
1275         if (!u.uhave.amulet)
1276             return;  /* must have the Amulet */
1277         if (!wizard) /* wizard ^V can bypass Earth level */
1278             assign_level(newlevel, &earth_level); /* (redundant) */
1279     }
1280     new_ledger = ledger_no(newlevel);
1281     if (new_ledger <= 0)
1282         done(ESCAPED); /* in fact < 0 is impossible */
1283 
1284     /* If you have the amulet and are trying to get out of Gehennom,
1285      * going up a set of stairs sometimes does some very strange things!
1286      * Biased against law and towards chaos.  (The chance to be sent
1287      * down multiple levels when attempting to go up are significantly
1288      * less than the corresponding comment in older versions indicated
1289      * due to overlooking the effect of the call to assign_rnd_lvl().)
1290      *
1291      * Odds for making it to the next level up, or of being sent down:
1292      *  "up"    L      N      C
1293      *   +1   75.0   75.0   75.0
1294      *    0    6.25   8.33  12.5
1295      *   -1   11.46  12.50  12.5
1296      *   -2    5.21   4.17   0.0
1297      *   -3    2.08   0.0    0.0
1298      */
1299     if (Inhell && up && u.uhave.amulet && !newdungeon && !portal
1300         && (dunlev(&u.uz) < dunlevs_in_dungeon(&u.uz) - 3)) {
1301         if (!rn2(4)) {
1302             int odds = 3 + (int) u.ualign.type,   /* 2..4 */
1303                 diff = odds <= 1 ? 0 : rn2(odds); /* paranoia */
1304 
1305             if (diff != 0) {
1306                 assign_rnd_level(newlevel, &u.uz, diff);
1307                 /* if inside the tower, stay inside */
1308                 if (was_in_W_tower && !On_W_tower_level(newlevel))
1309                     diff = 0;
1310             }
1311             if (diff == 0)
1312                 assign_level(newlevel, &u.uz);
1313 
1314             new_ledger = ledger_no(newlevel);
1315 
1316             pline("A mysterious force momentarily surrounds you...");
1317             if (on_level(newlevel, &u.uz)) {
1318                 (void) safe_teleds(FALSE);
1319                 (void) next_to_u();
1320                 return;
1321             } else
1322                 at_stairs = at_ladder = FALSE;
1323         }
1324     }
1325 
1326     /* Prevent the player from going past the first quest level unless
1327      * (s)he has been given the go-ahead by the leader.
1328      */
1329     if (on_level(&u.uz, &qstart_level) && !newdungeon && !ok_to_quest()) {
1330         pline("A mysterious force prevents you from descending.");
1331         return;
1332     }
1333 
1334     if (on_level(newlevel, &u.uz))
1335         return; /* this can happen */
1336 
1337     /* tethered movement makes level change while trapped feasible */
1338     if (u.utrap && u.utraptype == TT_BURIEDBALL)
1339         buried_ball_to_punishment(); /* (before we save/leave old level) */
1340 
1341     fd = currentlevel_rewrite();
1342     if (fd < 0)
1343         return;
1344 
1345     /* discard context which applies to the level we're leaving;
1346        for lock-picking, container may be carried, in which case we
1347        keep context; if on the floor, it's about to be saved+freed and
1348        maybe_reset_pick() needs to do its carried() check before that */
1349     maybe_reset_pick((struct obj *) 0);
1350     reset_trapset(); /* even if to-be-armed trap obj is accompanying hero */
1351     iflags.travelcc.x = iflags.travelcc.y = 0; /* travel destination cache */
1352     context.polearm.hitmon = (struct monst *) 0; /* polearm target */
1353     /* digging context is level-aware and can actually be resumed if
1354        hero returns to the previous level without any intervening dig */
1355 
1356     if (falling) /* assuming this is only trap door or hole */
1357         impact_drop((struct obj *) 0, u.ux, u.uy, newlevel->dlevel);
1358 
1359     check_special_room(TRUE); /* probably was a trap door */
1360     if (Punished)
1361         unplacebc();
1362     reset_utrap(FALSE); /* needed in level_tele */
1363     fill_pit(u.ux, u.uy);
1364     u.ustuck = 0; /* idem */
1365     u.uinwater = 0;
1366     u.uundetected = 0; /* not hidden, even if means are available */
1367     keepdogs(FALSE);
1368     if (u.uswallow) /* idem */
1369         u.uswldtim = u.uswallow = 0;
1370     recalc_mapseen(); /* recalculate map overview before we leave the level */
1371     /*
1372      *  We no longer see anything on the level.  Make sure that this
1373      *  follows u.uswallow set to null since uswallow overrides all
1374      *  normal vision.
1375      */
1376     vision_recalc(2);
1377 
1378     /*
1379      * Save the level we're leaving.  If we're entering the endgame,
1380      * we can get rid of all existing levels because they cannot be
1381      * reached any more.  We still need to use savelev()'s cleanup
1382      * for the level being left, to recover dynamic memory in use and
1383      * to avoid dangling timers and light sources.
1384      */
1385     cant_go_back = (newdungeon && In_endgame(newlevel));
1386     if (!cant_go_back) {
1387         update_mlstmv(); /* current monsters are becoming inactive */
1388         bufon(fd);       /* use buffered output */
1389     }
1390     savelev(fd, ledger_no(&u.uz),
1391             cant_go_back ? FREE_SAVE : (WRITE_SAVE | FREE_SAVE));
1392     /* air bubbles and clouds are saved in game-state rather than with the
1393        level they're used on; in normal play, you can't leave and return
1394        to any endgame level--bubbles aren't needed once you move to the
1395        next level so used to be discarded when the next special level was
1396        loaded; but in wizard mode you can leave and return, and since they
1397        aren't saved with the level and restored upon return (new ones are
1398        created instead), we need to discard them to avoid a memory leak;
1399        so bubbles are now discarded as we leave the level they're used on */
1400     if (Is_waterlevel(&u.uz) || Is_airlevel(&u.uz))
1401         save_waterlevel(-1, FREE_SAVE);
1402     bclose(fd);
1403     if (cant_go_back) {
1404         /* discard unreachable levels; keep #0 */
1405         for (l_idx = maxledgerno(); l_idx > 0; --l_idx)
1406             delete_levelfile(l_idx);
1407         /* mark #overview data for all dungeon branches as uninteresting */
1408         for (l_idx = 0; l_idx < n_dgns; ++l_idx)
1409             remdun_mapseen(l_idx);
1410     }
1411 
1412     if (Is_rogue_level(newlevel) || Is_rogue_level(&u.uz))
1413         assign_graphics(Is_rogue_level(newlevel) ? ROGUESET : PRIMARY);
1414 #ifdef USE_TILES
1415     substitute_tiles(newlevel);
1416 #endif
1417     check_gold_symbol();
1418     /* record this level transition as a potential seen branch unless using
1419      * some non-standard means of transportation (level teleport).
1420      */
1421     if ((at_stairs || falling || portal) && (u.uz.dnum != newlevel->dnum))
1422         recbranch_mapseen(&u.uz, newlevel);
1423     assign_level(&u.uz0, &u.uz);
1424     assign_level(&u.uz, newlevel);
1425     assign_level(&u.utolev, newlevel);
1426     u.utotype = 0;
1427     if (!builds_up(&u.uz)) { /* usual case */
1428         if (dunlev(&u.uz) > dunlev_reached(&u.uz))
1429             dunlev_reached(&u.uz) = dunlev(&u.uz);
1430     } else {
1431         if (dunlev_reached(&u.uz) == 0
1432             || dunlev(&u.uz) < dunlev_reached(&u.uz))
1433             dunlev_reached(&u.uz) = dunlev(&u.uz);
1434     }
1435     reset_rndmonst(NON_PM); /* u.uz change affects monster generation */
1436 
1437     /* set default level change destination areas */
1438     /* the special level code may override these */
1439     (void) memset((genericptr_t) &updest, 0, sizeof updest);
1440     (void) memset((genericptr_t) &dndest, 0, sizeof dndest);
1441 
1442     if (!(level_info[new_ledger].flags & LFILE_EXISTS)) {
1443         /* entering this level for first time; make it now */
1444         if (level_info[new_ledger].flags & (FORGOTTEN | VISITED)) {
1445             impossible("goto_level: returning to discarded level?");
1446             level_info[new_ledger].flags &= ~(FORGOTTEN | VISITED);
1447         }
1448         mklev();
1449         new = TRUE; /* made the level */
1450     } else {
1451         /* returning to previously visited level; reload it */
1452         fd = open_levelfile(new_ledger, whynot);
1453         if (tricked_fileremoved(fd, whynot)) {
1454             /* we'll reach here if running in wizard mode */
1455             error("Cannot continue this game.");
1456         }
1457         reseed_random(rn2);
1458         reseed_random(rn2_on_display_rng);
1459         minit(); /* ZEROCOMP */
1460         getlev(fd, hackpid, new_ledger, FALSE);
1461         /* when in wizard mode, it is possible to leave from and return to
1462            any level in the endgame; above, we discarded bubble/cloud info
1463            when leaving Plane of Water or Air so recreate some now */
1464         if (Is_waterlevel(&u.uz) || Is_airlevel(&u.uz))
1465             restore_waterlevel(-1);
1466         (void) nhclose(fd);
1467         oinit(); /* reassign level dependent obj probabilities */
1468     }
1469     reglyph_darkroom();
1470     u.uinwater = 0;
1471     /* do this prior to level-change pline messages */
1472     vision_reset();         /* clear old level's line-of-sight */
1473     vision_full_recalc = 0; /* don't let that reenable vision yet */
1474     flush_screen(-1);       /* ensure all map flushes are postponed */
1475 
1476     if (portal && !In_endgame(&u.uz)) {
1477         /* find the portal on the new level */
1478         register struct trap *ttrap;
1479 
1480         for (ttrap = ftrap; ttrap; ttrap = ttrap->ntrap)
1481             if (ttrap->ttyp == MAGIC_PORTAL)
1482                 break;
1483 
1484         if (!ttrap)
1485             panic("goto_level: no corresponding portal!");
1486         seetrap(ttrap);
1487         u_on_newpos(ttrap->tx, ttrap->ty);
1488     } else if (at_stairs && !In_endgame(&u.uz)) {
1489         if (up) {
1490             if (at_ladder)
1491                 u_on_newpos(xdnladder, ydnladder);
1492             else if (newdungeon)
1493                 u_on_sstairs(1);
1494             else
1495                 u_on_dnstairs();
1496             /* you climb up the {stairs|ladder};
1497                fly up the stairs; fly up along the ladder */
1498             great_effort = (Punished && !Levitation);
1499             if (flags.verbose || great_effort)
1500                 pline("%s %s up%s the %s.",
1501                       great_effort ? "With great effort, you" : "You",
1502                       Levitation ? "float" : Flying ? "fly" : "climb",
1503                       (Flying && at_ladder) ? " along" : "",
1504                       at_ladder ? "ladder" : "stairs");
1505         } else { /* down */
1506             if (at_ladder)
1507                 u_on_newpos(xupladder, yupladder);
1508             else if (newdungeon)
1509                 u_on_sstairs(0);
1510             else
1511                 u_on_upstairs();
1512             if (!u.dz) {
1513                 ; /* stayed on same level? (no transit effects) */
1514             } else if (Flying) {
1515                 if (flags.verbose)
1516                     You("fly down %s.",
1517                         at_ladder ? "along the ladder" : "the stairs");
1518             } else if (near_capacity() > UNENCUMBERED
1519                        || Punished || Fumbling) {
1520                 You("fall down the %s.", at_ladder ? "ladder" : "stairs");
1521                 if (Punished) {
1522                     drag_down();
1523                     ballrelease(FALSE);
1524                 }
1525                 /* falling off steed has its own losehp() call */
1526                 if (u.usteed)
1527                     dismount_steed(DISMOUNT_FELL);
1528                 else
1529                     losehp(Maybe_Half_Phys(rnd(3)),
1530                            at_ladder ? "falling off a ladder"
1531                                      : "tumbling down a flight of stairs",
1532                            KILLED_BY);
1533                 selftouch("Falling, you");
1534             } else { /* ordinary descent */
1535                 if (flags.verbose)
1536                     You("%s.", at_ladder ? "climb down the ladder"
1537                                          : "descend the stairs");
1538             }
1539         }
1540     } else { /* trap door or level_tele or In_endgame */
1541         u_on_rndspot((up ? 1 : 0) | (was_in_W_tower ? 2 : 0));
1542         if (falling) {
1543             if (Punished)
1544                 ballfall();
1545             selftouch("Falling, you");
1546         }
1547     }
1548 
1549     if (Punished)
1550         placebc();
1551     obj_delivery(FALSE);
1552     losedogs();
1553     kill_genocided_monsters(); /* for those wiped out while in limbo */
1554     /*
1555      * Expire all timers that have gone off while away.  Must be
1556      * after migrating monsters and objects are delivered
1557      * (losedogs and obj_delivery).
1558      */
1559     run_timers();
1560 
1561     /* hero might be arriving at a spot containing a monster;
1562        if so, move one or the other to another location */
1563     if ((mtmp = m_at(u.ux, u.uy)) != 0)
1564         u_collide_m(mtmp);
1565 
1566     initrack();
1567 
1568     /* initial movement of bubbles just before vision_recalc */
1569     if (Is_waterlevel(&u.uz) || Is_airlevel(&u.uz))
1570         movebubbles();
1571     else if (Is_firelevel(&u.uz))
1572         fumaroles();
1573 
1574     if (level_info[new_ledger].flags & FORGOTTEN) {
1575         forget_map(ALL_MAP); /* forget the map */
1576         forget_traps();      /* forget all traps too */
1577         familiar = TRUE;
1578         level_info[new_ledger].flags &= ~FORGOTTEN;
1579     }
1580 
1581     /* Reset the screen. */
1582     vision_reset(); /* reset the blockages */
1583     docrt();        /* does a full vision recalc */
1584     flush_screen(-1);
1585 
1586     /*
1587      *  Move all plines beyond the screen reset.
1588      */
1589 
1590     /* special levels can have a custom arrival message */
1591     deliver_splev_message();
1592 
1593     /* give room entrance message, if any */
1594     check_special_room(FALSE);
1595 
1596     /* deliver objects traveling with player */
1597     obj_delivery(TRUE);
1598 
1599     /* Check whether we just entered Gehennom. */
1600     if (!In_hell(&u.uz0) && Inhell) {
1601         if (Is_valley(&u.uz)) {
1602             You("arrive at the Valley of the Dead...");
1603             pline_The("odor of burnt flesh and decay pervades the air.");
1604 #ifdef MICRO
1605             display_nhwindow(WIN_MESSAGE, FALSE);
1606 #endif
1607             You_hear("groans and moans everywhere.");
1608         } else
1609             pline("It is hot here.  You smell smoke...");
1610         u.uachieve.enter_gehennom = 1;
1611     }
1612     /* in case we've managed to bypass the Valley's stairway down */
1613     if (Inhell && !Is_valley(&u.uz))
1614         u.uevent.gehennom_entered = 1;
1615 
1616     if (familiar) {
1617         static const char *const fam_msgs[4] = {
1618             "You have a sense of deja vu.",
1619             "You feel like you've been here before.",
1620             "This place %s familiar...", 0 /* no message */
1621         };
1622         static const char *const halu_fam_msgs[4] = {
1623             "Whoa!  Everything %s different.",
1624             "You are surrounded by twisty little passages, all alike.",
1625             "Gee, this %s like uncle Conan's place...", 0 /* no message */
1626         };
1627         const char *mesg;
1628         char buf[BUFSZ];
1629         int which = rn2(4);
1630 
1631         if (Hallucination)
1632             mesg = halu_fam_msgs[which];
1633         else
1634             mesg = fam_msgs[which];
1635         if (mesg && index(mesg, '%')) {
1636             Sprintf(buf, mesg, !Blind ? "looks" : "seems");
1637             mesg = buf;
1638         }
1639         if (mesg)
1640             pline1(mesg);
1641     }
1642 
1643     /* special location arrival messages/events */
1644     if (In_endgame(&u.uz)) {
1645         if (new &&on_level(&u.uz, &astral_level))
1646             final_level(); /* guardian angel,&c */
1647         else if (newdungeon && u.uhave.amulet)
1648             resurrect(); /* force confrontation with Wizard */
1649     } else if (In_quest(&u.uz)) {
1650         onquest(); /* might be reaching locate|goal level */
1651     } else if (In_V_tower(&u.uz)) {
1652         if (newdungeon && In_hell(&u.uz0))
1653             pline_The("heat and smoke are gone.");
1654     } else if (Is_knox(&u.uz)) {
1655         /* alarm stops working once Croesus has died */
1656         if (new || !mvitals[PM_CROESUS].died) {
1657             You("have penetrated a high security area!");
1658             pline("An alarm sounds!");
1659             for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
1660                 if (DEADMONSTER(mtmp))
1661                     continue;
1662                 mtmp->msleeping = 0;
1663             }
1664         }
1665     } else {
1666         if (new && Is_rogue_level(&u.uz))
1667             You("enter what seems to be an older, more primitive world.");
1668         /* main dungeon message from your quest leader */
1669         if (!In_quest(&u.uz0) && at_dgn_entrance("The Quest")
1670             && !(u.uevent.qcompleted || u.uevent.qexpelled
1671                  || quest_status.leader_is_dead)) {
1672             if (!u.uevent.qcalled) {
1673                 u.uevent.qcalled = 1;
1674                 com_pager(2); /* main "leader needs help" message */
1675             } else {          /* reminder message */
1676                 com_pager(Role_if(PM_ROGUE) ? 4 : 3);
1677             }
1678         }
1679     }
1680 
1681     assign_level(&u.uz0, &u.uz); /* reset u.uz0 */
1682 #ifdef INSURANCE
1683     save_currentstate();
1684 #endif
1685 
1686     if ((annotation = get_annotation(&u.uz)) != 0)
1687         You("remember this level as %s.", annotation);
1688 
1689     /* assume this will always return TRUE when changing level */
1690     (void) in_out_region(u.ux, u.uy);
1691     (void) pickup(1);
1692 }
1693 
1694 STATIC_OVL void
final_level()1695 final_level()
1696 {
1697     struct monst *mtmp;
1698 
1699     /* reset monster hostility relative to player */
1700     for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
1701         if (DEADMONSTER(mtmp))
1702             continue;
1703         reset_hostility(mtmp);
1704     }
1705 
1706     /* create some player-monsters */
1707     create_mplayers(rn1(4, 3), TRUE);
1708 
1709     /* create a guardian angel next to player, if worthy */
1710     gain_guardian_angel();
1711 }
1712 
1713 static char *dfr_pre_msg = 0,  /* pline() before level change */
1714             *dfr_post_msg = 0; /* pline() after level change */
1715 
1716 /* change levels at the end of this turn, after monsters finish moving */
1717 void
schedule_goto(tolev,at_stairs,falling,portal_flag,pre_msg,post_msg)1718 schedule_goto(tolev, at_stairs, falling, portal_flag, pre_msg, post_msg)
1719 d_level *tolev;
1720 boolean at_stairs, falling;
1721 int portal_flag;
1722 const char *pre_msg, *post_msg;
1723 {
1724     int typmask = 0100; /* non-zero triggers `deferred_goto' */
1725 
1726     /* destination flags (`goto_level' args) */
1727     if (at_stairs)
1728         typmask |= 1;
1729     if (falling)
1730         typmask |= 2;
1731     if (portal_flag)
1732         typmask |= 4;
1733     if (portal_flag < 0)
1734         typmask |= 0200; /* flag for portal removal */
1735     u.utotype = typmask;
1736     /* destination level */
1737     assign_level(&u.utolev, tolev);
1738 
1739     if (pre_msg)
1740         dfr_pre_msg = dupstr(pre_msg);
1741     if (post_msg)
1742         dfr_post_msg = dupstr(post_msg);
1743 }
1744 
1745 /* handle something like portal ejection */
1746 void
deferred_goto()1747 deferred_goto()
1748 {
1749     if (!on_level(&u.uz, &u.utolev)) {
1750         d_level dest;
1751         int typmask = u.utotype; /* save it; goto_level zeroes u.utotype */
1752 
1753         assign_level(&dest, &u.utolev);
1754         if (dfr_pre_msg)
1755             pline1(dfr_pre_msg);
1756         goto_level(&dest, !!(typmask & 1), !!(typmask & 2), !!(typmask & 4));
1757         if (typmask & 0200) { /* remove portal */
1758             struct trap *t = t_at(u.ux, u.uy);
1759 
1760             if (t) {
1761                 deltrap(t);
1762                 newsym(u.ux, u.uy);
1763             }
1764         }
1765         if (dfr_post_msg)
1766             pline1(dfr_post_msg);
1767     }
1768     u.utotype = 0; /* our caller keys off of this */
1769     if (dfr_pre_msg)
1770         free((genericptr_t) dfr_pre_msg), dfr_pre_msg = 0;
1771     if (dfr_post_msg)
1772         free((genericptr_t) dfr_post_msg), dfr_post_msg = 0;
1773 }
1774 
1775 /*
1776  * Return TRUE if we created a monster for the corpse.  If successful, the
1777  * corpse is gone.
1778  */
1779 boolean
revive_corpse(corpse)1780 revive_corpse(corpse)
1781 struct obj *corpse;
1782 {
1783     struct monst *mtmp, *mcarry;
1784     boolean is_uwep, chewed;
1785     xchar where;
1786     char cname[BUFSZ];
1787     struct obj *container = (struct obj *) 0;
1788     int container_where = 0;
1789 
1790     where = corpse->where;
1791     is_uwep = (corpse == uwep);
1792     chewed = (corpse->oeaten != 0);
1793     Strcpy(cname, corpse_xname(corpse,
1794                                chewed ? "bite-covered" : (const char *) 0,
1795                                CXN_SINGULAR));
1796     mcarry = (where == OBJ_MINVENT) ? corpse->ocarry : 0;
1797 
1798     if (where == OBJ_CONTAINED) {
1799         struct monst *mtmp2;
1800 
1801         container = corpse->ocontainer;
1802         mtmp2 = get_container_location(container, &container_where, (int *) 0);
1803         /* container_where is the outermost container's location even if
1804          * nested */
1805         if (container_where == OBJ_MINVENT && mtmp2)
1806             mcarry = mtmp2;
1807     }
1808     mtmp = revive(corpse, FALSE); /* corpse is gone if successful */
1809 
1810     if (mtmp) {
1811         switch (where) {
1812         case OBJ_INVENT:
1813             if (is_uwep)
1814                 pline_The("%s writhes out of your grasp!", cname);
1815             else
1816                 You_feel("squirming in your backpack!");
1817             break;
1818 
1819         case OBJ_FLOOR:
1820             if (cansee(mtmp->mx, mtmp->my))
1821                 pline("%s rises from the dead!",
1822                       chewed ? Adjmonnam(mtmp, "bite-covered")
1823                              : Monnam(mtmp));
1824             break;
1825 
1826         case OBJ_MINVENT: /* probably a nymph's */
1827             if (cansee(mtmp->mx, mtmp->my)) {
1828                 if (canseemon(mcarry))
1829                     pline("Startled, %s drops %s as it revives!",
1830                           mon_nam(mcarry), an(cname));
1831                 else
1832                     pline("%s suddenly appears!",
1833                           chewed ? Adjmonnam(mtmp, "bite-covered")
1834                                  : Monnam(mtmp));
1835             }
1836             break;
1837         case OBJ_CONTAINED: {
1838             char sackname[BUFSZ];
1839 
1840             if (container_where == OBJ_MINVENT && cansee(mtmp->mx, mtmp->my)
1841                 && mcarry && canseemon(mcarry) && container) {
1842                 pline("%s writhes out of %s!", Amonnam(mtmp),
1843                       yname(container));
1844             } else if (container_where == OBJ_INVENT && container) {
1845                 Strcpy(sackname, an(xname(container)));
1846                 pline("%s %s out of %s in your pack!",
1847                       Blind ? Something : Amonnam(mtmp),
1848                       locomotion(mtmp->data, "writhes"), sackname);
1849             } else if (container_where == OBJ_FLOOR && container
1850                        && cansee(mtmp->mx, mtmp->my)) {
1851                 Strcpy(sackname, an(xname(container)));
1852                 pline("%s escapes from %s!", Amonnam(mtmp), sackname);
1853             }
1854             break;
1855         }
1856         default:
1857             /* we should be able to handle the other cases... */
1858             impossible("revive_corpse: lost corpse @ %d", where);
1859             break;
1860         }
1861         return TRUE;
1862     }
1863     return FALSE;
1864 }
1865 
1866 /* Revive the corpse via a timeout. */
1867 /*ARGSUSED*/
1868 void
revive_mon(arg,timeout)1869 revive_mon(arg, timeout)
1870 anything *arg;
1871 long timeout UNUSED;
1872 {
1873     struct obj *body = arg->a_obj;
1874     struct permonst *mptr = &mons[body->corpsenm];
1875     struct monst *mtmp;
1876     xchar x, y;
1877 
1878     /* corpse will revive somewhere else if there is a monster in the way;
1879        Riders get a chance to try to bump the obstacle out of their way */
1880     if ((mptr->mflags3 & M3_DISPLACES) != 0 && body->where == OBJ_FLOOR
1881         && get_obj_location(body, &x, &y, 0) && (mtmp = m_at(x, y)) != 0) {
1882         boolean notice_it = canseemon(mtmp); /* before rloc() */
1883         char *monname = Monnam(mtmp);
1884 
1885         if (rloc(mtmp, TRUE)) {
1886             if (notice_it && !canseemon(mtmp))
1887                 pline("%s vanishes.", monname);
1888             else if (!notice_it && canseemon(mtmp))
1889                 pline("%s appears.", Monnam(mtmp)); /* not pre-rloc monname */
1890             else if (notice_it && dist2(mtmp->mx, mtmp->my, x, y) > 2)
1891                 pline("%s teleports.", monname); /* saw it and still see it */
1892         }
1893     }
1894 
1895     /* if we succeed, the corpse is gone */
1896     if (!revive_corpse(body)) {
1897         long when;
1898         int action;
1899 
1900         if (is_rider(mptr) && rn2(99)) { /* Rider usually tries again */
1901             action = REVIVE_MON;
1902             for (when = 3L; when < 67L; when++)
1903                 if (!rn2(3))
1904                     break;
1905         } else { /* rot this corpse away */
1906             You_feel("%sless hassled.", is_rider(mptr) ? "much " : "");
1907             action = ROT_CORPSE;
1908             when = 250L - (monstermoves - body->age);
1909             if (when < 1L)
1910                 when = 1L;
1911         }
1912         (void) start_timer(when, TIMER_OBJECT, action, arg);
1913     }
1914 }
1915 
1916 int
donull()1917 donull()
1918 {
1919     return 1; /* Do nothing, but let other things happen */
1920 }
1921 
1922 STATIC_PTR int
wipeoff(VOID_ARGS)1923 wipeoff(VOID_ARGS)
1924 {
1925     if (u.ucreamed < 4)
1926         u.ucreamed = 0;
1927     else
1928         u.ucreamed -= 4;
1929     if (Blinded < 4)
1930         Blinded = 0;
1931     else
1932         Blinded -= 4;
1933     if (!Blinded) {
1934         pline("You've got the glop off.");
1935         u.ucreamed = 0;
1936         if (!gulp_blnd_check()) {
1937             Blinded = 1;
1938             make_blinded(0L, TRUE);
1939         }
1940         return 0;
1941     } else if (!u.ucreamed) {
1942         Your("%s feels clean now.", body_part(FACE));
1943         return 0;
1944     }
1945     return 1; /* still busy */
1946 }
1947 
1948 int
dowipe()1949 dowipe()
1950 {
1951     if (u.ucreamed) {
1952         static NEARDATA char buf[39];
1953 
1954         Sprintf(buf, "wiping off your %s", body_part(FACE));
1955         set_occupation(wipeoff, buf, 0);
1956         /* Not totally correct; what if they change back after now
1957          * but before they're finished wiping?
1958          */
1959         return 1;
1960     }
1961     Your("%s is already clean.", body_part(FACE));
1962     return 1;
1963 }
1964 
1965 void
set_wounded_legs(side,timex)1966 set_wounded_legs(side, timex)
1967 register long side;
1968 register int timex;
1969 {
1970     /* KMH -- STEED
1971      * If you are riding, your steed gets the wounded legs instead.
1972      * You still call this function, but don't lose hp.
1973      * Caller is also responsible for adjusting messages.
1974      */
1975 
1976     if (!Wounded_legs) {
1977         ATEMP(A_DEX)--;
1978         context.botl = 1;
1979     }
1980 
1981     if (!Wounded_legs || (HWounded_legs & TIMEOUT))
1982         HWounded_legs = timex;
1983     EWounded_legs = side;
1984     (void) encumber_msg();
1985 }
1986 
1987 void
heal_legs(how)1988 heal_legs(how)
1989 int how; /* 0: ordinary, 1: dismounting steed, 2: limbs turn to stone */
1990 {
1991     if (Wounded_legs) {
1992         if (ATEMP(A_DEX) < 0) {
1993             ATEMP(A_DEX)++;
1994             context.botl = 1;
1995         }
1996 
1997         /* when mounted, wounded legs applies to the steed;
1998            during petrification countdown, "your limbs turn to stone"
1999            before the final stages and that calls us (how==2) to cure
2000            wounded legs, but we want to suppress the feel better message */
2001         if (!u.usteed && how != 2) {
2002             const char *legs = body_part(LEG);
2003 
2004             if ((EWounded_legs & BOTH_SIDES) == BOTH_SIDES)
2005                 legs = makeplural(legs);
2006             /* this used to say "somewhat better" but that was
2007                misleading since legs are being fully healed */
2008             Your("%s %s better.", legs, vtense(legs, "feel"));
2009         }
2010 
2011         HWounded_legs = EWounded_legs = 0L;
2012 
2013         /* Wounded_legs reduces carrying capacity, so we want
2014            an encumbrance check when they're healed.  However,
2015            while dismounting, first steed's legs get healed,
2016            then hero is dropped to floor and a new encumbrance
2017            check is made [in dismount_steed()].  So don't give
2018            encumbrance feedback during the dismount stage
2019            because it could seem to be shown out of order and
2020            it might be immediately contradicted [able to carry
2021            more when steed becomes healthy, then possible floor
2022            feedback, then able to carry less when back on foot]. */
2023         if (how == 0)
2024             (void) encumber_msg();
2025     }
2026 }
2027 
2028 /*do.c*/
2029