1 /* SCCS Id: @(#)do.c 3.4 2003/12/02 */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
5 /* Contains code for 'd', 'D' (drop), '>', '<' (up, down) */
12 STATIC_DCL void FDECL(trycall, (struct obj *));
14 STATIC_DCL void FDECL(dosinkring, (struct obj *));
17 STATIC_PTR int FDECL(drop, (struct obj *));
18 STATIC_PTR int NDECL(wipeoff);
21 STATIC_DCL int FDECL(menu_drop, (int));
24 STATIC_DCL int NDECL(currentlevel_rewrite);
25 STATIC_DCL void NDECL(final_level);
26 /* static boolean FDECL(badspot, (XCHAR_P,XCHAR_P)); */
31 static NEARDATA const char drop_types[] =
32 { ALLOW_COUNT, COIN_CLASS, ALL_CLASSES, 0 };
34 /* 'd' command: drop one inventory item */
39 int result, i = (invent || u.ugold) ? 0 : (SIZE(drop_types) - 1);
41 int result, i = (invent) ? 0 : (SIZE(drop_types) - 1);
44 if (*u.ushops) sellobj_state(SELL_DELIBERATE);
45 result = drop(getobj(&drop_types[i], "drop"));
46 if (*u.ushops) sellobj_state(SELL_NORMAL);
55 /* Called when a boulder is dropped, thrown, or pushed. If it ends up
56 * in a pool, it either fills the pool up or sinks away. In either case,
57 * it's gone for good... If the destination is not a pool, returns FALSE.
60 boulder_hits_pool(otmp, rx, ry, pushing)
65 if (!otmp || otmp->otyp != BOULDER)
66 impossible("Not a boulder?");
67 else if (!Is_waterlevel(&u.uz) && (is_pool(rx,ry) || is_lava(rx,ry))) {
68 boolean lava = is_lava(rx,ry), fills_up;
69 const char *what = waterbody_name(rx,ry);
70 schar ltyp = levl[rx][ry].typ;
71 int chance = rn2(10); /* water: 90%; lava: 10% */
72 fills_up = lava ? chance == 0 : chance != 0;
75 struct trap *ttmp = t_at(rx, ry);
77 if (ltyp == DRAWBRIDGE_UP) {
78 levl[rx][ry].drawbridgemask &= ~DB_UNDER; /* clear lava */
79 levl[rx][ry].drawbridgemask |= DB_FLOOR;
81 levl[rx][ry].typ = ROOM;
83 if (ttmp) (void) delfloortrap(ttmp);
88 You("push %s into the %s.", the(xname(otmp)), what);
89 if (flags.verbose && !Blind)
90 pline("Now you can cross it!");
91 /* no splashing in this case */
94 if (!fills_up || !pushing) { /* splashing occurs */
96 if (pushing ? !Blind : cansee(rx,ry)) {
97 There("is a large splash as %s %s the %s.",
98 the(xname(otmp)), fills_up? "fills":"falls into",
100 } else if (flags.soundok)
101 You_hear("a%s splash.", lava ? " sizzling" : "");
102 wake_nearto(rx, ry, 40);
105 if (fills_up && u.uinwater && distu(rx,ry) == 0) {
108 vision_full_recalc = 1;
109 You("find yourself on dry land again!");
110 } else if (lava && distu(rx,ry) <= 2) {
111 You("are hit by molten lava%c",
112 Fire_resistance ? '.' : '!');
114 losehp(d((Fire_resistance ? 1 : 3), 6),
115 "molten lava", KILLED_BY);
116 } else if (!fills_up && flags.verbose &&
117 (pushing ? !Blind : cansee(rx,ry)))
118 pline("It sinks without a trace!");
121 /* boulder is now gone */
122 if (pushing) delobj(otmp);
123 else obfree(otmp, (struct obj *)0);
129 /* Used for objects which sometimes do special things when dropped; must be
130 * called with the object not in any chain. Returns TRUE if the object goes
134 flooreffects(obj,x,y,verb)
142 if (obj->where != OBJ_FREE)
143 panic("flooreffects: obj not free");
145 /* make sure things like water_damage() have no pointers to follow */
146 obj->nobj = obj->nexthere = (struct obj *)0;
148 if (obj->otyp == BOULDER && boulder_hits_pool(obj, x, y, FALSE))
150 else if (obj->otyp == BOULDER && (t = t_at(x,y)) != 0 &&
151 (t->ttyp==PIT || t->ttyp==SPIKED_PIT
152 || t->ttyp==TRAPDOOR || t->ttyp==HOLE)) {
153 if (((mtmp = m_at(x, y)) && mtmp->mtrapped) ||
154 (u.utrap && u.ux == x && u.uy == y)) {
156 pline_The("boulder %s into the pit%s.",
157 vtense((const char *)0, verb),
158 (mtmp) ? "" : " with you");
160 if (!passes_walls(mtmp->data) &&
161 !throws_rocks(mtmp->data)) {
162 if (hmon(mtmp, obj, TRUE) && !is_whirly(mtmp->data))
163 return FALSE; /* still alive */
167 if (!Passes_walls && !throws_rocks(youmonst.data)) {
168 losehp(rnd(15), "squished under a boulder",
170 return FALSE; /* player remains trapped */
176 if ((x == u.ux) && (y == u.uy))
177 You_hear("a CRASH! beneath you.");
179 You_hear("the boulder %s.", verb);
180 } else if (cansee(x, y)) {
181 pline_The("boulder %s%s.",
182 t->tseen ? "" : "triggers and ",
183 t->ttyp == TRAPDOOR ? "plugs a trap door" :
184 t->ttyp == HOLE ? "plugs a hole" :
189 obfree(obj, (struct obj *)0);
193 } else if (is_lava(x, y)) {
194 return fire_damage(obj, FALSE, FALSE, x, y);
195 } else if (is_pool(x, y)) {
196 /* Reasonably bulky objects (arbitrary) splash when dropped.
197 * If you're floating above the water even small things make noise.
198 * Stuff dropped near fountains always misses */
199 if ((Blind || (Levitation || Flying)) && flags.soundok &&
200 ((x == u.ux) && (y == u.uy))) {
202 if (weight(obj) > 9) {
204 } else if (Levitation || Flying) {
208 map_background(x, y, 0);
211 water_damage(obj, FALSE, FALSE);
212 } else if (u.ux == x && u.uy == y &&
213 (!u.utrap || u.utraptype != TT_PIT) &&
214 (t = t_at(x,y)) != 0 && t->tseen &&
215 (t->ttyp==PIT || t->ttyp==SPIKED_PIT)) {
216 /* you escaped a pit and are standing on the precipice */
217 if (Blind && flags.soundok)
218 You_hear("%s %s downwards.",
219 The(xname(obj)), otense(obj, "tumble"));
221 pline("%s %s into %s pit.",
222 The(xname(obj)), otense(obj, "tumble"),
223 the_your[t->madeby_u]);
232 doaltarobj(obj) /* obj is an object dropped on an altar */
233 register struct obj *obj;
239 u.uconduct.gnostic++;
241 if ((obj->blessed || obj->cursed) && obj->oclass != COIN_CLASS) {
242 There("is %s flash as %s %s the altar.",
243 an(hcolor(obj->blessed ? NH_AMBER : NH_BLACK)),
244 doname(obj), otense(obj, "hit"));
245 if (!Hallucination) obj->bknown = 1;
247 pline("%s %s on the altar.", Doname2(obj),
248 otense(obj, "land"));
257 register struct obj *obj;
259 if(!objects[obj->otyp].oc_name_known &&
260 !objects[obj->otyp].oc_uname)
266 dosinkring(obj) /* obj is a ring being dropped over a kitchen sink */
267 register struct obj *obj;
269 register struct obj *otmp,*otmp2;
270 register boolean ideed = TRUE;
272 You("drop %s down the drain.", doname(obj));
273 obj->in_use = TRUE; /* block free identification via interrupt */
274 switch(obj->otyp) { /* effects that can be noticed without eyes */
276 You("thought your %s got lost in the sink, but there it is!",
279 case RIN_SLOW_DIGESTION:
280 pline_The("ring is regurgitated!");
287 pline_The("sink quivers upward for a moment.");
289 case RIN_POISON_RESISTANCE:
290 You("smell rotten %s.", makeplural(fruitname(FALSE)));
292 case RIN_AGGRAVATE_MONSTER:
293 pline("Several flies buzz angrily around the sink.");
295 case RIN_SHOCK_RESISTANCE:
296 pline("Static electricity surrounds the sink.");
299 You_hear("loud noises coming from the drain.");
301 case RIN_SUSTAIN_ABILITY: /* KMH */
302 pline_The("water flow seems fixed.");
304 case RIN_GAIN_STRENGTH:
305 pline_The("water flow seems %ser now.",
306 (obj->spe<0) ? "weak" : "strong");
308 case RIN_GAIN_CONSTITUTION:
309 pline_The("water flow seems %ser now.",
310 (obj->spe<0) ? "less" : "great");
312 case RIN_INCREASE_ACCURACY: /* KMH */
313 pline_The("water flow %s the drain.",
314 (obj->spe<0) ? "misses" : "hits");
316 case RIN_INCREASE_DAMAGE:
317 pline_The("water's force seems %ser now.",
318 (obj->spe<0) ? "small" : "great");
322 for(otmp = level.objects[u.ux][u.uy]; otmp; otmp = otmp2) {
323 otmp2 = otmp->nexthere;
324 if (otmp != uball && otmp != uchain &&
325 !obj_resists(otmp, 1, 99)) {
327 pline("Suddenly, %s %s from the sink!",
328 doname(otmp), otense(otmp, "vanish"));
336 /* Not the same as aggravate monster; besides, it's obvious. */
337 pline("Several flies buzz around the sink.");
343 if(!Blind && !ideed && obj->otyp != RIN_HUNGER) {
345 switch(obj->otyp) { /* effects that need eyes */
347 pline_The("faucets flash brightly for a moment.");
349 case RIN_REGENERATION:
350 pline_The("sink looks as good as new.");
352 case RIN_INVISIBILITY:
353 You("don't see anything happen to the sink.");
355 case RIN_FREE_ACTION:
356 You("see the ring slide right down the drain!");
358 case RIN_SEE_INVISIBLE:
359 You("see some air in the sink.");
362 pline_The("sink seems to blend into the floor for a moment.");
364 case RIN_FIRE_RESISTANCE:
365 pline_The("hot water faucet flashes brightly for a moment.");
367 case RIN_COLD_RESISTANCE:
368 pline_The("cold water faucet flashes brightly for a moment.");
370 case RIN_PROTECTION_FROM_SHAPE_CHAN:
371 pline_The("sink looks nothing like a fountain.");
374 pline_The("sink glows %s for a moment.",
375 hcolor((obj->spe<0) ? NH_BLACK : NH_SILVER));
378 pline_The("sink glows %s for a moment.", hcolor(NH_WHITE));
380 case RIN_TELEPORTATION:
381 pline_The("sink momentarily vanishes.");
383 case RIN_TELEPORT_CONTROL:
384 pline_The("sink looks like it is being beamed aboard somewhere.");
387 pline_The("sink momentarily looks like a fountain.");
389 case RIN_POLYMORPH_CONTROL:
390 pline_The("sink momentarily looks like a regularly erupting geyser.");
397 You_hear("the ring bouncing down the drainpipe.");
399 pline_The("sink backs up, leaving %s.", doname(obj));
410 /* some common tests when trying to drop or throw items */
413 register struct obj *obj;
414 register const char *word;
416 if(obj->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL)){
418 Norep("You cannot %s %s you are wearing.",word,
422 if (obj->otyp == LOADSTONE && obj->cursed) {
423 /* getobj() kludge sets corpsenm to user's specified count
424 when refusing to split a stack of cursed loadstones */
426 /* getobj() ignores a count for throwing since that is
427 implicitly forced to be 1; replicate its kludge... */
428 if (!strcmp(word, "throw") && obj->quan > 1L)
430 pline("For some reason, you cannot %s%s the stone%s!",
431 word, obj->corpsenm ? " any of" : "",
434 obj->corpsenm = 0; /* reset */
438 if (obj->otyp == LEASH && obj->leashmon != 0) {
440 pline_The("leash is tied around your %s.",
445 if (obj->owornmask & W_SADDLE) {
447 You("cannot %s %s you are sitting on.", word,
458 register struct obj *obj;
461 if(!canletgo(obj,"drop"))
468 setuwep((struct obj *)0);
471 setuqwep((struct obj *)0);
473 if (obj == uswapwep) {
474 setuswapwep((struct obj *)0);
478 /* barrier between you and the floor */
483 /* doname can call s_suffix, reusing its buffer */
484 Strcpy(buf, s_suffix(mon_nam(u.ustuck)));
485 You("drop %s into %s %s.", doname(obj), buf,
486 mbodypart(u.ustuck, STOMACH));
490 if((obj->oclass == RING_CLASS || obj->otyp == MEAT_RING) &&
491 IS_SINK(levl[u.ux][u.uy].typ)) {
496 if (!can_reach_floor()) {
497 if(flags.verbose) You("drop %s.", doname(obj));
499 if (obj->oclass != COIN_CLASS || obj == invent) freeinv(obj);
501 /* Ensure update when we drop gold objects */
502 if (obj->oclass == COIN_CLASS) flags.botl = 1;
508 if (!IS_ALTAR(levl[u.ux][u.uy].typ) && flags.verbose)
509 You("drop %s.", doname(obj));
515 /* Called in several places - may produce output */
516 /* eg ship_object() and dropy() -> sellobj() both produce output */
519 register struct obj *obj;
522 if (obj->oclass != COIN_CLASS || obj == invent) freeinv(obj);
524 /* Ensure update when we drop gold objects */
525 if (obj->oclass == COIN_CLASS) flags.botl = 1;
529 if (ship_object(obj, u.ux, u.uy, FALSE)) return;
530 if (IS_ALTAR(levl[u.ux][u.uy].typ))
531 doaltarobj(obj); /* set bknown */
538 register struct obj *obj;
540 if (obj == uwep) setuwep((struct obj *)0);
541 if (obj == uquiver) setuqwep((struct obj *)0);
542 if (obj == uswapwep) setuswapwep((struct obj *)0);
544 if (!u.uswallow && flooreffects(obj,u.ux,u.uy,"drop")) return;
545 /* uswallow check done by GAN 01/29/87 */
547 boolean could_petrify = FALSE;
548 boolean could_poly = FALSE;
549 boolean could_slime = FALSE;
550 boolean could_grow = FALSE;
551 boolean could_heal = FALSE;
553 if (obj != uball) { /* mon doesn't pick up ball */
554 if (obj->otyp == CORPSE) {
555 could_petrify = touch_petrifies(&mons[obj->corpsenm]);
556 could_poly = polyfodder(obj);
557 could_slime = (obj->corpsenm == PM_GREEN_SLIME);
558 could_grow = (obj->corpsenm == PM_WRAITH);
559 could_heal = (obj->corpsenm == PM_NURSE);
561 (void) mpickobj(u.ustuck,obj);
562 if (is_animal(u.ustuck->data)) {
563 if (could_poly || could_slime) {
564 (void) newcham(u.ustuck,
565 could_poly ? (struct permonst *)0 :
566 &mons[PM_GREEN_SLIME],
568 delobj(obj); /* corpse is digested */
569 } else if (could_petrify) {
570 minstapetrify(u.ustuck, TRUE);
571 /* Don't leave a cockatrice corpse in a statue */
572 if (!u.uswallow) delobj(obj);
573 } else if (could_grow) {
574 (void) grow_up(u.ustuck, (struct monst *)0);
575 delobj(obj); /* corpse is digested */
576 } else if (could_heal) {
577 u.ustuck->mhp = u.ustuck->mhpmax;
578 delobj(obj); /* corpse is digested */
583 place_object(obj, u.ux, u.uy);
585 drop_ball(u.ux,u.uy);
587 sellobj(obj, u.ux, u.uy);
589 if(Blind && Levitation)
591 newsym(u.ux,u.uy); /* remap location under self */
595 /* things that must change when not held; recurse into containers.
596 Called for both player and monsters */
598 obj_no_longer_held(obj)
603 } else if ((Is_container(obj) || obj->otyp == STATUE) && obj->cobj) {
604 struct obj *contents;
605 for(contents=obj->cobj; contents; contents=contents->nobj)
606 obj_no_longer_held(contents);
610 /* KMH -- Fixed crysknives have only 10% chance of reverting */
611 /* only changes when not held by player or monster */
612 if (!obj->oerodeproof || !rn2(10)) {
613 obj->otyp = WORM_TOOTH;
614 obj->oerodeproof = 0;
620 /* 'D' command: drop several things */
626 add_valid_menu_class(0); /* clear any classes already there */
627 if (*u.ushops) sellobj_state(SELL_DELIBERATE);
628 if (flags.menu_style != MENU_TRADITIONAL ||
629 (result = ggetobj("drop", drop, 0, FALSE, (unsigned *)0)) < -1)
630 result = menu_drop(result);
631 if (*u.ushops) sellobj_state(SELL_NORMAL);
637 /* Drop things from the hero's inventory, using a menu. */
642 int n, i, n_dropped = 0;
644 struct obj *otmp, *otmp2;
646 struct obj *u_gold = 0;
648 menu_item *pick_list;
649 boolean all_categories = TRUE;
650 boolean drop_everything = FALSE;
654 /* Hack: gold is not in the inventory, so make a gold object
655 and put it at the head of the inventory list. */
656 u_gold = mkgoldobj(u.ugold); /* removes from u.ugold */
657 u_gold->in_use = TRUE;
658 u.ugold = u_gold->quan; /* put the gold back */
659 assigninvlet(u_gold); /* might end up as NOINVSYM */
660 u_gold->nobj = invent;
665 all_categories = (retry == -2);
666 } else if (flags.menu_style == MENU_FULL) {
667 all_categories = FALSE;
668 n = query_category("Drop what type of items?",
670 UNPAID_TYPES | ALL_TYPES | CHOOSE_ALL |
671 BUC_BLESSED | BUC_CURSED | BUC_UNCURSED | BUC_UNKNOWN,
672 &pick_list, PICK_ANY);
673 if (!n) goto drop_done;
674 for (i = 0; i < n; i++) {
675 if (pick_list[i].item.a_int == ALL_TYPES_SELECTED)
676 all_categories = TRUE;
677 else if (pick_list[i].item.a_int == 'A')
678 drop_everything = TRUE;
680 add_valid_menu_class(pick_list[i].item.a_int);
682 free((genericptr_t) pick_list);
683 } else if (flags.menu_style == MENU_COMBINATION) {
684 unsigned ggoresults = 0;
685 all_categories = FALSE;
686 /* Gather valid classes via traditional NetHack method */
687 i = ggetobj("drop", drop, 0, TRUE, &ggoresults);
688 if (i == -2) all_categories = TRUE;
689 if (ggoresults & ALL_FINISHED) {
695 if (drop_everything) {
696 for(otmp = invent; otmp; otmp = otmp2) {
698 n_dropped += drop(otmp);
701 /* should coordinate with perm invent, maybe not show worn items */
702 n = query_objlist("What would you like to drop?", invent,
703 USE_INVLET|INVORDER_SORT, &pick_list,
704 PICK_ANY, all_categories ? allow_all : allow_category);
706 for (i = 0; i < n; i++) {
707 otmp = pick_list[i].item.a_obj;
708 cnt = pick_list[i].count;
709 if (cnt < otmp->quan) {
712 } else if (otmp->otyp == LOADSTONE && otmp->cursed) {
713 /* same kludge as getobj(), for canletgo()'s use */
714 otmp->corpsenm = (int) cnt; /* don't split */
717 if (otmp->oclass == COIN_CLASS)
718 (void) splitobj(otmp, otmp->quan - cnt);
721 otmp = splitobj(otmp, cnt);
724 n_dropped += drop(otmp);
726 free((genericptr_t) pick_list);
732 if (u_gold && invent && invent->oclass == COIN_CLASS) {
733 /* didn't drop [all of] it */
735 invent = u_gold->nobj;
736 u_gold->in_use = FALSE;
747 /* on a ladder, used in goto_level */
748 static NEARDATA boolean at_ladder = FALSE;
753 struct trap *trap = 0;
754 boolean stairs_down = ((u.ux == xdnstair && u.uy == ydnstair) ||
755 (u.ux == sstairs.sx && u.uy == sstairs.sy && !sstairs.up)),
756 ladder_down = (u.ux == xdnladder && u.uy == ydnladder);
759 if (u.usteed && !u.usteed->mcanmove) {
760 pline("%s won't move!", Monnam(u.usteed));
762 } else if (u.usteed && u.usteed->meating) {
763 pline("%s is still eating.", Monnam(u.usteed));
768 if ((HLevitation & I_SPECIAL) || (ELevitation & W_ARTI)) {
769 /* end controlled levitation */
770 if (ELevitation & W_ARTI) {
773 for(obj = invent; obj; obj = obj->nobj) {
774 if (obj->oartifact &&
775 artifact_has_invprop(obj,LEVITATION)) {
776 if (obj->age < monstermoves)
777 obj->age = monstermoves + rnz(100);
779 obj->age += rnz(100);
783 if (float_down(I_SPECIAL|TIMEOUT, W_ARTI))
784 return (1); /* came down, so moved */
786 floating_above(stairs_down ? "stairs" : ladder_down ?
787 "ladder" : surface(u.ux, u.uy));
788 return (0); /* didn't move */
790 if (!stairs_down && !ladder_down) {
791 if (!(trap = t_at(u.ux,u.uy)) ||
792 (trap->ttyp != TRAPDOOR && trap->ttyp != HOLE)
793 || !Can_fall_thru(&u.uz) || !trap->tseen) {
795 if (flags.autodig && !flags.nopick &&
796 uwep && is_pick(uwep)) {
797 return use_pick_axe2(uwep);
799 You_cant("go down here.");
805 You("are %s, and cannot go down.",
806 !u.uswallow ? "being held" : is_animal(u.ustuck->data) ?
807 "swallowed" : "engulfed");
810 if (on_level(&valley_level, &u.uz) && !u.uevent.gehennom_entered) {
811 You("are standing at the gate to Gehennom.");
812 pline("Unspeakable cruelty and harm lurk down there.");
813 if (yn("Are you sure you want to enter?") != 'y')
815 else pline("So be it.");
816 u.uevent.gehennom_entered = 1; /* don't ask again */
820 You("are held back by your pet!");
825 You("%s %s.", locomotion(youmonst.data, "jump"),
826 trap->ttyp == HOLE ? "down the hole" : "through the trap door");
828 if (trap && Is_stronghold(&u.uz)) {
829 goto_hell(FALSE, TRUE);
831 at_ladder = (boolean) (levl[u.ux][u.uy].typ == LADDER);
841 if( (u.ux != xupstair || u.uy != yupstair)
842 && (!xupladder || u.ux != xupladder || u.uy != yupladder)
843 && (!sstairs.sx || u.ux != sstairs.sx || u.uy != sstairs.sy
846 You_cant("go up here.");
850 if (u.usteed && !u.usteed->mcanmove) {
851 pline("%s won't move!", Monnam(u.usteed));
853 } else if (u.usteed && u.usteed->meating) {
854 pline("%s is still eating.", Monnam(u.usteed));
859 You("are %s, and cannot go up.",
860 !u.uswallow ? "being held" : is_animal(u.ustuck->data) ?
861 "swallowed" : "engulfed");
864 if(near_capacity() > SLT_ENCUMBER) {
865 /* No levitation check; inv_weight() already allows for it */
866 Your("load is too heavy to climb the %s.",
867 levl[u.ux][u.uy].typ == STAIRS ? "stairs" : "ladder");
870 if(ledger_no(&u.uz) == 1) {
871 if (yn("Beware, there will be no return! Still climb?") != 'y')
875 You("are held back by your pet!");
878 at_ladder = (boolean) (levl[u.ux][u.uy].typ == LADDER);
884 d_level save_dlevel = {0, 0};
886 /* check that we can write out the current level */
888 currentlevel_rewrite()
893 /* since level change might be a bit slow, flush any buffered screen
894 * output (like "you fall through a trap door") */
897 fd = create_levelfile(ledger_no(&u.uz), whynot);
900 * This is not quite impossible: e.g., we may have
901 * exceeded our quota. If that is the case then we
902 * cannot leave this level, and cannot save either.
903 * Another possibility is that the directory was not
911 if (!savelev(fd, ledger_no(&u.uz), COUNT_SAVE)) {
913 delete_levelfile(ledger_no(&u.uz));
914 pline("NetHack is out of disk space for making levels!");
915 You("can save, quit, or continue playing.");
928 if (flags.ins_chkpt) {
929 /* write out just-attained level, with pets and everything */
930 fd = currentlevel_rewrite();
933 savelev(fd,ledger_no(&u.uz), WRITE_SAVE);
937 /* write out non-level state */
947 return((levl[x][y].typ != ROOM && levl[x][y].typ != AIR &&
948 levl[x][y].typ != CORR) || MON_AT(x, y));
953 goto_level(newlevel, at_stairs, falling, portal)
955 boolean at_stairs, falling, portal;
959 boolean cant_go_back,
960 up = (depth(newlevel) < depth(&u.uz)),
961 newdungeon = (u.uz.dnum != newlevel->dnum),
962 was_in_W_tower = In_W_tower(u.ux, u.uy, &u.uz),
964 boolean new = FALSE; /* made a new level? */
968 if (dunlev(newlevel) > dunlevs_in_dungeon(newlevel))
969 newlevel->dlevel = dunlevs_in_dungeon(newlevel);
970 if (newdungeon && In_endgame(newlevel)) { /* 1st Endgame Level !!! */
972 assign_level(newlevel, &earth_level);
975 new_ledger = ledger_no(newlevel);
977 done(ESCAPED); /* in fact < 0 is impossible */
979 /* If you have the amulet and are trying to get out of Gehennom, going
980 * up a set of stairs sometimes does some very strange things!
981 * Biased against law and towards chaos, but not nearly as strongly
982 * as it used to be (prior to 3.2.0).
984 * "up" L N C "up" L N C
985 * +1 75.0 75.0 75.0 +1 75.0 75.0 75.0
986 * 0 0.0 12.5 25.0 0 6.25 8.33 12.5
987 * -1 8.33 4.17 0.0 -1 6.25 8.33 12.5
988 * -2 8.33 4.17 0.0 -2 6.25 8.33 0.0
989 * -3 8.33 4.17 0.0 -3 6.25 0.0 0.0
991 if (Inhell && up && u.uhave.amulet && !newdungeon && !portal &&
992 (dunlev(&u.uz) < dunlevs_in_dungeon(&u.uz)-3)) {
994 int odds = 3 + (int)u.ualign.type, /* 2..4 */
995 diff = odds <= 1 ? 0 : rn2(odds); /* paranoia */
998 assign_rnd_level(newlevel, &u.uz, diff);
999 /* if inside the tower, stay inside */
1000 if (was_in_W_tower &&
1001 !On_W_tower_level(newlevel)) diff = 0;
1004 assign_level(newlevel, &u.uz);
1006 new_ledger = ledger_no(newlevel);
1008 pline("A mysterious force momentarily surrounds you...");
1009 if (on_level(newlevel, &u.uz)) {
1010 (void) safe_teleds(FALSE);
1014 at_stairs = at_ladder = FALSE;
1018 /* Prevent the player from going past the first quest level unless
1019 * (s)he has been given the go-ahead by the leader.
1021 if (on_level(&u.uz, &qstart_level) && !newdungeon && !ok_to_quest()) {
1022 pline("A mysterious force prevents you from descending.");
1026 if (on_level(newlevel, &u.uz)) return; /* this can happen */
1028 fd = currentlevel_rewrite();
1031 if (falling) /* assuming this is only trap door or hole */
1032 impact_drop((struct obj *)0, u.ux, u.uy, newlevel->dlevel);
1034 check_special_room(TRUE); /* probably was a trap door */
1035 if (Punished) unplacebc();
1036 u.utrap = 0; /* needed in level_tele */
1037 fill_pit(u.ux, u.uy);
1038 u.ustuck = 0; /* idem */
1040 u.uundetected = 0; /* not hidden, even if means are available */
1042 if (u.uswallow) /* idem */
1043 u.uswldtim = u.uswallow = 0;
1045 * We no longer see anything on the level. Make sure that this
1046 * follows u.uswallow set to null since uswallow overrides all
1052 * Save the level we're leaving. If we're entering the endgame,
1053 * we can get rid of all existing levels because they cannot be
1054 * reached any more. We still need to use savelev()'s cleanup
1055 * for the level being left, to recover dynamic memory in use and
1056 * to avoid dangling timers and light sources.
1058 cant_go_back = (newdungeon && In_endgame(newlevel));
1059 if (!cant_go_back) {
1060 update_mlstmv(); /* current monsters are becoming inactive */
1061 bufon(fd); /* use buffered output */
1063 savelev(fd, ledger_no(&u.uz),
1064 cant_go_back ? FREE_SAVE : (WRITE_SAVE | FREE_SAVE));
1067 /* discard unreachable levels; keep #0 */
1068 for (l_idx = maxledgerno(); l_idx > 0; --l_idx)
1069 delete_levelfile(l_idx);
1072 #ifdef REINCARNATION
1073 if (Is_rogue_level(newlevel) || Is_rogue_level(&u.uz))
1074 assign_rogue_graphics(Is_rogue_level(newlevel));
1077 substitute_tiles(newlevel);
1079 assign_level(&u.uz0, &u.uz);
1080 assign_level(&u.uz, newlevel);
1081 assign_level(&u.utolev, newlevel);
1083 if (dunlev_reached(&u.uz) < dunlev(&u.uz))
1084 dunlev_reached(&u.uz) = dunlev(&u.uz);
1085 reset_rndmonst(NON_PM); /* u.uz change affects monster generation */
1087 /* set default level change destination areas */
1088 /* the special level code may override these */
1089 (void) memset((genericptr_t) &updest, 0, sizeof updest);
1090 (void) memset((genericptr_t) &dndest, 0, sizeof dndest);
1092 if (!(level_info[new_ledger].flags & LFILE_EXISTS)) {
1093 /* entering this level for first time; make it now */
1094 if (level_info[new_ledger].flags & (FORGOTTEN|VISITED)) {
1095 impossible("goto_level: returning to discarded level?");
1096 level_info[new_ledger].flags &= ~(FORGOTTEN|VISITED);
1099 new = TRUE; /* made the level */
1101 /* returning to previously visited level; reload it */
1102 fd = open_levelfile(new_ledger, whynot);
1104 pline("%s", whynot);
1105 pline("Probably someone removed it.");
1108 /* we'll reach here if running in wizard mode */
1109 error("Cannot continue this game.");
1111 minit(); /* ZEROCOMP */
1112 getlev(fd, hackpid, new_ledger, FALSE);
1115 /* do this prior to level-change pline messages */
1116 vision_reset(); /* clear old level's line-of-sight */
1117 vision_full_recalc = 0; /* don't let that reenable vision yet */
1118 flush_screen(-1); /* ensure all map flushes are postponed */
1120 if (portal && !In_endgame(&u.uz)) {
1121 /* find the portal on the new level */
1122 register struct trap *ttrap;
1124 for (ttrap = ftrap; ttrap; ttrap = ttrap->ntrap)
1125 if (ttrap->ttyp == MAGIC_PORTAL) break;
1127 if (!ttrap) panic("goto_level: no corresponding portal!");
1129 u_on_newpos(ttrap->tx, ttrap->ty);
1130 } else if (at_stairs && !In_endgame(&u.uz)) {
1133 u_on_newpos(xdnladder, ydnladder);
1136 if (Is_stronghold(&u.uz)) {
1137 register xchar x, y;
1140 x = (COLNO - 2 - rnd(5));
1141 y = rn1(ROWNO - 4, 3);
1142 } while(occupied(x, y) ||
1143 IS_WALL(levl[x][y].typ));
1145 } else u_on_sstairs();
1146 } else u_on_dnstairs();
1148 /* Remove bug which crashes with levitation/punishment KAA */
1149 if (Punished && !Levitation) {
1150 pline("With great effort you climb the %s.",
1151 at_ladder ? "ladder" : "stairs");
1152 } else if (at_ladder)
1153 You("climb up the ladder.");
1156 u_on_newpos(xupladder, yupladder);
1158 if (newdungeon) u_on_sstairs();
1159 else u_on_upstairs();
1162 You("fly down along the %s.",
1163 at_ladder ? "ladder" : "stairs");
1165 (near_capacity() > UNENCUMBERED || Punished || Fumbling)) {
1166 You("fall down the %s.", at_ladder ? "ladder" : "stairs");
1169 if (carried(uball)) {
1171 setuwep((struct obj *)0);
1172 if (uswapwep == uball)
1173 setuswapwep((struct obj *)0);
1174 if (uquiver == uball)
1175 setuqwep((struct obj *)0);
1180 /* falling off steed has its own losehp() call */
1182 dismount_steed(DISMOUNT_FELL);
1185 losehp(rnd(3), "falling downstairs", KILLED_BY);
1186 selftouch("Falling, you");
1187 } else if (u.dz && at_ladder)
1188 You("climb down the ladder.");
1190 } else { /* trap door or level_tele or In_endgame */
1191 if (was_in_W_tower && On_W_tower_level(&u.uz))
1192 /* Stay inside the Wizard's tower when feasible. */
1193 /* Note: up vs down doesn't really matter in this case. */
1194 place_lregion(dndest.nlx, dndest.nly,
1195 dndest.nhx, dndest.nhy,
1196 0,0, 0,0, LR_DOWNTELE, (d_level *) 0);
1198 place_lregion(updest.lx, updest.ly,
1199 updest.hx, updest.hy,
1200 updest.nlx, updest.nly,
1201 updest.nhx, updest.nhy,
1202 LR_UPTELE, (d_level *) 0);
1204 place_lregion(dndest.lx, dndest.ly,
1205 dndest.hx, dndest.hy,
1206 dndest.nlx, dndest.nly,
1207 dndest.nhx, dndest.nhy,
1208 LR_DOWNTELE, (d_level *) 0);
1210 if (Punished) ballfall();
1211 selftouch("Falling, you");
1215 if (Punished) placebc();
1216 obj_delivery(); /* before killing geno'd monsters' eggs */
1218 kill_genocided_monsters(); /* for those wiped out while in limbo */
1220 * Expire all timers that have gone off while away. Must be
1221 * after migrating monsters and objects are delivered
1222 * (losedogs and obj_delivery).
1228 if ((mtmp = m_at(u.ux, u.uy)) != 0
1233 /* There's a monster at your target destination; it might be one
1234 which accompanied you--see mon_arrive(dogmove.c)--or perhaps
1235 it was already here. Randomly move you to an adjacent spot
1236 or else the monster to any nearby location. Prior to 3.3.0
1237 the latter was done unconditionally. */
1241 enexto(&cc, u.ux, u.uy, youmonst.data) &&
1242 distu(cc.x, cc.y) <= 2)
1243 u_on_newpos(cc.x, cc.y); /*[maybe give message here?]*/
1247 if ((mtmp = m_at(u.ux, u.uy)) != 0) {
1248 impossible("mnexto failed (do.c)?");
1249 (void) rloc(mtmp, FALSE);
1253 /* initial movement of bubbles just before vision_recalc */
1254 if (Is_waterlevel(&u.uz))
1257 if (level_info[new_ledger].flags & FORGOTTEN) {
1258 forget_map(ALL_MAP); /* forget the map */
1259 forget_traps(); /* forget all traps too */
1261 level_info[new_ledger].flags &= ~FORGOTTEN;
1264 /* Reset the screen. */
1265 vision_reset(); /* reset the blockages */
1266 docrt(); /* does a full vision recalc */
1270 * Move all plines beyond the screen reset.
1273 /* give room entrance message, if any */
1274 check_special_room(FALSE);
1276 /* Check whether we just entered Gehennom. */
1277 if (!In_hell(&u.uz0) && Inhell) {
1278 if (Is_valley(&u.uz)) {
1279 You("arrive at the Valley of the Dead...");
1280 pline_The("odor of burnt flesh and decay pervades the air.");
1282 display_nhwindow(WIN_MESSAGE, FALSE);
1284 You_hear("groans and moans everywhere.");
1285 } else pline("It is hot here. You smell smoke...");
1289 static const char * const fam_msgs[4] = {
1290 "You have a sense of deja vu.",
1291 "You feel like you've been here before.",
1292 "This place %s familiar...",
1295 static const char * const halu_fam_msgs[4] = {
1296 "Whoa! Everything %s different.",
1297 "You are surrounded by twisty little passages, all alike.",
1298 "Gee, this %s like uncle Conan's place...",
1306 mesg = halu_fam_msgs[which];
1308 mesg = fam_msgs[which];
1309 if (mesg && index(mesg, '%')) {
1310 Sprintf(buf, mesg, !Blind ? "looks" : "seems");
1313 if (mesg) pline(mesg);
1316 #ifdef REINCARNATION
1317 if (new && Is_rogue_level(&u.uz))
1318 You("enter what seems to be an older, more primitive world.");
1320 /* Final confrontation */
1321 if (In_endgame(&u.uz) && newdungeon && u.uhave.amulet)
1323 if (newdungeon && In_V_tower(&u.uz) && In_hell(&u.uz0))
1324 pline_The("heat and smoke are gone.");
1326 /* the message from your quest leader */
1327 if (!In_quest(&u.uz0) && at_dgn_entrance("The Quest") &&
1328 !(u.uevent.qexpelled || u.uevent.qcompleted || quest_status.leader_is_dead)) {
1330 if (u.uevent.qcalled) {
1331 com_pager(Role_if(PM_ROGUE) ? 4 : 3);
1334 u.uevent.qcalled = TRUE;
1338 /* once Croesus is dead, his alarm doesn't work any more */
1339 if (Is_knox(&u.uz) && (new || !mvitals[PM_CROESUS].died)) {
1340 You("penetrated a high security area!");
1341 pline("An alarm sounds!");
1342 for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
1343 if (!DEADMONSTER(mtmp) && mtmp->msleeping) mtmp->msleeping = 0;
1346 if (on_level(&u.uz, &astral_level))
1350 assign_level(&u.uz0, &u.uz); /* reset u.uz0 */
1353 save_currentstate();
1356 /* assume this will always return TRUE when changing level */
1357 (void) in_out_region(u.ux, u.uy);
1369 /* reset monster hostility relative to player */
1370 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
1371 if (!DEADMONSTER(mtmp)) reset_hostility(mtmp);
1373 /* create some player-monsters */
1374 create_mplayers(rn1(4, 3), TRUE);
1376 /* create a guardian angel next to player, if worthy */
1379 "A voice booms: \"Thy desire for conflict shall be fulfilled!\"");
1380 for (i = rnd(4); i > 0; --i) {
1383 if (enexto(&mm, mm.x, mm.y, &mons[PM_ANGEL]))
1384 (void) mk_roamer(&mons[PM_ANGEL], u.ualign.type,
1388 } else if (u.ualign.record > 8) { /* fervent */
1389 pline("A voice whispers: \"Thou hast been worthy of me!\"");
1392 if (enexto(&mm, mm.x, mm.y, &mons[PM_ANGEL])) {
1393 if ((mtmp = mk_roamer(&mons[PM_ANGEL], u.ualign.type,
1394 mm.x, mm.y, TRUE)) != 0) {
1396 pline("An angel appears near you.");
1398 You_feel("the presence of a friendly angel near you.");
1399 /* guardian angel -- the one case mtame doesn't
1400 * imply an edog structure, so we don't want to
1404 /* make him strong enough vs. endgame foes */
1405 mtmp->m_lev = rn1(8,15);
1406 mtmp->mhp = mtmp->mhpmax =
1407 d((int)mtmp->m_lev,10) + 30 + rnd(30);
1408 if ((otmp = select_hwep(mtmp)) == 0) {
1409 otmp = mksobj(SILVER_SABER, FALSE, FALSE);
1410 if (mpickobj(mtmp, otmp))
1411 panic("merged weapon?");
1414 if (otmp->spe < 4) otmp->spe += rnd(4);
1415 if ((otmp = which_armor(mtmp, W_ARMS)) == 0 ||
1416 otmp->otyp != SHIELD_OF_REFLECTION) {
1417 (void) mongets(mtmp, AMULET_OF_REFLECTION);
1418 m_dowear(mtmp, TRUE);
1425 static char *dfr_pre_msg = 0, /* pline() before level change */
1426 *dfr_post_msg = 0; /* pline() after level change */
1428 /* change levels at the end of this turn, after monsters finish moving */
1430 schedule_goto(tolev, at_stairs, falling, portal_flag, pre_msg, post_msg)
1432 boolean at_stairs, falling;
1434 const char *pre_msg, *post_msg;
1436 int typmask = 0100; /* non-zero triggers `deferred_goto' */
1438 /* destination flags (`goto_level' args) */
1439 if (at_stairs) typmask |= 1;
1440 if (falling) typmask |= 2;
1441 if (portal_flag) typmask |= 4;
1442 if (portal_flag < 0) typmask |= 0200; /* flag for portal removal */
1443 u.utotype = typmask;
1444 /* destination level */
1445 assign_level(&u.utolev, tolev);
1448 dfr_pre_msg = strcpy((char *)alloc(strlen(pre_msg) + 1), pre_msg);
1450 dfr_post_msg = strcpy((char *)alloc(strlen(post_msg)+1), post_msg);
1453 /* handle something like portal ejection */
1457 if (!on_level(&u.uz, &u.utolev)) {
1459 int typmask = u.utotype; /* save it; goto_level zeroes u.utotype */
1461 assign_level(&dest, &u.utolev);
1462 if (dfr_pre_msg) pline(dfr_pre_msg);
1463 goto_level(&dest, !!(typmask&1), !!(typmask&2), !!(typmask&4));
1464 if (typmask & 0200) { /* remove portal */
1465 struct trap *t = t_at(u.ux, u.uy);
1472 if (dfr_post_msg) pline(dfr_post_msg);
1474 u.utotype = 0; /* our caller keys off of this */
1476 free((genericptr_t)dfr_pre_msg), dfr_pre_msg = 0;
1478 free((genericptr_t)dfr_post_msg), dfr_post_msg = 0;
1485 * Return TRUE if we created a monster for the corpse. If successful, the
1489 revive_corpse(corpse)
1492 struct monst *mtmp, *mcarry;
1493 boolean is_uwep, chewed;
1495 char *cname, cname_buf[BUFSZ];
1496 struct obj *container = (struct obj *)0;
1497 int container_where = 0;
1499 where = corpse->where;
1500 is_uwep = corpse == uwep;
1501 cname = eos(strcpy(cname_buf, "bite-covered "));
1502 Strcpy(cname, corpse_xname(corpse, TRUE));
1503 mcarry = (where == OBJ_MINVENT) ? corpse->ocarry : 0;
1505 if (where == OBJ_CONTAINED) {
1506 struct monst *mtmp2 = (struct monst *)0;
1507 container = corpse->ocontainer;
1508 mtmp2 = get_container_location(container, &container_where, (int *)0);
1509 /* container_where is the outermost container's location even if nested */
1510 if (container_where == OBJ_MINVENT && mtmp2) mcarry = mtmp2;
1512 mtmp = revive(corpse); /* corpse is gone if successful */
1515 chewed = (mtmp->mhp < mtmp->mhpmax);
1516 if (chewed) cname = cname_buf; /* include "bite-covered" prefix */
1520 pline_The("%s writhes out of your grasp!", cname);
1522 You_feel("squirming in your backpack!");
1526 if (cansee(mtmp->mx, mtmp->my))
1527 pline("%s rises from the dead!", chewed ?
1528 Adjmonnam(mtmp, "bite-covered") : Monnam(mtmp));
1531 case OBJ_MINVENT: /* probably a nymph's */
1532 if (cansee(mtmp->mx, mtmp->my)) {
1533 if (canseemon(mcarry))
1534 pline("Startled, %s drops %s as it revives!",
1535 mon_nam(mcarry), an(cname));
1537 pline("%s suddenly appears!", chewed ?
1538 Adjmonnam(mtmp, "bite-covered") : Monnam(mtmp));
1542 if (container_where == OBJ_MINVENT && cansee(mtmp->mx, mtmp->my) &&
1543 mcarry && canseemon(mcarry) && container) {
1544 char sackname[BUFSZ];
1545 Sprintf(sackname, "%s %s", s_suffix(mon_nam(mcarry)),
1547 pline("%s writhes out of %s!", Amonnam(mtmp), sackname);
1548 } else if (container_where == OBJ_INVENT && container) {
1549 char sackname[BUFSZ];
1550 Strcpy(sackname, an(xname(container)));
1551 pline("%s %s out of %s in your pack!",
1552 Blind ? Something : Amonnam(mtmp),
1553 locomotion(mtmp->data,"writhes"),
1555 } else if (container_where == OBJ_FLOOR && container &&
1556 cansee(mtmp->mx, mtmp->my)) {
1557 char sackname[BUFSZ];
1558 Strcpy(sackname, an(xname(container)));
1559 pline("%s escapes from %s!", Amonnam(mtmp), sackname);
1563 /* we should be able to handle the other cases... */
1564 impossible("revive_corpse: lost corpse @ %d", where);
1572 /* Revive the corpse via a timeout. */
1575 revive_mon(arg, timeout)
1579 struct obj *body = (struct obj *) arg;
1581 /* if we succeed, the corpse is gone, otherwise, rot it away */
1582 if (!revive_corpse(body)) {
1583 if (is_rider(&mons[body->corpsenm]))
1584 You_feel("less hassled.");
1585 (void) start_timer(250L - (monstermoves-body->age),
1586 TIMER_OBJECT, ROT_CORPSE, arg);
1593 return(1); /* Do nothing, but let other things happen */
1602 if(u.ucreamed < 4) u.ucreamed = 0;
1603 else u.ucreamed -= 4;
1604 if (Blinded < 4) Blinded = 0;
1607 pline("You've got the glop off.");
1610 make_blinded(0L,TRUE);
1612 } else if (!u.ucreamed) {
1613 Your("%s feels clean now.", body_part(FACE));
1616 return(1); /* still busy */
1623 static NEARDATA char buf[39];
1625 Sprintf(buf, "wiping off your %s", body_part(FACE));
1626 set_occupation(wipeoff, buf, 0);
1627 /* Not totally correct; what if they change back after now
1628 * but before they're finished wiping?
1632 Your("%s is already clean.", body_part(FACE));
1637 set_wounded_legs(side, timex)
1642 * If you are riding, your steed gets the wounded legs instead.
1643 * You still call this function, but don't lose hp.
1644 * Caller is also responsible for adjusting messages.
1652 if(!Wounded_legs || (HWounded_legs & TIMEOUT))
1653 HWounded_legs = timex;
1654 EWounded_legs = side;
1655 (void)encumber_msg();
1662 if (ATEMP(A_DEX) < 0) {
1671 /* KMH, intrinsics patch */
1672 if((EWounded_legs & BOTH_SIDES) == BOTH_SIDES) {
1673 Your("%s feel somewhat better.",
1674 makeplural(body_part(LEG)));
1676 Your("%s feels somewhat better.",
1680 HWounded_legs = EWounded_legs = 0;
1682 (void)encumber_msg();