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