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. */
4 
5 /* Contains code for 'd', 'D' (drop), '>', '<' (up, down) */
6 
7 #include "hack.h"
8 #include "lev.h"
9 
10 #ifdef SINKS
11 # ifdef OVLB
12 STATIC_DCL void FDECL(trycall, (struct obj *));
13 # endif /* OVLB */
14 STATIC_DCL void FDECL(dosinkring, (struct obj *));
15 #endif /* SINKS */
16 
17 STATIC_PTR int FDECL(drop, (struct obj *));
18 STATIC_PTR int NDECL(wipeoff);
19 
20 #ifdef OVL0
21 STATIC_DCL int FDECL(menu_drop, (int));
22 #endif
23 #ifdef OVL2
24 STATIC_DCL int NDECL(currentlevel_rewrite);
25 STATIC_DCL void NDECL(final_level);
26 /* static boolean FDECL(badspot, (XCHAR_P,XCHAR_P)); */
27 #endif
28 
29 #ifdef OVLB
30 
31 static NEARDATA const char drop_types[] =
32 	{ ALLOW_COUNT, COIN_CLASS, ALL_CLASSES, 0 };
33 
34 /* 'd' command: drop one inventory item */
35 int
dodrop()36 dodrop()
37 {
38 #ifndef GOLDOBJ
39 	int result, i = (invent || u.ugold) ? 0 : (SIZE(drop_types) - 1);
40 #else
41 	int result, i = (invent) ? 0 : (SIZE(drop_types) - 1);
42 #endif
43 
44 	if (*u.ushops) sellobj_state(SELL_DELIBERATE);
45 	result = drop(getobj(&drop_types[i], "drop"));
46 	if (*u.ushops) sellobj_state(SELL_NORMAL);
47 	reset_occupations();
48 
49 	return result;
50 }
51 
52 #endif /* OVLB */
53 #ifdef OVL0
54 
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.
58  */
59 boolean
boulder_hits_pool(otmp,rx,ry,pushing)60 boulder_hits_pool(otmp, rx, ry, pushing)
61 struct obj *otmp;
62 register int rx, ry;
63 boolean pushing;
64 {
65 	if (!otmp || otmp->otyp != BOULDER)
66 	    warning("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;
73 
74 	    if (fills_up) {
75 		struct trap *ttmp = t_at(rx, ry);
76 
77 		if (ltyp == DRAWBRIDGE_UP) {
78 		    levl[rx][ry].drawbridgemask &= ~DB_UNDER; /* clear lava */
79 		    levl[rx][ry].drawbridgemask |= DB_FLOOR;
80 		} else
81 		    levl[rx][ry].typ = ROOM;
82 
83 		if (ttmp) (void) delfloortrap(ttmp);
84 		bury_objs(rx, ry);
85 
86 		newsym(rx,ry);
87 		if (pushing) {
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 */
92 		}
93 	    }
94 	    if (!fills_up || !pushing) {	/* splashing occurs */
95 		if (!u.uinwater) {
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",
99 			      what);
100 		    } else if (flags.soundok)
101 			You_hear("a%s splash.", lava ? " sizzling" : "");
102 		    wake_nearto(rx, ry, 40);
103 		}
104 
105 		if (fills_up && u.uinwater && distu(rx,ry) == 0) {
106 		    u.uinwater = 0;
107 		    docrt();
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 ? '.' : '!');
113 			burn_away_slime();
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!");
119 	    }
120 
121 	    /* boulder is now gone */
122 	    if (pushing) delobj(otmp);
123 	    else obfree(otmp, (struct obj *)0);
124 	    return TRUE;
125 	}
126 	return FALSE;
127 }
128 
129 /* Used for objects which sometimes do special things when dropped; must be
130  * called with the object not in any chain.  Returns TRUE if the object goes
131  * away.
132  */
133 boolean
flooreffects(obj,x,y,verb)134 flooreffects(obj,x,y,verb)
135 struct obj *obj;
136 int x,y;
137 const char *verb;
138 {
139 	struct trap *t;
140 	struct monst *mtmp;
141 
142 	if (obj->where != OBJ_FREE)
143 	    panic("flooreffects: obj not free (%d)", obj->where);
144 
145 	/* make sure things like water_damage() have no pointers to follow */
146 	obj->nobj = obj->nexthere = (struct obj *)0;
147 
148 	if (obj->otyp == BOULDER && boulder_hits_pool(obj, x, y, FALSE))
149 		return TRUE;
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)) {
155 		    if (*verb)
156 			pline_The("boulder %s into the pit%s.",
157 				vtense((const char *)0, verb),
158 				(mtmp) ? "" : " with you");
159 		    if (mtmp) {
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 */
164 			}
165 			mtmp->mtrapped = 0;
166 		    } else {
167 			if (!Passes_walls && !throws_rocks(youmonst.data)) {
168 			    losehp(rnd(15), "squished under a boulder",
169 				   NO_KILLER_PREFIX);
170 			    return FALSE;	/* player remains trapped */
171 			} else u.utrap = 0;
172 		    }
173 		}
174 		if (*verb) {
175 			if (Blind) {
176 				if ((x == u.ux) && (y == u.uy))
177 					You_hear("a CRASH! beneath you.");
178 				else
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" :
185 				    "fills a pit");
186 			}
187 		}
188 		deltrap(t);
189 		obfree(obj, (struct obj *)0);
190 		bury_objs(x, y);
191 		newsym(x,y);
192 		return TRUE;
193 	} else if (obj->otyp==AMULET_OF_YENDOR &&
194 	           (obj->cursed ? rnf(1,2) :
195 		    obj->blessed ? rnf(1,16) : rnf(1,4))) {
196 		/* prevent recursive call of teleportation through flooreffects */
197 		if (!obj->orecursive &&
198 		    distu(x,y) < 9) {
199 			if (Blind) {
200 				You_hear("%s!",
201 				         (Hallucination) ? "nothing special happening" :
202 				                           "something teleporting");
203 			} else if (cansee(x,y)) {
204 				pline("Right after touching the %s the %s teleports away!",
205 				      surface(x, y),
206 				      (Hallucination) ? "teddy bear" : "amulet");
207 			}
208 			obj->orecursive = TRUE;
209 			rloco(obj);
210 			obj->orecursive = FALSE;
211 			return TRUE;
212 		} else {
213 			return FALSE;
214 		}
215 	} else if (is_lava(x, y)) {
216 		return fire_damage(obj, FALSE, FALSE, x, y);
217 	} else if (is_pool(x, y)) {
218 		/* Reasonably bulky objects (arbitrary) splash when dropped.
219 		 * If you're floating above the water even small things make noise.
220 		 * Stuff dropped near fountains always misses */
221 		if ((Blind || (Levitation || Flying)) && flags.soundok &&
222 		    ((x == u.ux) && (y == u.uy))) {
223 		    if (!Underwater) {
224 			if (weight(obj) > 9) {
225 				pline("Splash!");
226 		        } else if (Levitation || Flying) {
227 				pline("Plop!");
228 		        }
229 		    }
230 		    map_background(x, y, 0);
231 		    newsym(x, y);
232 		}
233 		return water_damage(obj, FALSE, FALSE);
234 	} else if (u.ux == x && u.uy == y &&
235 		(!u.utrap || u.utraptype != TT_PIT) &&
236 		(t = t_at(x,y)) != 0 && t->tseen &&
237 			(t->ttyp==PIT || t->ttyp==SPIKED_PIT)) {
238 		/* you escaped a pit and are standing on the precipice */
239 		if (Blind && flags.soundok)
240 			You_hear("%s %s downwards.",
241 				The(xname(obj)), otense(obj, "tumble"));
242 		else
243 			pline("%s %s into %s pit.",
244 				The(xname(obj)), otense(obj, "tumble"),
245 				the_your[t->madeby_u]);
246 	}
247 	return FALSE;
248 }
249 
250 #endif /* OVL0 */
251 #ifdef OVLB
252 
253 void
doaltarobj(obj)254 doaltarobj(obj)  /* obj is an object dropped on an altar */
255 	register struct obj *obj;
256 {
257 	if (Blind)
258 		return;
259 
260 	/* KMH, conduct */
261 	u.uconduct.gnostic++;
262 
263 	if ((obj->blessed || obj->cursed) && obj->oclass != COIN_CLASS) {
264 		There("is %s flash as %s %s the altar.",
265 			an(hcolor(obj->blessed ? NH_AMBER : NH_BLACK)),
266 			doname(obj), otense(obj, "hit"));
267 		if (!Hallucination) obj->bknown = 1;
268 	} else {
269 		pline("%s %s on the altar.", Doname2(obj),
270 			otense(obj, "land"));
271 		obj->bknown = 1;
272 	}
273 }
274 
275 #ifdef SINKS
276 STATIC_OVL
277 void
trycall(obj)278 trycall(obj)
279 register struct obj *obj;
280 {
281 	if(!objects[obj->otyp].oc_name_known &&
282 	   !objects[obj->otyp].oc_uname)
283 	   docall(obj);
284 }
285 
286 /** Transforms the sink at the player's position into
287  * a fountain, throne, altar or grave. */
288 STATIC_OVL
289 void
polymorph_sink()290 polymorph_sink()
291 {
292 	if (levl[u.ux][u.uy].typ != SINK) { return; }
293 
294 	level.flags.nsinks--;
295 	levl[u.ux][u.uy].doormask = 0;
296 	switch(rn2(4)) {
297 		case 0:
298 			levl[u.ux][u.uy].typ = FOUNTAIN;
299 			level.flags.nfountains++;
300 			break;
301 		case 1:
302 			levl[u.ux][u.uy].typ = THRONE;
303 			break;
304 		case 2:
305 			levl[u.ux][u.uy].typ = ALTAR;
306 			levl[u.ux][u.uy].altarmask = Align2amask(rn2((int)A_LAWFUL+2) - 1);
307 			break;
308 		case 3:
309 			levl[u.ux][u.uy].typ = ROOM;
310 			make_grave(u.ux, u.uy, (char *) 0);
311 			break;
312 	}
313 	pline_The("sink transforms into %s!",
314 			(levl[u.ux][u.uy].typ == THRONE) ?
315 			"a throne" : an(surface(u.ux, u.uy)));
316 	newsym(u.ux,u.uy);
317 }
318 
319 /** Teleports the sink at the player's position.
320  * @return TRUE if sink teleported */
321 STATIC_OVL
322 boolean
teleport_sink()323 teleport_sink()
324 {
325 	int cx, cy;
326 	int cnt = 0;
327 	struct trap *trp;
328 	do {
329 		cx = rnd(COLNO-1);
330 		cy = rn2(ROWNO);
331 		trp = t_at(cx,cy);
332 	} while (((levl[cx][cy].typ != ROOM) ||
333 	          (trp) ||
334 	          cansee(cx,cy)) &&
335 	         (cnt++ < 200));
336 	if ((levl[cx][cy].typ == ROOM) && !trp) {
337 		/* create sink at new position */
338 		levl[cx][cy].typ = SINK;
339 		levl[cx][cy].looted = levl[u.ux][u.uy].looted;
340 		newsym(cx,cy);
341 		/* remove old sink */
342 		levl[u.ux][u.uy].typ = ROOM;
343 		levl[u.ux][u.uy].looted = 0;
344 		newsym(u.ux,u.uy);
345 		return TRUE;
346 	}
347 	return FALSE;
348 }
349 
350 STATIC_OVL
351 void
dosinkring(obj)352 dosinkring(obj)  /* obj is a ring being dropped over a kitchen sink */
353 register struct obj *obj;
354 {
355 	register struct obj *otmp,*otmp2;
356 	register boolean ideed = TRUE;
357 
358 	You("drop %s down the drain.", doname(obj));
359 	obj->in_use = TRUE;	/* block free identification via interrupt */
360 	switch(obj->otyp) {	/* effects that can be noticed without eyes */
361 	    case RIN_SEARCHING:
362 		You("thought your %s got lost in the sink, but there it is!",
363 			xname(obj));
364 		goto giveback;
365 	    case RIN_SLOW_DIGESTION:
366 		pline_The("ring is regurgitated!");
367 giveback:
368 		obj->in_use = FALSE;
369 		dropx(obj);
370 		trycall(obj);
371 		return;
372 	    case RIN_LEVITATION:
373 		pline_The("sink quivers upward for a moment.");
374 		break;
375 	    case RIN_POISON_RESISTANCE:
376 		You("smell rotten %s.", makeplural(fruitname(FALSE)));
377 		break;
378 	    case RIN_AGGRAVATE_MONSTER:
379 		pline("Several %s buzz angrily around the sink.",
380 		      Hallucination ? makeplural(rndmonnam()) : "flies");
381 		break;
382 	    case RIN_SHOCK_RESISTANCE:
383 		pline("Static electricity surrounds the sink.");
384 		break;
385 	    case RIN_CONFLICT:
386 		You_hear("loud noises coming from the drain.");
387 		break;
388 	    case RIN_SUSTAIN_ABILITY:	/* KMH */
389 		pline_The("water flow seems fixed.");
390 		break;
391 	    case RIN_GAIN_STRENGTH:
392 		pline_The("water flow seems %ser now.",
393 			(obj->spe<0) ? "weak" : "strong");
394 		break;
395 	    case RIN_GAIN_CONSTITUTION:
396 		pline_The("water flow seems %ser now.",
397 			(obj->spe<0) ? "less" : "great");
398 		break;
399 	    case RIN_GAIN_INTELLIGENCE:
400 		pline("The water seems %ser now.",
401 			(obj->spe<0) ? "dimm" : "bright");
402 		break;
403 	    case RIN_GAIN_WISDOM:
404 		pline("The water flow seems %ser now.",
405 			(obj->spe<0) ? "dull" : "quick");
406 		break;
407 	    case RIN_GAIN_DEXTERITY:
408 		pline("The water flow seems %ser now.",
409 			(obj->spe<0) ? "slow" : "fast");
410 		break;
411 	    case RIN_INCREASE_ACCURACY:	/* KMH */
412 		pline_The("water flow %s the drain.",
413 			(obj->spe<0) ? "misses" : "hits");
414 		break;
415 	    case RIN_INCREASE_DAMAGE:
416 		pline_The("water's force seems %ser now.",
417 			(obj->spe<0) ? "small" : "great");
418 		break;
419 	    case RIN_HUNGER:
420 		ideed = FALSE;
421 		for(otmp = level.objects[u.ux][u.uy]; otmp; otmp = otmp2) {
422 		    otmp2 = otmp->nexthere;
423 		    if (otmp != uball && otmp != uchain &&
424 			    !obj_resists(otmp, 1, 99)) {
425 			if (!Blind) {
426 			    pline("Suddenly, %s %s from the sink!",
427 				  doname(otmp), otense(otmp, "vanish"));
428 			    ideed = TRUE;
429 			}
430 			delobj(otmp);
431 		    }
432 		}
433 		break;
434 	    case MEAT_RING:
435 		/* Not the same as aggravate monster; besides, it's obvious. */
436 		pline("Several %s buzz around the sink.",
437 		      Hallucination ? makeplural(rndmonnam()) : "flies");
438 		break;
439 	    default:
440 		ideed = FALSE;
441 		break;
442 	}
443 	if(!Blind && !ideed && obj->otyp != RIN_HUNGER) {
444 	    ideed = TRUE;
445 	    switch(obj->otyp) {		/* effects that need eyes */
446 		case RIN_ADORNMENT:
447 		    pline_The("faucets flash brightly for a moment.");
448 		    break;
449 		case RIN_REGENERATION:
450 		    pline_The("sink looks as good as new.");
451 		    break;
452 		case RIN_INVISIBILITY:
453 		    pline_The("water flow momentarily vanishes.");
454 		    break;
455 		case RIN_FREE_ACTION:
456 		    You("see the ring slide right down the drain!");
457 		    break;
458 		case RIN_SEE_INVISIBLE:
459 		    You("see some %s in the sink.",
460 		        Hallucination ? "oxygen molecules" : "air");
461 		    break;
462 		case RIN_STEALTH:
463 		pline_The("sink seems to blend into the floor for a moment.");
464 		    break;
465 		case RIN_FIRE_RESISTANCE:
466 		pline_The("hot water faucet flashes brightly for a moment.");
467 		    break;
468 		case RIN_COLD_RESISTANCE:
469 		pline_The("cold water faucet flashes brightly for a moment.");
470 		    break;
471 		case RIN_PROTECTION_FROM_SHAPE_CHAN:
472 		    pline_The("sink looks nothing like a fountain.");
473 		    break;
474 		case RIN_PROTECTION:
475 		    pline_The("sink glows %s for a moment.",
476 			    hcolor((obj->spe<0) ? NH_BLACK : NH_SILVER));
477 		    break;
478 		case RIN_WARNING:
479 		    pline_The("sink glows %s for a moment.", hcolor(NH_RED));
480 		    break;
481 		case RIN_TELEPORTATION:
482 		    if (teleport_sink())
483 			    pline_The("sink vanishes.");
484 		    else
485 			    pline_The("sink momentarily vanishes.");
486 		    break;
487 		case RIN_TELEPORT_CONTROL:
488 	    pline_The("sink looks like it is being beamed aboard somewhere.");
489 		    break;
490 		case RIN_POLYMORPH:
491 		    polymorph_sink();
492 		    break;
493 		case RIN_POLYMORPH_CONTROL:
494 		    pline_The("sink transforms into another sink!");
495 		    levl[u.ux][u.uy].looted = 0;
496 		    break;
497 	    }
498 	}
499 	if(ideed)
500 	    trycall(obj);
501 	else
502 	    You_hear("the ring bouncing down the drainpipe.");
503 	if (!rn2(20)) {
504 		pline_The("sink backs up, leaving %s.", doname(obj));
505 		obj->in_use = FALSE;
506 		dropx(obj);
507 	} else
508 		useup(obj);
509 }
510 #endif
511 
512 #endif /* OVLB */
513 #ifdef OVL0
514 
515 /* some common tests when trying to drop or throw items */
516 boolean
canletgo(obj,word)517 canletgo(obj,word)
518 register struct obj *obj;
519 register const char *word;
520 {
521 	if(obj->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL)){
522 		if (*word)
523 			Norep("You cannot %s %s you are wearing.",word,
524 				something);
525 		return(FALSE);
526 	}
527 	if (obj->otyp == LOADSTONE && obj->cursed) {
528 		/* getobj() kludge sets corpsenm to user's specified count
529 		   when refusing to split a stack of cursed loadstones */
530 		if (*word) {
531 			/* getobj() ignores a count for throwing since that is
532 			   implicitly forced to be 1; replicate its kludge... */
533 			if (!strcmp(word, "throw") && obj->quan > 1L)
534 			    obj->corpsenm = 1;
535 			pline("For some reason, you cannot %s%s the stone%s!",
536 			      word, obj->corpsenm ? " any of" : "",
537 			      plur(obj->quan));
538 		}
539 		obj->corpsenm = 0;		/* reset */
540 		obj->bknown = 1;
541 		return(FALSE);
542 	}
543 	if (obj->otyp == LEASH && obj->leashmon != 0) {
544 		if (*word)
545 			pline_The("leash is tied around your %s.",
546 					body_part(HAND));
547 		return(FALSE);
548 	}
549 #ifdef STEED
550 	if (obj->owornmask & W_SADDLE) {
551 		if (*word)
552 			You("cannot %s %s you are sitting on.", word,
553 				something);
554 		return (FALSE);
555 	}
556 #endif
557 	return(TRUE);
558 }
559 
560 STATIC_PTR
561 int
drop(obj)562 drop(obj)
563 register struct obj *obj;
564 {
565 	if(!obj) return(0);
566 	if(!canletgo(obj,"drop"))
567 		return(0);
568 	if(obj == uwep) {
569 		if(welded(uwep)) {
570 			weldmsg(obj);
571 			return(0);
572 		}
573 		setuwep((struct obj *)0);
574 	}
575 	if(obj == uquiver) {
576 		setuqwep((struct obj *)0);
577 	}
578 	if (obj == uswapwep) {
579 		setuswapwep((struct obj *)0);
580 	}
581 
582 	obj->was_dropped = TRUE;
583 
584 	if (u.uswallow) {
585 		/* barrier between you and the floor */
586 		if(flags.verbose)
587 		{
588 			char buf[BUFSZ];
589 
590 			/* doname can call s_suffix, reusing its buffer */
591 			Strcpy(buf, s_suffix(mon_nam(u.ustuck)));
592 			You("drop %s into %s %s.", doname(obj), buf,
593 				mbodypart(u.ustuck, STOMACH));
594 		}
595 	} else {
596 #ifdef SINKS
597 	    if((obj->oclass == RING_CLASS || obj->otyp == MEAT_RING) &&
598 			IS_SINK(levl[u.ux][u.uy].typ)) {
599 		dosinkring(obj);
600 		return(1);
601 	    }
602 #endif
603 	    if (!can_reach_floor()) {
604 		if(flags.verbose) You("drop %s.", doname(obj));
605 #ifndef GOLDOBJ
606 		if (obj->oclass != COIN_CLASS || obj == invent) freeinv(obj);
607 #else
608 		/* Ensure update when we drop gold objects */
609 		if (obj->oclass == COIN_CLASS) flags.botl = 1;
610 		freeinv(obj);
611 #endif
612 		hitfloor(obj);
613 		return(1);
614 	    }
615 	    if (!IS_ALTAR(levl[u.ux][u.uy].typ) && flags.verbose)
616 		You("drop %s.", doname(obj));
617 	}
618 	dropx(obj);
619 	return(1);
620 }
621 
622 /* Called in several places - may produce output */
623 /* eg ship_object() and dropy() -> sellobj() both produce output */
624 void
dropx(obj)625 dropx(obj)
626 register struct obj *obj;
627 {
628 #ifndef GOLDOBJ
629 	if (obj->oclass != COIN_CLASS || obj == invent) freeinv(obj);
630 #else
631         /* Ensure update when we drop gold objects */
632         if (obj->oclass == COIN_CLASS) flags.botl = 1;
633         freeinv(obj);
634 #endif
635 	if (!u.uswallow) {
636 	    if (ship_object(obj, u.ux, u.uy, FALSE)) return;
637 	    if (IS_ALTAR(levl[u.ux][u.uy].typ))
638 		doaltarobj(obj); /* set bknown */
639 	}
640 	dropy(obj);
641 }
642 
643 void
dropy(obj)644 dropy(obj)
645 register struct obj *obj;
646 {
647 	if (obj == uwep) setuwep((struct obj *)0);
648 	if (obj == uquiver) setuqwep((struct obj *)0);
649 	if (obj == uswapwep) setuswapwep((struct obj *)0);
650 
651 	if (!u.uswallow && flooreffects(obj,u.ux,u.uy,"drop")) return;
652 	/* uswallow check done by GAN 01/29/87 */
653 	if(u.uswallow) {
654 	    boolean could_petrify = FALSE;
655 	    boolean could_poly = FALSE;
656 	    boolean could_slime = FALSE;
657 	    boolean could_grow = FALSE;
658 	    boolean could_heal = FALSE;
659 
660 	    if (obj != uball) {		/* mon doesn't pick up ball */
661 		if (obj->otyp == CORPSE) {
662 		    could_petrify = touch_petrifies(&mons[obj->corpsenm]);
663 		    could_poly = polyfodder(obj);
664 		    could_slime = (obj->corpsenm == PM_GREEN_SLIME);
665 		    could_grow = (obj->corpsenm == PM_WRAITH);
666 		    could_heal = (obj->corpsenm == PM_NURSE);
667 		}
668 		(void) mpickobj(u.ustuck,obj);
669 		if (is_animal(u.ustuck->data)) {
670 		    if (could_poly || could_slime) {
671 			(void) newcham(u.ustuck,
672 				       could_poly ? (struct permonst *)0 :
673 				       &mons[PM_GREEN_SLIME],
674 				       FALSE, could_slime);
675 			delobj(obj);	/* corpse is digested */
676 		    } else if (could_petrify) {
677 			minstapetrify(u.ustuck, TRUE);
678 			/* Don't leave a cockatrice corpse in a statue */
679 			if (!u.uswallow) delobj(obj);
680 		    } else if (could_grow) {
681 			(void) grow_up(u.ustuck, (struct monst *)0);
682 			delobj(obj);	/* corpse is digested */
683 		    } else if (could_heal) {
684 			u.ustuck->mhp = u.ustuck->mhpmax;
685 			delobj(obj);	/* corpse is digested */
686 		    }
687 		}
688 	    }
689 	} else {
690 	    place_object(obj, u.ux, u.uy);
691 	    if (obj == uball)
692 		drop_ball(u.ux,u.uy);
693 	    else
694 		sellobj(obj, u.ux, u.uy);
695 	    stackobj(obj);
696 	    if(Blind && Levitation)
697 		map_object(obj, 0);
698 	    newsym(u.ux,u.uy);	/* remap location under self */
699 	}
700 }
701 
702 /* things that must change when not held; recurse into containers.
703    Called for both player and monsters */
704 void
obj_no_longer_held(obj)705 obj_no_longer_held(obj)
706 struct obj *obj;
707 {
708 	if (!obj) {
709 	    return;
710 	} else if ((Is_container(obj) || obj->otyp == STATUE) && obj->cobj) {
711 	    struct obj *contents;
712 	    for(contents=obj->cobj; contents; contents=contents->nobj)
713 		obj_no_longer_held(contents);
714 	}
715 	switch(obj->otyp) {
716 	case CRYSKNIFE:
717 	    /* KMH -- Fixed crysknives have only 10% chance of reverting */
718 	    /* only changes when not held by player or monster */
719 	    if (!obj->oerodeproof || !rn2(10)) {
720 		obj->otyp = WORM_TOOTH;
721 		obj->oerodeproof = 0;
722 	    }
723 	    break;
724 	}
725 }
726 
727 /* 'D' command: drop several things */
728 int
doddrop()729 doddrop()
730 {
731 	int result = 0;
732 
733 	add_valid_menu_class(0); /* clear any classes already there */
734 	if (*u.ushops) sellobj_state(SELL_DELIBERATE);
735 	if (flags.menu_style != MENU_TRADITIONAL ||
736 		(result = ggetobj("drop", drop, 0, FALSE, (unsigned *)0)) < -1)
737 	    result = menu_drop(result);
738 	if (*u.ushops) sellobj_state(SELL_NORMAL);
739 	reset_occupations();
740 
741 	return result;
742 }
743 
744 /* Drop things from the hero's inventory, using a menu. */
745 STATIC_OVL int
menu_drop(retry)746 menu_drop(retry)
747 int retry;
748 {
749     int n, i, n_dropped = 0;
750     long cnt;
751     struct obj *otmp, *otmp2;
752 #ifndef GOLDOBJ
753     struct obj *u_gold = 0;
754 #endif
755     menu_item *pick_list;
756     boolean all_categories = TRUE;
757     boolean drop_everything = FALSE;
758 
759 #ifndef GOLDOBJ
760     if (u.ugold) {
761 	/* Hack: gold is not in the inventory, so make a gold object
762 	   and put it at the head of the inventory list. */
763 	u_gold = mkgoldobj(u.ugold);	/* removes from u.ugold */
764 	u_gold->in_use = TRUE;
765 	u.ugold = u_gold->quan;		/* put the gold back */
766 	assigninvlet(u_gold);		/* might end up as NOINVSYM */
767 	u_gold->nobj = invent;
768 	invent = u_gold;
769     }
770 #endif
771     if (retry) {
772 	all_categories = (retry == -2);
773     } else if (flags.menu_style == MENU_FULL) {
774 	all_categories = FALSE;
775 	n = query_category("Drop what type of items?",
776 			invent,
777 			UNPAID_TYPES | ALL_TYPES | CHOOSE_ALL |
778 			BUC_BLESSED | BUC_CURSED | BUC_UNCURSED | BUC_UNKNOWN,
779 			&pick_list, PICK_ANY);
780 	if (!n) goto drop_done;
781 	for (i = 0; i < n; i++) {
782 	    if (pick_list[i].item.a_int == ALL_TYPES_SELECTED)
783 		all_categories = TRUE;
784 	    else if (pick_list[i].item.a_int == 'A')
785 		drop_everything = TRUE;
786 	    else
787 		add_valid_menu_class(pick_list[i].item.a_int);
788 	}
789 	free((genericptr_t) pick_list);
790     } else if (flags.menu_style == MENU_COMBINATION) {
791 	unsigned ggoresults = 0;
792 	all_categories = FALSE;
793 	/* Gather valid classes via traditional NetHack method */
794 	i = ggetobj("drop", drop, 0, TRUE, &ggoresults);
795 	if (i == -2) all_categories = TRUE;
796 	if (ggoresults & ALL_FINISHED) {
797 		n_dropped = i;
798 		goto drop_done;
799 	}
800     }
801 
802     if (drop_everything) {
803 	for(otmp = invent; otmp; otmp = otmp2) {
804 	    otmp2 = otmp->nobj;
805 	    n_dropped += drop(otmp);
806 	}
807     } else {
808 	/* should coordinate with perm invent, maybe not show worn items */
809 	n = query_objlist("What would you like to drop?", invent,
810 			USE_INVLET|INVORDER_SORT, &pick_list,
811 			PICK_ANY, all_categories ? allow_all : allow_category);
812 	if (n > 0) {
813 	    for (i = 0; i < n; i++) {
814 		otmp = pick_list[i].item.a_obj;
815 		cnt = pick_list[i].count;
816 		if (cnt < otmp->quan) {
817 		    if (welded(otmp)) {
818 			;	/* don't split */
819 		    } else if (otmp->otyp == LOADSTONE && otmp->cursed) {
820 			/* same kludge as getobj(), for canletgo()'s use */
821 			otmp->corpsenm = (int) cnt;	/* don't split */
822 		    } else {
823 #ifndef GOLDOBJ
824 			if (otmp->oclass == COIN_CLASS)
825 			    (void) splitobj(otmp, otmp->quan - cnt);
826 			else
827 #endif
828 			    otmp = splitobj(otmp, cnt);
829 		    }
830 		}
831 		n_dropped += drop(otmp);
832 	    }
833 	    free((genericptr_t) pick_list);
834 	}
835     }
836 
837  drop_done:
838 #ifndef GOLDOBJ
839     if (u_gold && invent && invent->oclass == COIN_CLASS) {
840 	/* didn't drop [all of] it */
841 	u_gold = invent;
842 	invent = u_gold->nobj;
843 	u_gold->in_use = FALSE;
844 	dealloc_obj(u_gold);
845 	update_inventory();
846     }
847 #endif
848     return n_dropped;
849 }
850 
851 #endif /* OVL0 */
852 #ifdef OVL2
853 
854 /* on a ladder, used in goto_level */
855 static NEARDATA boolean at_ladder = FALSE;
856 
857 int
dodown()858 dodown()
859 {
860 	struct trap *trap = 0;
861 	boolean stairs_down = ((u.ux == xdnstair && u.uy == ydnstair) ||
862 		    (u.ux == sstairs.sx && u.uy == sstairs.sy && !sstairs.up)),
863 		ladder_down = (u.ux == xdnladder && u.uy == ydnladder);
864 
865 #ifdef STEED
866 	if (u.usteed && !u.usteed->mcanmove) {
867 		pline("%s won't move!", Monnam(u.usteed));
868 		return(0);
869 	} else if (u.usteed && u.usteed->meating) {
870 		pline("%s is still eating.", Monnam(u.usteed));
871 		return(0);
872 	} else
873 #endif
874 	if (Levitation) {
875 	    if ((HLevitation & I_SPECIAL) || (ELevitation & W_ARTI)) {
876 		/* end controlled levitation */
877 		if (ELevitation & W_ARTI) {
878 		    struct obj *obj;
879 
880 		    for(obj = invent; obj; obj = obj->nobj) {
881 			if (obj->oartifact &&
882 					artifact_has_invprop(obj,LEVITATION)) {
883 			    if (obj->age < monstermoves)
884 				obj->age = monstermoves + rnz(100);
885 			    else
886 				obj->age += rnz(100);
887 			}
888 		    }
889 		}
890 		if (float_down(I_SPECIAL|TIMEOUT, W_ARTI))
891 		    return (1);   /* came down, so moved */
892 	    }
893 	    floating_above(stairs_down ? "stairs" : ladder_down ?
894 			   "ladder" : surface(u.ux, u.uy));
895 	    return (0);   /* didn't move */
896 	}
897 	if (!stairs_down && !ladder_down) {
898 		if (!(trap = t_at(u.ux,u.uy)) ||
899 			(trap->ttyp != TRAPDOOR && trap->ttyp != HOLE &&
900 			 trap->ttyp != PIT && trap->ttyp != SPIKED_PIT)
901 			|| !Can_fall_thru(&u.uz) || !trap->tseen) {
902 
903 			if (flags.autodig && !flags.nopick &&
904 				uwep && is_pick(uwep)) {
905 				return use_pick_axe2(uwep);
906 			} else {
907 				You_cant("go down here.");
908 				return(0);
909 			}
910 		}
911 	}
912 	if(u.ustuck) {
913 		You("are %s, and cannot go down.",
914 			!u.uswallow ? "being held" : is_animal(u.ustuck->data) ?
915 			"swallowed" : "engulfed");
916 		return(1);
917 	}
918 	if (on_level(&valley_level, &u.uz) && !u.uevent.gehennom_entered) {
919 		You("are standing at the gate to Gehennom.");
920 		pline("Unspeakable cruelty and harm lurk down there.");
921 		if (yn("Are you sure you want to enter?") != 'y')
922 			return(0);
923 		else pline("So be it.");
924 		u.uevent.gehennom_entered = 1;	/* don't ask again */
925 	}
926 
927 	if(!next_to_u()) {
928 		You("are held back by your pet!");
929 		return(0);
930 	}
931 
932 	if (trap) {
933 		if (trap->ttyp == PIT || trap->ttyp == SPIKED_PIT) {
934 			if (u.utrap && (u.utraptype == TT_PIT)) {
935 				if (flags.autodig && !flags.nopick &&
936 					uwep && is_pick(uwep)) {
937 					return use_pick_axe2(uwep);
938 				} else {
939 					You("are already in the pit."); /* YAFM needed */
940 				}
941 			} else {
942 				u.utrap = 1;
943 				u.utraptype = TT_PIT;
944 				You("%s down into the pit.", locomotion(youmonst.data, "go"));
945 			}
946 			return(0);
947 		} else {
948 			You("%s %s.", locomotion(youmonst.data, "jump"),
949 					trap->ttyp == HOLE ? "down the hole" : "through the trap door");
950 		}
951 	}
952 
953 	if (trap && Is_stronghold(&u.uz)) {
954 		goto_hell(FALSE, TRUE);
955 	} else {
956 		at_ladder = (boolean) (levl[u.ux][u.uy].typ == LADDER);
957 		next_level(!trap);
958 		at_ladder = FALSE;
959 	}
960 	return(1);
961 }
962 
963 int
doup()964 doup()
965 {
966 	if( (u.ux != xupstair || u.uy != yupstair)
967 	     && (!xupladder || u.ux != xupladder || u.uy != yupladder)
968 	     && (!sstairs.sx || u.ux != sstairs.sx || u.uy != sstairs.sy
969 			|| !sstairs.up)
970 	  ) {
971 		You_cant("go up here.");
972 		return(0);
973 	}
974 #ifdef STEED
975 	if (u.usteed && !u.usteed->mcanmove) {
976 		pline("%s won't move!", Monnam(u.usteed));
977 		return(0);
978 	} else if (u.usteed && u.usteed->meating) {
979 		pline("%s is still eating.", Monnam(u.usteed));
980 		return(0);
981 	} else
982 #endif
983 	if(u.ustuck) {
984 		You("are %s, and cannot go up.",
985 			!u.uswallow ? "being held" : is_animal(u.ustuck->data) ?
986 			"swallowed" : "engulfed");
987 		return(1);
988 	}
989 	if(near_capacity() > SLT_ENCUMBER) {
990 		/* No levitation check; inv_weight() already allows for it */
991 		Your("load is too heavy to climb the %s.",
992 			levl[u.ux][u.uy].typ == STAIRS ? "stairs" : "ladder");
993 		return(1);
994 	}
995 	if(ledger_no(&u.uz) == 1) {
996 		if (yn("Beware, there will be no return! Still climb?") != 'y')
997 			return(0);
998 	}
999 	if(!next_to_u()) {
1000 		You("are held back by your pet!");
1001 		return(0);
1002 	}
1003 	at_ladder = (boolean) (levl[u.ux][u.uy].typ == LADDER);
1004 	prev_level(TRUE);
1005 	at_ladder = FALSE;
1006 	return(1);
1007 }
1008 
1009 d_level save_dlevel = {0, 0};
1010 
1011 /* check that we can write out the current level */
1012 STATIC_OVL int
currentlevel_rewrite()1013 currentlevel_rewrite()
1014 {
1015 	register int fd;
1016 	char whynot[BUFSZ];
1017 
1018 	/* since level change might be a bit slow, flush any buffered screen
1019 	 *  output (like "you fall through a trap door") */
1020 	mark_synch();
1021 
1022 	fd = create_levelfile(ledger_no(&u.uz), whynot);
1023 	if (fd < 0) {
1024 		/*
1025 		 * This is not quite impossible: e.g., we may have
1026 		 * exceeded our quota. If that is the case then we
1027 		 * cannot leave this level, and cannot save either.
1028 		 * Another possibility is that the directory was not
1029 		 * writable.
1030 		 */
1031 		pline("%s", whynot);
1032 		return -1;
1033 	}
1034 
1035 #ifdef MFLOPPY
1036 	if (!savelev(fd, ledger_no(&u.uz), COUNT_SAVE)) {
1037 		(void) close(fd);
1038 		delete_levelfile(ledger_no(&u.uz));
1039 		pline("UnNetHack is out of disk space for making levels!");
1040 		You("can save, quit, or continue playing.");
1041 		return -1;
1042 	}
1043 #endif
1044 	return fd;
1045 }
1046 
1047 #ifdef INSURANCE
1048 void
save_currentstate()1049 save_currentstate()
1050 {
1051 	int fd;
1052 
1053 	if (flags.ins_chkpt) {
1054 		/* write out just-attained level, with pets and everything */
1055 		fd = currentlevel_rewrite();
1056 		if(fd < 0) return;
1057 		bufon(fd);
1058 		savelev(fd,ledger_no(&u.uz), WRITE_SAVE);
1059 		bclose(fd);
1060 	}
1061 
1062 	/* write out non-level state */
1063 	savestateinlock();
1064 }
1065 #endif
1066 
1067 /*
1068 static boolean
1069 badspot(x, y)
1070 register xchar x, y;
1071 {
1072 	return((levl[x][y].typ != ROOM && levl[x][y].typ != AIR &&
1073 			 levl[x][y].typ != CORR) || MON_AT(x, y));
1074 }
1075 */
1076 
1077 #ifdef BLACKMARKET
1078 d_level new_dlevel = {0, 0};
1079 #endif
1080 
1081 void
goto_level(newlevel,at_stairs,falling,portal)1082 goto_level(newlevel, at_stairs, falling, portal)
1083 d_level *newlevel;
1084 boolean at_stairs, falling, portal;
1085 {
1086 	int fd, l_idx;
1087 	xchar new_ledger;
1088 	boolean cant_go_back,
1089 		up = (depth(newlevel) < depth(&u.uz)),
1090 		newdungeon = (u.uz.dnum != newlevel->dnum),
1091 		was_in_W_tower = In_W_tower(u.ux, u.uy, &u.uz),
1092 		familiar = FALSE;
1093 	boolean new = FALSE;	/* made a new level? */
1094 	struct monst *mtmp;
1095 	char whynot[BUFSZ];
1096 
1097 	if (dunlev(newlevel) > dunlevs_in_dungeon(newlevel))
1098 		newlevel->dlevel = dunlevs_in_dungeon(newlevel);
1099 	if (newdungeon && In_endgame(newlevel)) { /* 1st Endgame Level !!! */
1100 		if (u.uhave.amulet) {
1101 #ifdef RANDOMIZED_PLANES
1102 			pline("Well done, mortal!");
1103 			pline("But now thou must face the final Test...");
1104 			pline("Prove thyself worthy or perish!");
1105 		    assign_level(newlevel, get_first_elemental_plane());
1106 #else
1107 		    assign_level(newlevel, &earth_level);
1108 #endif
1109 		}
1110 		else return;
1111 	}
1112 	new_ledger = ledger_no(newlevel);
1113 	if (new_ledger <= 0)
1114 		done(ESCAPED);	/* in fact < 0 is impossible */
1115 
1116 #ifdef BLACKMARKET
1117 	assign_level(&new_dlevel, newlevel);
1118 #endif
1119 
1120 	/* Prevent the player from going past the first quest level unless
1121 	 * (s)he has been given the go-ahead by the leader.
1122 	 */
1123 	if (on_level(&u.uz, &qstart_level) && !newdungeon && !ok_to_quest()) {
1124 		pline("A mysterious force prevents you from descending.");
1125 		return;
1126 	}
1127 
1128 	if (on_level(newlevel, &u.uz)) return;		/* this can happen */
1129 
1130 	fd = currentlevel_rewrite();
1131 	if (fd < 0) return;
1132 
1133 	if (falling) /* assuming this is only trap door or hole */
1134 	    impact_drop((struct obj *)0, u.ux, u.uy, newlevel->dlevel);
1135 
1136 	check_special_room(TRUE);		/* probably was a trap door */
1137 	if (Punished) unplacebc();
1138 	u.utrap = 0;				/* needed in level_tele */
1139 	fill_pit(u.ux, u.uy);
1140 	u.ustuck = 0;				/* idem */
1141 	u.uinwater = 0;
1142 	u.uundetected = 0;	/* not hidden, even if means are available */
1143 	keepdogs(FALSE);
1144 	if (u.uswallow)				/* idem */
1145 		u.uswldtim = u.uswallow = 0;
1146 	recalc_mapseen(); /* recalculate map overview before we leave the level */
1147 	/*
1148 	 *  We no longer see anything on the level.  Make sure that this
1149 	 *  follows u.uswallow set to null since uswallow overrides all
1150 	 *  normal vision.
1151 	 */
1152 	vision_recalc(2);
1153 
1154 	/*
1155 	 * Save the level we're leaving.  If we're entering the endgame,
1156 	 * we can get rid of all existing levels because they cannot be
1157 	 * reached any more.  We still need to use savelev()'s cleanup
1158 	 * for the level being left, to recover dynamic memory in use and
1159 	 * to avoid dangling timers and light sources.
1160 	 */
1161 	cant_go_back = (newdungeon && In_endgame(newlevel));
1162 	if (!cant_go_back) {
1163 	    update_mlstmv();	/* current monsters are becoming inactive */
1164 	    bufon(fd);		/* use buffered output */
1165 	}
1166 	savelev(fd, ledger_no(&u.uz),
1167 		cant_go_back ? FREE_SAVE : (WRITE_SAVE | FREE_SAVE));
1168 	bclose(fd);
1169 	if (cant_go_back) {
1170 	    /* discard unreachable levels; keep #0 */
1171 	    for (l_idx = maxledgerno(); l_idx > 0; --l_idx)
1172 		delete_levelfile(l_idx);
1173 	}
1174 
1175 #ifdef REINCARNATION
1176 	if (Is_rogue_level(newlevel) || Is_rogue_level(&u.uz))
1177 		assign_rogue_graphics(Is_rogue_level(newlevel));
1178 #endif
1179 #ifdef USE_TILES
1180 	substitute_tiles(newlevel);
1181 #endif
1182 	/* record this level transition as a potential seen branch unless using
1183 	 * some non-standard means of transportation (level teleport).
1184 	 */
1185 	if ((at_stairs || falling || portal) && (u.uz.dnum != newlevel->dnum))
1186 		recbranch_mapseen(&u.uz, newlevel);
1187 	assign_level(&u.uz0, &u.uz);
1188 	assign_level(&u.uz, newlevel);
1189 	assign_level(&u.utolev, newlevel);
1190 	u.utotype = 0;
1191 	if (dunlev_reached(&u.uz) < dunlev(&u.uz))
1192 		dunlev_reached(&u.uz) = dunlev(&u.uz);
1193 	reset_rndmonst(NON_PM);   /* u.uz change affects monster generation */
1194 
1195 	/* set default level change destination areas */
1196 	/* the special level code may override these */
1197 	(void) memset((genericptr_t) &updest, 0, sizeof updest);
1198 	(void) memset((genericptr_t) &dndest, 0, sizeof dndest);
1199 
1200 	if (!(level_info[new_ledger].flags & LFILE_EXISTS)) {
1201 		/* entering this level for first time; make it now */
1202 		if (level_info[new_ledger].flags & (FORGOTTEN|VISITED)) {
1203 		    impossible("goto_level: returning to discarded level?");
1204 		    level_info[new_ledger].flags &= ~(FORGOTTEN|VISITED);
1205 		}
1206 		mklev();
1207 		new = TRUE;	/* made the level */
1208 	} else {
1209 		/* returning to previously visited level; reload it */
1210 		fd = open_levelfile(new_ledger, whynot);
1211 		if (fd < 0) {
1212 			pline("%s", whynot);
1213 			pline("Probably someone removed it.");
1214 			killer = whynot;
1215 			done(TRICKED);
1216 			/* we'll reach here if running in wizard mode */
1217 			error("Cannot continue this game.");
1218 		}
1219 		minit();	/* ZEROCOMP */
1220 		getlev(fd, hackpid, new_ledger, FALSE);
1221 		(void) close(fd);
1222 	}
1223 	/* do this prior to level-change pline messages */
1224 	vision_reset();		/* clear old level's line-of-sight */
1225 	vision_full_recalc = 0;	/* don't let that reenable vision yet */
1226 	flush_screen(-1);	/* ensure all map flushes are postponed */
1227 
1228 	if (portal && !In_endgame(&u.uz)) {
1229 	    /* find the portal on the new level */
1230 	    register struct trap *ttrap;
1231 
1232 	    for (ttrap = ftrap; ttrap; ttrap = ttrap->ntrap)
1233 		if (ttrap->ttyp == MAGIC_PORTAL) break;
1234 
1235 	    if (!ttrap) panic("goto_level: no corresponding portal!");
1236 	    seetrap(ttrap);
1237 	    u_on_newpos(ttrap->tx, ttrap->ty);
1238 	} else if (at_stairs && !In_endgame(&u.uz)) {
1239 	    if (up) {
1240 		if (at_ladder) {
1241 		    u_on_newpos(xdnladder, ydnladder);
1242 		} else {
1243 		    if (newdungeon) {
1244 			if (Is_stronghold(&u.uz)) {
1245 			    register xchar x, y;
1246 			    int trycnt = 0;
1247 
1248 			    do {
1249 				do {
1250 				    x = rn1((updest.hx - updest.lx)+1, updest.lx);
1251 				    y = rn1((updest.hy - updest.ly)+1, updest.ly);
1252 				} while ((x < updest.nlx ||
1253 					  x > updest.nhx) &&
1254 					 (y < updest.nly ||
1255 					  y > updest.nhy));
1256 			    } while ((occupied(x, y) ||
1257 				      IS_STWALL(levl[x][y].typ)) && (trycnt++ < 1000));
1258 			    if (trycnt >= 1000) warning("castle: placement failed to find good position"); /* TODO: change impossible() to warning() */
1259 			    u_on_newpos(x, y);
1260 			} else u_on_sstairs();
1261 		    } else u_on_dnstairs();
1262 		}
1263 		/* Remove bug which crashes with levitation/punishment  KAA */
1264 		if (Punished && !Levitation) {
1265 			pline("With great effort you climb the %s.",
1266 				at_ladder ? "ladder" : "stairs");
1267 		} else if (at_ladder)
1268 		    You("climb up the ladder.");
1269 	    } else {	/* down */
1270 		if (at_ladder) {
1271 		    u_on_newpos(xupladder, yupladder);
1272 		} else {
1273 		    if (newdungeon) u_on_sstairs();
1274 		    else u_on_upstairs();
1275 		}
1276 		if (u.dz && Flying)
1277 		    You("fly down along the %s.",
1278 			at_ladder ? "ladder" : "stairs");
1279 		else if (u.dz &&
1280 		    (near_capacity() > UNENCUMBERED || Punished || Fumbling)) {
1281 		    You("fall down the %s.", at_ladder ? "ladder" : "stairs");
1282 		    if (Punished) {
1283 			drag_down();
1284 			if (carried(uball)) {
1285 			    if (uwep == uball)
1286 				setuwep((struct obj *)0);
1287 			    if (uswapwep == uball)
1288 				setuswapwep((struct obj *)0);
1289 			    if (uquiver == uball)
1290 				setuqwep((struct obj *)0);
1291 			    freeinv(uball);
1292 			}
1293 		    }
1294 #ifdef STEED
1295 		    /* falling off steed has its own losehp() call */
1296 		    if (u.usteed)
1297 			dismount_steed(DISMOUNT_FELL);
1298 		    else
1299 #endif
1300 			losehp(rnd(3), "falling downstairs", KILLED_BY);
1301 		    selftouch("Falling, you");
1302 		} else if (u.dz && at_ladder)
1303 		    You("climb down the ladder.");
1304 	    }
1305 	} else {	/* trap door or level_tele or In_endgame */
1306 	    if (was_in_W_tower && On_W_tower_level(&u.uz))
1307 		/* Stay inside the Wizard's tower when feasible.	*/
1308 		/* Note: up vs down doesn't really matter in this case. */
1309 		place_lregion(dndest.nlx, dndest.nly,
1310 				dndest.nhx, dndest.nhy,
1311 				0,0, 0,0, LR_DOWNTELE, (d_level *) 0);
1312 	    else if (up)
1313 		place_lregion(updest.lx, updest.ly,
1314 				updest.hx, updest.hy,
1315 				updest.nlx, updest.nly,
1316 				updest.nhx, updest.nhy,
1317 				LR_UPTELE, (d_level *) 0);
1318 	    else
1319 		place_lregion(dndest.lx, dndest.ly,
1320 				dndest.hx, dndest.hy,
1321 				dndest.nlx, dndest.nly,
1322 				dndest.nhx, dndest.nhy,
1323 				LR_DOWNTELE, (d_level *) 0);
1324 	    if (falling) {
1325 		if (Punished) ballfall();
1326 		selftouch("Falling, you");
1327 	    }
1328 	}
1329 
1330 	if (Punished) placebc();
1331 	obj_delivery();		/* before killing geno'd monsters' eggs */
1332 	losedogs();
1333 	kill_genocided_monsters();  /* for those wiped out while in limbo */
1334 	/*
1335 	 * Expire all timers that have gone off while away.  Must be
1336 	 * after migrating monsters and objects are delivered
1337 	 * (losedogs and obj_delivery).
1338 	 */
1339 	run_timers();
1340 
1341 	initrack();
1342 
1343 	if ((mtmp = m_at(u.ux, u.uy)) != 0
1344 #ifdef STEED
1345 		&& mtmp != u.usteed
1346 #endif
1347 		) {
1348 	    /* There's a monster at your target destination; it might be one
1349 	       which accompanied you--see mon_arrive(dogmove.c)--or perhaps
1350 	       it was already here.  Randomly move you to an adjacent spot
1351 	       or else the monster to any nearby location.  Prior to 3.3.0
1352 	       the latter was done unconditionally. */
1353 	    coord cc;
1354 
1355 	    if (!rn2(2) &&
1356 		    enexto(&cc, u.ux, u.uy, youmonst.data) &&
1357 		    distu(cc.x, cc.y) <= 2)
1358 		u_on_newpos(cc.x, cc.y);	/*[maybe give message here?]*/
1359 	    else
1360 		mnexto(mtmp);
1361 
1362 	    if ((mtmp = m_at(u.ux, u.uy)) != 0) {
1363 		impossible("mnexto failed (do.c)?");
1364 		(void) rloc(mtmp, FALSE);
1365 	    }
1366 	}
1367 
1368 	/* initial movement of bubbles just before vision_recalc */
1369 	if (Is_waterlevel(&u.uz))
1370 		movebubbles();
1371 
1372 	if (level_info[new_ledger].flags & FORGOTTEN) {
1373 	    forget_map(ALL_MAP);	/* forget the map */
1374 	    forget_traps();		/* forget all traps too */
1375 	    familiar = TRUE;
1376 	    level_info[new_ledger].flags &= ~FORGOTTEN;
1377 	}
1378 
1379 	/* Reset the screen. */
1380 	vision_reset();		/* reset the blockages */
1381 	docrt();		/* does a full vision recalc */
1382 	flush_screen(-1);
1383 
1384 	/*
1385 	 *  Move all plines beyond the screen reset.
1386 	 */
1387 
1388 	/* give room entrance message, if any */
1389 	check_special_room(FALSE);
1390 
1391 	/* Check whether we just entered Gehennom. */
1392 	if (!In_hell(&u.uz0) && Inhell) {
1393 	    if (Is_valley(&u.uz)) {
1394 		You("arrive at the Valley of the Dead...");
1395 		pline_The("odor of burnt flesh and decay pervades the air.");
1396 #ifdef MICRO
1397 		display_nhwindow(WIN_MESSAGE, FALSE);
1398 #endif
1399 		You_hear("groans and moans everywhere.");
1400 	    } else pline("It is hot here.  You smell smoke...");
1401 
1402 #ifdef RECORD_ACHIEVE
1403 	achieve.enter_gehennom = 1;
1404 #ifdef LIVELOGFILE
1405 	livelog_achieve_update();
1406 #endif
1407 #endif
1408 	}
1409 
1410 	if (familiar) {
1411 	    static const char * const fam_msgs[4] = {
1412 		"You have a sense of deja vu.",
1413 		"You feel like you've been here before.",
1414 		"This place %s familiar...",
1415 		0	/* no message */
1416 	    };
1417 	    static const char * const halu_fam_msgs[4] = {
1418 		"Whoa!  Everything %s different.",
1419 		"You are surrounded by twisty little passages, all alike.",
1420 		"Gee, this %s like uncle Conan's place...",
1421 		0	/* no message */
1422 	    };
1423 	    const char *mesg;
1424 	    char buf[BUFSZ];
1425 	    int which = rn2(4);
1426 
1427 	    if (Hallucination)
1428 		mesg = halu_fam_msgs[which];
1429 	    else
1430 		mesg = fam_msgs[which];
1431 	    if (mesg && index(mesg, '%')) {
1432 		Sprintf(buf, mesg, !Blind ? "looks" : "seems");
1433 		mesg = buf;
1434 	    }
1435 	    if (mesg) pline(mesg);
1436 	}
1437 
1438 #ifdef REINCARNATION
1439 	if (new && Is_rogue_level(&u.uz))
1440 	    You("enter what seems to be an older, more primitive world.");
1441 #endif
1442 	if (new && Hallucination &&
1443 	    Role_if(PM_ARCHEOLOGIST) &&
1444 	    Is_juiblex_level(&u.uz))
1445 		pline("Ahh, Venice.");
1446 
1447 	/* Final confrontation */
1448 	if (In_endgame(&u.uz) && newdungeon && u.uhave.amulet)
1449 		resurrect();
1450 	if (newdungeon && In_V_tower(&u.uz) && In_hell(&u.uz0))
1451 		pline_The("heat and smoke are gone.");
1452 
1453 	/* the message from your quest leader */
1454 	if (!In_quest(&u.uz0) && at_dgn_entrance("The Quest") &&
1455 		!(u.uevent.qexpelled || u.uevent.qcompleted || quest_status.leader_is_dead)) {
1456 		if (u.uprops[TELEPAT].blocked) {
1457 		    if (uarmh)
1458 			You("sense something being blocked by %s.", yname(uarmh));
1459 		} else if (u.uevent.qcalled) {
1460 			com_pager(Role_if(PM_ROGUE) ? 4 : 3);
1461 		} else {
1462 			com_pager(2);
1463 			u.uevent.qcalled = TRUE;
1464 		}
1465 	}
1466 
1467 	/* once Croesus is dead, his alarm doesn't work any more */
1468 	if (Is_knox(&u.uz) && (new || !mvitals[PM_CROESUS].died)) {
1469 		You("penetrated a high security area!");
1470 		pline("An alarm sounds!");
1471 		for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
1472 		    if (!DEADMONSTER(mtmp) && mtmp->msleeping) mtmp->msleeping = 0;
1473 	}
1474 
1475 #ifdef BLACKMARKET
1476 	if (Is_blackmarket(&u.uz) && Conflict) {
1477 		set_black_marketeer_angry();
1478 	}
1479 #endif /* BLACKMARKET */
1480 
1481 	if (on_level(&u.uz, &astral_level))
1482 	    final_level();
1483 	else
1484 	    onquest();
1485 	assign_level(&u.uz0, &u.uz); /* reset u.uz0 */
1486 
1487 #ifdef INSURANCE
1488 	save_currentstate();
1489 #endif
1490 
1491 	/* assume this will always return TRUE when changing level */
1492 	(void) in_out_region(u.ux, u.uy);
1493 	(void) pickup(1);
1494 #ifdef WHEREIS_FILE
1495 	touch_whereis();
1496 #endif
1497 }
1498 
1499 STATIC_OVL void
final_level()1500 final_level()
1501 {
1502 	struct monst *mtmp;
1503 	struct obj *otmp;
1504 	coord mm;
1505 	int i;
1506 
1507 	/* reset monster hostility relative to player */
1508 	for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
1509 	    if (!DEADMONSTER(mtmp)) reset_hostility(mtmp);
1510 
1511 	/* create some player-monsters */
1512 	create_mplayers(rn1(4, 3), TRUE);
1513 
1514 	/* create a guardian angel next to player, if worthy */
1515 	if (Conflict) {
1516 	    pline(
1517 	     "A voice booms: \"Thy desire for conflict shall be fulfilled!\"");
1518 	    for (i = rnd(4); i > 0; --i) {
1519 		mm.x = u.ux;
1520 		mm.y = u.uy;
1521 		if (enexto(&mm, mm.x, mm.y, &mons[PM_ANGEL]))
1522 		    (void) mk_roamer(&mons[PM_ANGEL], u.ualign.type,
1523 				     mm.x, mm.y, FALSE);
1524 	    }
1525 
1526 	} else if (u.ualign.record > 8) {	/* fervent */
1527 	    pline("A voice whispers: \"Thou hast been worthy of me!\"");
1528 	    mm.x = u.ux;
1529 	    mm.y = u.uy;
1530 	    if (enexto(&mm, mm.x, mm.y, &mons[PM_ANGEL])) {
1531 		if ((mtmp = mk_roamer(&mons[PM_ANGEL], u.ualign.type,
1532 				      mm.x, mm.y, TRUE)) != 0) {
1533 		    if (!Blind)
1534 			pline("An angel appears near you.");
1535 		    else
1536 			You_feel("the presence of a friendly angel near you.");
1537 		    /* guardian angel -- the one case mtame doesn't
1538 		     * imply an edog structure, so we don't want to
1539 		     * call tamedog().
1540 		     */
1541 		    mtmp->mtame = 10;
1542 		    /* make him strong enough vs. endgame foes */
1543 		    mtmp->m_lev = rn1(8,15);
1544 		    mtmp->mhp = mtmp->mhpmax =
1545 					d((int)mtmp->m_lev,10) + 30 + rnd(30);
1546 		    if ((otmp = select_hwep(mtmp)) == 0) {
1547 			otmp = mksobj(SILVER_SABER, FALSE, FALSE);
1548 			if (mpickobj(mtmp, otmp))
1549 			    panic("merged weapon?");
1550 		    }
1551 		    bless(otmp);
1552 		    if (otmp->spe < 4) otmp->spe += rnd(4);
1553 		    if ((otmp = which_armor(mtmp, W_ARMS)) == 0 ||
1554 			    otmp->otyp != SHIELD_OF_REFLECTION) {
1555 			(void) mongets(mtmp, AMULET_OF_REFLECTION);
1556 			m_dowear(mtmp, TRUE);
1557 		    }
1558 		}
1559 	    }
1560 	}
1561 }
1562 
1563 static char *dfr_pre_msg = 0,	/* pline() before level change */
1564 	    *dfr_post_msg = 0;	/* pline() after level change */
1565 
1566 /* change levels at the end of this turn, after monsters finish moving */
1567 void
schedule_goto(tolev,at_stairs,falling,portal_flag,pre_msg,post_msg)1568 schedule_goto(tolev, at_stairs, falling, portal_flag, pre_msg, post_msg)
1569 d_level *tolev;
1570 boolean at_stairs, falling;
1571 int portal_flag;
1572 const char *pre_msg, *post_msg;
1573 {
1574 	int typmask = 0100;		/* non-zero triggers `deferred_goto' */
1575 
1576 	/* destination flags (`goto_level' args) */
1577 	if (at_stairs)	 typmask |= 1;
1578 	if (falling)	 typmask |= 2;
1579 	if (portal_flag) typmask |= 4;
1580 	if (portal_flag < 0) typmask |= 0200;	/* flag for portal removal */
1581 	u.utotype = typmask;
1582 	/* destination level */
1583 	assign_level(&u.utolev, tolev);
1584 
1585 	if (pre_msg)
1586 	    dfr_pre_msg = strcpy((char *)alloc(strlen(pre_msg) + 1), pre_msg);
1587 	if (post_msg)
1588 	    dfr_post_msg = strcpy((char *)alloc(strlen(post_msg)+1), post_msg);
1589 }
1590 
1591 /* handle something like portal ejection */
1592 void
deferred_goto()1593 deferred_goto()
1594 {
1595 	if (!on_level(&u.uz, &u.utolev)) {
1596 	    d_level dest;
1597 	    int typmask = u.utotype; /* save it; goto_level zeroes u.utotype */
1598 
1599 	    assign_level(&dest, &u.utolev);
1600 	    if (dfr_pre_msg) pline(dfr_pre_msg);
1601 	    goto_level(&dest, !!(typmask&1), !!(typmask&2), !!(typmask&4));
1602 	    if (typmask & 0200) {	/* remove portal */
1603 		struct trap *t = t_at(u.ux, u.uy);
1604 
1605 		if (t) {
1606 		    deltrap(t);
1607 		    newsym(u.ux, u.uy);
1608 		}
1609 	    }
1610 	    if (dfr_post_msg) pline(dfr_post_msg);
1611 	}
1612 	u.utotype = 0;		/* our caller keys off of this */
1613 	if (dfr_pre_msg)
1614 	    free((genericptr_t)dfr_pre_msg),  dfr_pre_msg = 0;
1615 	if (dfr_post_msg)
1616 	    free((genericptr_t)dfr_post_msg),  dfr_post_msg = 0;
1617 }
1618 
1619 #endif /* OVL2 */
1620 #ifdef OVL3
1621 
1622 /*
1623  * Return TRUE if we created a monster for the corpse.  If successful, the
1624  * corpse is gone.
1625  */
1626 boolean
revive_corpse(corpse)1627 revive_corpse(corpse)
1628 struct obj *corpse;
1629 {
1630     struct monst *mtmp, *mcarry;
1631     boolean is_uwep, chewed;
1632     xchar where;
1633     char *cname, cname_buf[BUFSZ];
1634     struct obj *container = (struct obj *)0;
1635     int container_where = 0;
1636 
1637     where = corpse->where;
1638     is_uwep = corpse == uwep;
1639     cname = eos(strcpy(cname_buf, "bite-covered "));
1640     Strcpy(cname, corpse_xname(corpse, TRUE));
1641     mcarry = (where == OBJ_MINVENT) ? corpse->ocarry : 0;
1642 
1643     if (where == OBJ_CONTAINED) {
1644     	struct monst *mtmp2 = (struct monst *)0;
1645 	container = corpse->ocontainer;
1646     	mtmp2 = get_container_location(container, &container_where, (int *)0);
1647 	/* container_where is the outermost container's location even if nested */
1648 	if (container_where == OBJ_MINVENT && mtmp2) mcarry = mtmp2;
1649     }
1650     mtmp = revive(corpse);	/* corpse is gone if successful */
1651 
1652     if (mtmp) {
1653 	chewed = (mtmp->mhp < mtmp->mhpmax);
1654 	if (chewed) cname = cname_buf;	/* include "bite-covered" prefix */
1655 	switch (where) {
1656 	    case OBJ_INVENT:
1657 		if (is_uwep)
1658 		    pline_The("%s writhes out of your grasp!", cname);
1659 		else
1660 		    You_feel("squirming in your backpack!");
1661 		break;
1662 
1663 	    case OBJ_FLOOR:
1664 		if (cansee(mtmp->mx, mtmp->my))
1665 		    pline("%s rises from the dead!", chewed ?
1666 			  Adjmonnam(mtmp, "bite-covered") : Monnam(mtmp));
1667 		break;
1668 
1669 	    case OBJ_MINVENT:		/* probably a nymph's */
1670 		if (cansee(mtmp->mx, mtmp->my)) {
1671 		    if (canseemon(mcarry))
1672 			pline("Startled, %s drops %s as it revives!",
1673 			      mon_nam(mcarry), an(cname));
1674 		    else
1675 			pline("%s suddenly appears!", chewed ?
1676 			      Adjmonnam(mtmp, "bite-covered") : Monnam(mtmp));
1677 		}
1678 		break;
1679 	   case OBJ_CONTAINED:
1680 	   	if (container_where == OBJ_MINVENT && cansee(mtmp->mx, mtmp->my) &&
1681 		    mcarry && canseemon(mcarry) && container) {
1682 		        char sackname[BUFSZ];
1683 		        Sprintf(sackname, "%s %s", s_suffix(mon_nam(mcarry)),
1684 				xname(container));
1685 	   		pline("%s writhes out of %s!", Amonnam(mtmp), sackname);
1686 	   	} else if (container_where == OBJ_INVENT && container) {
1687 		        char sackname[BUFSZ];
1688 		        Strcpy(sackname, an(xname(container)));
1689 	   		pline("%s %s out of %s in your pack!",
1690 	   			Blind ? Something : Amonnam(mtmp),
1691 				locomotion(mtmp->data,"writhes"),
1692 	   			sackname);
1693 	   	} else if (container_where == OBJ_FLOOR && container &&
1694 		            cansee(mtmp->mx, mtmp->my)) {
1695 		        char sackname[BUFSZ];
1696 		        Strcpy(sackname, an(xname(container)));
1697 			pline("%s escapes from %s!", Amonnam(mtmp), sackname);
1698 		}
1699 		break;
1700 	    default:
1701 		/* we should be able to handle the other cases... */
1702 		impossible("revive_corpse: lost corpse @ %d", where);
1703 		break;
1704 	}
1705 	return TRUE;
1706     }
1707     return FALSE;
1708 }
1709 
1710 /* Revive the corpse via a timeout. */
1711 /*ARGSUSED*/
1712 void
revive_mon(arg,timeout)1713 revive_mon(arg, timeout)
1714 genericptr_t arg;
1715 long timeout;
1716 {
1717     struct obj *body = (struct obj *) arg;
1718 
1719     /* if we succeed, the corpse is gone, otherwise, rot it away */
1720     if (!revive_corpse(body)) {
1721 	if (is_rider(&mons[body->corpsenm]))
1722 	    You_feel("less hassled.");
1723 	(void) start_timer(250L - (monstermoves-body->age),
1724 					TIMER_OBJECT, ROT_CORPSE, arg);
1725     }
1726 }
1727 
1728 int
donull()1729 donull()
1730 {
1731 	return(1);	/* Do nothing, but let other things happen */
1732 }
1733 
1734 #endif /* OVL3 */
1735 #ifdef OVLB
1736 
1737 STATIC_PTR int
wipeoff()1738 wipeoff()
1739 {
1740 	if(u.ucreamed < 4)	u.ucreamed = 0;
1741 	else			u.ucreamed -= 4;
1742 	if (Blinded < 4)	Blinded = 0;
1743 	else			Blinded -= 4;
1744 	if (!Blinded) {
1745 		pline("You've got the glop off.");
1746 		u.ucreamed = 0;
1747 		Blinded = 1;
1748 		make_blinded(0L,TRUE);
1749 		return(0);
1750 	} else if (!u.ucreamed) {
1751 		Your("%s feels clean now.", body_part(FACE));
1752 		return(0);
1753 	}
1754 	return(1);		/* still busy */
1755 }
1756 
1757 int
dowipe()1758 dowipe()
1759 {
1760 	if(u.ucreamed)  {
1761 		static NEARDATA char buf[39];
1762 
1763 		Sprintf(buf, "wiping off your %s", body_part(FACE));
1764 		set_occupation(wipeoff, buf, 0);
1765 		/* Not totally correct; what if they change back after now
1766 		 * but before they're finished wiping?
1767 		 */
1768 		return(1);
1769 	}
1770 	Your("%s is already clean.", body_part(FACE));
1771 	return(1);
1772 }
1773 
1774 void
set_wounded_legs(side,timex)1775 set_wounded_legs(side, timex)
1776 register long side;
1777 register int timex;
1778 {
1779 	/* KMH -- STEED
1780 	 * If you are riding, your steed gets the wounded legs instead.
1781 	 * You still call this function, but don't lose hp.
1782 	 * Caller is also responsible for adjusting messages.
1783 	 */
1784 
1785 	if(!Wounded_legs) {
1786 		ATEMP(A_DEX)--;
1787 		flags.botl = 1;
1788 	}
1789 
1790 	if(!Wounded_legs || (HWounded_legs & TIMEOUT))
1791 		HWounded_legs = timex;
1792 	EWounded_legs = side;
1793 	(void)encumber_msg();
1794 }
1795 
1796 void
heal_legs()1797 heal_legs()
1798 {
1799 	if(Wounded_legs) {
1800 		if (ATEMP(A_DEX) < 0) {
1801 			ATEMP(A_DEX)++;
1802 			flags.botl = 1;
1803 		}
1804 
1805 #ifdef STEED
1806 		if (!u.usteed)
1807 #endif
1808 		{
1809 			/* KMH, intrinsics patch */
1810 			if((EWounded_legs & BOTH_SIDES) == BOTH_SIDES) {
1811 			Your("%s feel somewhat better.",
1812 				makeplural(body_part(LEG)));
1813 		} else {
1814 			Your("%s feels somewhat better.",
1815 				body_part(LEG));
1816 		}
1817 		}
1818 		HWounded_legs = EWounded_legs = 0;
1819 	}
1820 	(void)encumber_msg();
1821 }
1822 
1823 #endif /* OVLB */
1824 
1825 /*do.c*/
1826