1    | /*	SCCS Id: @(#)do.c	3.3	1999/11/29	*/
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   | #include <errno.h>
11   | #ifdef _MSC_VER	/* MSC 6.0 defines errno quite differently */
12   | # if (_MSC_VER >= 600)
13   | #  define SKIP_ERRNO
14   | # endif
15   | #endif
16   | #ifndef SKIP_ERRNO
17   | #ifdef _DCC
18   | const
19   | #endif
20   | extern int errno;
21   | #endif
22   | 
23   | #ifdef SINKS
24   | # ifdef OVLB
25   | STATIC_DCL void FDECL(trycall, (struct obj *));
26   | # endif /* OVLB */
27   | STATIC_DCL void FDECL(dosinkring, (struct obj *));
28   | #endif /* SINKS */
29   | 
30   | STATIC_PTR int FDECL(drop, (struct obj *));
31   | STATIC_PTR int NDECL(wipeoff);
32   | 
33   | #ifdef OVL0
34   | STATIC_DCL int FDECL(menu_drop, (int));
35   | #endif
36   | #ifdef OVL2
37   | STATIC_DCL int NDECL(currentlevel_rewrite);
38   | STATIC_DCL void NDECL(final_level);
39   | /* static boolean FDECL(badspot, (XCHAR_P,XCHAR_P)); */
40   | #endif
41   | 
42   | #ifdef OVLB
43   | 
44   | static NEARDATA const char drop_types[] =
45   | 	{ ALLOW_COUNT, GOLD_CLASS, ALL_CLASSES, 0 };
46   | 
47   | /* 'd' command: drop one inventory item */
48   | int
49   | dodrop()
50   | {
51   | 	int result, i = (invent || u.ugold) ? 0 : (SIZE(drop_types) - 1);
52   | 
53   | 	if (*u.ushops) sellobj_state(TRUE);
54   | 	result = drop(getobj(&drop_types[i], "drop"));
55   | 	if (*u.ushops) sellobj_state(FALSE);
56   | 	reset_occupations();
57   | 
58   | 	return result;
59   | }
60   | 
61   | #endif /* OVLB */
62   | #ifdef OVL0
63   | 
64   | /* Called when a boulder is dropped, thrown, or pushed.  If it ends up
65   |  * in a pool, it either fills the pool up or sinks away.  In either case,
66   |  * it's gone for good...  If the destination is not a pool, returns FALSE.
67   |  */
68   | boolean
69   | boulder_hits_pool(otmp, rx, ry, pushing)
70   | struct obj *otmp;
71   | register int rx, ry;
72   | boolean pushing;
73   | {
74   | 	if (!otmp || otmp->otyp != BOULDER)
75   | 	    impossible("Not a boulder?");
76   | 	else if (!Is_waterlevel(&u.uz) && (is_pool(rx,ry) || is_lava(rx,ry))) {
77   | 	    boolean lava = is_lava(rx,ry), fills_up;
78   | 	    const char *what = lava ? "lava" : "water";
79   | 	    schar ltyp = levl[rx][ry].typ;
80   | 	    int chance = rn2(10);		/* water: 90%; lava: 10% */
81   | 	    fills_up = lava ? chance == 0 : chance != 0;
82   | 
83   | 	    if (fills_up) {
84   | 		if (ltyp == DRAWBRIDGE_UP) {
85   | 		    levl[rx][ry].drawbridgemask &= ~DB_UNDER; /* clear lava */
86   | 		    levl[rx][ry].drawbridgemask |= DB_FLOOR;
87   | 		} else
88   | 		    levl[rx][ry].typ = ROOM;
89   | 
90   | 		bury_objs(rx, ry);
91   | 		newsym(rx,ry);
92   | 		if (pushing) {
93   | 		    You("push %s into the %s.", the(xname(otmp)), what);
94   | 		    if (flags.verbose && !Blind)
95   | 			pline("Now you can cross it!");
96   | 		    /* no splashing in this case */
97   | 		}
98   | 	    }
99   | 	    if (!fills_up || !pushing) {	/* splashing occurs */
100  | 		if (!u.uinwater) {
101  | 		    if (pushing ? !Blind : cansee(rx,ry)) {
102  | 			boolean moat = (ltyp != WATER) &&
103  | 			    !Is_medusa_level(&u.uz) && !Is_waterlevel(&u.uz);
104  | 
105  | 			There("is a large splash as %s %s the %s.",
106  | 			      the(xname(otmp)), fills_up? "fills":"falls into",
107  | 			      lava ? "lava" : ltyp==POOL ? "pool" :
108  | 			      moat ? "moat" : "water");
109  | 		    } else if (flags.soundok)
110  | 			You_hear("a%s splash.", lava ? " sizzling" : "");
111  | 		    wake_nearto(rx, ry, 40);
112  | 		}
113  | 
114  | 		if (fills_up && u.uinwater && distu(rx,ry) == 0) {
115  | 		    u.uinwater = 0;
116  | 		    docrt();
117  | 		    vision_full_recalc = 1;
118  | 		    You("find yourself on dry land again!");
119  | 		} else if (lava && distu(rx,ry) <= 2) {
120  | 		    You("are hit by molten lava%c",
121  | 			Fire_resistance ? '.' : '!');
122  | 			burn_away_slime();
123  | 		    losehp(d((Fire_resistance ? 1 : 3), 6),
124  | 			   "molten lava", KILLED_BY);
125  | 		} else if (!fills_up && flags.verbose &&
126  | 			   (pushing ? !Blind : cansee(rx,ry)))
127  | 		    pline("It sinks without a trace!");
128  | 	    }
129  | 
130  | 	    /* boulder is now gone */
131  | 	    if (pushing) delobj(otmp);
132  | 	    else obfree(otmp, (struct obj *)0);
133  | 	    return TRUE;
134  | 	}
135  | 	return FALSE;
136  | }
137  | 
138  | /* Used for objects which sometimes do special things when dropped; must be
139  |  * called with the object not in any chain.  Returns TRUE if the object goes
140  |  * away.
141  |  */
142  | boolean
143  | flooreffects(obj,x,y,verb)
144  | struct obj *obj;
145  | int x,y;
146  | const char *verb;
147  | {
148  | 	struct trap *t;
149  | 	struct monst *mtmp;
150  | 
151  | 	if (obj->where != OBJ_FREE)
152  | 	    panic("flooreffects: obj not free");
153  | 
154  | 	/* make sure things like water_damage() have no pointers to follow */
155  | 	obj->nobj = obj->nexthere = (struct obj *)0;
156  | 
157  | 	if (obj->otyp == BOULDER && boulder_hits_pool(obj, x, y, FALSE))
158  | 		return TRUE;
159  | 	else if (obj->otyp == BOULDER && (t = t_at(x,y)) != 0 &&
160  | 		 (t->ttyp==PIT || t->ttyp==SPIKED_PIT
161  | 			|| t->ttyp==TRAPDOOR || t->ttyp==HOLE)) {
162  | 		if (((mtmp = m_at(x, y)) && mtmp->mtrapped) ||
163  | 			(u.utrap && u.ux == x && u.uy == y)) {
164  | 		    if (*verb)
165  | 			pline_The("boulder %ss into the pit%s.", verb,
166  | 				(mtmp) ? "" : " with you");
167  | 		    if (mtmp) {
168  | 			if (!passes_walls(mtmp->data) &&
169  | 				!throws_rocks(mtmp->data)) {
170  | 			    if (hmon(mtmp, obj, TRUE))
171  | 				return FALSE;	/* still alive */
172  | 			} else mtmp->mtrapped = 0;
173  | 		    } else {
174  | 			if (!Passes_walls && !throws_rocks(youmonst.data)) {
175  | 			    losehp(rnd(15), "squished under a boulder",
176  | 				   NO_KILLER_PREFIX);
177  | 			    return FALSE;	/* player remains trapped */
178  | 			} else u.utrap = 0;
179  | 		    }
180  | 		}
181  | 		if (*verb) {
182  | 			if (Blind) {
183  | 				if ((x == u.ux) && (y == u.uy))
184  | 					You_hear("a CRASH! beneath you.");
185  | 				else
186  | 					You_hear("the boulder %s.", verb);
187  | 			} else if (cansee(x, y)) {
188  | 				pline_The("boulder %s%s.",
189  | 				    t->tseen ? "" : "triggers and ",
190  | 				    t->ttyp == TRAPDOOR ? "plugs a trap door" :
191  | 				    t->ttyp == HOLE ? "plugs a hole" :
192  | 				    "fills a pit");
193  | 			}
194  | 		}
195  | 		deltrap(t);
196  | 		obfree(obj, (struct obj *)0);
197  | 		bury_objs(x, y);
198  | 		newsym(x,y);
199  | 		return TRUE;
200  | 	} else if (is_pool(x, y)) {
201  | 		water_damage(obj, FALSE, FALSE);
202  | 	}
203  | 	return FALSE;
204  | }
205  | 
206  | #endif /* OVL0 */
207  | #ifdef OVLB
208  | 
209  | void
210  | doaltarobj(obj)  /* obj is an object dropped on an altar */
211  | 	register struct obj *obj;
212  | {
213  | 	if (Blind) return;
214  | 
215  | 	/* KMH, conduct */
216  | 	u.uconduct.gnostic++;
217  | 
218  | 	if (obj->blessed || obj->cursed) {
219  | 		There("is %s flash as %s hit%s the altar.",
220  | 			an(hcolor(obj->blessed ? amber : Black)),
221  | 			doname(obj),
222  | 			(obj->quan == 1L) ? "s" : "");
223  | 		if (!Hallucination) obj->bknown = 1;
224  | 	} else {
225  | 		pline("%s land%s on the altar.", Doname2(obj),
226  | 			(obj->quan == 1L) ? "s" : "");
227  | 		obj->bknown = 1;
228  | 	}
229  | }
230  | 
231  | #ifdef SINKS
232  | STATIC_OVL
233  | void
234  | trycall(obj)
235  | register struct obj *obj;
236  | {
237  | 	if(!objects[obj->otyp].oc_name_known &&
238  | 	   !objects[obj->otyp].oc_uname)
239  | 	   docall(obj);
240  | }
241  | 
242  | STATIC_OVL
243  | void
244  | dosinkring(obj)  /* obj is a ring being dropped over a kitchen sink */
245  | register struct obj *obj;
246  | {
247  | 	register struct obj *otmp,*otmp2;
248  | 	register boolean ideed = TRUE;
249  | 
250  | 	You("drop %s down the drain.", doname(obj));
251  | 	obj->in_use = TRUE;	/* block free identification via interrupt */
252  | 	switch(obj->otyp) {	/* effects that can be noticed without eyes */
253  | 	    case RIN_SEARCHING:
254  | 		You("thought your %s got lost in the sink, but there it is!",
255  | 			xname(obj));
256  | 		goto giveback;
257  | 	    case RIN_SLOW_DIGESTION:
258  | 		pline_The("ring is regurgitated!");
259  | giveback:
260  | 		obj->in_use = FALSE;
261  | 		dropx(obj);
262  | 		trycall(obj);
263  | 		return;
264  | 	    case RIN_LEVITATION:
265  | 		pline_The("sink quivers upward for a moment.");
266  | 		break;
267  | 	    case RIN_POISON_RESISTANCE:
268  | 		You("smell rotten %s.", makeplural(pl_fruit));
269  | 		break;
270  | 	    case RIN_AGGRAVATE_MONSTER:
271  | 		pline("Several flies buzz angrily around the sink.");
272  | 		break;
273  | 	    case RIN_SHOCK_RESISTANCE:
274  | 		pline("Static electricity surrounds the sink.");
275  | 		break;
276  | 	    case RIN_CONFLICT:
277  | 		You_hear("loud noises coming from the drain.");
278  | 		break;
279  | 	    case RIN_SUSTAIN_ABILITY:	/* KMH */
280  | 		pline_The("water flow seems fixed.");
281  | 		break;
282  | 	    case RIN_GAIN_STRENGTH:
283  | 		pline_The("water flow seems %ser now.",
284  | 			(obj->spe<0) ? "weak" : "strong");
285  | 		break;
286  | 	    case RIN_GAIN_CONSTITUTION:
287  | 		pline_The("water flow seems %ser now.",
288  | 			(obj->spe<0) ? "less" : "great");
289  | 		break;
290  | 	    case RIN_INCREASE_ACCURACY:	/* KMH */
291  | 		pline_The("water flow %s the drain.",
292  | 			(obj->spe<0) ? "misses" : "hits");
293  | 		break;
294  | 	    case RIN_INCREASE_DAMAGE:
295  | 		pline_The("water's force seems %ser now.",
296  | 			(obj->spe<0) ? "small" : "great");
297  | 		break;
298  | 	    case RIN_HUNGER:
299  | 		ideed = FALSE;
300  | 		for(otmp = level.objects[u.ux][u.uy]; otmp; otmp = otmp2) {
301  | 		    otmp2 = otmp->nexthere;
302  | 		    if (otmp != uball && otmp != uchain &&
303  | 			    !obj_resists(otmp, 1, 99)) {
304  | 			if (!Blind) {
305  | 			    pline("Suddenly, %s vanishes from the sink!",
306  | 							doname(otmp));
307  | 			    ideed = TRUE;
308  | 			}
309  | 			delobj(otmp);
310  | 		    }
311  | 		}
312  | 		break;
313  | 	    case MEAT_RING:
314  | 		/* Not the same as aggravate monster; besides, it's obvious. */
315  | 		pline("Several flies buzz around the sink.");
316  | 		break;
317  | 	    default:
318  | 		ideed = FALSE;
319  | 		break;
320  | 	}
321  | 	if(!Blind && !ideed && obj->otyp != RIN_HUNGER) {
322  | 	    ideed = TRUE;
323  | 	    switch(obj->otyp) {		/* effects that need eyes */
324  | 		case RIN_ADORNMENT:
325  | 		    pline_The("faucets flash brightly for a moment.");
326  | 		    break;
327  | 		case RIN_REGENERATION:
328  | 		    pline_The("sink looks as good as new.");
329  | 		    break;
330  | 		case RIN_INVISIBILITY:
331  | 		    You("don't see anything happen to the sink.");
332  | 		    break;
333  | 		case RIN_FREE_ACTION:
334  | 		    You("see the ring slide right down the drain!");
335  | 		    break;
336  | 		case RIN_SEE_INVISIBLE:
337  | 		    You("see some air in the sink.");
338  | 		    break;
339  | 		case RIN_STEALTH:
340  | 		pline_The("sink seems to blend into the floor for a moment.");
341  | 		    break;
342  | 		case RIN_FIRE_RESISTANCE:
343  | 		pline_The("hot water faucet flashes brightly for a moment.");
344  | 		    break;
345  | 		case RIN_COLD_RESISTANCE:
346  | 		pline_The("cold water faucet flashes brightly for a moment.");
347  | 		    break;
348  | 		case RIN_PROTECTION_FROM_SHAPE_CHAN:
349  | 		    pline_The("sink looks nothing like a fountain.");
350  | 		    break;
351  | 		case RIN_PROTECTION:
352  | 		    pline_The("sink glows %s for a moment.",
353  | 			    hcolor((obj->spe<0) ? Black : silver));
354  | 		    break;
355  | 		case RIN_WARNING:
356  | 		    pline_The("sink glows %s for a moment.", hcolor(White));
357  | 		    break;
358  | 		case RIN_TELEPORTATION:
359  | 		    pline_The("sink momentarily vanishes.");
360  | 		    break;
361  | 		case RIN_TELEPORT_CONTROL:
362  | 	    pline_The("sink looks like it is being beamed aboard somewhere.");
363  | 		    break;
364  | 		case RIN_POLYMORPH:
365  | 		    pline_The("sink momentarily looks like a fountain.");
366  | 		    break;
367  | 		case RIN_POLYMORPH_CONTROL:
368  | 	pline_The("sink momentarily looks like a regularly erupting geyser.");
369  | 		    break;
370  | 	    }
371  | 	}
372  | 	if(ideed)
373  | 	    trycall(obj);
374  | 	else
375  | 	    You_hear("the ring bouncing down the drainpipe.");
376  | 	if (!rn2(20)) {
377  | 		pline_The("sink backs up, leaving %s.", doname(obj));
378  | 		obj->in_use = FALSE;
379  | 		dropx(obj);
380  | 	} else
381  | 		useup(obj);
382  | }
383  | #endif
384  | 
385  | #endif /* OVLB */
386  | #ifdef OVL0
387  | 
388  | /* some common tests when trying to drop or throw items */
389  | boolean
390  | canletgo(obj,word)
391  | register struct obj *obj;
392  | register const char *word;
393  | {
394  | 	if(obj->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL)){
395  | 		if (*word)
396  | 			Norep("You cannot %s %s you are wearing.",word,
397  | 				something);
398  | 		return(FALSE);
399  | 	}
400  | 	if (obj->otyp == LOADSTONE && obj->cursed) {
401  | 		if (*word)
402  | 			pline("For some reason, you cannot %s the stone%s!",
403  | 				word, plur(obj->quan));
404  | 		/* Kludge -- see invent.c */
405  | 		if (obj->corpsenm) {
406  | 			struct obj *otmp;
407  | 
408  | 			otmp = obj;
409  | 			obj = obj->nobj;
410  | 			obj->quan += otmp->quan;
411  | 			obj->owt = weight(obj);
412  | 			freeinv(otmp);
413  | 			obfree(otmp, obj);
414  | 		}
415  | 		obj->bknown = 1;
416  | 		return(FALSE);
417  | 	}
418  | 	if (obj->otyp == LEASH && obj->leashmon != 0) {
419  | 		if (*word)
420  | 			pline_The("leash is tied around your %s.",
421  | 					body_part(HAND));
422  | 		return(FALSE);
423  | 	}
424  | #ifdef STEED
425  | 	if (obj->owornmask & W_SADDLE) {
426  | 		if (*word)
427  | 			You("cannot %s %s you are sitting on.", word,
428  | 				something);
429  | 		return (FALSE);
430  | 	}
431  | #endif
432  | 	return(TRUE);
433  | }
434  | 
435  | STATIC_PTR
436  | int
437  | drop(obj)
438  | register struct obj *obj;
439  | {
440  | 	if(!obj) return(0);
441  | 	if(!canletgo(obj,"drop"))
442  | 		return(0);
443  | 	if(obj == uwep) {
444  | 		if(welded(uwep)) {
445  | 			weldmsg(obj);
446  | 			return(0);
447  | 		}
448  | 		setuwep((struct obj *)0);
449  | 		if(uwep) return 0; /* lifesaved and rewielded */
450  | 	}
451  | 	if(obj == uquiver) {
452  | 		setuqwep((struct obj *)0);
453  | 	}
454  | 	if (obj == uswapwep) {
455  | 		setuswapwep((struct obj *)0);
456  | 	}
457  | 
458  | 	if (u.uswallow) {
459  | 		/* barrier between you and the floor */
460  | 		if(flags.verbose)
461  | 			You("drop %s into %s %s.", doname(obj),
462  | 				s_suffix(mon_nam(u.ustuck)),
463  | 				is_animal(u.ustuck->data) ?
464  | 				"stomach" : "interior");
465  | 	} else {
466  | #ifdef SINKS
467  | 	    if((obj->oclass == RING_CLASS || obj->otyp == MEAT_RING) &&
468  | 			IS_SINK(levl[u.ux][u.uy].typ)) {
469  | 		dosinkring(obj);
470  | 		return(1);
471  | 	    }
472  | #endif
473  | 	    if (!can_reach_floor()) {
474  | 		if(flags.verbose) You("drop %s.", doname(obj));
475  | 		if (obj->oclass != GOLD_CLASS || obj == invent) freeinv(obj);
476  | 		hitfloor(obj);
477  | 		return(1);
478  | 	    }
479  | 	    if (IS_ALTAR(levl[u.ux][u.uy].typ)) {
480  | 		doaltarobj(obj);	/* set bknown */
481  | 	    } else
482  | 		if(flags.verbose) You("drop %s.", doname(obj));
483  | 	}
484  | 	dropx(obj);
485  | 	return(1);
486  | }
487  | 
488  | /* Called in several places - should not produce texts */
489  | /* ship_object() _can_ produce texts--is that comment still correct? */
490  | void
491  | dropx(obj)
492  | register struct obj *obj;
493  | {
494  | 	/* Money is usually not in our inventory */
495  | 	if (obj->oclass != GOLD_CLASS || obj == invent) freeinv(obj);
496  | 	if (!u.uswallow && ship_object(obj, u.ux, u.uy, FALSE)) return;
497  | 	dropy(obj);
498  | }
499  | 
500  | void
501  | dropy(obj)
502  | register struct obj *obj;
503  | {
504  | 	if (!u.uswallow && flooreffects(obj,u.ux,u.uy,"drop")) return;
505  | 	/* KMH -- Fixed crysknives have only 10% chance of reverting */
506  | 	if (obj->otyp == CRYSKNIFE && (!obj->oerodeproof || !rn2(10))) {
507  | 		obj->otyp = WORM_TOOTH;
508  | 		obj->oerodeproof = 0;
509  | 	}
510  | 	/* uswallow check done by GAN 01/29/87 */
511  | 	if(u.uswallow) {
512  | 		if (obj != uball) {		/* mon doesn't pick up ball */
513  | 		    (void) mpickobj(u.ustuck,obj);
514  | 		}
515  | 	} else  {
516  | 		place_object(obj, u.ux, u.uy);
517  | 		if (obj == uball)
518  | 		    drop_ball(u.ux,u.uy);
519  | 		else
520  | 		    sellobj(obj, u.ux, u.uy);
521  | 		stackobj(obj);
522  | 		if(Blind && Levitation)
523  | 		    map_object(obj, 0);
524  | 		newsym(u.ux,u.uy);	/* remap location under self */
525  | 	}
526  | }
527  | 
528  | /* 'D' command: drop several things */
529  | int
530  | doddrop()
531  | {
532  | 	int result = 0;
533  | 
534  | 	add_valid_menu_class(0); /* clear any classes already there */
535  | 	if (*u.ushops) sellobj_state(TRUE);
536  | 	if (flags.menu_style != MENU_TRADITIONAL ||
537  | 		(result = ggetobj("drop", drop, 0, FALSE)) < -1)
538  | 	    result = menu_drop(result);
539  | 	if (*u.ushops) sellobj_state(FALSE);
540  | 	reset_occupations();
541  | 
542  | 	return result;
543  | }
544  | 
545  | /* Drop things from the hero's inventory, using a menu. */
546  | STATIC_OVL int
547  | menu_drop(retry)
548  | int retry;
549  | {
550  |     int n, i, n_dropped = 0;
551  |     long cnt;
552  |     struct obj *otmp, *otmp2, *u_gold = 0;
553  |     menu_item *pick_list;
554  |     boolean all_categories = TRUE;
555  |     boolean drop_everything = FALSE;
556  | 
557  |     if (u.ugold) {
558  | 	/* Hack: gold is not in the inventory, so make a gold object
559  | 	   and put it at the head of the inventory list. */
560  | 	u_gold = mkgoldobj(u.ugold);	/* removes from u.ugold */
561  | 	u.ugold = u_gold->quan;		/* put the gold back */
562  | 	assigninvlet(u_gold);		/* might end up as NOINVSYM */
563  | 	u_gold->nobj = invent;
564  | 	invent = u_gold;
565  |     }
566  | 
567  |     if (retry) {
568  | 	all_categories = (retry == -2);
569  |     } else if (flags.menu_style == MENU_FULL) {
570  | 	all_categories = FALSE;
571  | 	n = query_category("Drop what type of items?",
572  | 			invent,
573  | 			UNPAID_TYPES | ALL_TYPES | CHOOSE_ALL,
574  | 			&pick_list, PICK_ANY);
575  | 	if (!n) goto drop_done;
576  | 	for (i = 0; i < n; i++) {
577  | 	    if (pick_list[i].item.a_int == ALL_TYPES_SELECTED)
578  | 		all_categories = TRUE;
579  | 	    else if (pick_list[i].item.a_int == 'A')
580  | 		drop_everything = TRUE;
581  | 	    else
582  | 		add_valid_menu_class(pick_list[i].item.a_int);
583  | 	}
584  | 	free((genericptr_t) pick_list);
585  |     } else if (flags.menu_style == MENU_COMBINATION) {
586  | 	all_categories = FALSE;
587  | 	/* Gather valid classes via traditional NetHack method */
588  | 	i = ggetobj("drop", drop, 0, TRUE);
589  | 	if (i == -2) all_categories = TRUE;
590  |     }
591  | 
592  |     if (drop_everything) {
593  | 	for(otmp = invent; otmp; otmp = otmp2) {
594  | 	    otmp2 = otmp->nobj;
595  | 	    n_dropped += drop(otmp);
596  | 	}
597  |     } else {
598  | 	/* should coordinate with perm invent, maybe not show worn items */
599  | 	n = query_objlist("What would you like to drop?", invent,
600  | 			USE_INVLET|INVORDER_SORT, &pick_list,
601  | 			PICK_ANY, all_categories ? allow_all : allow_category);
602  | 	if (n > 0) {
603  | 	    for (i = 0; i < n; i++) {
604  | 		otmp = pick_list[i].item.a_obj;
605  | 		cnt = pick_list[i].count;
606  | 		if (cnt < otmp->quan && !welded(otmp) &&
607  | 			(!otmp->cursed || otmp->otyp != LOADSTONE)) {
608  | 		    otmp2 = splitobj(otmp, cnt);
609  | 		    /* assume other worn items aren't mergable */
610  | 		    if (otmp == uwep) setuwep(otmp2);
611  | 			if (otmp == uquiver) setuqwep(otmp2);
612  | 			if (otmp == uswapwep) setuswapwep(otmp2);
613  | 		}
614  | 		n_dropped += drop(otmp);
615  | 	    }
616  | 	    free((genericptr_t) pick_list);
617  | 	}
618  |     }
619  | 
620  |  drop_done:
621  |     if (u_gold && invent && invent->oclass == GOLD_CLASS) {
622  | 	/* didn't drop [all of] it */
623  | 	u_gold = invent;
624  | 	invent = u_gold->nobj;
625  | 	dealloc_obj(u_gold);
626  |     }
627  |     return n_dropped;
628  | }
629  | 
630  | #endif /* OVL0 */
631  | #ifdef OVL2
632  | 
633  | /* on a ladder, used in goto_level */
634  | static NEARDATA boolean at_ladder = FALSE;
635  | 
636  | int
637  | dodown()
638  | {
639  | 	struct trap *trap = 0;
640  | 	boolean stairs_down = ((u.ux == xdnstair && u.uy == ydnstair) ||
641  | 		    (u.ux == sstairs.sx && u.uy == sstairs.sy && !sstairs.up)),
642  | 		ladder_down = (u.ux == xdnladder && u.uy == ydnladder);
643  | 
644  | 	if (Levitation) {
645  | 	    if ((HLevitation & I_SPECIAL) || (ELevitation & W_ARTI)) {
646  | 		/* end controlled levitation */
647  | 			if (float_down(I_SPECIAL|TIMEOUT, W_ARTI))
648  | 			    return (1);   /* came down, so moved */
649  | 	    }
650  | 	    floating_above(stairs_down ? "stairs" : ladder_down ?
651  | 			   "ladder" : surface(u.ux, u.uy));
652  | 	    return (0);   /* didn't move */
653  | 	}
654  | 	if (!stairs_down && !ladder_down) {
655  | 		if (!(trap = t_at(u.ux,u.uy)) ||
656  | 			(trap->ttyp != TRAPDOOR && trap->ttyp != HOLE)
657  | 			|| !Can_fall_thru(&u.uz) || !trap->tseen) {
658  | 			You_cant("go down here.");
659  | 			return(0);
660  | 		}
661  | 	}
662  | 	if(u.ustuck) {
663  | 		You("are being held, and cannot go down.");
664  | 		return(1);
665  | 	}
666  | 	if (on_level(&valley_level, &u.uz) && !u.uevent.gehennom_entered) {
667  | 		You("are standing at the gate to Gehennom.");
668  | 		pline("Unspeakable cruelty and harm lurk down there.");
669  | 		if (yn("Are you sure you want to enter?") != 'y')
670  | 			return(0);
671  | 		else pline("So be it.");
672  | 		u.uevent.gehennom_entered = 1;	/* don't ask again */
673  | 	}
674  | 
675  | 	if(!next_to_u()) {
676  | 		You("are held back by your pet!");
677  | 		return(0);
678  | 	}
679  | 
680  | 	if (trap)
681  | 	    You("%s %s.", locomotion(youmonst.data, "jump"),
682  | 		trap->ttyp == HOLE ? "down the hole" : "through the trap door");
683  | 
684  | 	if (trap && Is_stronghold(&u.uz)) {
685  | 		goto_hell(TRUE, TRUE);
686  | 	} else {
687  | 		at_ladder = (boolean) (levl[u.ux][u.uy].typ == LADDER);
688  | 		next_level(!trap);
689  | 		at_ladder = FALSE;
690  | 	}
691  | 	return(1);
692  | }
693  | 
694  | int
695  | doup()
696  | {
697  | 	if( (u.ux != xupstair || u.uy != yupstair)
698  | 	     && (!xupladder || u.ux != xupladder || u.uy != yupladder)
699  | 	     && (!sstairs.sx || u.ux != sstairs.sx || u.uy != sstairs.sy
700  | 			|| !sstairs.up)
701  | 	  ) {
702  | 		You_cant("go up here.");
703  | 		return(0);
704  | 	}
705  | 	if(u.ustuck) {
706  | 		You("are being held, and cannot go up.");
707  | 		return(1);
708  | 	}
709  | 	if(near_capacity() > SLT_ENCUMBER) {
710  | 		/* No levitation check; inv_weight() already allows for it */
711  | 		Your("load is too heavy to climb the %s.",
712  | 			levl[u.ux][u.uy].typ == STAIRS ? "stairs" : "ladder");
713  | 		return(1);
714  | 	}
715  | 	if(ledger_no(&u.uz) == 1) {
716  | 		if (yn("Beware, there will be no return! Still climb?") != 'y')
717  | 			return(0);
718  | 	}
719  | 	if(!next_to_u()) {
720  | 		You("are held back by your pet!");
721  | 		return(0);
722  | 	}
723  | 	at_ladder = (boolean) (levl[u.ux][u.uy].typ == LADDER);
724  | 	prev_level(TRUE);
725  | 	at_ladder = FALSE;
726  | 	return(1);
727  | }
728  | 
729  | d_level save_dlevel = {0, 0};
730  | 
731  | /* check that we can write out the current level */
732  | STATIC_OVL int
733  | currentlevel_rewrite()
734  | {
735  | 	register int fd;
736  | 
737  | 	/* since level change might be a bit slow, flush any buffered screen
738  | 	 *  output (like "you fall through a trap door") */
739  | 	mark_synch();
740  | 
741  | 	fd = create_levelfile(ledger_no(&u.uz));
742  | 
743  | 	if(fd < 0) {
744  | 		/*
745  | 		 * This is not quite impossible: e.g., we may have
746  | 		 * exceeded our quota. If that is the case then we
747  | 		 * cannot leave this level, and cannot save either.
748  | 		 * Another possibility is that the directory was not
749  | 		 * writable.
750  | 		 */
751  | 		pline("Cannot create level file for level %d.",
752  | 						ledger_no(&u.uz));
753  | 		return -1;
754  | 	}
755  | 
756  | #ifdef MFLOPPY
757  | 	if (!savelev(fd, ledger_no(&u.uz), COUNT_SAVE)) {
758  | 		(void) close(fd);
759  | 		delete_levelfile(ledger_no(&u.uz));
760  | 		pline("NetHack is out of disk space for making levels!");
761  | 		You("can save, quit, or continue playing.");
762  | 		return -1;
763  | 	}
764  | #endif
765  | 	return fd;
766  | }
767  | 
768  | #ifdef INSURANCE
769  | void
770  | save_currentstate()
771  | {
772  | 	int fd;
773  | 
774  | 	if (flags.ins_chkpt) {
775  | 		/* write out just-attained level, with pets and everything */
776  | 		fd = currentlevel_rewrite();
777  | 		if(fd < 0) return;
778  | 		bufon(fd);
779  | 		savelev(fd,ledger_no(&u.uz), WRITE_SAVE);
780  | 		bclose(fd);
781  | 	}
782  | 
783  | 	/* write out non-level state */
784  | 	savestateinlock();
785  | }
786  | #endif
787  | 
788  | /*
789  | static boolean
790  | badspot(x, y)
791  | register xchar x, y;
792  | {
793  | 	return((levl[x][y].typ != ROOM && levl[x][y].typ != AIR &&
794  | 			 levl[x][y].typ != CORR) || MON_AT(x, y));
795  | }
796  | */
797  | 
798  | void
799  | goto_level(newlevel, at_stairs, falling, portal)
800  | d_level *newlevel;
801  | boolean at_stairs, falling, portal;
802  | {
803  | 	int fd, l_idx;
804  | 	xchar new_ledger;
805  | 	boolean cant_go_back,
806  | 		up = (depth(newlevel) < depth(&u.uz)),
807  | 		newdungeon = (u.uz.dnum != newlevel->dnum),
808  | 		was_in_W_tower = In_W_tower(u.ux, u.uy, &u.uz),
809  | 		familiar = FALSE;
810  | 	boolean new = FALSE;	/* made a new level? */
811  | 	struct monst *mtmp;
812  | 
813  | 	if (dunlev(newlevel) > dunlevs_in_dungeon(newlevel))
814  | 		newlevel->dlevel = dunlevs_in_dungeon(newlevel);
815  | 	if (newdungeon && In_endgame(newlevel)) { /* 1st Endgame Level !!! */
816  | 		if (u.uhave.amulet)
817  | 		    assign_level(newlevel, &earth_level);
818  | 		else return;
819  | 	}
820  | 	new_ledger = ledger_no(newlevel);
821  | 	if (new_ledger <= 0)
822  | 		done(ESCAPED);	/* in fact < 0 is impossible */
823  | 
824  | 	/* If you have the amulet and are trying to get out of Gehennom, going
825  | 	 * up a set of stairs sometimes does some very strange things!
826  | 	 * Biased against law and towards chaos, but not nearly as strongly
827  | 	 * as it used to be (prior to 3.2.0).
828  | 	 * Odds:	    old				    new
829  | 	 *	"up"    L      N      C		"up"    L      N      C
830  | 	 *	 +1   75.0   75.0   75.0	 +1   75.0   75.0   75.0
831  | 	 *	  0    0.0   12.5   25.0	  0    6.25   8.33  12.5
832  | 	 *	 -1    8.33   4.17   0.0	 -1    6.25   8.33  12.5
833  | 	 *	 -2    8.33   4.17   0.0	 -2    6.25   8.33   0.0
834  | 	 *	 -3    8.33   4.17   0.0	 -3    6.25   0.0    0.0
835  | 	 */
836  | 	if (Inhell && up && u.uhave.amulet && !newdungeon && !portal &&
837  | 				(dunlev(&u.uz) < dunlevs_in_dungeon(&u.uz)-3)) {
838  | 		if (!rn2(4)) {
839  | 		    int odds = 3 + (int)u.ualign.type,		/* 2..4 */
840  | 			diff = odds <= 1 ? 0 : rn2(odds);	/* paranoia */
841  | 
842  | 		    if (diff != 0) {
843  | 			assign_rnd_level(newlevel, &u.uz, diff);
844  | 			/* if inside the tower, stay inside */
845  | 			if (was_in_W_tower &&
846  | 			    !On_W_tower_level(newlevel)) diff = 0;
847  | 		    }
848  | 		    if (diff == 0)
849  | 			assign_level(newlevel, &u.uz);
850  | 
851  | 		    new_ledger = ledger_no(newlevel);
852  | 
853  | 		    pline("A mysterious force momentarily surrounds you...");
854  | 		    if (on_level(newlevel, &u.uz)) {
855  | 			(void) safe_teleds();
856  | 			(void) next_to_u();
857  | 			return;
858  | 		    } else
859  | 			at_stairs = at_ladder = FALSE;
860  | 		}
861  | 	}
862  | 
863  | 	/* Prevent the player from going past the first quest level unless
864  | 	 * (s)he has been given the go-ahead by the leader.
865  | 	 */
866  | 	if (on_level(&u.uz, &qstart_level) && !newdungeon && !ok_to_quest()) {
867  | 		pline("A mysterious force prevents you from descending.");
868  | 		return;
869  | 	}
870  | 
871  | 	if (on_level(newlevel, &u.uz)) return;		/* this can happen */
872  | 
873  | 	fd = currentlevel_rewrite();
874  | 	if (fd < 0) return;
875  | 
876  | 	if (falling) /* assuming this is only trap door or hole */
877  | 	    impact_drop((struct obj *)0, u.ux, u.uy, newlevel->dlevel);
878  | 
879  | 	check_special_room(TRUE);		/* probably was a trap door */
880  | 	if (Punished) unplacebc();
881  | 	u.utrap = 0;				/* needed in level_tele */
882  | 	fill_pit(u.ux, u.uy);
883  | 	u.ustuck = 0;				/* idem */
884  | 	u.uinwater = 0;
885  | 	keepdogs(FALSE);
886  | 	if (u.uswallow)				/* idem */
887  | 		u.uswldtim = u.uswallow = 0;
888  | 	/*
889  | 	 *  We no longer see anything on the level.  Make sure that this
890  | 	 *  follows u.uswallow set to null since uswallow overrides all
891  | 	 *  normal vision.
892  | 	 */
893  | 	vision_recalc(2);
894  | 
895  | 	/*
896  | 	 * Save the level we're leaving.  If we're entering the endgame,
897  | 	 * we can get rid of all existing levels because they cannot be
898  | 	 * reached any more.  We still need to use savelev()'s cleanup
899  | 	 * for the level being left, to recover dynamic memory in use and
900  | 	 * to avoid dangling timers and light sources.
901  | 	 */
902  | 	cant_go_back = (newdungeon && In_endgame(newlevel));
903  | 	if (!cant_go_back) {
904  | 	    update_mlstmv();	/* current monsters are becoming inactive */
905  | 	    bufon(fd);		/* use buffered output */
906  | 	}
907  | 	savelev(fd, ledger_no(&u.uz),
908  | 		cant_go_back ? FREE_SAVE : (WRITE_SAVE | FREE_SAVE));
909  | 	bclose(fd);
910  | 	if (cant_go_back) {
911  | 	    /* discard unreachable levels; keep #0 */
912  | 	    for (l_idx = maxledgerno(); l_idx > 0; --l_idx)
913  | 		delete_levelfile(l_idx);
914  | 	}
915  | 
916  | #ifdef REINCARNATION
917  | 	if (Is_rogue_level(newlevel) || Is_rogue_level(&u.uz))
918  | 		assign_rogue_graphics(Is_rogue_level(newlevel));
919  | #endif
920  | #ifdef USE_TILES
921  | 	substitute_tiles(newlevel);
922  | #endif
923  | 	assign_level(&u.uz0, &u.uz);
924  | 	assign_level(&u.uz, newlevel);
925  | 	assign_level(&u.utolev, newlevel);
926  | 	u.utotype = 0;
927  | 	if (dunlev_reached(&u.uz) < dunlev(&u.uz))
928  | 		dunlev_reached(&u.uz) = dunlev(&u.uz);
929  | 	reset_rndmonst(NON_PM);   /* u.uz change affects monster generation */
930  | 
931  | 	/* set default level change destination areas */
932  | 	/* the special level code may override these */
933  | 	(void) memset((genericptr_t) &updest, 0, sizeof updest);
934  | 	(void) memset((genericptr_t) &dndest, 0, sizeof dndest);
935  | 
936  | 	if (!(level_info[new_ledger].flags & LFILE_EXISTS)) {
937  | 		/* entering this level for first time; make it now */
938  | 		if (level_info[new_ledger].flags & (FORGOTTEN|VISITED)) {
939  | 		    impossible("goto_level: returning to discarded level?");
940  | 		    level_info[new_ledger].flags &= ~(FORGOTTEN|VISITED);
941  | 		}
942  | 		mklev();
943  | 		new = TRUE;	/* made the level */
944  | 	} else {
945  | 		/* returning to previously visited level; reload it */
946  | 		fd = open_levelfile(new_ledger);
947  | 		if (fd < 0) {
948  | 			pline("Cannot open file (#%d) for level %d (errno %d).",
949  | 					(int) new_ledger, depth(&u.uz), errno);
950  | 			pline("Probably someone removed it.");
951  | 			done(TRICKED);
952  | 		}
953  | 		minit();	/* ZEROCOMP */
954  | 		getlev(fd, hackpid, new_ledger, FALSE);
955  | 		(void) close(fd);
956  | 	}
957  | 	/* do this prior to level-change pline messages */
958  | 	vision_reset();		/* clear old level's line-of-sight */
959  | 	vision_full_recalc = 0;	/* don't let that reenable vision yet */
960  | 
961  | 	if (portal && !In_endgame(&u.uz)) {
962  | 	    /* find the portal on the new level */
963  | 	    register struct trap *ttrap;
964  | 
965  | 	    for (ttrap = ftrap; ttrap; ttrap = ttrap->ntrap)
966  | 		if (ttrap->ttyp == MAGIC_PORTAL) break;
967  | 
968  | 	    if (!ttrap) panic("goto_level: no corresponding portal!");
969  | 	    seetrap(ttrap);
970  | 	    u_on_newpos(ttrap->tx, ttrap->ty);
971  | 	} else if (at_stairs && !In_endgame(&u.uz)) {
972  | 	    if (up) {
973  | 		if (at_ladder) {
974  | 		    u_on_newpos(xdnladder, ydnladder);
975  | 		} else {
976  | 		    if (newdungeon) {
977  | 			if (Is_stronghold(&u.uz)) {
978  | 			    register xchar x, y;
979  | 
980  | 			    do {
981  | 				x = (COLNO - 2 - rnd(5));
982  | 				y = rn1(ROWNO - 4, 3);
983  | 			    } while(occupied(x, y) ||
984  | 				    IS_WALL(levl[x][y].typ));
985  | 			    u_on_newpos(x, y);
986  | 			} else u_on_sstairs();
987  | 		    } else u_on_dnstairs();
988  | 		}
989  | 		/* Remove bug which crashes with levitation/punishment  KAA */
990  | 		if (Punished && !Levitation) {
991  | 			pline("With great effort you climb the %s.",
992  | 				at_ladder ? "ladder" : "stairs");
993  | 		} else if (at_ladder)
994  | 		    You("climb up the ladder.");
995  | 	    } else {	/* down */
996  | 		if (at_ladder) {
997  | 		    u_on_newpos(xupladder, yupladder);
998  | 		} else {
999  | 		    if (newdungeon) u_on_sstairs();
1000 | 		    else u_on_upstairs();
1001 | 		}
1002 | 		if (u.dz && Flying)
1003 | 		    You("fly down along the %s.",
1004 | 			at_ladder ? "ladder" : "stairs");
1005 | 		else if (u.dz &&
1006 | 		    (near_capacity() > UNENCUMBERED || Punished || Fumbling)) {
1007 | 		    You("fall down the %s.", at_ladder ? "ladder" : "stairs");
1008 | 		    if (Punished) {
1009 | 			drag_down();
1010 | 			if (carried(uball)) {
1011 | 			    if (uwep == uball)
1012 | 				setuwep((struct obj *)0);
1013 | 			    if (uswapwep == uball)
1014 | 				setuswapwep((struct obj *)0);
1015 | 			    if (uquiver == uball)
1016 | 				setuqwep((struct obj *)0);
1017 | 			    freeinv(uball);
1018 | 			}
1019 | 		    }
1020 | 		    losehp(rnd(3), "falling downstairs", KILLED_BY);
1021 | #ifdef STEED
1022 | 		    if (u.usteed) dismount_steed(DISMOUNT_FELL);
1023 | #endif
1024 | 		    selftouch("Falling, you");
1025 | 		} else if (u.dz && at_ladder)
1026 | 		    You("climb down the ladder.");
1027 | 	    }
1028 | 	} else {	/* trap door or level_tele or In_endgame */
1029 | 	    if (was_in_W_tower && On_W_tower_level(&u.uz))
1030 | 		/* Stay inside the Wizard's tower when feasible.	*/
1031 | 		/* Note: up vs down doesn't really matter in this case. */
1032 | 		place_lregion(dndest.nlx, dndest.nly,
1033 | 				dndest.nhx, dndest.nhy,
1034 | 				0,0, 0,0, LR_DOWNTELE, (d_level *) 0);
1035 | 	    else if (up)
1036 | 		place_lregion(updest.lx, updest.ly,
1037 | 				updest.hx, updest.hy,
1038 | 				updest.nlx, updest.nly,
1039 | 				updest.nhx, updest.nhy,
1040 | 				LR_UPTELE, (d_level *) 0);
1041 | 	    else
1042 | 		place_lregion(dndest.lx, dndest.ly,
1043 | 				dndest.hx, dndest.hy,
1044 | 				dndest.nlx, dndest.nly,
1045 | 				dndest.nhx, dndest.nhy,
1046 | 				LR_DOWNTELE, (d_level *) 0);
1047 | 	    if (falling) {
1048 | 		if (Punished) ballfall();
1049 | 		selftouch("Falling, you");
1050 | 	    }
1051 | 	}
1052 | 
1053 | 	if (Punished) placebc();
1054 | 	obj_delivery();		/* before killing geno'd monsters' eggs */
1055 | 	losedogs();
1056 | 	kill_genocided_monsters();  /* for those wiped out while in limbo */
1057 | 	/*
1058 | 	 * Expire all timers that have gone off while away.  Must be
1059 | 	 * after migrating monsters and objects are delivered
1060 | 	 * (losedogs and obj_delivery).
1061 | 	 */
1062 | 	run_timers();
1063 | 
1064 | 	initrack();
1065 | 
1066 | 	if ((mtmp = m_at(u.ux, u.uy)) != 0
1067 | #ifdef STEED
1068 | 		&& mtmp != u.usteed
1069 | #endif
1070 | 		) {
1071 | 	    /* There's a monster at your target destination; it might be one
1072 | 	       which accompanied you--see mon_arrive(dogmove.c)--or perhaps
1073 | 	       it was already here.  Randomly move you to an adjacent spot
1074 | 	       or else the monster to any nearby location.  Prior to 3.3.0
1075 | 	       the latter was done unconditionally. */
1076 | 	    coord cc;
1077 | 
1078 | 	    if (!rn2(2) &&
1079 | 		    enexto(&cc, u.ux, u.uy, youmonst.data) &&
1080 | 		    distu(cc.x, cc.y) <= 2)
1081 | 		u_on_newpos(cc.x, cc.y);	/*[maybe give message here?]*/
1082 | 	    else
1083 | 		mnexto(mtmp);
1084 | 
1085 | 	    if ((mtmp = m_at(u.ux, u.uy)) != 0) {
1086 | 		impossible("mnexto failed (do.c)?");
1087 | 		rloc(mtmp);
1088 | 	    }
1089 | 	}
1090 | 
1091 | 	/* initial movement of bubbles just before vision_recalc */
1092 | 	if (Is_waterlevel(&u.uz))
1093 | 		movebubbles();
1094 | 
1095 | 	if (level_info[new_ledger].flags & FORGOTTEN) {
1096 | 	    forget_map(ALL_MAP);	/* forget the map */
1097 | 	    forget_traps();		/* forget all traps too */
1098 | 	    familiar = TRUE;
1099 | 	    level_info[new_ledger].flags &= ~FORGOTTEN;
1100 | 	}
1101 | 
1102 | 	/* Reset the screen. */
1103 | 	vision_reset();		/* reset the blockages */
1104 | 	docrt();		/* does a full vision recalc */
1105 | 	flush_screen(1);
1106 | 
1107 | 	/*
1108 | 	 *  Move all plines beyond the screen reset.
1109 | 	 */
1110 | 
1111 | 	/* give room entrance message, if any */
1112 | 	check_special_room(FALSE);
1113 | 
1114 | 	/* Check whether we just entered Gehennom. */
1115 | 	if (!In_hell(&u.uz0) && Inhell) {
1116 | 	    if (Is_valley(&u.uz)) {
1117 | 		You("arrive at the Valley of the Dead...");
1118 | 		pline_The("odor of burnt flesh and decay pervades the air.");
1119 | #ifdef MICRO
1120 | 		display_nhwindow(WIN_MESSAGE, FALSE);
1121 | #endif
1122 | 		You_hear("groans and moans everywhere.");
1123 | 	    } else pline("It is hot here.  You smell smoke...");
1124 | 	}
1125 | 
1126 | 	if (familiar) {
1127 | 	    static const char *fam_msgs[4] = {
1128 | 		"You have a sense of deja vu.",
1129 | 		"You feel like you've been here before.",
1130 | 		"This place looks familiar...",
1131 | 		0	/* no message */
1132 | 	    };
1133 | 	    static const char *halu_fam_msgs[4] = {
1134 | 		"Whoa!  Everything looks different.",
1135 | 		"You are surrounded by twisty little passages, all alike.",
1136 | 		"Gee, this looks like uncle Conan's place...",
1137 | 		0	/* no message */
1138 | 	    };
1139 | 	    const char *mesg;
1140 | 	    int which = rn2(4);
1141 | 
1142 | 	    if (Hallucination)
1143 | 		mesg = halu_fam_msgs[which];
1144 | 	    else
1145 | 		mesg = fam_msgs[which];
1146 | 	    if (mesg) pline(mesg);
1147 | 	}
1148 | 
1149 | #ifdef REINCARNATION
1150 | 	if (new && Is_rogue_level(&u.uz))
1151 | 	    You("enter what seems to be an older, more primitive world.");
1152 | #endif
1153 | 	/* Final confrontation */
1154 | 	if (In_endgame(&u.uz) && newdungeon && u.uhave.amulet)
1155 | 		resurrect();
1156 | 	if (newdungeon && In_V_tower(&u.uz) && In_hell(&u.uz0))
1157 | 		pline_The("heat and smoke are gone.");
1158 | 
1159 | 	/* the message from your quest leader */
1160 | 	if (!In_quest(&u.uz0) && at_dgn_entrance("The Quest") &&
1161 | 		!(u.uevent.qexpelled || u.uevent.qcompleted || leaderless())) {
1162 | 
1163 | 		if (u.uevent.qcalled) {
1164 | 			com_pager(Role_if(PM_ROGUE) ? 4 : 3);
1165 | 		} else {
1166 | 			com_pager(2);
1167 | 			u.uevent.qcalled = TRUE;
1168 | 		}
1169 | 	}
1170 | 
1171 | 	/* once Croesus is dead, his alarm doesn't work any more */
1172 | 	if (Is_knox(&u.uz) && (new || !mvitals[PM_CROESUS].died)) {
1173 | 		You("penetrated a high security area!");
1174 | 		pline("An alarm sounds!");
1175 | 		for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
1176 | 		    if (!DEADMONSTER(mtmp) && mtmp->msleeping) mtmp->msleeping = 0;
1177 | 	}
1178 | 
1179 | 	if (on_level(&u.uz, &astral_level))
1180 | 	    final_level();
1181 | 	else
1182 | 	    onquest();
1183 | 	assign_level(&u.uz0, &u.uz); /* reset u.uz0 */
1184 | 
1185 | #ifdef INSURANCE
1186 | 	save_currentstate();
1187 | #endif
1188 | 
1189 | 	(void) pickup(1);
1190 | }
1191 | 
1192 | STATIC_OVL void
1193 | final_level()
1194 | {
1195 | 	struct monst *mtmp;
1196 | 	struct obj *otmp;
1197 | 	coord mm;
1198 | 	int i;
1199 | 
1200 | 	/* reset monster hostility relative to player */
1201 | 	for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
1202 | 	    if (!DEADMONSTER(mtmp)) reset_hostility(mtmp);
1203 | 
1204 | 	/* create some player-monsters */
1205 | 	create_mplayers(rn1(4, 3), TRUE);
1206 | 
1207 | 	/* create a guardian angel next to player, if worthy */
1208 | 	if (Conflict) {
1209 | 	    pline(
1210 | 	     "A voice booms: \"Thy desire for conflict shall be fulfilled!\"");
1211 | 	    for (i = rnd(4); i > 0; --i) {
1212 | 		mm.x = u.ux;
1213 | 		mm.y = u.uy;
1214 | 		if (enexto(&mm, mm.x, mm.y, &mons[PM_ANGEL]))
1215 | 		    (void) mk_roamer(&mons[PM_ANGEL], u.ualign.type,
1216 | 				     mm.x, mm.y, FALSE);
1217 | 	    }
1218 | 
1219 | 	} else if (u.ualign.record > 8) {	/* fervent */
1220 | 	    pline("A voice whispers: \"Thou hast been worthy of me!\"");
1221 | 	    mm.x = u.ux;
1222 | 	    mm.y = u.uy;
1223 | 	    if (enexto(&mm, mm.x, mm.y, &mons[PM_ANGEL])) {
1224 | 		if ((mtmp = mk_roamer(&mons[PM_ANGEL], u.ualign.type,
1225 | 				      mm.x, mm.y, TRUE)) != 0) {
1226 | 		    if (!Blind)
1227 | 			pline("An angel appears near you.");
1228 | 		    else
1229 | 			You_feel("the presence of a friendly angel near you.");
1230 | 		    /* guardian angel -- the one case mtame doesn't
1231 | 		     * imply an edog structure, so we don't want to
1232 | 		     * call tamedog().
1233 | 		     */
1234 | 		    mtmp->mtame = 10;
1235 | 		    /* make him strong enough vs. endgame foes */
1236 | 		    mtmp->m_lev = rn1(8,15);
1237 | 		    mtmp->mhp = mtmp->mhpmax =
1238 | 					d((int)mtmp->m_lev,10) + 30 + rnd(30);
1239 | 		    if ((otmp = select_hwep(mtmp)) == 0) {
1240 | 			otmp = mksobj(SILVER_SABER, FALSE, FALSE);
1241 | 			if (mpickobj(mtmp, otmp))
1242 | 			    panic("merged weapon?");
1243 | 		    }
1244 | 		    bless(otmp);
1245 | 		    if (otmp->spe < 4) otmp->spe += rnd(4);
1246 | 		    if ((otmp = which_armor(mtmp, W_ARMS)) == 0 ||
1247 | 			    otmp->otyp != SHIELD_OF_REFLECTION) {
1248 | 			(void) mongets(mtmp, AMULET_OF_REFLECTION);
1249 | 			m_dowear(mtmp, TRUE);
1250 | 		    }
1251 | 		}
1252 | 	    }
1253 | 	}
1254 | }
1255 | 
1256 | static char *dfr_pre_msg = 0,	/* pline() before level change */
1257 | 	    *dfr_post_msg = 0;	/* pline() after level change */
1258 | 
1259 | /* change levels at the end of this turn, after monsters finish moving */
1260 | void
1261 | schedule_goto(tolev, at_stairs, falling, portal_flag, pre_msg, post_msg)
1262 | d_level *tolev;
1263 | boolean at_stairs, falling;
1264 | int portal_flag;
1265 | const char *pre_msg, *post_msg;
1266 | {
1267 | 	int typmask = 0100;		/* non-zero triggers `deferred_goto' */
1268 | 
1269 | 	/* destination flags (`goto_level' args) */
1270 | 	if (at_stairs)	 typmask |= 1;
1271 | 	if (falling)	 typmask |= 2;
1272 | 	if (portal_flag) typmask |= 4;
1273 | 	if (portal_flag < 0) typmask |= 0200;	/* flag for portal removal */
1274 | 	u.utotype = typmask;
1275 | 	/* destination level */
1276 | 	assign_level(&u.utolev, tolev);
1277 | 
1278 | 	if (pre_msg)
1279 | 	    dfr_pre_msg = strcpy((char *)alloc(strlen(pre_msg) + 1), pre_msg);
1280 | 	if (post_msg)
1281 | 	    dfr_post_msg = strcpy((char *)alloc(strlen(post_msg)+1), post_msg);
1282 | }
1283 | 
1284 | /* handle something like portal ejection */
1285 | void
1286 | deferred_goto()
1287 | {
1288 | 	if (!on_level(&u.uz, &u.utolev)) {
1289 | 	    d_level dest;
1290 | 	    int typmask = u.utotype; /* save it; goto_level zeroes u.utotype */
1291 | 
1292 | 	    assign_level(&dest, &u.utolev);
1293 | 	    if (dfr_pre_msg) pline(dfr_pre_msg);
1294 | 	    goto_level(&dest, !!(typmask&1), !!(typmask&2), !!(typmask&4));
1295 | 	    if (typmask & 0200) {	/* remove portal */
1296 | 		struct trap *t = t_at(u.ux, u.uy);
1297 | 
1298 | 		if (t) {
1299 | 		    deltrap(t);
1300 | 		    newsym(u.ux, u.uy);
1301 | 		}
1302 | 	    }
1303 | 	    if (dfr_post_msg) pline(dfr_post_msg);
1304 | 	}
1305 | 	u.utotype = 0;		/* our caller keys off of this */
1306 | 	if (dfr_pre_msg)
1307 | 	    free((genericptr_t)dfr_pre_msg),  dfr_pre_msg = 0;
1308 | 	if (dfr_post_msg)
1309 | 	    free((genericptr_t)dfr_post_msg),  dfr_post_msg = 0;
1310 | }
1311 | 
1312 | #endif /* OVL2 */
1313 | #ifdef OVL3
1314 | 
1315 | /*
1316 |  * Return TRUE if we created a monster for the corpse.  If successful, the
1317 |  * corpse is gone.
1318 |  */
1319 | boolean
1320 | revive_corpse(corpse)
1321 | struct obj *corpse;
1322 | {
1323 |     struct monst *mtmp, *mcarry;
1324 |     boolean is_uwep, chewed;
1325 |     xchar where;
1326 |     char *cname, cname_buf[BUFSZ];
1327 | 
1328 |     where = corpse->where;
1329 |     is_uwep = corpse == uwep;
1330 |     cname = eos(strcpy(cname_buf, "bite-covered "));
1331 |     Strcpy(cname, corpse_xname(corpse, TRUE));
1332 |     mcarry = (where == OBJ_MINVENT) ? corpse->ocarry : 0;
1333 |     mtmp = revive(corpse);	/* corpse is gone if successful */
1334 | 
1335 |     if (mtmp) {
1336 | 	chewed = (mtmp->mhp < mtmp->mhpmax);
1337 | 	if (chewed) cname = cname_buf;	/* include "bite-covered" prefix */
1338 | 	switch (where) {
1339 | 	    case OBJ_INVENT:
1340 | 		if (is_uwep)
1341 | 		    pline_The("%s writhes out of your grasp!", cname);
1342 | 		else
1343 | 		    You_feel("squirming in your backpack!");
1344 | 		break;
1345 | 
1346 | 	    case OBJ_FLOOR:
1347 | 		if (cansee(mtmp->mx, mtmp->my))
1348 | 		    pline("%s rises from the dead!", chewed ?
1349 | 			  Adjmonnam(mtmp, "bite-covered") : Monnam(mtmp));
1350 | 		break;
1351 | 
1352 | 	    case OBJ_MINVENT:		/* probably a nymph's */
1353 | 		if (cansee(mtmp->mx, mtmp->my)) {
1354 | 		    if (canseemon(mcarry))
1355 | 			pline("Startled, %s drops %s as it revives!",
1356 | 			      mon_nam(mcarry), an(cname));
1357 | 		    else
1358 | 			pline("%s suddenly appears!", chewed ?
1359 | 			      Adjmonnam(mtmp, "bite-covered") : Monnam(mtmp));
1360 | 		}
1361 | 		break;
1362 | 
1363 | 	    default:
1364 | 		/* we should be able to handle the other cases... */
1365 | 		impossible("revive_corpse: lost corpse @ %d", where);
1366 | 		break;
1367 | 	}
1368 | 	return TRUE;
1369 |     }
1370 |     return FALSE;
1371 | }
1372 | 
1373 | /* Revive the corpse via a timeout. */
1374 | /*ARGSUSED*/
1375 | void
1376 | revive_mon(arg, timeout)
1377 | genericptr_t arg;
1378 | long timeout;
1379 | {
1380 |     struct obj *body = (struct obj *) arg;
1381 | 
1382 |     /* if we succeed, the corpse is gone, otherwise, rot it away */
1383 |     if (!revive_corpse(body)) {
1384 | 	if (is_rider(&mons[body->corpsenm]))
1385 | 	    You_feel("less hassled.");
1386 | 	(void) start_timer(250L - (monstermoves-body->age),
1387 | 					TIMER_OBJECT, ROT_CORPSE, arg);
1388 |     }
1389 | }
1390 | 
1391 | int
1392 | donull()
1393 | {
1394 | 	return(1);	/* Do nothing, but let other things happen */
1395 | }
1396 | 
1397 | #endif /* OVL3 */
1398 | #ifdef OVLB
1399 | 
1400 | STATIC_PTR int
1401 | wipeoff()
1402 | {
1403 | 	if(u.ucreamed < 4)	u.ucreamed = 0;
1404 | 	else			u.ucreamed -= 4;
1405 | 	if (Blinded < 4)	Blinded = 0;
1406 | 	else			Blinded -= 4;
1407 | 	if (!Blinded) {
1408 | 		pline("You've got the glop off.");
1409 | 		u.ucreamed = 0;
1410 | 		Blinded = 1;
1411 | 		make_blinded(0L,TRUE);
1412 | 		return(0);
1413 | 	} else if (!u.ucreamed) {
1414 | 		Your("%s feels clean now.", body_part(FACE));
1415 | 		return(0);
1416 | 	}
1417 | 	return(1);		/* still busy */
1418 | }
1419 | 
1420 | int
1421 | dowipe()
1422 | {
1423 | 	if(u.ucreamed)  {
1424 | 		static NEARDATA char buf[39];
1425 | 
1426 | 		Sprintf(buf, "wiping off your %s", body_part(FACE));
1427 | 		set_occupation(wipeoff, buf, 0);
1428 | 		/* Not totally correct; what if they change back after now
1429 | 		 * but before they're finished wiping?
1430 | 		 */
1431 | 		return(1);
1432 | 	}
1433 | 	Your("%s is already clean.", body_part(FACE));
1434 | 	return(1);
1435 | }
1436 | 
1437 | void
1438 | set_wounded_legs(side, timex)
1439 | register long side;
1440 | register int timex;
1441 | {
1442 | 	/* KMH -- STEED
1443 | 	 * If you are riding, your steed gets the wounded legs instead.
1444 | 	 * You still call this function, but don't lose hp.
1445 | 	 * Caller is also responsible for adjusting messages.
1446 | 	 */
1447 | 
1448 | 	if(!Wounded_legs) {
1449 | 		ATEMP(A_DEX)--;
1450 | 		flags.botl = 1;
1451 | 	}
1452 | 
1453 | 	if(!Wounded_legs || (HWounded_legs & TIMEOUT))
1454 | 		HWounded_legs = timex;
1455 | 	EWounded_legs = side;
1456 | 	(void)encumber_msg();
1457 | }
1458 | 
1459 | void
1460 | heal_legs()
1461 | {
1462 | 	if(Wounded_legs) {
1463 | 		if (ATEMP(A_DEX) < 0) {
1464 | 			ATEMP(A_DEX)++;
1465 | 			flags.botl = 1;
1466 | 		}
1467 | 
1468 | #ifdef STEED
1469 | 		if (!u.usteed)
1470 | #endif
1471 | 		{
1472 | 			/* KMH, intrinsics patch */
1473 | 			if((EWounded_legs & BOTH_SIDES) == BOTH_SIDES) {
1474 | 			Your("%s feel somewhat better.",
1475 | 				makeplural(body_part(LEG)));
1476 | 		} else {
1477 | 			Your("%s feels somewhat better.",
1478 | 				body_part(LEG));
1479 | 		}
1480 | 		}
1481 | 		HWounded_legs = EWounded_legs = 0;
1482 | 	}
1483 | 	(void)encumber_msg();
1484 | }
1485 | 
1486 | #endif /* OVLB */
1487 | 
1488 | /*do.c*/