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