make rank() static again
[NetHack.git] / src / do.c
blob41828b8acb2f6e589b5f64dbe7b8661d24a3be95
1 /* NetHack 3.7 do.c $NHDT-Date: 1737287889 2025/01/19 03:58:09 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.399 $ */
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. */
6 /* Contains code for 'd', 'D' (drop), '>', '<' (up, down) */
8 #include "hack.h"
10 staticfn boolean teleport_sink(void);
11 staticfn void dosinkring(struct obj *);
12 staticfn int drop(struct obj *);
13 staticfn int menudrop_split(struct obj *, long);
14 staticfn boolean engulfer_digests_food(struct obj *);
15 staticfn boolean danger_uprops(void);
16 staticfn int wipeoff(void);
17 staticfn int menu_drop(int);
18 staticfn boolean u_stuck_cannot_go(const char *);
19 staticfn NHFILE *currentlevel_rewrite(void);
20 staticfn void familiar_level_msg(void);
21 staticfn void final_level(void);
22 staticfn void temperature_change_msg(schar);
23 staticfn boolean better_not_try_to_drop_that(struct obj *);
25 /* static boolean badspot(coordxy,coordxy); */
27 /* the #drop command: drop one inventory item */
28 int
29 dodrop(void)
31 int result;
33 if (*u.ushops)
34 sellobj_state(SELL_DELIBERATE);
35 result = drop(getobj("drop", any_obj_ok,
36 GETOBJ_PROMPT | GETOBJ_ALLOWCNT));
37 if (*u.ushops)
38 sellobj_state(SELL_NORMAL);
39 if (result)
40 reset_occupations();
42 return result;
45 /* Called when a boulder is dropped, thrown, or pushed. If it ends up
46 * in a pool, it either fills the pool up or sinks away. In either case,
47 * it's gone for good... If the destination is not a pool, returns FALSE.
49 boolean
50 boulder_hits_pool(
51 struct obj *otmp, /* the object falling into a pool or water or lava */
52 coordxy rx, coordxy ry, /* coordinates of the pool */
53 boolean pushing) /* for a boulder, whether or not it is being pushed */
55 if (!otmp || otmp->otyp != BOULDER) {
56 impossible("Not a boulder?");
57 } else if (is_pool_or_lava(rx, ry)) {
58 boolean lava = is_lava(rx, ry), fills_up;
59 const char *what = waterbody_name(rx, ry);
60 schar ltyp = levl[rx][ry].typ;
61 int chance = rn2(10); /* water: 90%; lava: 10% */
62 struct monst *mtmp;
64 /* chance for boulder to fill pool: Plane of Water==0%,
65 lava 10%, wall of water==50%, other water==90% */
66 fills_up = Is_waterlevel(&u.uz) ? FALSE
67 : IS_WATERWALL(ltyp) ? (chance < 5)
68 : lava ? (chance == 0) : (chance != 0);
70 if (fills_up) {
71 struct trap *ttmp = t_at(rx, ry);
73 if (ltyp == DRAWBRIDGE_UP) {
74 levl[rx][ry].drawbridgemask &= ~DB_UNDER; /* clear lava */
75 levl[rx][ry].drawbridgemask |= DB_FLOOR;
76 } else {
77 levl[rx][ry].typ = ROOM, levl[rx][ry].flags = 0;
78 recalc_block_point(rx, ry);
80 /* 3.7: normally DEADMONSTER() is used when traversing the fmon
81 list--dead monsters usually aren't still at specific map
82 locations; however, if ice melts causing a giant to drown,
83 that giant would still be on the map when it drops inventory;
84 if it was carrying a boulder which now fills the pool, 'mtmp'
85 will be dead here; killing it again would yield impossible
86 "dmonsfree: N removed doesn't match N+1 pending" when other
87 monsters have finished their current turn */
88 if ((mtmp = m_at(rx, ry)) != 0 && !DEADMONSTER(mtmp)
89 && !m_in_air(mtmp))
90 mondied(mtmp);
92 if (ttmp)
93 (void) delfloortrap(ttmp);
94 bury_objs(rx, ry);
96 newsym(rx, ry);
97 if (pushing) {
98 char whobuf[BUFSZ];
100 Strcpy(whobuf, "you");
101 if (u.usteed)
102 Strcpy(whobuf, y_monnam(u.usteed));
103 pline("%s %s %s into the %s.", upstart(whobuf),
104 vtense(whobuf, "push"), the(xname(otmp)), what);
105 if (flags.verbose && !Blind)
106 pline("Now you can cross it!");
107 /* no splashing in this case */
110 if (!fills_up || !pushing) { /* splashing occurs */
111 if (!u.uinwater) {
112 if (pushing ? !Blind : cansee(rx, ry)) {
113 There("is a large splash as %s %s the %s.",
114 the(xname(otmp)), fills_up ? "fills" : "falls into",
115 what);
116 } else if (!Deaf) {
117 if (lava) {
118 Soundeffect(se_sizzling, 100);
119 } else {
120 Soundeffect(se_splash, 100);
122 You_hear("a%s splash.", lava ? " sizzling" : "");
124 wake_nearto(rx, ry, 40);
127 if (fills_up && u.uinwater && distu(rx, ry) == 0) {
128 set_uinwater(0); /* u.uinwater = 0 */
129 docrt();
130 gv.vision_full_recalc = 1;
131 You("find yourself on dry land again!");
132 } else if (lava && next2u(rx, ry)) {
133 int dmg;
135 You("are hit by molten %s%c",
136 hliquid("lava"), Fire_resistance ? '.' : '!');
137 burn_away_slime();
138 dmg = d((Fire_resistance ? 1 : 3), 6);
139 losehp(Maybe_Half_Phys(dmg), /* lava damage */
140 "molten lava", KILLED_BY);
141 } else if (!fills_up && flags.verbose
142 && (pushing ? !Blind : cansee(rx, ry))) {
143 pline("It sinks without a trace!");
147 /* boulder is now gone */
148 if (pushing)
149 useupf(otmp, otmp->quan);
150 else
151 obfree(otmp, (struct obj *) 0);
152 return TRUE;
154 return FALSE;
157 /* Used for objects which sometimes do special things when dropped; must be
158 * called with the object not in any chain. Returns TRUE if the object goes
159 * away.
161 boolean
162 flooreffects(
163 struct obj *obj, /* the object landing on the floor */
164 coordxy x, coordxy y, /* map coordinates for spot where it is landing */
165 const char *verb) /* "fall", "drop", "land", &c */
167 struct trap *t;
168 struct monst *mtmp;
169 struct obj *otmp;
170 coord save_bhitpos;
171 boolean tseen;
172 int ttyp = NO_TRAP, res = FALSE;
174 if (obj->where != OBJ_FREE)
175 panic("flooreffects: obj not free");
177 /* make sure things like water_damage() have no pointers to follow */
178 obj->nobj = obj->nexthere = (struct obj *) 0;
179 /* erode_obj() (called from water_damage() or lava_damage()) needs
180 bhitpos, but that was screwing up wand zapping that called us from
181 rloco(), so we now restore bhitpos before we return */
182 save_bhitpos = gb.bhitpos;
183 gb.bhitpos.x = x, gb.bhitpos.y = y;
185 if (obj->otyp == BOULDER && boulder_hits_pool(obj, x, y, FALSE)) {
186 res = TRUE;
187 } else if (obj->otyp == BOULDER && (t = t_at(x, y)) != 0
188 && (is_pit(t->ttyp) || is_hole(t->ttyp))) {
189 ttyp = t->ttyp;
190 tseen = t->tseen ? TRUE : FALSE;
191 if (((mtmp = m_at(x, y)) && mtmp->mtrapped)
192 || (u.utrap && u_at(x,y))) {
193 if (*verb && (cansee(x, y) || distu(x, y) == 0))
194 pline("%s boulder %s into the pit%s.",
195 Blind ? "A" : "The",
196 vtense((const char *) 0, verb),
197 mtmp ? "" : " with you");
198 if (mtmp) {
199 if (!passes_walls(mtmp->data) && !throws_rocks(mtmp->data)) {
200 /* dieroll was rnd(20); 1: maximum chance to hit
201 since trapped target is a sitting duck */
202 int damage, dieroll = 1;
204 /* As of 3.6.2: this was calling hmon() unconditionally
205 so always credited/blamed the hero but the boulder
206 might have been thrown by a giant or launched by
207 a rolling boulder trap triggered by a monster or
208 dropped by a scroll of earth read by a monster */
209 if (svc.context.mon_moving) {
210 /* normally we'd use ohitmon() but it can call
211 drop_throw() which calls flooreffects() */
212 damage = dmgval(obj, mtmp);
213 mtmp->mhp -= damage;
214 if (DEADMONSTER(mtmp)) {
215 if (canspotmon(mtmp))
216 pline("%s is %s!", Monnam(mtmp),
217 (nonliving(mtmp->data)
218 || is_vampshifter(mtmp))
219 ? "destroyed" : "killed");
220 mondied(mtmp);
222 } else {
223 (void) hmon(mtmp, obj, HMON_THROWN, dieroll);
225 if (!DEADMONSTER(mtmp) && !is_whirly(mtmp->data))
226 res = FALSE; /* still alive, boulder still intact */
227 nhUse(res);
229 mtmp->mtrapped = 0;
230 } else {
231 if (!Passes_walls && !throws_rocks(gy.youmonst.data)) {
232 losehp(Maybe_Half_Phys(rnd(15)),
233 "squished under a boulder", NO_KILLER_PREFIX);
234 goto deletedwithboulder;
235 } else
236 reset_utrap(TRUE);
239 if (*verb) {
240 if (Blind && u_at(x, y)) {
241 Soundeffect(se_crashing_boulder, 100);
242 You_hear("a CRASH! beneath you.");
243 } else if (!Blind && cansee(x, y)) {
244 pline_The("boulder %s%s.",
245 (ttyp == TRAPDOOR && !tseen) ? "triggers and " : "",
246 (ttyp == TRAPDOOR) ? "plugs a trap door"
247 : (ttyp == HOLE) ? "plugs a hole"
248 : "fills a pit");
249 } else {
250 Soundeffect(se_boulder_drop, 100);
251 You_hear("a boulder %s.", verb);
255 * Note: trap might have gone away via ((hmon -> killed -> xkilled)
256 * || mondied) -> mondead -> m_detach -> fill_pit.
258 deletedwithboulder:
259 /* creating a pit in ice results in that ice being turned into
260 floor so we shouldn't need any special ice handing here */
261 if ((t = t_at(x, y)) != 0) {
262 (void) delfloortrap(t);
263 if (u.utrap && u_at(x, y))
264 reset_utrap(FALSE);
266 useupf(obj, 1L);
267 bury_objs(x, y);
268 newsym(x, y);
269 res = TRUE;
270 } else if (is_lava(x, y)) {
271 res = lava_damage(obj, x, y);
272 } else if (is_pool(x, y)) {
273 /* Reasonably bulky objects (arbitrary) splash when dropped.
274 * If you're floating above the water even small things make
275 * noise. Stuff dropped near fountains always misses */
276 if ((Blind || (Levitation || Flying)) && !Deaf && u_at(x, y)) {
277 if (!Underwater) {
278 if (weight(obj) > 9) {
279 pline("Splash!");
280 } else if (Levitation || Flying) {
281 pline("Plop!");
284 map_background(x, y, 0);
285 newsym(x, y);
287 res = water_damage(obj, NULL, FALSE) == ER_DESTROYED;
288 } else if (u_at(x, y) && (t = t_at(x, y)) != 0
289 && (uteetering_at_seen_pit(t) || uescaped_shaft(t))) {
290 if (is_pit(t->ttyp)) {
291 if (Blind && !Deaf) {
292 Soundeffect(se_item_tumble_downwards, 50);
293 You_hear("%s tumble downwards.", the(xname(obj)));
294 } else {
295 pline("%s into %s pit.", Tobjnam(obj, "tumble"),
296 the_your[t->madeby_u]);
298 } else if (ship_object(obj, x, y, FALSE)) {
299 /* ship_object will print an appropriate "the item falls
300 * through the hole" message, so no need to do it here. */
301 res = TRUE;
303 } else if (obj->globby) {
304 struct obj *globbyobj = obj; /* allow obj to be nonnull arg */
306 /* Globby things like puddings might stick together */
307 while (globbyobj
308 && (otmp = obj_nexto_xy(globbyobj, x, y, TRUE)) != 0) {
309 pudding_merge_message(globbyobj, otmp);
310 /* intentionally not getting the melded object; obj_meld may set
311 * obj to null. */
312 (void) obj_meld(&globbyobj, &otmp);
314 res = (boolean) !globbyobj;
315 } else if (svc.context.mon_moving && IS_ALTAR(levl[x][y].typ)
316 && cansee(x,y)) {
317 doaltarobj(obj);
318 } else if (obj->oclass == POTION_CLASS && svl.level.flags.temperature > 0
319 && (levl[x][y].typ == ROOM || levl[x][y].typ == CORR)) {
320 /* Potions are sometimes destroyed when landing on very hot
321 ground. The basic odds are 50% for nonblessed potions and
322 30% for blessed potions; if you have handled the object
323 (i.e. it is or was yours), these odds are adjusted by Luck
324 (each Luck point affects them by 2%). Artifact potions
325 would not be affected, if any existed.
327 Oil is not affected because its boiling point (and flash
328 point) are higher than that of water. For example, whale
329 oil, one of the substances traditionally used in oil lamps,
330 can survive over 100 degrees Centigrade more heat than
331 water can.*/
332 if (cansee(x,y)) {
333 /* unconditional "ground" is safe as this only runs for
334 room and corridor tiles */
335 pline("%s up as %s the hot ground.", Tobjnam(obj, "heat"),
336 is_plural(obj) ? "they hit" : "it hits");
339 int survival_chance = obj->blessed ? 70 : 50;
340 if (obj->invlet)
341 survival_chance += Luck * 2;
342 if (obj->otyp == POT_OIL)
343 survival_chance = 100;
345 if (!obj_resists(obj, survival_chance, 100)) {
346 if (cansee(x,y)) {
347 pline("%s from the heat!",
348 is_plural(obj) ? "They shatter" : "It shatters");
349 } else {
350 You_hear("a shattering noise.");
352 breakobj(obj, x, y, FALSE, FALSE);
353 res = TRUE;
357 gb.bhitpos = save_bhitpos;
358 return res;
361 /* obj is an object dropped on an altar */
362 void
363 doaltarobj(struct obj *obj)
365 if (Blind)
366 return;
368 if (obj->oclass != COIN_CLASS) {
369 /* KMH, conduct */
370 if (!svc.context.mon_moving && !u.uconduct.gnostic++)
371 livelog_printf(LL_CONDUCT,
372 "eschewed atheism, by dropping %s on an altar",
373 doname(obj));
374 } else {
375 /* coins don't have bless/curse status */
376 obj->blessed = obj->cursed = 0;
379 if (obj->blessed || obj->cursed) {
380 There("is %s flash as %s %s the altar.",
381 an(hcolor(obj->blessed ? NH_AMBER : NH_BLACK)), doname(obj),
382 otense(obj, "hit"));
383 if (!Hallucination)
384 obj->bknown = 1; /* ok to bypass set_bknown() */
385 } else {
386 pline("%s %s on the altar.", Doname2(obj), otense(obj, "land"));
387 if (obj->oclass != COIN_CLASS)
388 obj->bknown = 1; /* ok to bypass set_bknown() */
392 /* If obj is neither formally identified nor informally called something
393 * already, prompt the player to call its object type. */
394 void
395 trycall(struct obj *obj)
397 if (!objects[obj->otyp].oc_name_known && !objects[obj->otyp].oc_uname)
398 docall(obj);
401 /* Transforms the sink at the player's position into
402 a fountain, throne, altar or grave. */
403 void
404 polymorph_sink(void)
406 uchar sym = S_sink;
407 boolean sinklooted;
408 int algn;
410 if (levl[u.ux][u.uy].typ != SINK)
411 return;
413 sinklooted = levl[u.ux][u.uy].looted != 0;
414 /* svl.level.flags.nsinks--; // set_levltyp() will update this */
415 levl[u.ux][u.uy].flags = 0;
416 switch (rn2(4)) {
417 default:
418 case 0:
419 sym = S_fountain;
420 set_levltyp(u.ux, u.uy, FOUNTAIN); /* updates level.flags.nfountains */
421 levl[u.ux][u.uy].blessedftn = 0;
422 if (sinklooted)
423 SET_FOUNTAIN_LOOTED(u.ux, u.uy);
424 break;
425 case 1:
426 sym = S_throne;
427 set_levltyp(u.ux, u.uy, THRONE);
428 if (sinklooted)
429 levl[u.ux][u.uy].looted = T_LOOTED;
430 break;
431 case 2:
432 sym = S_altar;
433 set_levltyp(u.ux, u.uy, ALTAR);
434 /* 3.6.3: this used to pass 'rn2(A_LAWFUL + 2) - 1' to
435 Align2amask() but that evaluates its argument more than once */
436 algn = rn2(3) - 1; /* -1 (A_Cha) or 0 (A_Neu) or +1 (A_Law) */
437 levl[u.ux][u.uy].altarmask = ((Inhell && rn2(3)) ? AM_NONE
438 : Align2amask(algn));
439 break;
440 case 3:
441 sym = S_room;
442 set_levltyp(u.ux, u.uy, ROOM);
443 make_grave(u.ux, u.uy, (char *) 0);
444 if (levl[u.ux][u.uy].typ == GRAVE)
445 sym = S_grave;
446 break;
448 /* give message even if blind; we know we're not levitating,
449 so can feel the outcome even if we can't directly see it */
450 if (levl[u.ux][u.uy].typ != ROOM)
451 pline_The("sink transforms into %s!", an(defsyms[sym].explanation));
452 else
453 pline_The("sink vanishes.");
454 newsym(u.ux, u.uy);
457 /* Teleports the sink at the player's position;
458 return True if sink teleported. */
459 staticfn boolean
460 teleport_sink(void)
462 coordxy cx, cy;
463 unsigned alreadylooted;
464 int trycnt = 0;
466 do {
467 #if 0 /* this isn't incorrect but it is extremely unlikely that spots
468 * on the level's edge will be ROOM so picking such wastes tries */
469 cx = rnd(COLNO - 1); /* 1..COLNO-1 */
470 cy = rn2(ROWNO); /* 0..ROWNO-1 */
471 #else /* use this instead */
472 cx = 1 + rnd((COLNO - 1) - 2); /* 2..COLNO-2 */
473 cy = 1 + rn2(ROWNO - 2); /* 1..ROWNO-2 */
474 #endif
475 if (levl[cx][cy].typ == ROOM
476 && !t_at(cx, cy) && !engr_at(cx, cy)
477 && (!cansee(cx, cy) || distu(cx, cy) > 3 * 3)) {
478 /* this ends up having set_levltyp() count all sinks and
479 fountains on the level twice but that is not a problem */
480 alreadylooted = levl[u.ux][u.uy].looted;
481 /* remove old sink */
482 set_levltyp(u.ux, u.uy, ROOM); /* was SINK so updates nsinks */
483 levl[u.ux][u.uy].looted = 0;
484 newsym(u.ux, u.uy);
485 /* create sink at new position */
486 set_levltyp(cx, cy, SINK); /* now SINK so also updates nsinks */
487 levl[cx][cy].looted = alreadylooted ? 1 : 0;
488 newsym(cx, cy);
489 return TRUE;
491 } while (++trycnt < 200);
493 return FALSE;
496 /* obj is a ring being dropped over a kitchen sink */
497 staticfn void
498 dosinkring(struct obj *obj)
500 struct obj *otmp, *otmp2;
501 boolean ideed = TRUE;
502 boolean nosink = FALSE;
504 You("drop %s down the drain.", doname(obj));
505 obj->in_use = TRUE; /* block free identification via interrupt */
506 switch (obj->otyp) { /* effects that can be noticed without eyes */
507 case RIN_SEARCHING:
508 You("thought %s got lost in the sink, but there it is!", yname(obj));
509 goto giveback;
510 case RIN_SLOW_DIGESTION:
511 pline_The("ring is regurgitated!");
512 giveback:
513 obj->in_use = FALSE;
514 dropx(obj);
515 trycall(obj);
516 return;
517 case RIN_LEVITATION:
518 pline_The("sink quivers upward for a moment.");
519 break;
520 case RIN_POISON_RESISTANCE:
521 You("smell rotten %s.", makeplural(fruitname(FALSE)));
522 break;
523 case RIN_AGGRAVATE_MONSTER:
524 pline("Several %s buzz angrily around the sink.",
525 Hallucination ? makeplural(rndmonnam(NULL)) : "flies");
526 break;
527 case RIN_SHOCK_RESISTANCE:
528 pline("Static electricity surrounds the sink.");
529 break;
530 case RIN_CONFLICT:
531 Soundeffect(se_drain_noises, 50);
532 You_hear("loud noises coming from the drain.");
533 break;
534 case RIN_SUSTAIN_ABILITY: /* KMH */
535 pline_The("%s flow seems fixed.", hliquid("water"));
536 break;
537 case RIN_GAIN_STRENGTH:
538 pline_The("%s flow seems %ser now.",
539 hliquid("water"),
540 (obj->spe < 0) ? "weak" : "strong");
541 break;
542 case RIN_GAIN_CONSTITUTION:
543 pline_The("%s flow seems %ser now.",
544 hliquid("water"),
545 (obj->spe < 0) ? "less" : "great");
546 break;
547 case RIN_INCREASE_ACCURACY: /* KMH */
548 pline_The("%s flow %s the drain.",
549 hliquid("water"),
550 (obj->spe < 0) ? "misses" : "hits");
551 break;
552 case RIN_INCREASE_DAMAGE:
553 pline_The("water's force seems %ser now.",
554 (obj->spe < 0) ? "small" : "great");
555 break;
556 case RIN_HUNGER:
557 ideed = FALSE;
558 for (otmp = svl.level.objects[u.ux][u.uy]; otmp; otmp = otmp2) {
559 otmp2 = otmp->nexthere;
560 if (otmp != uball && otmp != uchain
561 && !obj_resists(otmp, 1, 99)) {
562 if (!Blind) {
563 pline("Suddenly, %s %s from the sink!", doname(otmp),
564 otense(otmp, "vanish"));
565 ideed = TRUE;
567 delobj(otmp);
570 break;
571 case MEAT_RING:
572 /* Not the same as aggravate monster; besides, it's obvious. */
573 pline("Several flies buzz around the sink.");
574 break;
575 case RIN_TELEPORTATION:
576 nosink = teleport_sink();
577 /* give message even if blind; we know we're not levitating,
578 so can feel the outcome even if we can't directly see it */
579 pline_The("sink %svanishes.", nosink ? "" : "momentarily ");
580 ideed = FALSE;
581 break;
582 case RIN_POLYMORPH:
583 polymorph_sink();
584 nosink = TRUE;
585 /* for S_room case, same message as for teleportation is given */
586 ideed = (levl[u.ux][u.uy].typ != ROOM);
587 break;
588 default:
589 ideed = FALSE;
590 break;
592 if (!Blind && !ideed) {
593 ideed = TRUE;
594 switch (obj->otyp) { /* effects that need eyes */
595 case RIN_ADORNMENT:
596 pline_The("faucets flash brightly for a moment.");
597 break;
598 case RIN_REGENERATION:
599 pline_The("sink looks as good as new.");
600 break;
601 case RIN_INVISIBILITY:
602 You("don't see anything happen to the sink.");
603 break;
604 case RIN_FREE_ACTION:
605 You_see("the ring slide right down the drain!");
606 break;
607 case RIN_SEE_INVISIBLE:
608 You_see("some %s in the sink.",
609 Hallucination ? "oxygen molecules" : "air");
610 break;
611 case RIN_STEALTH:
612 pline_The("sink seems to blend into the floor for a moment.");
613 break;
614 case RIN_FIRE_RESISTANCE:
615 pline_The("hot %s faucet flashes brightly for a moment.",
616 hliquid("water"));
617 break;
618 case RIN_COLD_RESISTANCE:
619 pline_The("cold %s faucet flashes brightly for a moment.",
620 hliquid("water"));
621 break;
622 case RIN_PROTECTION_FROM_SHAPE_CHAN:
623 pline_The("sink looks nothing like a fountain.");
624 break;
625 case RIN_PROTECTION:
626 pline_The("sink glows %s for a moment.",
627 hcolor((obj->spe < 0) ? NH_BLACK : NH_SILVER));
628 break;
629 case RIN_WARNING:
630 pline_The("sink glows %s for a moment.", hcolor(NH_WHITE));
631 break;
632 case RIN_TELEPORT_CONTROL:
633 pline_The("sink looks like it is being beamed aboard somewhere.");
634 break;
635 case RIN_POLYMORPH_CONTROL:
636 pline_The(
637 "sink momentarily looks like a regularly erupting geyser.");
638 break;
639 default:
640 break;
643 if (ideed) {
644 trycall(obj);
645 } else if (!nosink) {
646 Soundeffect(se_ring_in_drain, 50);
647 You_hear("the ring bouncing down the drainpipe.");
649 if (!rn2(20) && !nosink) {
650 pline_The("sink backs up, leaving %s.", doname(obj));
651 obj->in_use = FALSE;
652 dropx(obj);
653 } else if (!rn2(5)) {
654 freeinv(obj);
655 obj->in_use = FALSE;
656 obj->ox = u.ux;
657 obj->oy = u.uy;
658 add_to_buried(obj);
659 } else
660 useup(obj);
663 /* some common tests when trying to drop or throw items */
664 boolean
665 canletgo(struct obj *obj, const char *word)
667 if (obj->owornmask & (W_ARMOR | W_ACCESSORY)) {
668 if (*word)
669 Norep("You cannot %s %s you are wearing.", word, something);
670 return FALSE;
672 if (obj == uwep && welded(uwep)) {
673 /* no weldmsg(), so uwep->bknown might become set silently
674 if word is "" */
675 if (*word) {
676 const char *hand = body_part(HAND);
678 if (bimanual(uwep))
679 hand = makeplural(hand);
680 Norep("You cannot %s %s welded to your %s.", word, something,
681 hand);
683 return FALSE;
685 if (obj->otyp == LOADSTONE && obj->cursed) {
686 /* getobj() kludge sets corpsenm to user's specified count
687 when refusing to split a stack of cursed loadstones */
688 if (*word) {
689 /* getobj() ignores a count for throwing since that is
690 implicitly forced to be 1; replicate its kludge... */
691 if (!strcmp(word, "throw") && obj->quan > 1L)
692 obj->corpsenm = 1;
693 pline("For some reason, you cannot %s%s the stone%s!", word,
694 obj->corpsenm ? " any of" : "", plur(obj->quan));
696 obj->corpsenm = 0; /* reset */
697 set_bknown(obj, 1);
698 return FALSE;
700 if (obj->otyp == LEASH && obj->leashmon != 0) {
701 if (*word)
702 pline_The("leash is tied around your %s.", body_part(HAND));
703 return FALSE;
705 if (obj->owornmask & W_SADDLE) {
706 if (*word)
707 You("cannot %s %s you are sitting on.", word, something);
708 return FALSE;
710 return TRUE;
713 staticfn int
714 drop(struct obj *obj)
716 if (!obj)
717 return ECMD_FAIL;
718 if (!canletgo(obj, "drop"))
719 return ECMD_FAIL;
720 if (obj->otyp == CORPSE && better_not_try_to_drop_that(obj))
721 return ECMD_FAIL;
722 if (obj == uwep) {
723 if (welded(uwep)) {
724 weldmsg(obj);
725 return ECMD_FAIL;
727 setuwep((struct obj *) 0);
729 if (obj == uquiver) {
730 setuqwep((struct obj *) 0);
732 if (obj == uswapwep) {
733 setuswapwep((struct obj *) 0);
736 if (u.uswallow) {
737 /* barrier between you and the floor */
738 if (flags.verbose) {
739 char *onam_p, *mnam_p, monbuf[BUFSZ];
741 mnam_p = mon_nam(u.ustuck);
742 /* doname can call s_suffix, reusing its buffer */
743 if (digests(u.ustuck->data)) {
744 Sprintf(monbuf, "%s %s", s_suffix(mnam_p),
745 mbodypart(u.ustuck, STOMACH));
746 mnam_p = monbuf;
748 onam_p = is_unpaid(obj) ? yobjnam(obj, (char *) 0) : doname(obj);
750 You("drop %s into %s.", onam_p, mnam_p);
752 } else {
753 if ((obj->oclass == RING_CLASS || obj->otyp == MEAT_RING)
754 && IS_SINK(levl[u.ux][u.uy].typ)) {
755 dosinkring(obj);
756 return ECMD_TIME;
758 if (!can_reach_floor(TRUE)) {
759 /* we might be levitating due to #invoke Heart of Ahriman;
760 if so, levitation would end during call to freeinv()
761 and we want hitfloor() to happen before float_down() */
762 boolean levhack = finesse_ahriman(obj);
764 if (levhack)
765 ELevitation = W_ART; /* other than W_ARTI */
766 if (flags.verbose)
767 You("drop %s.", doname(obj));
768 freeinv(obj);
769 hitfloor(obj, TRUE);
770 if (levhack)
771 float_down(I_SPECIAL | TIMEOUT, W_ARTI | W_ART);
772 return ECMD_TIME;
774 if (!IS_ALTAR(levl[u.ux][u.uy].typ) && flags.verbose)
775 You("drop %s.", doname(obj));
777 obj->how_lost = LOST_DROPPED;
778 dropx(obj);
779 return ECMD_TIME;
782 /* dropx - take dropped item out of inventory;
783 called in several places - may produce output
784 (eg ship_object() and dropy() -> sellobj() both produce output) */
785 void
786 dropx(struct obj *obj)
788 freeinv(obj);
789 if (!u.uswallow) {
790 if (ship_object(obj, u.ux, u.uy, FALSE))
791 return;
792 if (IS_ALTAR(levl[u.ux][u.uy].typ))
793 doaltarobj(obj); /* set bknown */
795 dropy(obj);
798 /* dropy - put dropped object at destination; called from lots of places */
799 void
800 dropy(struct obj *obj)
802 dropz(obj, FALSE);
805 /* dropz - really put dropped object at its destination... */
806 void
807 dropz(struct obj *obj, boolean with_impact)
809 if (obj == uwep)
810 setuwep((struct obj *) 0);
811 if (obj == uquiver)
812 setuqwep((struct obj *) 0);
813 if (obj == uswapwep)
814 setuswapwep((struct obj *) 0);
816 if (u.uswallow) {
817 /* hero has dropped an item while inside an engulfer */
818 if (obj != uball) { /* mon doesn't pick up ball */
819 /* moving shop item into engulfer's inventory treated as theft */
820 if (is_unpaid(obj))
821 (void) stolen_value(obj, u.ux, u.uy, TRUE, FALSE);
822 /* add to engulfer's inventory if not immediately eaten */
823 if (!engulfer_digests_food(obj))
824 (void) mpickobj(u.ustuck, obj);
826 } else {
827 if (flooreffects(obj, u.ux, u.uy, "drop"))
828 return;
829 place_object(obj, u.ux, u.uy);
830 if (with_impact)
831 container_impact_dmg(obj, u.ux, u.uy);
832 impact_disturbs_zombies(obj, with_impact);
833 if (obj == uball)
834 drop_ball(u.ux, u.uy);
835 else if (svl.level.flags.has_shop)
836 sellobj(obj, u.ux, u.uy);
837 stackobj(obj);
838 if (Blind && Levitation)
839 map_object(obj, 0);
840 newsym(u.ux, u.uy); /* remap location under self */
842 (void) encumber_msg();
845 /* when swallowed, move dropped object from OBJ_FREE to u.ustuck's inventory;
846 for purple worm, immediately eat any corpse, glob, or special meat item
847 from object polymorph; return True if object is used up, False otherwise */
848 staticfn boolean
849 engulfer_digests_food(struct obj *obj)
851 /* animal swallower (purple worn) eats any
852 corpse, glob, or meat <item> but not other types of food */
853 if (digests(u.ustuck->data)
854 && (obj->otyp == CORPSE || obj->globby
855 || obj->otyp == MEATBALL || obj->otyp == ENORMOUS_MEATBALL
856 || obj->otyp == MEAT_RING || obj->otyp == MEAT_STICK)) {
857 boolean could_petrify = FALSE,
858 could_poly = FALSE, could_slime = FALSE,
859 could_grow = FALSE, could_heal = FALSE;
861 if (obj->otyp == CORPSE) {
862 could_petrify = touch_petrifies(&mons[obj->corpsenm]);
863 could_poly = polyfood(obj);
864 could_grow = (obj->corpsenm == PM_WRAITH);
865 could_heal = (obj->corpsenm == PM_NURSE);
866 } else if (obj->otyp == GLOB_OF_GREEN_SLIME) {
867 could_slime = TRUE;
869 /* see or feel the effect */
870 pline("%s instantly digested!", Tobjnam(obj, "are"));
872 if (could_poly || could_slime) {
873 (void) newcham(u.ustuck, could_slime ? &mons[PM_GREEN_SLIME] : 0,
874 could_slime ? NC_SHOW_MSG : NO_NC_FLAGS);
875 } else if (could_petrify) {
876 minstapetrify(u.ustuck, TRUE);
877 } else if (could_grow) {
878 (void) grow_up(u.ustuck, (struct monst *) 0);
879 } else if (could_heal) {
880 healmon(u.ustuck, u.ustuck->mhpmax, 0);
881 /* False: don't realize that sight is cured from inside */
882 mcureblindness(u.ustuck, FALSE);
884 delobj(obj); /* always used up */
885 return TRUE;
887 return FALSE;
890 /* things that must change when not held; recurse into containers.
891 Called for both player and monsters */
892 void
893 obj_no_longer_held(struct obj *obj)
895 if (!obj) {
896 return;
897 } else if (Has_contents(obj)) {
898 struct obj *contents;
900 for (contents = obj->cobj; contents; contents = contents->nobj)
901 obj_no_longer_held(contents);
903 switch (obj->otyp) {
904 case CRYSKNIFE:
905 /* Normal crysknife reverts to worm tooth when not held by hero
906 * or monster; fixed crysknife has only 10% chance of reverting.
907 * When a stack of the latter is involved, it could be worthwhile
908 * to give each individual crysknife its own separate 10% chance,
909 * but we aren't in any position to handle stack splitting here.
911 if (!obj->oerodeproof || !rn2(10)) {
912 /* if monsters aren't moving, assume player is responsible */
913 if (!svc.context.mon_moving && !program_state.gameover)
914 costly_alteration(obj, COST_DEGRD);
915 obj->otyp = WORM_TOOTH;
916 obj->oerodeproof = 0;
918 break;
922 /* the #droptype command: drop several things */
924 doddrop(void)
926 int result = ECMD_OK;
928 if (!gi.invent) {
929 You("have nothing to drop.");
930 return ECMD_OK;
932 add_valid_menu_class(0); /* clear any classes already there */
933 if (*u.ushops)
934 sellobj_state(SELL_DELIBERATE);
935 if (flags.menu_style != MENU_TRADITIONAL
936 || (result = ggetobj("drop", drop, 0, FALSE, (unsigned *) 0)) < -1)
937 result = menu_drop(result);
938 if (*u.ushops)
939 sellobj_state(SELL_NORMAL);
940 if (result)
941 reset_occupations();
943 return result;
946 staticfn boolean
947 better_not_try_to_drop_that(struct obj *otmp)
949 char buf[BUFSZ];
951 /* u_safe_from_fatal_corpse() with st_all checks for gloves and stoning
952 * resistance before bothering to prompt you.
954 if (otmp->otyp == CORPSE && !u_safe_from_fatal_corpse(otmp, st_all)) {
955 Snprintf(
956 buf, sizeof buf,
957 "Drop the %s corpse without %s protection on?",
958 obj_pmname(otmp), body_part(HAND));
959 return (paranoid_ynq(TRUE, buf, FALSE) != 'y');
961 return FALSE;
963 staticfn int /* check callers */
964 menudrop_split(struct obj *otmp, long cnt)
966 if (cnt && cnt < otmp->quan) {
967 if (welded(otmp)) {
968 ; /* don't split */
969 } else if (otmp->otyp == LOADSTONE && otmp->cursed) {
970 /* same kludge as getobj(), for canletgo()'s use */
971 otmp->corpsenm = (int) cnt; /* don't split */
972 } else {
973 otmp = splitobj(otmp, cnt);
976 return drop(otmp);
979 /* Drop things from the hero's inventory, using a menu. */
980 staticfn int
981 menu_drop(int retry)
983 int n, i, n_dropped = 0;
984 struct obj *otmp, *otmp2;
985 menu_item *pick_list;
986 boolean all_categories = TRUE, drop_everything = FALSE, autopick = FALSE;
987 boolean drop_justpicked = FALSE;
988 long justpicked_quan = 0;
990 if (retry) {
991 all_categories = (retry == -2);
992 } else if (flags.menu_style == MENU_FULL) {
993 all_categories = FALSE;
994 n = query_category("Drop what type of items?", gi.invent,
995 (UNPAID_TYPES | ALL_TYPES | CHOOSE_ALL
996 | BUC_BLESSED | BUC_CURSED | BUC_UNCURSED
997 | BUC_UNKNOWN | JUSTPICKED | INCLUDE_VENOM),
998 &pick_list, PICK_ANY);
999 /* when paranoid_confirm:A is set, 'A' by itself implies
1000 'A'+'a' which will be followed by a confirmation prompt;
1001 when that option isn't set, 'A' by itself is rejected
1002 by query_categorry() and result here will be n==0 */
1003 if (!n)
1004 goto drop_done; /* no non-autopick category filters specified */
1006 for (i = 0; i < n; i++) {
1007 if (pick_list[i].item.a_int == ALL_TYPES_SELECTED) {
1008 all_categories = TRUE;
1009 } else if (pick_list[i].item.a_int == 'A') {
1010 drop_everything = autopick = TRUE;
1011 } else if (pick_list[i].item.a_int == 'P') {
1012 justpicked_quan = max(0, pick_list[i].count);
1013 drop_justpicked = TRUE;
1014 drop_everything = FALSE;
1015 add_valid_menu_class(pick_list[i].item.a_int);
1016 } else {
1017 add_valid_menu_class(pick_list[i].item.a_int);
1018 drop_everything = FALSE;
1021 free((genericptr_t) pick_list);
1022 } else if (flags.menu_style == MENU_COMBINATION) {
1023 unsigned ggoresults = 0;
1025 all_categories = FALSE;
1026 /* Gather valid classes via traditional NetHack method */
1027 i = ggetobj("drop", drop, 0, TRUE, &ggoresults);
1028 if (i == -2)
1029 all_categories = TRUE;
1030 if ((ggoresults & ALL_FINISHED) != 0) {
1031 n_dropped = i;
1032 goto drop_done;
1036 if (autopick) {
1038 * Dropping a burning potion of oil while levitating can cause
1039 * an explosion which might destroy some of hero's inventory,
1040 * so the old code
1041 * for (otmp = gi.invent; otmp; otmp = otmp2) {
1042 * otmp2 = otmp->nobj;
1043 * n_dropped += drop(otmp);
1045 * was unreliable and could lead to an "object lost" panic.
1047 * Use the bypass bit to mark items already processed (hence
1048 * not droppable) and rescan inventory until no unbypassed
1049 * items remain.
1051 * FIXME? if something explodes, or even breaks, we probably
1052 * ought to halt the traversal or perhaps ask player whether
1053 * to halt it.
1055 bypass_objlist(gi.invent, FALSE); /* clear bypass bit for invent */
1056 while ((otmp = nxt_unbypassed_obj(gi.invent)) != 0) {
1057 if (drop_everything || all_categories || allow_category(otmp))
1058 n_dropped += ((drop(otmp) & ECMD_TIME) != 0) ? 1 : 0;
1060 /* we might not have dropped everything (worn armor, welded weapon,
1061 cursed loadstones), so reset any remaining inventory to normal */
1062 bypass_objlist(gi.invent, FALSE);
1063 } else if (drop_justpicked && count_justpicked(gi.invent) == 1) {
1064 /* drop the just picked item automatically, if only one stack */
1065 otmp = find_justpicked(gi.invent);
1066 if (otmp)
1067 n_dropped += ((menudrop_split(otmp, justpicked_quan)
1068 & ECMD_TIME) != 0) ? 1 : 0;
1069 } else {
1070 /* should coordinate with perm invent, maybe not show worn items */
1071 n = query_objlist("What would you like to drop?", &gi.invent,
1072 (USE_INVLET | INVORDER_SORT | INCLUDE_VENOM),
1073 &pick_list, PICK_ANY,
1074 all_categories ? allow_all : allow_category);
1075 if (n > 0) {
1077 * picklist[] contains a set of pointers into inventory, but
1078 * as soon as something gets dropped, they might become stale
1079 * (see the autopick code above for an explanation).
1080 * Just checking to see whether one is still in the gi.invent
1081 * chain is not sufficient validation since destroyed items
1082 * will be freed and items we've split here might have already
1083 * reused that memory and put the same pointer value back into
1084 * gi.invent. Ditto for using invlet to validate. So we start
1085 * by setting bypass on all of gi.invent, then check each pointer
1086 * to verify that it is in gi.invent and has that bit set.
1088 bypass_objlist(gi.invent, TRUE);
1089 for (i = 0; i < n; i++) {
1090 otmp = pick_list[i].item.a_obj;
1091 for (otmp2 = gi.invent; otmp2; otmp2 = otmp2->nobj)
1092 if (otmp2 == otmp)
1093 break;
1094 if (!otmp2 || !otmp2->bypass)
1095 continue;
1096 /* found next selected invent item */
1097 n_dropped += ((menudrop_split(otmp, pick_list[i].count)
1098 & ECMD_TIME) != 0) ? 1 : 0;
1100 bypass_objlist(gi.invent, FALSE); /* reset gi.invent to normal */
1101 free((genericptr_t) pick_list);
1105 drop_done:
1106 return (n_dropped ? ECMD_TIME : ECMD_OK);
1109 staticfn boolean
1110 u_stuck_cannot_go(const char *updn)
1112 if (u.ustuck) {
1113 if (u.uswallow || !sticks(gy.youmonst.data)) {
1114 You("are %s, and cannot go %s.",
1115 !u.uswallow ? "being held"
1116 : digests(u.ustuck->data) ? "swallowed"
1117 : "engulfed", updn);
1118 return TRUE;
1119 } else {
1120 struct monst *mtmp = u.ustuck;
1122 set_ustuck((struct monst *) 0);
1123 You("release %s.", mon_nam(mtmp));
1126 return FALSE;
1129 /* the #down command */
1131 dodown(void)
1133 struct trap *trap = 0;
1134 stairway *stway;
1135 boolean stairs_down, ladder_down;
1137 set_move_cmd(DIR_DOWN, 0);
1139 if (u_rooted())
1140 return ECMD_TIME;
1142 if (stucksteed(TRUE)) {
1143 return ECMD_OK;
1146 stairs_down = ladder_down = FALSE;
1147 if ((stway = stairway_at(u.ux, u.uy)) != 0 && !stway->up) {
1148 stairs_down = !stway->isladder;
1149 ladder_down = !stairs_down;
1152 /* Levitation might be blocked, but player can still use '>' to
1153 turn off controlled levitation */
1154 if (HLevitation || ELevitation) {
1155 if ((HLevitation & I_SPECIAL) || (ELevitation & W_ARTI)) {
1156 /* end controlled levitation */
1157 if (ELevitation & W_ARTI) {
1158 struct obj *obj;
1160 for (obj = gi.invent; obj; obj = obj->nobj) {
1161 if (obj->oartifact
1162 && artifact_has_invprop(obj, LEVITATION)) {
1163 if (obj->age < svm.moves)
1164 obj->age = svm.moves;
1165 obj->age += rnz(100);
1169 if (float_down(I_SPECIAL | TIMEOUT, W_ARTI)) {
1170 return ECMD_TIME; /* came down, so moved */
1171 } else if (!HLevitation && !ELevitation) {
1172 Your("latent levitation ceases.");
1173 return ECMD_TIME; /* did something, effectively moved */
1176 if (BLevitation) {
1177 ; /* weren't actually floating after all */
1178 } else if (Blind) {
1179 /* glyph_to_cmap() is a macro which expands its argument many
1180 times; use this to do part of its work just once */
1181 int glyph_at_uxuy = levl[u.ux][u.uy].glyph;
1183 /* Avoid alerting player to an unknown stair or ladder.
1184 * Changes the message for a covered, known staircase
1185 * too; staircase knowledge is not stored anywhere.
1187 if (stairs_down)
1188 stairs_down = (glyph_to_cmap(glyph_at_uxuy) == S_dnstair);
1189 else if (ladder_down)
1190 ladder_down = (glyph_to_cmap(glyph_at_uxuy) == S_dnladder);
1192 if (Is_airlevel(&u.uz))
1193 You("are floating in the %s.", surface(u.ux, u.uy));
1194 else if (Is_waterlevel(&u.uz))
1195 You("are floating in %s.",
1196 is_pool(u.ux, u.uy) ? "the water" : "a bubble of air");
1197 else
1198 floating_above(stairs_down ? "stairs"
1199 : ladder_down ? "ladder"
1200 : surface(u.ux, u.uy));
1201 return ECMD_OK; /* didn't move */
1204 if (Upolyd && ceiling_hider(&mons[u.umonnum]) && u.uundetected) {
1205 u.uundetected = 0;
1206 if (Flying) { /* lurker above */
1207 You("fly out of hiding.");
1208 } else { /* piercer */
1209 You("drop to the %s.", surface(u.ux, u.uy));
1210 if (is_pool_or_lava(u.ux, u.uy)) {
1211 pooleffects(FALSE);
1212 } else {
1213 (void) pickup(1);
1214 if ((trap = t_at(u.ux, u.uy)) != 0)
1215 dotrap(trap, TOOKPLUNGE);
1218 return ECMD_TIME; /* came out of hiding; need '>' again to go down */
1221 if (u_stuck_cannot_go("down"))
1222 return ECMD_TIME;
1224 if (!stairs_down && !ladder_down) {
1225 trap = t_at(u.ux, u.uy);
1226 if (trap && (uteetering_at_seen_pit(trap) || uescaped_shaft(trap))) {
1227 dotrap(trap, TOOKPLUNGE);
1228 return ECMD_TIME;
1229 } else if (!trap || !is_hole(trap->ttyp)
1230 || !Can_fall_thru(&u.uz) || !trap->tseen) {
1231 if (flags.autodig && !svc.context.nopick
1232 && uwep && is_pick(uwep)) {
1233 return use_pick_axe2(uwep);
1234 } else {
1235 You_cant("go down here%s.",
1236 (trap && trap->ttyp == VIBRATING_SQUARE) ? " yet"
1237 : "");
1238 return ECMD_OK;
1242 if (on_level(&valley_level, &u.uz) && !u.uevent.gehennom_entered) {
1243 You("are standing at the gate to Gehennom.");
1244 pline("Unspeakable cruelty and harm lurk down there.");
1245 if (y_n("Are you sure you want to enter?") != 'y')
1246 return ECMD_OK;
1247 pline("So be it.");
1248 u.uevent.gehennom_entered = 1; /* don't ask again */
1251 if (!next_to_u()) {
1252 You("are held back by your pet!");
1253 return ECMD_OK;
1256 if (trap) {
1257 const char *down_or_thru = trap->ttyp == HOLE ? "down" : "through";
1258 const char *actn = u_locomotion("jump");
1260 if (gy.youmonst.data->msize >= MZ_HUGE) {
1261 char qbuf[QBUFSZ];
1263 You("don't fit %s easily.", down_or_thru);
1264 Sprintf(qbuf, "Try to squeeze %s?", down_or_thru);
1265 if (y_n(qbuf) == 'y') {
1266 if (!rn2(3)) {
1267 actn = "manage to squeeze";
1268 losehp(Maybe_Half_Phys(rnd(4)),
1269 "contusion from a small passage", KILLED_BY);
1270 } else {
1271 You("were unable to fit %s.", down_or_thru);
1272 return ECMD_OK;
1274 } else {
1275 return ECMD_OK;
1278 You("%s %s the %s.", actn, down_or_thru,
1279 trap->ttyp == HOLE ? "hole" : "trap door");
1281 if (trap && Is_stronghold(&u.uz)) {
1282 goto_hell(FALSE, TRUE);
1283 } else if (trap && trap->dst.dlevel != -1) {
1284 d_level tdst;
1285 assign_level(&tdst, &(trap->dst));
1286 (void) clamp_hole_destination(&tdst);
1287 goto_level(&tdst, FALSE, FALSE, FALSE);
1288 } else {
1289 ga.at_ladder = (boolean) (levl[u.ux][u.uy].typ == LADDER);
1290 next_level(!trap);
1291 ga.at_ladder = FALSE;
1293 return ECMD_TIME;
1296 /* the #up command - move up a staircase */
1298 doup(void)
1300 stairway *stway = stairway_at(u.ux,u.uy);
1302 set_move_cmd(DIR_UP, 0);
1304 if (u_rooted())
1305 return ECMD_TIME;
1307 /* "up" to get out of a pit... */
1308 if (u.utrap && u.utraptype == TT_PIT) {
1309 climb_pit();
1310 return ECMD_TIME;
1313 if (!stway || (stway && !stway->up)) {
1314 You_cant("go up here.");
1315 return ECMD_OK;
1317 if (stucksteed(TRUE)) {
1318 return ECMD_OK;
1321 if (u_stuck_cannot_go("up"))
1322 return ECMD_TIME;
1324 if (near_capacity() > SLT_ENCUMBER) {
1325 /* No levitation check; inv_weight() already allows for it */
1326 Your("load is too heavy to climb the %s.",
1327 levl[u.ux][u.uy].typ == STAIRS ? "stairs" : "ladder");
1328 return ECMD_TIME;
1330 if (ledger_no(&u.uz) == 1) {
1331 if (iflags.debug_fuzzer)
1332 return ECMD_OK;
1333 if (y_n("Beware, there will be no return! Still climb?") != 'y')
1334 return ECMD_OK;
1336 if (!next_to_u()) {
1337 You("are held back by your pet!");
1338 return ECMD_OK;
1340 ga.at_ladder = (boolean) (levl[u.ux][u.uy].typ == LADDER);
1341 prev_level(TRUE);
1342 ga.at_ladder = FALSE;
1343 return ECMD_TIME;
1346 /* check that we can write out the current level */
1347 staticfn NHFILE *
1348 currentlevel_rewrite(void)
1350 NHFILE *nhfp;
1351 char whynot[BUFSZ];
1353 /* since level change might be a bit slow, flush any buffered screen
1354 * output (like "you fall through a trap door") */
1355 mark_synch();
1357 nhfp = create_levelfile(ledger_no(&u.uz), whynot);
1358 if (!nhfp) {
1360 * This is not quite impossible: e.g., we may have
1361 * exceeded our quota. If that is the case then we
1362 * cannot leave this level, and cannot save either.
1363 * Another possibility is that the directory was not
1364 * writable.
1366 pline1(whynot);
1367 return (NHFILE *) 0;
1370 return nhfp;
1373 #ifdef INSURANCE
1374 void
1375 save_currentstate(void)
1377 NHFILE *nhfp;
1379 program_state.in_checkpoint++;
1380 if (flags.ins_chkpt) {
1381 /* write out just-attained level, with pets and everything */
1382 nhfp = currentlevel_rewrite();
1383 if (!nhfp)
1384 return;
1385 if (nhfp->structlevel)
1386 bufon(nhfp->fd);
1387 nhfp->mode = WRITING;
1388 savelev(nhfp,ledger_no(&u.uz));
1389 close_nhfile(nhfp);
1392 /* write out non-level state */
1393 savestateinlock();
1394 program_state.in_checkpoint--;
1396 #endif
1399 static boolean
1400 badspot(coordxy x, coordxy y)
1402 return (boolean) ((levl[x][y].typ != ROOM
1403 && levl[x][y].typ != AIR
1404 && levl[x][y].typ != CORR)
1405 || MON_AT(x, y));
1409 /* when arriving on a level, if hero and a monster are trying to share same
1410 spot, move one; extracted from goto_level(); also used by wiz_makemap() */
1411 void
1412 u_collide_m(struct monst *mtmp)
1414 coord cc;
1416 if (!mtmp || mtmp == u.usteed || mtmp != m_at(u.ux, u.uy)) {
1417 impossible("level arrival collision: %s?",
1418 !mtmp ? "no monster"
1419 : (mtmp == u.usteed) ? "steed is on map"
1420 : "monster not co-located");
1421 return;
1424 /* There's a monster at your target destination; it might be one
1425 which accompanied you--see mon_arrive(dogmove.c)--or perhaps
1426 it was already here. Randomly move you to an adjacent spot
1427 or else the monster to any nearby location. Prior to 3.3.0
1428 the latter was done unconditionally. */
1429 if (!rn2(2) && enexto(&cc, u.ux, u.uy, gy.youmonst.data)
1430 && next2u(cc.x, cc.y))
1431 u_on_newpos(cc.x, cc.y); /*[maybe give message here?]*/
1432 else
1433 mnexto(mtmp, RLOC_NOMSG);
1435 if ((mtmp = m_at(u.ux, u.uy)) != 0) {
1436 /* there was an unconditional impossible("mnexto failed")
1437 here, but it's not impossible and we're prepared to cope
1438 with the situation, so only say something when debugging */
1439 if (wizard)
1440 pline("(monster in hero's way)");
1441 if (!rloc(mtmp, RLOC_NOMSG) || (mtmp = m_at(u.ux, u.uy)) != 0)
1442 /* no room to move it; send it away, to return later */
1443 m_into_limbo(mtmp);
1447 staticfn void
1448 familiar_level_msg(void)
1450 static const char *const fam_msgs[4] = {
1451 "You have a sense of deja vu.",
1452 "You feel like you've been here before.",
1453 "This place %s familiar...", 0 /* no message */
1455 static const char *const halu_fam_msgs[4] = {
1456 "Whoa! Everything %s different.",
1457 "You are surrounded by twisty little passages, all alike.",
1458 "Gee, this %s like uncle Conan's place...", 0 /* no message */
1460 const char *mesg;
1461 char buf[BUFSZ];
1462 int which = rn2(4);
1464 if (Hallucination)
1465 mesg = halu_fam_msgs[which];
1466 else
1467 mesg = fam_msgs[which];
1468 if (mesg && strchr(mesg, '%')) {
1469 DISABLE_WARNING_FORMAT_NONLITERAL
1470 Sprintf(buf, mesg, !Blind ? "looks" : "seems");
1471 RESTORE_WARNING_FORMAT_NONLITERAL
1472 mesg = buf;
1474 if (mesg)
1475 pline1(mesg);
1478 void
1479 goto_level(
1480 d_level *newlevel, /* destination */
1481 boolean at_stairs, /* True if arriving via stairs/ladder */
1482 boolean falling, /* when falling to level, objects might tag along */
1483 boolean portal) /* True if arriving via magic portal */
1485 int l_idx, save_mode;
1486 NHFILE *nhfp;
1487 xint16 new_ledger;
1488 boolean cant_go_back, great_effort,
1489 up = (depth(newlevel) < depth(&u.uz)),
1490 newdungeon = (u.uz.dnum != newlevel->dnum),
1491 leaving_tutorial = FALSE,
1492 was_in_W_tower = In_W_tower(u.ux, u.uy, &u.uz),
1493 familiar = FALSE,
1494 new = FALSE; /* made a new level? */
1495 struct monst *mtmp;
1496 char whynot[BUFSZ];
1497 int dist = depth(newlevel) - depth(&u.uz);
1498 boolean do_fall_dmg = FALSE;
1499 schar prev_temperature = svl.level.flags.temperature;
1501 if (dunlev(newlevel) > dunlevs_in_dungeon(newlevel))
1502 newlevel->dlevel = dunlevs_in_dungeon(newlevel);
1503 if (newdungeon) {
1504 if (In_endgame(newlevel)) { /* 1st Endgame Level !!! */
1505 if (!u.uhave.amulet)
1506 return; /* must have the Amulet */
1507 if (!wizard) /* wizard ^V can bypass Earth level */
1508 assign_level(newlevel, &earth_level); /* (redundant) */
1509 } else if (In_tutorial(newlevel)) {
1510 tutorial(TRUE); /* entering tutorial */
1511 } else if (In_tutorial(&u.uz)) {
1512 tutorial(FALSE); /* leaving tutorial */
1513 up = FALSE; /* re-enter level 1 as if starting new game */
1514 leaving_tutorial = TRUE;
1517 new_ledger = ledger_no(newlevel);
1518 if (new_ledger <= 0)
1519 done(ESCAPED); /* in fact < 0 is impossible */
1521 /* If you have the amulet and are trying to get out of Gehennom,
1522 * going up a set of stairs sometimes does some very strange things!
1523 * Biased against law and towards chaos. (The chance to be sent
1524 * down multiple levels when attempting to go up are significantly
1525 * less than the corresponding comment in older versions indicated
1526 * due to overlooking the effect of the call to assign_rnd_lvl().)
1528 * Odds for making it to the next level up, or of being sent down:
1529 * "up" L N C
1530 * +1 75.0 75.0 75.0
1531 * 0 6.25 8.33 12.5
1532 * -1 11.46 12.50 12.5
1533 * -2 5.21 4.17 0.0
1534 * -3 2.08 0.0 0.0
1536 * 3.7.0: the chance for the "mysterious force" to kick in goes down
1537 * as it kicks in, starting at 25% per climb attempt and dropping off
1538 * gradually but substantially. The drop off is greater when hero is
1539 * sent down farther so benefits lawfuls more than chaotics this time.
1541 if (Inhell && up && u.uhave.amulet && !newdungeon && !portal
1542 && (dunlev(&u.uz) < dunlevs_in_dungeon(&u.uz) - 3)) {
1543 if (!rn2(4 + svc.context.mysteryforce)) {
1544 int odds = 3 + (int) u.ualign.type, /* 2..4 */
1545 diff = (odds <= 1) ? 0 : rn2(odds); /* paranoia */
1547 if (diff != 0) {
1548 assign_rnd_level(newlevel, &u.uz, diff);
1549 /* assign_rnd_level() may have used a value less than diff */
1550 diff = newlevel->dlevel - u.uz.dlevel; /* actual descent */
1551 /* if inside the tower, stay inside */
1552 if (was_in_W_tower && !On_W_tower_level(newlevel))
1553 diff = 0;
1555 if (diff == 0)
1556 assign_level(newlevel, &u.uz);
1558 pline("A mysterious force momentarily surrounds you...");
1559 /* each time it kicks in, the chance of doing so again may drop;
1560 that drops faster, on average, when being sent down farther so
1561 while the impact is reduced for everybody compared to earlier
1562 versions, it is reduced least for chaotics, most for lawfuls */
1563 svc.context.mysteryforce += rn2(diff + 2); /* L:0-4,N:0-3,C:0-2 */
1565 if (on_level(newlevel, &u.uz)) {
1566 (void) safe_teleds(TELEDS_NO_FLAGS);
1567 (void) next_to_u();
1568 return;
1570 new_ledger = ledger_no(newlevel);
1571 at_stairs = ga.at_ladder = FALSE;
1575 /* Prevent the player from going past the first quest level unless
1576 * (s)he has been given the go-ahead by the leader.
1578 if (on_level(&u.uz, &qstart_level) && !newdungeon && !ok_to_quest()) {
1579 pline("A mysterious force prevents you from descending.");
1580 return;
1583 if (on_level(newlevel, &u.uz))
1584 return; /* this can happen */
1586 if (gl.luacore && nhcb_counts[NHCB_LVL_LEAVE]) {
1587 lua_getglobal(gl.luacore, "nh_callback_run");
1588 lua_pushstring(gl.luacore, nhcb_name[NHCB_LVL_LEAVE]);
1589 nhl_pcall_handle(gl.luacore, 1, 0, "goto_level", NHLpa_panic);
1590 lua_settop(gl.luacore, 0);
1593 /* tethered movement makes level change while trapped feasible */
1594 if (u.utrap && u.utraptype == TT_BURIEDBALL)
1595 buried_ball_to_punishment(); /* (before we save/leave old level) */
1597 nhfp = currentlevel_rewrite();
1598 if (!nhfp)
1599 return;
1601 /* discard context which applies to the level we're leaving;
1602 for lock-picking, container may be carried, in which case we
1603 keep context; if on the floor, it's about to be saved+freed and
1604 maybe_reset_pick() needs to do its carried() check before that */
1605 maybe_reset_pick((struct obj *) 0);
1606 reset_trapset(); /* even if to-be-armed trap obj is accompanying hero */
1607 iflags.travelcc.x = iflags.travelcc.y = 0; /* travel destination cache */
1608 svc.context.polearm.hitmon = (struct monst *) 0; /* polearm target */
1609 /* digging context is level-aware and can actually be resumed if
1610 hero returns to the previous level without any intervening dig */
1612 if (falling) /* assuming this is only trap door or hole */
1613 impact_drop((struct obj *) 0, u.ux, u.uy, newlevel->dlevel);
1615 check_special_room(TRUE); /* probably was a trap door */
1616 if (Punished)
1617 unplacebc();
1618 reset_utrap(FALSE); /* needed in level_tele */
1619 fill_pit(u.ux, u.uy);
1620 set_ustuck((struct monst *) 0); /* clear u.ustuck and u.uswallow */
1621 set_uinwater(0); /* u.uinwater = 0 */
1622 u.uundetected = 0; /* not hidden, even if means are available */
1623 if (!iflags.nofollowers)
1624 keepdogs(FALSE);
1625 recalc_mapseen(); /* recalculate map overview before we leave the level */
1627 * We no longer see anything on the level. Make sure that this
1628 * follows u.uswallow set to null since uswallow overrides all
1629 * normal vision.
1631 vision_recalc(2);
1634 * Save the level we're leaving. If we're entering the endgame,
1635 * we can get rid of all existing levels because they cannot be
1636 * reached any more. We still need to use savelev()'s cleanup
1637 * for the level being left, to recover dynamic memory in use and
1638 * to avoid dangling timers and light sources.
1640 cant_go_back = ((newdungeon && In_endgame(newlevel)) || leaving_tutorial);
1641 if (!cant_go_back) {
1642 update_mlstmv(); /* current monsters are becoming inactive */
1643 if (nhfp->structlevel)
1644 bufon(nhfp->fd); /* use buffered output */
1645 } else {
1646 free_luathemes(leaving_tutorial ? tut_themes : most_themes);
1648 save_mode = nhfp->mode;
1649 nhfp->mode = cant_go_back ? FREEING : (WRITING | FREEING);
1650 savelev(nhfp, ledger_no(&u.uz));
1651 nhfp->mode = save_mode;
1652 close_nhfile(nhfp);
1653 if (cant_go_back) {
1654 /* discard unreachable levels; keep #0 */
1655 for (l_idx = maxledgerno(); l_idx > 0; --l_idx)
1656 if (!leaving_tutorial || ledger_to_dnum(l_idx) == tutorial_dnum)
1657 delete_levelfile(l_idx);
1658 /* mark #overview data for all dungeon branches as uninteresting */
1659 for (l_idx = 0; l_idx < svn.n_dgns; ++l_idx)
1660 if (!leaving_tutorial || l_idx == tutorial_dnum)
1661 remdun_mapseen(l_idx);
1662 /* get rid of mons & objs scheduled to migrate to discarded levels */
1663 discard_migrations();
1666 if (Is_rogue_level(newlevel) || Is_rogue_level(&u.uz))
1667 assign_graphics(Is_rogue_level(newlevel) ? ROGUESET : PRIMARYSET);
1668 check_gold_symbol();
1669 /* record this level transition as a potential seen branch unless using
1670 * some non-standard means of transportation (level teleport).
1672 if ((at_stairs || falling || portal) && (u.uz.dnum != newlevel->dnum))
1673 recbranch_mapseen(&u.uz, newlevel);
1674 assign_level(&u.uz0, &u.uz);
1675 assign_level(&u.uz, newlevel);
1676 assign_level(&u.utolev, newlevel);
1677 u.utotype = UTOTYPE_NONE;
1678 if (!builds_up(&u.uz)) { /* usual case */
1679 if (dunlev(&u.uz) > dunlev_reached(&u.uz))
1680 dunlev_reached(&u.uz) = dunlev(&u.uz);
1681 } else {
1682 if (dunlev_reached(&u.uz) == 0
1683 || dunlev(&u.uz) < dunlev_reached(&u.uz))
1684 dunlev_reached(&u.uz) = dunlev(&u.uz);
1687 stairway_free_all();
1688 /* set default level change destination areas */
1689 /* the special level code may override these */
1690 (void) memset((genericptr_t) &svu.updest, 0, sizeof svu.updest);
1691 (void) memset((genericptr_t) &svd.dndest, 0, sizeof svd.dndest);
1693 if (!(svl.level_info[new_ledger].flags & LFILE_EXISTS)) {
1694 /* entering this level for first time; make it now */
1695 if (svl.level_info[new_ledger].flags & (VISITED)) {
1696 impossible("goto_level: returning to discarded level?");
1697 svl.level_info[new_ledger].flags &= ~(VISITED);
1699 mklev();
1700 new = TRUE; /* made the level */
1701 familiar = bones_include_name(svp.plname);
1702 } else {
1703 /* returning to previously visited level; reload it */
1704 nhfp = open_levelfile(new_ledger, whynot);
1705 if (tricked_fileremoved(nhfp, whynot)) {
1706 /* we'll reach here if running in wizard mode */
1707 error("Cannot continue this game.");
1709 reseed_random(rn2);
1710 reseed_random(rn2_on_display_rng);
1711 minit(); /* ZEROCOMP */
1712 getlev(nhfp, svh.hackpid, new_ledger);
1713 close_nhfile(nhfp);
1714 oinit(); /* reassign level dependent obj probabilities */
1716 reglyph_darkroom();
1717 set_uinwater(0); /* u.uinwater = 0 */
1718 /* do this prior to level-change pline messages */
1719 vision_reset(); /* clear old level's line-of-sight */
1720 gv.vision_full_recalc = 0; /* don't let that reenable vision yet */
1721 flush_screen(-1); /* ensure all map flushes are postponed */
1723 if (portal && !In_endgame(&u.uz)) {
1724 /* find the portal on the new level */
1725 struct trap *ttrap;
1727 for (ttrap = gf.ftrap; ttrap; ttrap = ttrap->ntrap)
1728 if (ttrap->ttyp == MAGIC_PORTAL)
1729 break;
1731 if (!ttrap) {
1732 if (u.uevent.qexpelled
1733 && (Is_qstart(&u.uz0) || Is_qstart(&u.uz))) {
1734 /* we're coming back from or going into the quest home level,
1735 after already getting expelled once. The portal back
1736 doesn't exist anymore - see expulsion(). */
1737 u_on_rndspot(0);
1738 } else {
1739 if (!iflags.debug_fuzzer)
1740 impossible("goto_level: no corresponding portal!");
1741 u_on_rndspot(0);
1743 } else {
1744 seetrap(ttrap);
1745 u_on_newpos(ttrap->tx, ttrap->ty);
1747 } else if (at_stairs && !In_endgame(&u.uz)) {
1748 if (up) {
1749 stairway *stway = stairway_find_from(&u.uz0, ga.at_ladder);
1750 if (stway) {
1751 u_on_newpos(stway->sx, stway->sy);
1752 stway->u_traversed = TRUE;
1753 } else if (newdungeon)
1754 u_on_sstairs(1);
1755 else
1756 u_on_dnstairs();
1757 /* you climb up the {stairs|ladder};
1758 fly up the stairs; fly up along the ladder */
1759 great_effort = (Punished && !Levitation);
1760 if (flags.verbose || great_effort)
1761 pline("%s %s up%s the %s.",
1762 great_effort ? "With great effort, you" : "You",
1763 u_locomotion("climb"),
1764 (Flying && ga.at_ladder) ? " along" : "",
1765 ga.at_ladder ? "ladder" : "stairs");
1766 } else { /* down */
1767 stairway *stway = stairway_find_from(&u.uz0, ga.at_ladder);
1768 if (stway) {
1769 u_on_newpos(stway->sx, stway->sy);
1770 stway->u_traversed = TRUE;
1771 } else if (newdungeon)
1772 u_on_sstairs(0);
1773 else
1774 u_on_upstairs();
1775 if (!u.dz) {
1776 ; /* stayed on same level? (no transit effects) */
1777 } else if (Flying) {
1778 if (flags.verbose)
1779 You("fly down %s.",
1780 ga.at_ladder ? "along the ladder" : "the stairs");
1781 } else if (near_capacity() > UNENCUMBERED
1782 || Punished || Fumbling) {
1783 You("fall down the %s.", ga.at_ladder ? "ladder" : "stairs");
1784 if (Punished) {
1785 drag_down();
1786 if (!welded(uball))
1787 ballrelease(FALSE);
1789 /* falling off steed has its own losehp() call */
1790 if (u.usteed)
1791 dismount_steed(DISMOUNT_FELL);
1792 else
1793 losehp(Maybe_Half_Phys(rnd(3)),
1794 ga.at_ladder ? "falling off a ladder"
1795 : "tumbling down a flight of stairs",
1796 KILLED_BY);
1797 selftouch("Falling, you");
1798 } else { /* ordinary descent */
1799 if (flags.verbose)
1800 You("%s.", ga.at_ladder ? "climb down the ladder"
1801 : "descend the stairs");
1804 } else { /* trap door or level_tele or In_endgame */
1805 u_on_rndspot((up ? 1 : 0) | (was_in_W_tower ? 2 : 0));
1806 if (falling) {
1807 if (Punished && !welded(uball))
1808 ballfall();
1809 selftouch("Falling, you");
1810 do_fall_dmg = TRUE;
1814 if (Punished)
1815 placebc();
1816 obj_delivery(FALSE);
1817 losedogs();
1818 kill_genocided_monsters(); /* for those wiped out while in limbo */
1820 * Expire all timers that have gone off while away. Must be
1821 * after migrating monsters and objects are delivered
1822 * (losedogs and obj_delivery).
1824 run_timers();
1826 /* hero might be arriving at a spot containing a monster;
1827 if so, move one or the other to another location */
1828 if ((mtmp = m_at(u.ux, u.uy)) != 0)
1829 u_collide_m(mtmp);
1831 /* initial movement of bubbles just before vision_recalc */
1832 if (Is_waterlevel(&u.uz) || Is_airlevel(&u.uz))
1833 movebubbles();
1834 else if (svl.level.flags.fumaroles)
1835 fumaroles();
1837 /* Reset the screen. */
1838 vision_reset(); /* reset the blockages */
1839 reset_glyphmap(gm_levelchange);
1840 notice_mon_off(); /* not noticing monsters yet! */
1841 docrt(); /* does a full vision recalc */
1842 flush_screen(-1);
1845 * Move all plines beyond the screen reset.
1848 /* deferred arrival message for level teleport looks odd if given
1849 after the various messages below, so give it before them;
1850 [it might have already been delivered via docrt() -> see_monsters()
1851 -> Sting_effects() -> maybe_lvltport_feedback(), in which case
1852 'dfr_post_msg' has already been reset to Null];
1853 if 'dfr_post_msg' is "you materialize on a different level" then
1854 maybe_lvltport_feedback() will deliver it now and then free it */
1855 if (gd.dfr_post_msg)
1856 maybe_lvltport_feedback(); /* potentially called by Sting_effects() */
1858 /* special levels can have a custom arrival message */
1859 deliver_splev_message();
1861 /* Check whether we just entered Gehennom. */
1862 if (!In_hell(&u.uz0) && Inhell) {
1863 if (Is_valley(&u.uz)) {
1864 You("arrive at the Valley of the Dead...");
1865 pline_The("odor of burnt flesh and decay pervades the air.");
1866 #ifdef MICRO
1867 display_nhwindow(WIN_MESSAGE, FALSE);
1868 #endif
1869 Soundeffect(se_groans_and_moans, 25);
1870 You_hear("groans and moans everywhere.");
1873 record_achievement(ACH_HELL); /* reached Gehennom */
1875 /* in case we've managed to bypass the Valley's stairway down */
1876 if (Inhell && !Is_valley(&u.uz))
1877 u.uevent.gehennom_entered = 1;
1879 if (familiar)
1880 familiar_level_msg();
1882 /* special location arrival messages/events */
1883 if (In_endgame(&u.uz)) {
1884 if (newdungeon)
1885 record_achievement(ACH_ENDG); /* reached endgame */
1886 if (new && on_level(&u.uz, &astral_level)) {
1887 final_level(); /* guardian angel,&c */
1888 record_achievement(ACH_ASTR); /* reached Astral level */
1889 } else if (newdungeon && u.uhave.amulet) {
1890 resurrect(); /* force confrontation with Wizard */
1892 } else if (In_quest(&u.uz)) {
1893 onquest(); /* might be reaching locate|goal level */
1894 } else if (Is_knox(&u.uz)) {
1895 /* alarm stops working once Croesus has died */
1896 if (new || !svm.mvitals[PM_CROESUS].died) {
1897 You("have penetrated a high security area!");
1898 Soundeffect(se_alarm, 100);
1899 pline("An alarm sounds!");
1900 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
1901 if (DEADMONSTER(mtmp))
1902 continue;
1903 mtmp->msleeping = 0;
1906 } else if (In_mines(&u.uz)) {
1907 if (newdungeon)
1908 record_achievement(ACH_MINE);
1909 } else if (In_sokoban(&u.uz)) {
1910 if (newdungeon)
1911 record_achievement(ACH_SOKO);
1912 } else {
1913 if (new && Is_rogue_level(&u.uz)) {
1914 You("enter what seems to be an older, more primitive world.");
1915 } else if (new && Is_bigroom(&u.uz)) {
1916 record_achievement(ACH_BGRM);
1918 /* main dungeon message from your quest leader */
1919 if (!In_quest(&u.uz0) && at_dgn_entrance("The Quest")
1920 && !(u.uevent.qcompleted || u.uevent.qexpelled
1921 || svq.quest_status.leader_is_dead)) {
1922 /* [TODO: copy of same TODO below; if an achievement for
1923 receiving quest call from leader gets added, that should
1924 come after logging new level entry] */
1925 if (!u.uevent.qcalled) {
1926 u.uevent.qcalled = 1;
1927 /* main "leader needs help" message */
1928 com_pager("quest_portal");
1929 } else { /* reminder message */
1930 com_pager(Role_if(PM_ROGUE) ? "quest_portal_demand"
1931 : "quest_portal_again");
1936 temperature_change_msg(prev_temperature);
1938 /* this was originally done earlier; moved here to be logged after
1939 any achievement related to entering a dungeon branch
1940 [TODO: if an achievement for receiving quest call from leader
1941 gets added, that should come after this rather than take place
1942 where the message is delivered above] */
1943 if (new) {
1944 char dloc[QBUFSZ];
1945 /* Astral is excluded as a major event here because entry to it
1946 is already one due to that being an achievement */
1947 boolean major = In_endgame(&u.uz) && !Is_astralevel(&u.uz);
1949 (void) describe_level(dloc, 2);
1950 livelog_printf(major ? LL_ACHIEVE : LL_DEBUG, "entered %s", dloc);
1952 if (Role_if(PM_TOURIST)) {
1953 more_experienced(level_difficulty(), 0);
1954 newexplevel();
1958 assign_level(&u.uz0, &u.uz); /* reset u.uz0 */
1959 #ifdef INSURANCE
1960 save_currentstate();
1961 #endif
1962 notice_mon_on();
1963 notice_all_mons(TRUE);
1965 print_level_annotation();
1966 /* give room entrance message, if any */
1967 check_special_room(FALSE);
1968 /* deliver objects traveling with player */
1969 obj_delivery(TRUE);
1971 /* assume this will always return TRUE when changing level */
1972 (void) in_out_region(u.ux, u.uy);
1973 /* shop repair is normally done when shopkeepers move, but we may
1974 need to catch up for lost time here; do this before maybe dying
1975 so bones map will include it */
1976 if (!new)
1977 fix_shop_damage();
1979 /* fall damage? */
1980 if (do_fall_dmg) {
1981 int dmg = d(max(dist, 1), 6);
1983 dmg = Maybe_Half_Phys(dmg);
1984 losehp(dmg, "falling down a mine shaft", KILLED_BY);
1987 (void) pickup(1);
1988 return;
1991 /* give a message when entering a Gehennom level other than the Valley;
1992 also given if restoring a game in that situation */
1993 void
1994 hellish_smoke_mesg(void)
1996 if (svl.level.flags.temperature)
1997 pline("It is %s here.",
1998 svl.level.flags.temperature > 0 ? "hot" : "cold");
2000 if (In_hell(&u.uz) && svl.level.flags.temperature > 0)
2001 You("%s smoke...",
2002 olfaction(gy.youmonst.data) ? "smell" : "sense");
2005 /* give a message when the level temperature is different from previous */
2006 staticfn void
2007 temperature_change_msg(schar prev_temperature)
2009 if (prev_temperature != svl.level.flags.temperature) {
2010 if (svl.level.flags.temperature)
2011 hellish_smoke_mesg();
2012 else if (prev_temperature > 0)
2013 pline_The("heat %s gone.",
2014 In_hell(&u.uz0)
2015 ? "and smoke are" : "is");
2016 else if (prev_temperature < 0)
2017 You("are out of the cold.");
2021 /* usually called from goto_level(); might be called from Sting_effects() */
2022 void
2023 maybe_lvltport_feedback(void)
2025 if (gd.dfr_post_msg
2026 && !strncmpi(gd.dfr_post_msg, "You materialize", 15)) {
2027 /* "You materialize on a different level." */
2028 pline("%s", gd.dfr_post_msg);
2029 free((genericptr_t) gd.dfr_post_msg), gd.dfr_post_msg = 0;
2033 staticfn void
2034 final_level(void)
2036 /* reset monster hostility relative to player */
2037 iter_mons(reset_hostility);
2039 /* create some player-monsters */
2040 create_mplayers(rn1(4, 3), TRUE);
2042 /* create a guardian angel next to player, if worthy */
2043 gain_guardian_angel();
2046 /* change levels at the end of this turn, after monsters finish moving */
2047 void
2048 schedule_goto(
2049 d_level *tolev,
2050 int utotype_flags,
2051 const char *pre_msg, const char *post_msg)
2053 /* UTOTYPE_DEFERRED is used, so UTOTYPE_NONE can trigger deferred_goto() */
2054 u.utotype = utotype_flags | UTOTYPE_DEFERRED;
2055 /* destination level */
2056 assign_level(&u.utolev, tolev);
2058 if (pre_msg)
2059 gd.dfr_pre_msg = dupstr(pre_msg);
2060 if (post_msg)
2061 gd.dfr_post_msg = dupstr(post_msg);
2064 /* handle something like portal ejection */
2065 void
2066 deferred_goto(void)
2068 if (!on_level(&u.uz, &u.utolev)) {
2069 d_level dest, oldlev;
2070 int typmask = u.utotype; /* save it; goto_level zeroes u.utotype */
2072 assign_level(&dest, &u.utolev);
2073 assign_level(&oldlev, &u.uz);
2074 if (gd.dfr_pre_msg)
2075 pline1(gd.dfr_pre_msg);
2076 goto_level(&dest, !!(typmask & UTOTYPE_ATSTAIRS),
2077 !!(typmask & UTOTYPE_FALLING),
2078 !!(typmask & UTOTYPE_PORTAL));
2079 if (typmask & UTOTYPE_RMPORTAL) { /* remove portal */
2080 struct trap *t = t_at(u.ux, u.uy);
2082 if (t) {
2083 deltrap(t);
2084 newsym(u.ux, u.uy);
2087 if (gd.dfr_post_msg && !on_level(&u.uz, &oldlev))
2088 pline1(gd.dfr_post_msg);
2090 u.utotype = UTOTYPE_NONE; /* our caller keys off of this */
2091 if (gd.dfr_pre_msg)
2092 free((genericptr_t) gd.dfr_pre_msg), gd.dfr_pre_msg = 0;
2093 if (gd.dfr_post_msg)
2094 free((genericptr_t) gd.dfr_post_msg), gd.dfr_post_msg = 0;
2098 * Return TRUE if we created a monster for the corpse. If successful, the
2099 * corpse is gone.
2101 boolean
2102 revive_corpse(struct obj *corpse)
2104 struct monst *mtmp, *mcarry;
2105 boolean is_uwep, chewed;
2106 xint16 where;
2107 char cname[BUFSZ];
2108 struct obj *container = (struct obj *) 0;
2109 int container_where = 0;
2110 int montype;
2111 boolean is_zomb;
2112 coordxy corpsex, corpsey;
2114 where = corpse->where;
2115 montype = corpse->corpsenm;
2116 /* treat buried auto-reviver (troll, Rider?) like a zombie
2117 so that it can dig itself out of the ground if it revives */
2118 is_zomb = (mons[montype].mlet == S_ZOMBIE
2119 || (where == OBJ_BURIED && is_reviver(&mons[montype])));
2120 is_uwep = (corpse == uwep);
2121 chewed = (corpse->oeaten != 0);
2122 Strcpy(cname, corpse_xname(corpse,
2123 chewed ? "bite-covered" : (const char *) 0,
2124 CXN_SINGULAR));
2125 mcarry = (where == OBJ_MINVENT) ? corpse->ocarry : 0;
2126 /* mcarry is NULL for (where == OBJ_BURIED and OBJ_CONTAINED) now */
2128 (void) get_obj_location(corpse, &corpsex, &corpsey,
2129 CONTAINED_TOO | BURIED_TOO);
2131 if (where == OBJ_CONTAINED) {
2132 struct monst *mtmp2;
2134 container = corpse->ocontainer;
2135 mtmp2 = get_container_location(container, &container_where,
2136 (int *) 0);
2137 /* container_where is outermost container's location even if nested */
2138 if (container_where == OBJ_MINVENT && mtmp2)
2139 mcarry = mtmp2;
2141 mtmp = revive(corpse, FALSE); /* corpse is gone if successful */
2143 if (mtmp) {
2144 switch (where) {
2145 case OBJ_INVENT:
2146 if (is_uwep)
2147 pline_The("%s writhes out of your grasp!", cname);
2148 else
2149 You_feel("squirming in your backpack!");
2150 break;
2152 case OBJ_FLOOR:
2153 if (cansee(corpsex, corpsey) || canseemon(mtmp)) {
2154 const char *effect = "";
2156 if (mtmp->data == &mons[PM_DEATH])
2157 effect = " in a whirl of spectral skulls";
2158 else if (mtmp->data == &mons[PM_PESTILENCE])
2159 effect = " in a churning pillar of flies";
2160 else if (mtmp->data == &mons[PM_FAMINE])
2161 effect = " in a ring of withered crops";
2163 if (canseemon(mtmp)) {
2164 pline("%s rises from the dead%s!",
2165 chewed ? Adjmonnam(mtmp, "bite-covered")
2166 : Monnam(mtmp),
2167 effect);
2168 } else {
2169 pline("%s disappears%s!", The(cname), effect);
2172 break;
2174 case OBJ_MINVENT: /* probably a nymph's */
2175 if (cansee(mtmp->mx, mtmp->my)) {
2176 if (mcarry && canseemon(mcarry))
2177 pline("Startled, %s drops %s as it %s!",
2178 mon_nam(mcarry), an(cname),
2179 canspotmon(mtmp) ? "revives" : "disappears");
2180 else if (canspotmon(mtmp))
2181 pline("%s suddenly appears!",
2182 chewed ? Adjmonnam(mtmp, "bite-covered")
2183 : Monnam(mtmp));
2185 break;
2186 case OBJ_CONTAINED: {
2187 char sackname[BUFSZ];
2188 /* Could use x_monnam(..., AUGMENT_IT) but that'd say "someone"
2189 for humanoid monsters, which seems like a distinction the hero
2190 doesn't have knowledge to make here. */
2191 const char *mnam = canspotmon(mtmp) ? Amonnam(mtmp) : Something;
2193 if (!container) {
2194 impossible("reviving corpse from non-existent container");
2195 } else if (mcarry && canseemon(mcarry)) {
2196 pline("%s writhes out of %s!", mnam, yname(container));
2197 } else if (container_where == OBJ_INVENT) {
2198 Strcpy(sackname, an(xname(container)));
2199 pline("%s %s out of %s in your pack!", mnam,
2200 locomotion(mtmp->data, "writhes"), sackname);
2201 } else if (container_where == OBJ_FLOOR
2202 && cansee(corpsex, corpsey)) {
2203 Strcpy(sackname, an(xname(container)));
2204 pline("%s escapes from %s!", mnam, sackname);
2206 break;
2208 case OBJ_BURIED:
2209 if (is_zomb) {
2210 maketrap(mtmp->mx, mtmp->my, PIT);
2211 if (cansee(mtmp->mx, mtmp->my)) {
2212 struct trap *ttmp;
2214 ttmp = t_at(mtmp->mx, mtmp->my);
2215 if (ttmp)
2216 ttmp->tseen = TRUE;
2217 pline("%s claws itself out of the ground!",
2218 canspotmon(mtmp) ? Amonnam(mtmp) : Something);
2219 newsym(mtmp->mx, mtmp->my);
2220 } else if (mdistu(mtmp) < 5*5) {
2221 Soundeffect(se_scratching, 50);
2222 You_hear("scratching noises.");
2224 fill_pit(mtmp->mx, mtmp->my);
2225 break;
2227 FALLTHROUGH;
2228 /*FALLTHRU*/
2229 default:
2230 /* we should be able to handle the other cases... */
2231 impossible("revive_corpse: lost corpse @ %d", where);
2232 break;
2234 return TRUE;
2236 return FALSE;
2239 /* Revive the corpse via a timeout. */
2240 /*ARGSUSED*/
2241 void
2242 revive_mon(anything *arg, long timeout UNUSED)
2244 struct obj *body = arg->a_obj;
2245 struct permonst *mptr = &mons[body->corpsenm];
2246 struct monst *mtmp;
2247 coordxy x, y;
2249 /* corpse will revive somewhere else if there is a monster in the way;
2250 Riders get a chance to try to bump the obstacle out of their way */
2251 if (is_displacer(mptr) && body->where == OBJ_FLOOR
2252 && get_obj_location(body, &x, &y, 0) && (mtmp = m_at(x, y)) != 0) {
2253 boolean notice_it = canseemon(mtmp); /* before rloc() */
2254 char *monname = Monnam(mtmp);
2256 if (rloc(mtmp, RLOC_NOMSG)) {
2257 if (notice_it && !canseemon(mtmp))
2258 pline("%s vanishes.", monname);
2259 else if (!notice_it && canseemon(mtmp))
2260 pline("%s appears.", Monnam(mtmp)); /* not pre-rloc monname */
2261 else if (notice_it && dist2(mtmp->mx, mtmp->my, x, y) > 2)
2262 pline("%s teleports.", monname); /* saw it and still see it */
2266 /* if we succeed, the corpse is gone */
2267 if (!revive_corpse(body)) {
2268 long when;
2269 int action;
2271 if (is_rider(mptr) && rn2(99)) { /* Rider usually tries again */
2272 action = REVIVE_MON;
2273 when = rider_revival_time(body, TRUE);
2274 } else { /* rot this corpse away */
2275 if (!obj_has_timer(body, ROT_CORPSE))
2276 You_feel("%sless hassled.", is_rider(mptr) ? "much " : "");
2277 action = ROT_CORPSE;
2278 when = (long) d(5, 50) - (svm.moves - body->age);
2279 if (when < 1L)
2280 when = 1L;
2282 if (!obj_has_timer(body, action))
2283 (void) start_timer(when, TIMER_OBJECT, action, arg);
2287 /* Timeout callback. Revive the corpse as a zombie. */
2288 void
2289 zombify_mon(anything *arg, long timeout)
2291 struct obj *body = arg->a_obj;
2292 int zmon = zombie_form(&mons[body->corpsenm]);
2294 if (zmon != NON_PM && !(svm.mvitals[zmon].mvflags & G_GENOD)) {
2295 if (has_omid(body))
2296 free_omid(body);
2297 if (has_omonst(body))
2298 free_omonst(body);
2300 set_corpsenm(body, zmon);
2301 revive_mon(arg, timeout);
2302 } else {
2303 rot_corpse(arg, timeout);
2307 /* return TRUE if hero properties are dangerous to hero */
2308 staticfn boolean
2309 danger_uprops(void)
2311 return (Stoned || Slimed || Strangled || Sick);
2314 boolean
2315 cmd_safety_prevention(const char *ucverb, const char *cmddesc,
2316 const char *act, int *flagcounter)
2318 if (flags.safe_wait && !iflags.menu_requested && !gm.multi) {
2319 char buf[QBUFSZ];
2321 buf[0] = '\0';
2322 if (iflags.cmdassist || !(*flagcounter)++)
2323 Sprintf(buf, " Use '%s' prefix to force %s.",
2324 visctrl(cmd_from_func(do_reqmenu)), cmddesc);
2326 if (monster_nearby()) {
2327 Norep("%s%s", act, buf);
2328 return TRUE;
2329 } else if (danger_uprops()) {
2330 Norep("%s doesn't feel like a good idea right now.", ucverb);
2331 return TRUE;
2334 *flagcounter = 0;
2335 return FALSE;
2338 /* '.' command: do nothing == rest; also the
2339 ' ' command iff 'rest_on_space' option is On */
2341 donull(void)
2343 if (cmd_safety_prevention("Waiting", "a no-op (to rest)",
2344 "Are you waiting to get hit?",
2345 &gd.did_nothing_flag))
2346 return ECMD_OK;
2347 return ECMD_TIME; /* Do nothing, but let other things happen */
2350 staticfn int
2351 wipeoff(void)
2353 unsigned udelta = u.ucreamed;
2354 long ldelta = BlindedTimeout;
2356 if (udelta > 4)
2357 udelta = 4;
2358 u.ucreamed -= udelta; /*u.ucreamed -= min(u.ucreamed,4);*/
2359 if (ldelta > 4L)
2360 ldelta = 4L;
2361 incr_itimeout(&HBlinded, -ldelta); /*HBlinded -= min(BlindedTimeout,4L);*/
2363 if (!HBlinded) {
2364 pline("You've got the glop off.");
2365 u.ucreamed = 0;
2366 if (!gulp_blnd_check()) {
2367 set_itimeout(&HBlinded, 1L);
2368 make_blinded(0L, TRUE);
2370 return 0;
2371 } else if (!u.ucreamed) {
2372 Your("%s feels clean now.", body_part(FACE));
2373 return 0;
2375 return 1; /* still busy */
2378 /* the #wipe command - wipe off your face */
2380 dowipe(void)
2382 if (u.ucreamed) {
2383 static NEARDATA char buf[39];
2385 Sprintf(buf, "wiping off your %s", body_part(FACE));
2386 set_occupation(wipeoff, buf, 0);
2387 /* Not totally correct; what if they change back after now
2388 * but before they're finished wiping?
2390 return ECMD_TIME;
2392 Your("%s is already clean.", body_part(FACE));
2393 return ECMD_TIME;
2396 /* common wounded legs feedback */
2397 void
2398 legs_in_no_shape(const char *for_what, /* jumping, kicking, riding */
2399 boolean by_steed)
2401 if (by_steed && u.usteed) {
2402 pline("%s is in no shape for %s.", Monnam(u.usteed), for_what);
2403 } else {
2404 long wl = (EWounded_legs & BOTH_SIDES);
2405 const char *bp = body_part(LEG);
2407 if (wl == BOTH_SIDES)
2408 bp = makeplural(bp);
2409 Your("%s%s %s in no shape for %s.",
2410 (wl == LEFT_SIDE) ? "left " : (wl == RIGHT_SIDE) ? "right " : "",
2411 bp, (wl == BOTH_SIDES) ? "are" : "is", for_what);
2415 void
2416 set_wounded_legs(long side, int timex)
2418 /* KMH -- STEED
2419 * If you are riding, your steed gets the wounded legs instead.
2420 * You still call this function, but don't lose hp.
2421 * Caller is also responsible for adjusting messages.
2423 disp.botl = TRUE;
2424 if (!Wounded_legs)
2425 ATEMP(A_DEX)--;
2427 if (!Wounded_legs || (HWounded_legs & TIMEOUT) < (long) timex)
2428 set_itimeout(&HWounded_legs, (long) timex);
2429 /* the leg being wounded and its timeout might differ from one
2430 attack to the next, but we don't track the legs separately;
2431 3.7: both legs will ultimately heal together; this used to use
2432 direct assignment instead of bitwise-OR so getting wounded in
2433 one leg mysteriously healed the other */
2434 EWounded_legs |= side;
2435 (void) encumber_msg();
2438 void
2439 heal_legs(
2440 int how) /* 0: ordinary, 1: dismounting steed, 2: limbs turn to stone */
2442 if (Wounded_legs) {
2443 disp.botl = TRUE;
2444 if (ATEMP(A_DEX) < 0)
2445 ATEMP(A_DEX)++;
2447 /* when mounted, wounded legs applies to the steed;
2448 during petrification countdown, "your limbs turn to stone"
2449 before the final stages and that calls us (how==2) to cure
2450 wounded legs, but we want to suppress the feel better message */
2451 if (!u.usteed && how != 2) {
2452 const char *legs = body_part(LEG);
2454 if ((EWounded_legs & BOTH_SIDES) == BOTH_SIDES)
2455 legs = makeplural(legs);
2456 /* this used to say "somewhat better" but that was
2457 misleading since legs are being fully healed */
2458 Your("%s %s better.", legs, vtense(legs, "feel"));
2461 HWounded_legs = EWounded_legs = 0L;
2463 /* Wounded_legs reduces carrying capacity, so we want
2464 an encumbrance check when they're healed. However,
2465 while dismounting, first steed's legs get healed,
2466 then hero is dropped to floor and a new encumbrance
2467 check is made [in dismount_steed()]. So don't give
2468 encumbrance feedback during the dismount stage
2469 because it could seem to be shown out of order and
2470 it might be immediately contradicted [able to carry
2471 more when steed becomes healthy, then possible floor
2472 feedback, then able to carry less when back on foot]. */
2473 if (how == 0)
2474 (void) encumber_msg();
2478 /*do.c*/