diff -Naurd ../nethack-3.4.0/include/amiconf.h ./include/amiconf.h
--- ../nethack-3.4.0/include/amiconf.h Wed Mar 20 23:42:42 2002
+++ ./include/amiconf.h Mon Feb 24 15:25:05 2003
@@ -38,7 +38,7 @@
 
 #define NOCWD_ASSUMPTIONS	/* Allow paths to be specified for HACKDIR,
 				   LEVELDIR, SAVEDIR, BONESDIR, DATADIR,
-				   SCOREDIR, LOCKDIR, and CONFIGDIR. */
+				   SCOREDIR, LOCKDIR, CONFIGDIR, and TROUBLEDIR */
 
 /* data librarian defs */
 #ifndef NOCWD_ASSUMPTIONS
@@ -47,6 +47,8 @@
 #else
 # define DLBFILE	"nhdat"			/* main library */
 # define DLBFILE2	"nhsdat"		/* sound library */
+#endif
+
 #define FILENAME_CMP	stricmp			/* case insensitive */
 
 #ifndef __SASC_60
diff -Naurd ../nethack-3.4.0/include/artilist.h ./include/artilist.h
--- ../nethack-3.4.0/include/artilist.h Wed Mar 20 23:42:42 2002
+++ ./include/artilist.h Mon Feb 24 15:25:05 2003
@@ -107,7 +107,7 @@
 
 A("Werebane",			SILVER_SABER,
 	(SPFX_RESTR|SPFX_DFLAG2), 0, M2_WERE,
-	PHYS(5,0),	NO_DFNS,	NO_CARY,	0, A_NONE, NON_PM, NON_PM, 1500L ),
+	PHYS(5,0),	DFNS(AD_WERE),	NO_CARY,	0, A_NONE, NON_PM, NON_PM, 1500L ),
 
 A("Grayswandir",		SILVER_SABER,
 	(SPFX_RESTR|SPFX_HALRES), 0, 0,
diff -Naurd ../nethack-3.4.0/include/color.h ./include/color.h
--- ../nethack-3.4.0/include/color.h Wed Mar 20 23:42:43 2002
+++ ./include/color.h Mon Feb 24 15:25:05 2003
@@ -46,6 +46,7 @@
 #define HI_PAPER	CLR_WHITE
 #define HI_GLASS	CLR_BRIGHT_CYAN
 #define HI_MINERAL	CLR_GRAY
+#define DRAGON_SILVER	CLR_BRIGHT_CYAN
 #define HI_ZAP		CLR_BRIGHT_BLUE
 
 #endif /* COLOR_H */
diff -Naurd ../nethack-3.4.0/include/config.h ./include/config.h
--- ../nethack-3.4.0/include/config.h Wed Mar 20 23:42:43 2002
+++ ./include/config.h Mon Feb 24 15:25:05 2003
@@ -83,7 +83,9 @@
 #endif
 
 #ifdef QT_GRAPHICS
+# define DEFAULT_WC_TILED_MAP   /* Default to tiles if users doesn't say wc_ascii_map */
 # define USER_SOUNDS		/* Use sounds */
+# define USER_SOUNDS_REGEX
 # define USE_XPM		/* Use XPM format for images (required) */
 # define GRAPHIC_TOMBSTONE	/* Use graphical tombstone (rip.ppm) */
 # ifndef DEFAULT_WINDOW_SYS
@@ -131,9 +133,10 @@
 
 /*
  * Section 2:	Some global parameters and filenames.
- *		Commenting out WIZARD, LOGFILE, or NEWS removes that feature
- *		from the game; otherwise set the appropriate wizard name.
- *		LOGFILE and NEWS refer to files in the playground.
+ *		Commenting out WIZARD, LOGFILE, NEWS or PANICLOG removes that
+ *		feature from the game; otherwise set the appropriate wizard
+ *		name.  LOGFILE, NEWS and PANICLOG refer to files in the
+ *		playground.
  */
 
 #ifndef WIZARD		/* allow for compile-time or Makefile changes */
@@ -147,6 +150,7 @@
 
 #define LOGFILE "logfile"	/* larger file for debugging purposes */
 #define NEWS "news"		/* the file containing the latest hack news */
+#define PANICLOG "paniclog"	/* log of panic and impossible events */
 
 /*
  *	If COMPRESS is defined, it should contain the full path name of your
diff -Naurd ../nethack-3.4.0/include/decl.h ./include/decl.h
--- ../nethack-3.4.0/include/decl.h Wed Mar 20 23:42:44 2002
+++ ./include/decl.h Mon Feb 24 15:25:05 2003
@@ -270,16 +270,16 @@
 		*const c_silver, *const c_blue, *const c_purple,
 		*const c_white;
 } c_color_names;
-#define Black		c_color_names.c_black
-#define amber		c_color_names.c_amber
-#define golden		c_color_names.c_golden
-#define light_blue	c_color_names.c_light_blue
-#define red		c_color_names.c_red
-#define green		c_color_names.c_green
-#define silver		c_color_names.c_silver
-#define blue		c_color_names.c_blue
-#define purple		c_color_names.c_purple
-#define White		c_color_names.c_white
+#define NH_BLACK		c_color_names.c_black
+#define NH_AMBER		c_color_names.c_amber
+#define NH_GOLDEN		c_color_names.c_golden
+#define NH_LIGHT_BLUE		c_color_names.c_light_blue
+#define NH_RED			c_color_names.c_red
+#define NH_GREEN		c_color_names.c_green
+#define NH_SILVER		c_color_names.c_silver
+#define NH_BLUE			c_color_names.c_blue
+#define NH_PURPLE		c_color_names.c_purple
+#define NH_WHITE		c_color_names.c_white
 
 /* The names of the colors used for gems, etc. */
 E const char *c_obj_colors[];
@@ -337,7 +337,7 @@
 #endif
 
 /* xxxexplain[] is in drawing.c */
-E const char *monexplain[], *invisexplain, *objexplain[], *oclass_names[];
+E const char * const monexplain[], invisexplain[], * const objexplain[], * const oclass_names[];
 
 /* Some systems want to use full pathnames for some subsets of file names,
  * rather than assuming that they're all in the current directory.  This
@@ -348,11 +348,12 @@
 #define LEVELPREFIX	1
 #define SAVEPREFIX	2
 #define BONESPREFIX	3
-#define DATAPREFIX	4
+#define DATAPREFIX	4	/* this one must match hardcoded value in dlb.c */
 #define SCOREPREFIX	5
 #define LOCKPREFIX	6
 #define CONFIGPREFIX	7
-#define PREFIX_COUNT	8
+#define TROUBLEPREFIX	8
+#define PREFIX_COUNT	9
 /* used in files.c; xxconf.h can override if needed */
 # ifndef FQN_MAX_FILENAME
 #define FQN_MAX_FILENAME 512
diff -Naurd ../nethack-3.4.0/include/display.h ./include/display.h
--- ../nethack-3.4.0/include/display.h Wed Mar 20 23:42:44 2002
+++ ./include/display.h Mon Feb 24 15:25:05 2003
@@ -125,6 +125,7 @@
 
 /*
  * canseeself()
+ * senseself()
  *
  * This returns true if the hero can see her/himself.
  *
@@ -132,7 +133,8 @@
  * invisible.  If not, then we don't need the check.
  */
 #define canseeself()	(Blind || u.uswallow || (!Invisible && !u.uundetected))
-
+#define senseself()	(canseeself() || Infravision || Unblind_telepat || \
+			 Detect_monsters)
 
 /*
  * random_monster()
@@ -192,28 +194,22 @@
  * _if_ the hero can be seen have already been done.
  */
 #ifdef STEED
-#define display_self()							\
-    show_glyph(u.ux, u.uy,						\
-	(u.usteed && mon_visible(u.usteed)) ?			\
-				ridden_mon_to_glyph(u.usteed) :		\
-	youmonst.m_ap_type == M_AP_NOTHING ?				\
-				hero_glyph :					\
-	youmonst.m_ap_type == M_AP_FURNITURE ?				\
-				cmap_to_glyph(youmonst.mappearance) :	\
-	youmonst.m_ap_type == M_AP_OBJECT ?				\
-				objnum_to_glyph(youmonst.mappearance) : \
-	/* else M_AP_MONSTER */ monnum_to_glyph(youmonst.mappearance))
+#define maybe_display_usteed	(u.usteed && mon_visible(u.usteed)) ? \
+					ridden_mon_to_glyph(u.usteed) :
 #else
+#define maybe_display_usteed	/* empty */
+#endif
+
 #define display_self()							\
     show_glyph(u.ux, u.uy,						\
+	maybe_display_usteed			/* else */		\
 	youmonst.m_ap_type == M_AP_NOTHING ?				\
-				hero_glyph :					\
+				hero_glyph :				\
 	youmonst.m_ap_type == M_AP_FURNITURE ?				\
 				cmap_to_glyph(youmonst.mappearance) :	\
 	youmonst.m_ap_type == M_AP_OBJECT ?				\
 				objnum_to_glyph(youmonst.mappearance) : \
 	/* else M_AP_MONSTER */ monnum_to_glyph(youmonst.mappearance))
-#endif
 
 /*
  * A glyph is an abstraction that represents a _unique_ monster, object,
@@ -314,10 +310,12 @@
 #define ridden_monnum_to_glyph(mnum)	((int) (mnum) + GLYPH_RIDDEN_OFF)
 #define petnum_to_glyph(mnum)	((int) (mnum) + GLYPH_PET_OFF)
 
-/* The hero's glyph when seen as a monster.  Could also be...
- * mon_to_glyph(Upolyd || Race_if(PM_HUMAN) ? u.umonnum : urace.malenum)
+/* The hero's glyph when seen as a monster.
  */
-#define hero_glyph monnum_to_glyph(u.umonnum)
+#define hero_glyph \
+	monnum_to_glyph((Upolyd || !iflags.showrace) ? u.umonnum : \
+	                (flags.female && urace.femalenum != NON_PM) ? urace.femalenum : \
+	                urace.malenum)
 
 
 /*
diff -Naurd ../nethack-3.4.0/include/dlb.h ./include/dlb.h
--- ../nethack-3.4.0/include/dlb.h Wed Mar 20 23:42:44 2002
+++ ./include/dlb.h Mon Feb 24 15:25:05 2003
@@ -125,12 +125,12 @@
 #endif
 
 #define RDTMODE "r"
-#if (defined(MSDOS) || defined(WIN32) || defined(TOS)) && defined(DLB)
+#if (defined(MSDOS) || defined(WIN32) || defined(TOS) || defined(OS2)) && defined(DLB)
 #define WRTMODE "w+b"
 #else
 #define WRTMODE "w+"
 #endif
-#if (defined(MICRO) && !defined(AMIGA)) || defined(THINK_C) || defined(__MWERKS__)
+#if (defined(MICRO) && !defined(AMIGA)) || defined(THINK_C) || defined(__MWERKS__) || defined(WIN32)
 # define RDBMODE "rb"
 # define WRBMODE "w+b"
 #else
diff -Naurd ../nethack-3.4.0/include/extern.h ./include/extern.h
--- ../nethack-3.4.0/include/extern.h Wed Mar 20 23:42:46 2002
+++ ./include/extern.h Mon Feb 24 15:25:05 2003
@@ -39,7 +39,6 @@
 E boolean NDECL(next_to_u);
 E struct obj *FDECL(get_mleash, (struct monst *));
 E void FDECL(check_leash, (XCHAR_P,XCHAR_P));
-E boolean FDECL(wield_tool, (struct obj *));
 E boolean FDECL(um_dist, (XCHAR_P,XCHAR_P,XCHAR_P));
 E boolean FDECL(snuff_candle, (struct obj *));
 E boolean FDECL(snuff_lit, (struct obj *));
@@ -62,6 +61,8 @@
 E void FDECL(artifact_exists, (struct obj *,const char *,BOOLEAN_P));
 E int NDECL(nartifact_exist);
 E boolean FDECL(spec_ability, (struct obj *,unsigned long));
+E boolean FDECL(confers_luck, (struct obj *));
+E boolean FDECL(arti_reflects, (struct obj *));
 E boolean FDECL(restrict_name, (struct obj *,const char *));
 E boolean FDECL(defends, (int,struct obj *));
 E boolean FDECL(protects, (int,struct obj *));
@@ -109,7 +110,7 @@
 E void FDECL(set_bc, (int));
 E void FDECL(move_bc, (int,int,XCHAR_P,XCHAR_P,XCHAR_P,XCHAR_P));
 E boolean FDECL(drag_ball, (XCHAR_P,XCHAR_P,
-		    int *,xchar *,xchar *,xchar *,xchar *, boolean *));
+		int *,xchar *,xchar *,xchar *,xchar *, boolean *,BOOLEAN_P));
 E void FDECL(drop_ball, (XCHAR_P,XCHAR_P));
 E void NDECL(drag_down);
 
@@ -171,6 +172,7 @@
 E int FDECL(getdir, (const char *));
 E void NDECL(confdir);
 E int FDECL(isok, (int,int));
+E int FDECL(get_adjacent_loc, (const char *, const char *, XCHAR_P, XCHAR_P, coord *));
 E const char *FDECL(click_to_cmd, (int,int,int));
 E char NDECL(readchar);
 #ifdef WIZARD
@@ -382,6 +384,7 @@
 E void NDECL(glibr);
 E struct obj *FDECL(some_armor,(struct monst *));
 E void FDECL(erode_armor, (struct monst *,BOOLEAN_P));
+E struct obj *FDECL(stuck_ring, (struct obj *,int));
 E void NDECL(reset_remarm);
 E int NDECL(doddoremarm);
 E int FDECL(destroy_arm, (struct obj *));
@@ -577,12 +580,12 @@
 E void FDECL(losexp, (const char *));
 E void NDECL(newexplevel);
 E void FDECL(pluslvl, (BOOLEAN_P));
-E long NDECL(rndexp);
+E long FDECL(rndexp, (BOOLEAN_P));
 
 /* ### explode.c ### */
 
 E void FDECL(explode, (int,int,int,int,CHAR_P,int));
-E void FDECL(scatter, (int, int, int, unsigned int, struct obj *));
+E long FDECL(scatter, (int, int, int, unsigned int, struct obj *));
 E void FDECL(splatter_burning_oil, (int, int));
 
 /* ### extralev.c ### */
@@ -595,19 +598,21 @@
 
 /* ### files.c ### */
 
+E char *FDECL(fname_encode, (const char *, CHAR_P, char *, char *, int));
+E char *FDECL(fname_decode, (CHAR_P, char *, char *, int));
 E const char *FDECL(fqname, (const char *, int, int));
-E FILE *FDECL(fopen_datafile, (const char *,const char *,BOOLEAN_P));
+E FILE *FDECL(fopen_datafile, (const char *,const char *,int));
 E boolean FDECL(uptodate, (int,const char *));
 E void FDECL(store_version, (int));
 #ifdef MFLOPPY
 E void NDECL(set_lock_and_bones);
 #endif
 E void FDECL(set_levelfile_name, (char *,int));
-E int FDECL(create_levelfile, (int));
-E int FDECL(open_levelfile, (int));
+E int FDECL(create_levelfile, (int,char *));
+E int FDECL(open_levelfile, (int,char *));
 E void FDECL(delete_levelfile, (int));
 E void NDECL(clearlocks);
-E int FDECL(create_bonesfile, (d_level*,char **));
+E int FDECL(create_bonesfile, (d_level*,char **, char *));
 #ifdef MFLOPPY
 E void NDECL(cancel_bonesfile);
 #endif
@@ -638,6 +643,16 @@
 #if defined(WIZARD)
 E void NDECL(read_wizkit);
 #endif
+E void FDECL(paniclog, (const char *, const char *));
+E int FDECL(validate_prefix_locations, (char *));
+E char** NDECL(get_saved_games);
+E void FDECL(free_saved_games, (char**));
+#ifdef SELF_RECOVER
+E boolean NDECL(recover_savefile);
+#endif
+#ifdef HOLD_LOCKFILE_OPEN
+E void NDECL(really_close);
+#endif
 
 /* ### fountain.c ### */
 
@@ -662,11 +677,12 @@
 E boolean FDECL(may_passwall, (XCHAR_P,XCHAR_P));
 E boolean FDECL(bad_rock, (struct permonst *,XCHAR_P,XCHAR_P));
 E boolean FDECL(invocation_pos, (XCHAR_P,XCHAR_P));
-E boolean FDECL(test_move, (int, int, int, int, BOOLEAN_P));
+E boolean FDECL(test_move, (int, int, int, int, int));
 E void NDECL(domove);
 E void NDECL(invocation_message);
 E void FDECL(spoteffects, (BOOLEAN_P));
 E char *FDECL(in_rooms, (XCHAR_P,XCHAR_P,int));
+E boolean FDECL(in_town, (int,int));
 E void FDECL(check_special_room, (BOOLEAN_P));
 E int NDECL(dopickup);
 E void NDECL(lookaround);
@@ -695,6 +711,7 @@
 E char *FDECL(upstart, (char *));
 E char *FDECL(mungspaces, (char *));
 E char *FDECL(eos, (char *));
+E char *FDECL(strkitten, (char *,CHAR_P));
 E char *FDECL(s_suffix, (const char *));
 E char *FDECL(xcrypt, (const char *,char *));
 E boolean FDECL(onlyspace, (const char *));
@@ -790,6 +807,7 @@
 E int FDECL(count_buc, (struct obj *,int));
 E void FDECL(carry_obj_effects, (struct obj *));
 E const char *FDECL(currency, (long));
+E void FDECL(silly_thing, (const char *,struct obj *));
 
 /* ### ioctl.c ### */
 
@@ -905,6 +923,7 @@
 E void FDECL(set_malign, (struct monst *));
 E void FDECL(set_mimic_sym, (struct monst *));
 E int FDECL(mbirth_limit, (int));
+E void FDECL(mimic_hit_msg, (struct monst *, SHORT_P));
 #ifdef GOLDOBJ
 E void FDECL(mkmonmoney, (struct monst *, long));
 #endif
@@ -925,6 +944,7 @@
 E int FDECL(noattacks, (struct permonst *));
 E int FDECL(sleep_monst, (struct monst *,int,int));
 E void FDECL(slept_monst, (struct monst *));
+E long FDECL(attk_protection, (int));
 
 /* ### mhitu.c ### */
 
@@ -934,6 +954,7 @@
 E void FDECL(expels, (struct monst *,struct permonst *,BOOLEAN_P));
 E struct attack *FDECL(getmattk, (struct permonst *,int,int *,struct attack *));
 E int FDECL(mattacku, (struct monst *));
+E int FDECL(magic_negation, (struct monst *));
 E int FDECL(gazemu, (struct monst *,struct attack *));
 E void FDECL(mdamageu, (struct monst *,int));
 E int FDECL(could_seduce, (struct monst *,struct monst *,struct attack *));
@@ -943,7 +964,7 @@
 
 /* ### minion.c ### */
 
-E void FDECL(msummon, (struct permonst *));
+E void FDECL(msummon, (struct monst *));
 E void FDECL(summon_minion, (ALIGNTYP_P,BOOLEAN_P));
 E int FDECL(demon_talk, (struct monst *));
 E long FDECL(bribe, (struct monst *));
@@ -1107,7 +1128,7 @@
 E void NDECL(restartcham);
 E void FDECL(restore_cham, (struct monst *));
 E void FDECL(mon_animal_list, (BOOLEAN_P));
-E int FDECL(newcham, (struct monst *,struct permonst *,BOOLEAN_P));
+E int FDECL(newcham, (struct monst *,struct permonst *,BOOLEAN_P,BOOLEAN_P));
 E int FDECL(can_be_hatched, (int));
 E int FDECL(egg_type_from_parent, (int,BOOLEAN_P));
 E boolean FDECL(dead_species, (int,BOOLEAN_P));
@@ -1128,10 +1149,12 @@
 E boolean FDECL(can_blnd, (struct monst *,struct monst *,UCHAR_P,struct obj *));
 E boolean FDECL(ranged_attk, (struct permonst *));
 E boolean FDECL(hates_silver, (struct permonst *));
+E boolean FDECL(passes_bars, (struct permonst *));
 E boolean FDECL(can_track, (struct permonst *));
 E boolean FDECL(breakarm, (struct permonst *));
 E boolean FDECL(sliparm, (struct permonst *));
 E boolean FDECL(sticks, (struct permonst *));
+E int FDECL(num_horns, (struct permonst *));
 /* E boolean FDECL(canseemon, (struct monst *)); */
 E struct attack *FDECL(dmgtype_fromattack, (struct permonst *,int,int));
 E boolean FDECL(dmgtype, (struct permonst *,int));
@@ -1145,6 +1168,8 @@
 E int FDECL(big_to_little, (int));
 E const char *FDECL(locomotion, (const struct permonst *,const char *));
 E const char *FDECL(stagger, (const struct permonst *,const char *));
+E const char *FDECL(on_fire, (struct permonst *,struct attack *));
+E const struct permonst *FDECL(raceptr, (struct monst *));
 
 /* ### monmove.c ### */
 
@@ -1176,7 +1201,7 @@
 E void FDECL(create_mplayers, (int,BOOLEAN_P));
 E void FDECL(mplayer_talk, (struct monst *));
 
-#ifdef MICRO
+#if defined(MICRO) || defined(WIN32)
 
 /* ### msdos.c,os2.c,tos.c,winnt.c ### */
 
@@ -1225,8 +1250,7 @@
 E int NDECL((*nt_kbhit));
 E void FDECL(Delay, (int));
 # endif /* WIN32 */
-
-#endif /* MICRO */
+#endif /* MICRO || WIN32 */
 
 /* ### mthrowu.c ### */
 
@@ -1240,6 +1264,7 @@
 E struct obj *FDECL(m_carrying, (struct monst *,int));
 E void FDECL(m_useup, (struct monst *,struct obj *));
 E void FDECL(m_throw, (struct monst *,int,int,int,int,int,struct obj *));
+E boolean FDECL(hits_bars, (struct obj **,int,int,int,int));
 
 /* ### muse.c ### */
 
@@ -1310,6 +1335,7 @@
 E char *FDECL(simple_typename, (int));
 E boolean FDECL(obj_is_pname, (struct obj *));
 E char *FDECL(distant_name, (struct obj *,char *(*)(OBJ_P)));
+E char *FDECL(fruitname, (BOOLEAN_P));
 E char *FDECL(xname, (struct obj *));
 E char *FDECL(mshot_xname, (struct obj *));
 E boolean FDECL(the_unique_obj, (struct obj *obj));
@@ -1334,6 +1360,7 @@
 E struct obj *FDECL(readobjnam, (char *,struct obj *,BOOLEAN_P));
 E int FDECL(rnd_class, (int,int));
 E const char *FDECL(cloak_simple_name, (struct obj *));
+E const char *FDECL(mimic_obj_name, (struct monst *));
 
 /* ### options.c ### */
 
@@ -1352,7 +1379,7 @@
 E char *FDECL(nh_getenv, (const char *));
 E void FDECL(set_duplicate_opt_detection, (int));
 E void FDECL(set_wc_option_mod_status, (unsigned long, int));
-E void FDECL(set_option_mod_status, (char *, int));
+E void FDECL(set_option_mod_status, (const char *,int));
 
 /* ### pager.c ### */
 
@@ -1360,20 +1387,21 @@
 E int NDECL(doquickwhatis);
 E int NDECL(doidtrap);
 E int NDECL(dowhatdoes);
+E char *FDECL(dowhatdoes_core,(CHAR_P, char *));
 E int NDECL(dohelp);
 E int NDECL(dohistory);
 
 /* ### pcmain.c ### */
 
-#if defined(MICRO)
+#if defined(MICRO) || defined(WIN32)
 # ifdef CHDIR
 E void FDECL(chdirx, (char *,BOOLEAN_P));
 # endif /* CHDIR */
-#endif /* MICRO */
+#endif /* MICRO || WIN32 */
 
 /* ### pcsys.c ### */
 
-#ifdef MICRO
+#if defined(MICRO) || defined(WIN32)
 E void NDECL(flushout);
 E int NDECL(dosh);
 # ifdef MFLOPPY
@@ -1389,11 +1417,11 @@
 E void VDECL(msmsg, (const char *,...));
 # endif
 E FILE *FDECL(fopenp, (const char *,const char *));
-#endif /* MICRO */
+#endif /* MICRO || WIN32 */
 
 /* ### pctty.c ### */
 
-#if defined(MICRO)
+#if defined(MICRO) || defined(WIN32)
 E void NDECL(gettty);
 E void FDECL(settty, (const char *));
 E void NDECL(setftty);
@@ -1401,7 +1429,7 @@
 #if defined(TIMED_DELAY) && defined(_MSC_VER)
 E void FDECL(msleep, (unsigned));
 #endif
-#endif /* MICRO */
+#endif /* MICRO || WIN32 */
 
 /* ### pcunix.c ### */
 
@@ -1416,10 +1444,10 @@
 
 #ifdef GOLDOBJ
 E int FDECL(collect_obj_classes,
-	(char *,struct obj *,BOOLEAN_P,boolean FDECL((*),(OBJ_P))));
+	(char *,struct obj *,BOOLEAN_P,boolean FDECL((*),(OBJ_P)), int *));
 #else
 E int FDECL(collect_obj_classes,
-	(char *,struct obj *,BOOLEAN_P,BOOLEAN_P,boolean FDECL((*),(OBJ_P))));
+	(char *,struct obj *,BOOLEAN_P,BOOLEAN_P,boolean FDECL((*),(OBJ_P)), int *));
 #endif
 E void FDECL(add_valid_menu_class, (int));
 E boolean FDECL(allow_all, (struct obj *));
@@ -1619,14 +1647,14 @@
 E NhRegion *FDECL(visible_region_at, (XCHAR_P,XCHAR_P));
 E void FDECL(show_region, (NhRegion*, XCHAR_P, XCHAR_P));
 E void FDECL(save_regions, (int,int));
-E void FDECL(rest_regions, (int));
+E void FDECL(rest_regions, (int,BOOLEAN_P));
 E NhRegion* FDECL(create_gas_cloud, (XCHAR_P, XCHAR_P, int, int));
 
 /* ### restore.c ### */
 
 E void FDECL(inven_inuse, (BOOLEAN_P));
 E int FDECL(dorecover, (int));
-E void NDECL(trickery);
+E void FDECL(trickery, (char *));
 E void FDECL(getlev, (int,int,XCHAR_P,BOOLEAN_P));
 E void NDECL(minit);
 E boolean FDECL(lookup_id_mapping, (unsigned, unsigned *));
@@ -1741,7 +1769,7 @@
 E void FDECL(hot_pursuit, (struct monst *));
 E void FDECL(make_angry_shk, (struct monst *,XCHAR_P,XCHAR_P));
 E int NDECL(dopay);
-E boolean FDECL(paybill, (BOOLEAN_P));
+E boolean FDECL(paybill, (int));
 E void NDECL(finish_paybill);
 E struct obj *FDECL(find_oid, (unsigned));
 E long FDECL(contained_cost, (struct obj *,struct monst *,long,BOOLEAN_P, BOOLEAN_P));
@@ -1759,9 +1787,10 @@
 E void FDECL(add_damage, (XCHAR_P,XCHAR_P,long));
 E int FDECL(repair_damage, (struct monst *,struct damage *,BOOLEAN_P));
 E int FDECL(shk_move, (struct monst *));
+E void FDECL(after_shk_move, (struct monst *));
 E boolean FDECL(is_fshk, (struct monst *));
 E void FDECL(shopdig, (int));
-E void FDECL(pay_for_damage, (const char *));
+E void FDECL(pay_for_damage, (const char *,BOOLEAN_P));
 E boolean FDECL(costly_spot, (XCHAR_P,XCHAR_P));
 E struct obj *FDECL(shop_object, (XCHAR_P,XCHAR_P));
 E void FDECL(price_quote, (struct obj *));
@@ -1798,6 +1827,7 @@
 E int NDECL(dotalk);
 #ifdef USER_SOUNDS
 E int FDECL(add_sound_mapping, (const char *));
+E void FDECL(play_sound_for_message, (const char *));
 #endif
 
 /* ### sys/msdos/sound.c ### */
@@ -1843,7 +1873,7 @@
 E long NDECL(somegold);
 #endif
 E void FDECL(stealgold, (struct monst *));
-E void FDECL(remove_worn_item, (struct obj *));
+E void FDECL(remove_worn_item, (struct obj *,BOOLEAN_P));
 E int FDECL(steal, (struct monst *, char *));
 E int FDECL(mpickobj, (struct monst *,struct obj *));
 E void FDECL(stealamulet, (struct monst *));
@@ -1855,6 +1885,7 @@
 /* ### steed.c ### */
 
 #ifdef STEED
+E void NDECL(rider_cant_reach);
 E boolean FDECL(can_saddle, (struct monst *));
 E int FDECL(use_saddle, (struct obj *));
 E boolean FDECL(can_ride, (struct monst *));
@@ -1868,10 +1899,11 @@
 
 /* ### teleport.c ### */
 
-E boolean FDECL(goodpos, (int,int,struct monst *));
+E boolean FDECL(goodpos, (int,int,struct monst *,unsigned));
 E boolean FDECL(enexto, (coord *,XCHAR_P,XCHAR_P,struct permonst *));
-E void FDECL(teleds, (int,int));
-E boolean NDECL(safe_teleds);
+E boolean FDECL(enexto_core, (coord *,XCHAR_P,XCHAR_P,struct permonst *,unsigned));
+E void FDECL(teleds, (int,int,BOOLEAN_P));
+E boolean FDECL(safe_teleds, (BOOLEAN_P));
 E boolean FDECL(teleport_pet, (struct monst *,BOOLEAN_P));
 E void NDECL(tele);
 E int NDECL(dotele);
@@ -1978,6 +2010,7 @@
 
 E void FDECL(hurtmarmor,(struct monst *,int));
 E boolean FDECL(attack_checks, (struct monst *,struct obj *));
+E void FDECL(check_caitiff, (struct monst *));
 E schar FDECL(find_roll_to_hit, (struct monst *));
 E boolean FDECL(attack, (struct monst *));
 E boolean FDECL(hmon, (struct monst *,struct obj *,int));
@@ -2051,6 +2084,9 @@
 				const char *,BOOLEAN_P));
 E unsigned long FDECL(get_feature_notice_ver, (char *));
 E unsigned long NDECL(get_current_feature_ver);
+#ifdef RUNTIME_PORT_ID
+E void FDECL(append_port_id, (char *));
+#endif
 
 /* ### video.c ### */
 
@@ -2163,7 +2199,7 @@
 E int FDECL(dmgval, (struct obj *,struct monst *));
 E struct obj *FDECL(select_rwep, (struct monst *));
 E struct obj *FDECL(select_hwep, (struct monst *));
-E void FDECL(possibly_unwield, (struct monst *));
+E void FDECL(possibly_unwield, (struct monst *,BOOLEAN_P));
 E int FDECL(mon_wield_item, (struct monst *));
 E int NDECL(abon);
 E int NDECL(dbon);
@@ -2176,7 +2212,7 @@
 E int NDECL(uwep_skill_type);
 E int FDECL(weapon_hit_bonus, (struct obj *));
 E int FDECL(weapon_dam_bonus, (struct obj *));
-E void FDECL(skill_init, (struct def_skill *));
+E void FDECL(skill_init, (const struct def_skill *));
 
 /* ### were.c ### */
 
@@ -2194,12 +2230,14 @@
 E int NDECL(dowield);
 E int NDECL(doswapweapon);
 E int NDECL(dowieldquiver);
-E int NDECL(dotwoweapon);
+E boolean FDECL(wield_tool, (struct obj *,const char *));
 E int NDECL(can_twoweapon);
-E void NDECL(untwoweapon);
+E void NDECL(drop_uswapwep);
+E int NDECL(dotwoweapon);
 E void NDECL(uwepgone);
 E void NDECL(uswapwepgone);
 E void NDECL(uqwepgone);
+E void NDECL(untwoweapon);
 E void FDECL(erode_obj, (struct obj *,BOOLEAN_P,BOOLEAN_P));
 E int FDECL(chwepon, (struct obj *,int));
 E int FDECL(welded, (struct obj *));
@@ -2251,13 +2289,15 @@
 E void FDECL(setnotworn, (struct obj *));
 E void FDECL(mon_set_minvis, (struct monst *));
 E void FDECL(mon_adjust_speed, (struct monst *,int,struct obj *));
-E void FDECL(update_mon_intrinsics, (struct monst *,struct obj *,BOOLEAN_P));
+E void FDECL(update_mon_intrinsics,
+		(struct monst *,struct obj *,BOOLEAN_P,BOOLEAN_P));
 E int FDECL(find_mac, (struct monst *));
 E void FDECL(m_dowear, (struct monst *,BOOLEAN_P));
 E struct obj *FDECL(which_armor, (struct monst *,long));
 E void FDECL(mon_break_armor, (struct monst *,BOOLEAN_P));
 E void FDECL(bypass_obj, (struct obj *));
 E void NDECL(clear_bypasses);
+E int FDECL(racial_exception, (struct monst *, struct obj *));
 
 /* ### write.c ### */
 
@@ -2285,8 +2325,8 @@
 E void FDECL(zapnodir, (struct obj *));
 E int NDECL(dozap);
 E int FDECL(zapyourself, (struct obj *,BOOLEAN_P));
-E void FDECL(cancel_monst, (struct monst *,struct obj *,
-			    BOOLEAN_P,BOOLEAN_P,BOOLEAN_P));
+E boolean FDECL(cancel_monst, (struct monst *,struct obj *,
+			       BOOLEAN_P,BOOLEAN_P,BOOLEAN_P));
 E void FDECL(weffects, (struct obj *));
 E int NDECL(spell_damage_bonus);
 E const char *FDECL(exclam, (int force));
diff -Naurd ../nethack-3.4.0/include/flag.h ./include/flag.h
--- ../nethack-3.4.0/include/flag.h Wed Mar 20 23:42:46 2002
+++ ./include/flag.h Mon Feb 24 15:25:05 2003
@@ -165,6 +165,8 @@
 	boolean  window_inited; /* true if init_nhwindows() completed */
 	boolean  vision_inited; /* true if vision is ready */
 	boolean  menu_tab_sep;	/* Use tabs to separate option menu fields */
+	boolean  menu_requested; /* Flag for overloaded use of 'm' prefix
+				  * on some non-move commands */
 	int      purge_monsters;	/* # of dead monsters still on fmon list */
 	int *opt_booldup;	/* for duplication of boolean opts in config file */
 	int *opt_compdup;	/* for duplication of compound opts in config file */
@@ -174,7 +176,7 @@
 	boolean  mon_polycontrol;	/* debug: control monster polymorphs */
 #endif
 #ifdef TTY_GRAPHICS
-	boolean prevmsg_window;	/* show more old messages at a time */
+	char prevmsg_window;	/* type of old message window to use */
 	boolean  extmenu;	/* extended commands use menu interface */
 #endif
 #ifdef MFLOPPY
@@ -241,6 +243,7 @@
 	int     wc_fontsiz_status;	/* font size for the status window     */
 	int     wc_fontsiz_menu;	/* font size for the menu window       */
 	int     wc_fontsiz_text;	/* font size for text windows          */
+	int	wc_scroll_amount;	/* scroll this amount at scroll_margin */
 	int	wc_scroll_margin;	/* scroll map when this far from
 						the edge */
 	int	wc_map_mode;		/* specify map viewing options, mostly
@@ -249,9 +252,16 @@
 	boolean	wc_splash_screen;	/* display an opening splash screen or not */
 	boolean	wc_popup_dialog;	/* put queries in pop up dialogs instead of
 				   		in the message window */
-	boolean wc_large_font;		/* draw in larger fonts (say, 12pt instead
-				   		of 9pt) */
 	boolean wc_eight_bit_input;	/* allow eight bit input               */
+	boolean wc_mouse_support;	/* allow mouse support */
+
+	boolean  cmdassist;	/* provide detailed assistance for some commands */
+	boolean	 obsolete;	/* obsolete options can point at this, it isn't used */
+	/* Items which belong in flags, but are here to allow save compatibility */
+	boolean  lootabc;	/* use "a/b/c" rather than "o/i/b" when looting */
+	boolean  showrace;	/* show hero glyph by race rather than by role */
+	boolean  travelcmd;	/* allow travel command */
+	int	 runmode;	/* update screen display during run moves */
 };
 
 /*
@@ -266,7 +276,7 @@
 #define hilite_pet wc_hilite_pet
 #define use_inverse wc_inverse
 #ifdef MAC_GRAPHICS_ENV
-#define large_font wc_large_font
+#define large_font obsolete
 #endif
 #ifdef MAC
 #define popup_dialog wc_popup_dialog
@@ -276,4 +286,10 @@
 extern NEARDATA struct flag flags;
 extern NEARDATA struct instance_flags iflags;
 
+/* runmode options */
+#define RUN_TPORT	0	/* don't update display until movement stops */
+#define RUN_LEAP	1	/* update display every 7 steps */
+#define RUN_STEP	2	/* update display every single step */
+#define RUN_CRAWL	3	/* walk w/ extra delay after each update */
+
 #endif /* FLAG_H */
diff -Naurd ../nethack-3.4.0/include/global.h ./include/global.h
--- ../nethack-3.4.0/include/global.h Wed Mar 20 23:42:47 2002
+++ ./include/global.h Mon Feb 24 15:25:05 2003
@@ -333,7 +339,7 @@
 
 #define MAXULEV		30	/* max character experience level */
 
-#define MAXMONNO	120	/* geno monst after this number killed */
+#define MAXMONNO	120	/* extinct monst after this number created */
 #define MHPMAX		500	/* maximum monster hp */
 
 #endif /* GLOBAL_H */
diff -Naurd ../nethack-3.4.0/include/hack.h ./include/hack.h
--- ../nethack-3.4.0/include/hack.h Wed Mar 20 23:42:47 2002
+++ ./include/hack.h Mon Feb 24 15:25:05 2003
@@ -24,11 +24,11 @@
 
 /* symbolic names for capacity levels */
 #define UNENCUMBERED	0
-#define SLT_ENCUMBER	1
-#define MOD_ENCUMBER	2
-#define HVY_ENCUMBER	3
-#define EXT_ENCUMBER	4
-#define OVERLOADED	5
+#define SLT_ENCUMBER	1	/* Burdened */
+#define MOD_ENCUMBER	2	/* Stressed */
+#define HVY_ENCUMBER	3	/* Strained */
+#define EXT_ENCUMBER	4	/* Overtaxed */
+#define OVERLOADED	5	/* Overloaded */
 
 /* Macros for how a rumor was delivered in outrumor() */
 #define BY_ORACLE	0
@@ -139,6 +139,7 @@
 #define MM_ANGRY	  0x10  /* monster is created angry */
 #define MM_NONAME	  0x20  /* monster is not christened */
 #define MM_NOCOUNTBIRTH	  0x40  /* don't increment born counter (for revival) */
+#define MM_IGNOREWATER	  0x80	/* ignore water when positioning */
 
 /* flags for special ggetobj status returns */
 #define ALL_FINISHED	  0x01  /* called routine already finished the job */
@@ -178,6 +179,11 @@
 /* Flags to control dotrap() in trap.c */
 #define NOWEBMSG	0x01	/* suppress stumble into web message */
 
+/* Flags to control test_move in hack.c */
+#define DO_MOVE		0	/* really doing the move */
+#define TEST_MOVE	1	/* test a normal move (move there next) */
+#define TEST_TRAV	2	/* test a future travel location */
+
 /*** some utility macros ***/
 #define yn(query) yn_function(query,ynchars, 'n')
 #define ynq(query) yn_function(query,ynqchars, 'q')
@@ -195,8 +201,9 @@
 #define MAY_FRACTURE	0x10	/* boulders & statues may fracture */
 
 /* Macros for launching objects */
-#define ROLL	1
-#define FLING	2
+#define ROLL		0x01	/* the object is rolling */
+#define FLING		0x02	/* the object is flying thru the air */
+#define LAUNCH_KNOWN	0x80	/* the hero caused this by explicit action */
 
 /* Macros for explosion types */
 #define EXPL_DARK	0
diff -Naurd ../nethack-3.4.0/include/mfndpos.h ./include/mfndpos.h
--- ../nethack-3.4.0/include/mfndpos.h Wed Mar 20 23:42:49 2002
+++ ./include/mfndpos.h Mon Feb 24 15:25:05 2003
@@ -17,6 +17,7 @@
 #define ALLOW_ROCK	0x02000000L	/* pushes rocks */
 #define ALLOW_WALL	0x04000000L	/* walks thru walls */
 #define ALLOW_DIG	0x08000000L	/* digs */
+#define ALLOW_BARS	0x10000000L	/* may pass thru iron bars */
 #define ALLOW_SANCT	0x20000000L	/* enters temples */
 #define ALLOW_SSM	0x40000000L	/* ignores scare monster */
 #ifdef NHSTDC
diff -Naurd ../nethack-3.4.0/include/mkroom.h ./include/mkroom.h
--- ../nethack-3.4.0/include/mkroom.h Wed Mar 20 23:42:49 2002
+++ ./include/mkroom.h Mon Feb 24 15:25:05 2003
@@ -31,7 +31,7 @@
 	    int iprob;		/* probability of an item type */
 	    int itype;	/* item type: if >=0 a class, if < 0 a specific item */
 	} iprobs[5];
-	const char **shknms;	/* list of shopkeeper names for this type */
+	const char * const *shknms;	/* list of shopkeeper names for this type */
 };
 
 extern NEARDATA struct mkroom rooms[(MAXNROFROOMS+1)*2];
diff -Naurd ../nethack-3.4.0/include/monattk.h ./include/monattk.h
--- ../nethack-3.4.0/include/monattk.h Wed Mar 20 23:42:49 2002
+++ ./include/monattk.h Mon Feb 24 15:25:05 2003
@@ -8,6 +8,7 @@
 /*	Add new attack types below - ordering affects experience (exper.c).
  *	Attacks > AT_BUTT are worth extra experience.
  */
+#define AT_ANY		(-1)	/* fake attack; dmgtype_fromattack wildcard */
 #define AT_NONE		0	/* passive monster (ex. acid blob) */
 #define AT_CLAW		1	/* claw (punch, hit, etc.) */
 #define AT_BITE		2	/* bite */
@@ -32,6 +33,7 @@
  *	Note that 1-10 correspond to the types of attack used in buzz().
  *	Please don't disturb the order unless you rewrite the buzz() code.
  */
+#define AD_ANY		(-1)	/* fake damage; attacktype_fordmg wildcard */
 #define AD_PHYS		0	/* ordinary physical */
 #define AD_MAGM		1	/* magic missiles */
 #define AD_FIRE		2	/* fire damage */
diff -Naurd ../nethack-3.4.0/include/mondata.h ./include/mondata.h
--- ../nethack-3.4.0/include/mondata.h Wed Mar 20 23:42:49 2002
+++ ./include/mondata.h Mon Feb 24 15:25:05 2003
@@ -19,6 +19,11 @@
 #define resists_acid(mon)	(((mon)->mintrinsics & MR_ACID) != 0)
 #define resists_ston(mon)	(((mon)->mintrinsics & MR_STONE) != 0)
 
+#define is_lminion(mon)		(is_minion((mon)->data) && \
+				 (mon)->data->maligntyp >= A_COALIGNED && \
+				 ((mon)->data != &mons[PM_ANGEL] || \
+				  EPRI(mon)->shralign > 0))
+
 #define is_flyer(ptr)		(((ptr)->mflags1 & M1_FLY) != 0L)
 #define is_floater(ptr)		((ptr)->mlet == S_EYE)
 #define is_clinger(ptr)		(((ptr)->mflags1 & M1_CLING) != 0L)
@@ -40,6 +45,7 @@
 #define nolimbs(ptr)		(((ptr)->mflags1 & M1_NOLIMBS) == M1_NOLIMBS)
 #define notake(ptr)		(((ptr)->mflags1 & M1_NOTAKE) != 0L)
 #define has_head(ptr)		(((ptr)->mflags1 & M1_NOHEAD) == 0L)
+#define has_horns(ptr)		(num_horns(ptr) > 0)
 #define is_whirly(ptr)		((ptr)->mlet == S_VORTEX || \
 				 (ptr) == &mons[PM_AIR_ELEMENTAL])
 #define is_silent(ptr)		((ptr)->msound == MS_SILENT)
@@ -105,8 +111,6 @@
 #define is_dlord(ptr)		(is_demon(ptr) && is_lord(ptr))
 #define is_dprince(ptr)		(is_demon(ptr) && is_prince(ptr))
 #define is_minion(ptr)		((ptr)->mflags2 & M2_MINION)
-#define is_lminion(ptr)		(is_minion(ptr) && \
-				 (ptr)->maligntyp >= A_COALIGNED)
 #define likes_gold(ptr)		(((ptr)->mflags2 & M2_GREEDY) != 0L)
 #define likes_gems(ptr)		(((ptr)->mflags2 & M2_JEWELS) != 0L)
 #define likes_objs(ptr)		(((ptr)->mflags2 & M2_COLLECT) != 0L || \
diff -Naurd ../nethack-3.4.0/include/monst.h ./include/monst.h
--- ../nethack-3.4.0/include/monst.h Wed Mar 20 23:42:50 2002
+++ ./include/monst.h Mon Feb 24 15:25:05 2003
@@ -6,7 +6,7 @@
 #define MONST_H
 
 /* The weapon_check flag is used two ways:
- * 1) When calling mon_wield_item, is 2, 3, or 4 depending on what is desired.
+ * 1) When calling mon_wield_item, is 2-6 depending on what is desired.
  * 2) Between calls to mon_wield_item, is 0 or 1 depending on whether or not
  *    the weapon is known by the monster to be cursed (so it shouldn't bother
  *    trying for another weapon).
@@ -20,6 +20,8 @@
 # define NEED_RANGED_WEAPON 2
 # define NEED_HTH_WEAPON 3
 # define NEED_PICK_AXE 4
+# define NEED_AXE 5
+# define NEED_PICK_OR_AXE 6
 
 /* The following flags are used for the second argument to display_minventory
  * in invent.c:
@@ -98,7 +100,7 @@
 	Bitfield(mstun,1);	/* stunned (off balance) */
 	Bitfield(mconf,1);	/* confused */
 	Bitfield(mpeaceful,1);	/* does not attack unprovoked */
-	Bitfield(mtrapped,1);	/* trapped in a pit or bear trap */
+	Bitfield(mtrapped,1);	/* trapped in a pit, web or bear trap */
 	Bitfield(mleashed,1);	/* monster is on a leash */
 	Bitfield(isshk,1);	/* is shopkeeper */
 	Bitfield(isminion,1);	/* is a minion */
diff -Naurd ../nethack-3.4.0/include/obj.h ./include/obj.h
--- ../nethack-3.4.0/include/obj.h Wed Mar 20 23:42:51 2002
+++ ./include/obj.h Mon Feb 24 15:25:05 2003
@@ -70,6 +70,7 @@
 	Bitfield(olocked,1);	/* object is locked */
 	Bitfield(obroken,1);	/* lock has been broken */
 	Bitfield(otrapped,1);	/* container is trapped */
+				/* or accidental tripped rolling boulder trap */
 #define opoisoned otrapped	/* object (weapon) is coated with poison */
 
 	Bitfield(recharged,3);	/* number of times it's been recharged */
@@ -179,7 +180,24 @@
 			 objects[otmp->otyp].oc_armcat == ARM_SHIRT)
 #define is_suit(otmp)	(otmp->oclass == ARMOR_CLASS && \
 			 objects[otmp->otyp].oc_armcat == ARM_SUIT)
+#define is_elven_armor(otmp)	((otmp)->otyp == ELVEN_LEATHER_HELM\
+				|| (otmp)->otyp == ELVEN_MITHRIL_COAT\
+				|| (otmp)->otyp == ELVEN_CLOAK\
+				|| (otmp)->otyp == ELVEN_SHIELD\
+				|| (otmp)->otyp == ELVEN_BOOTS)
+#define is_orcish_armor(otmp)	((otmp)->otyp == ORCISH_HELM\
+				|| (otmp)->otyp == ORCISH_CHAIN_MAIL\
+				|| (otmp)->otyp == ORCISH_RING_MAIL\
+				|| (otmp)->otyp == ORCISH_CLOAK\
+				|| (otmp)->otyp == URUK_HAI_SHIELD\
+				|| (otmp)->otyp == ORCISH_SHIELD)
+#define is_dwarvish_armor(otmp)	((otmp)->otyp == DWARVISH_IRON_HELM\
+				|| (otmp)->otyp == DWARVISH_MITHRIL_COAT\
+				|| (otmp)->otyp == DWARVISH_CLOAK\
+				|| (otmp)->otyp == DWARVISH_ROUNDSHIELD)
+#define is_gnomish_armor(otmp)	(FALSE)
 
+				
 /* Eggs and other food */
 #define MAX_EGG_HATCH_TIME 200	/* longest an egg can remain unhatched */
 #define stale_egg(egg)	((monstermoves - (egg)->age) > (2*MAX_EGG_HATCH_TIME))
@@ -211,6 +229,32 @@
 				      - GRAY_DRAGON_SCALE_MAIL]
 #define Dragon_to_scales(pm)	(GRAY_DRAGON_SCALES + (pm - mons))
 
+/* Elven gear */
+#define is_elven_weapon(otmp)	((otmp)->otyp == ELVEN_ARROW\
+				|| (otmp)->otyp == ELVEN_SPEAR\
+				|| (otmp)->otyp == ELVEN_DAGGER\
+				|| (otmp)->otyp == ELVEN_SHORT_SWORD\
+				|| (otmp)->otyp == ELVEN_BROADSWORD\
+				|| (otmp)->otyp == ELVEN_BOW)
+#define is_elven_obj(otmp)	(is_elven_armor(otmp) || is_elven_weapon(otmp))
+
+/* Orcish gear */
+#define is_orcish_obj(otmp)	(is_orcish_armor(otmp)\
+				|| (otmp)->otyp == ORCISH_ARROW\
+				|| (otmp)->otyp == ORCISH_SPEAR\
+				|| (otmp)->otyp == ORCISH_DAGGER\
+				|| (otmp)->otyp == ORCISH_SHORT_SWORD\
+				|| (otmp)->otyp == ORCISH_BOW)
+
+/* Dwarvish gear */
+#define is_dwarvish_obj(otmp)	(is_dwarvish_armor(otmp)\
+				|| (otmp)->otyp == DWARVISH_SPEAR\
+				|| (otmp)->otyp == DWARVISH_SHORT_SWORD\
+				|| (otmp)->otyp == DWARVISH_MATTOCK)
+
+/* Gnomish gear */
+#define is_gnomish_obj(otmp)	(is_gnomish_armor(otmp))
+
 /* Light sources */
 #define Is_candle(otmp) (otmp->otyp == TALLOW_CANDLE || \
 			 otmp->otyp == WAX_CANDLE)
diff -Naurd ../nethack-3.4.0/include/objclass.h ./include/objclass.h
--- ../nethack-3.4.0/include/objclass.h Wed Mar 20 23:42:51 2002
+++ ./include/objclass.h Mon Feb 24 15:25:05 2003
@@ -133,7 +133,7 @@
 #define SCROLL_CLASS	 9
 #define SPBOOK_CLASS	10	/* actually SPELL-book */
 #define WAND_CLASS	11
-#define GOLD_CLASS	12
+#define COIN_CLASS	12
 #define GEM_CLASS	13
 #define ROCK_CLASS	14
 #define BALL_CLASS	15
diff -Naurd ../nethack-3.4.0/include/pcconf.h ./include/pcconf.h
--- ../nethack-3.4.0/include/pcconf.h Wed Mar 20 23:42:51 2002
+++ ./include/pcconf.h Mon Feb 24 15:25:05 2003
@@ -17,7 +17,7 @@
  *     _MSC_VER is defined automatically by Microsoft C.
  *     __BORLANDC__ is defined automatically by Borland C.
  *     __SC__ is defined automatically by Symantec C.
- *	Note: 3.4.0 was not verified with Symantec C.
+ *	Note: 3.4.1 was not verified with Symantec C.
  */
 
 /*
@@ -99,10 +99,6 @@
 			/* amiconf.h).	In the future this will be the */
 			/* hook for mail reader implementation.        */
 
-/*# define PC_LOCKING */	/* Allow confirmation before overwriting game  */
-			/* that is in progress or aborted when another */
-			/* game is started with the same player name.  */
-
 /* The following is needed for prototypes of certain functions */
 
 #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__SC__)
@@ -141,7 +137,7 @@
 # endif
 #define NOCWD_ASSUMPTIONS	/* Allow paths to be specified for HACKDIR,
 				   LEVELDIR, SAVEDIR, BONESDIR, DATADIR,
-				   SCOREDIR, LOCKDIR, and CONFIGDIR */
+				   SCOREDIR, LOCKDIR, CONFIGDIR, and TROUBLEDIR. */
 
 #endif /* MSDOS configuration stuff */
 
@@ -160,12 +156,16 @@
 #include "system.h"
 #endif
 
-#ifdef __GO32__
+#ifdef __DJGPP__
 #include <unistd.h> /* close(), etc. */
-/* setmode is in io.h but lock() in io.h interferes with lock[] in decl.h */
-extern int FDECL(setmode, (int,int));
+/* lock() in io.h interferes with lock[] in decl.h */
+#define lock djlock
+#include <io.h>
+#undef lock
 #include <pc.h> /* kbhit() */
 #define PC_LOCKING
+#define HOLD_LOCKFILE_OPEN
+#define SELF_RECOVER		/* NetHack itself can recover games */
 #endif
 
 # ifdef MSDOS
diff -Naurd ../nethack-3.4.0/include/qtext.h ./include/qtext.h
--- ../nethack-3.4.0/include/qtext.h Wed Mar 20 23:42:52 2002
+++ ./include/qtext.h Mon Feb 24 15:25:05 2003
@@ -35,6 +35,7 @@
 #define CREC_IN_MSG	"Control record encountered during message - line %d\n"
 #define DUP_MSG		"Duplicate message number at line %d\n"
 #define END_NOT_IN_MSG	"End record encountered before message - line %d\n"
+#define TEXT_NOT_IN_MSG	"Text encountered outside message - line %d\n"
 #define UNREC_CREC	"Unrecognized Control record at line %d\n"
 #define OUT_OF_HEADERS	"Too many message types (line %d)\nAdjust N_HDR in qtext.h and recompile.\n"
 #define OUT_OF_MESSAGES "Too many messages in class (line %d)\nAdjust N_MSG in qtext.h and recompile.\n"
@@ -105,6 +106,7 @@
 #define QT_DEMONIC	30
 #define QTN_DEMONIC	20
 
+#define QT_BANISHED	60
 #endif	/***** !MAKEDEFS *****/
 
 #endif /* QTEXT_H */
diff -Naurd ../nethack-3.4.0/include/region.h ./include/region.h
--- ../nethack-3.4.0/include/region.h Wed Mar 20 23:42:54 2002
+++ ./include/region.h Mon Feb 24 15:25:05 2003
@@ -9,6 +9,27 @@
 
 typedef boolean FDECL((*callback_proc), (genericptr_t, genericptr_t));
 
+/*
+ * Overload the old player_inside field with two values, coded in such
+ * a way as to retain compatibility with 3.4.0 save and bones files;
+ * this relies on the fact that nethack's `boolean' is really stored
+ * in a `char' (or bigger type) rather than in a single bit.
+ *
+ * 3.4.1 save and bones files will be correct.
+ * 3.4.0 save files restored under 3.4.1 will be correct.
+ * 3.4.0 bones files used with 3.4.1 will continue to have the minor
+ *	 3.4.0 bug of falsely claiming that the current game's hero is
+ *	 responsible for the dead former hero's stinking clouds.
+ */
+#define REG_HERO_INSIDE	1
+#define REG_NOT_HEROS	2
+#define hero_inside(r)	((unsigned)(r)->player_flags & REG_HERO_INSIDE)
+#define heros_fault(r)	(!((unsigned)(r)->player_flags & REG_NOT_HEROS))
+#define set_hero_inside(r)	((r)->player_flags |= REG_HERO_INSIDE)
+#define clear_hero_inside(r)	((r)->player_flags &= ~REG_HERO_INSIDE)
+#define set_heros_fault(r)	((r)->player_flags &= ~REG_NOT_HEROS)
+#define clear_heros_fault(r)	((r)->player_flags |= REG_NOT_HEROS)
+
 typedef struct {
   NhRect bounding_box;		/* Bounding box of the region */
   NhRect *rects;		/* Rectangles composing the region */
@@ -28,7 +49,7 @@
   short leave_f;		/* Function to call when the player leaves */
   short inside_f;		/* Function to call every turn if player's
 				   inside */
-  boolean player_inside;	/* Is the player inside this region */
+  boolean player_flags;	/* (see above) */
   unsigned int* monsters;	/* Monsters currently inside this region */
   short n_monst;		/* Number of monsters inside this region */
   short max_monst;		/* Maximum number of monsters that can be
diff -Naurd ../nethack-3.4.0/include/rm.h ./include/rm.h
--- ../nethack-3.4.0/include/rm.h Wed Mar 20 23:42:54 2002
+++ ./include/rm.h Mon Feb 24 15:25:05 2003
@@ -267,6 +267,12 @@
  */
 #define F_LOOTED	1
 #define F_WARNED	2
+#define FOUNTAIN_IS_WARNED(x,y)		(levl[x][y].looted & F_WARNED)
+#define FOUNTAIN_IS_LOOTED(x,y)		(levl[x][y].looted & F_LOOTED)
+#define SET_FOUNTAIN_WARNED(x,y)	levl[x][y].looted |= F_WARNED;
+#define SET_FOUNTAIN_LOOTED(x,y)	levl[x][y].looted |= F_LOOTED;
+#define CLEAR_FOUNTAIN_WARNED(x,y)	levl[x][y].looted &= ~F_WARNED;
+#define CLEAR_FOUNTAIN_LOOTED(x,y)	levl[x][y].looted &= ~F_LOOTED;
 
 /*
  * Doors are even worse :-) The special warning has a side effect
diff -Naurd ../nethack-3.4.0/include/wceconf.h ./include/wceconf.h
--- ../nethack-3.4.0/include/wceconf.h Thu Jan 1 01:00:00 1970
+++ ./include/wceconf.h Mon Feb 24 15:25:05 2003
@@ -0,0 +1,319 @@
+/* Copyright (C) 2001 by Alex Kompel <shurikk@pacbell.net> */
+/* Copyright (c) NetHack PC Development Team 1993, 1994.  */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef WCECONF_H
+#define WCECONF_H
+
+#pragma warning(disable:4142) /* benign redefinition of type */
+
+#define WIN32_LEAN_AND_MEAN		// Exclude rarely-used stuff from Windows headers
+
+#include <windows.h>
+
+/* Detect the targe device */
+#if defined(WIN32_PLATFORM_PSPC) 
+#	if _WIN32_WCE >= 300
+#		define WIN_CE_POCKETPC
+#	else
+#		define WIN_CE_PS2xx
+#	endif
+#elif defined(WIN32_PLATFORM_HPCPRO)
+#	define WIN_CE_HPCPRO
+#elif defined(WIN32_PLATFORM_WFSP)
+#	define WIN_CE_SMARTPHONE
+#else
+#	error "Unsupported Windows CE platform"
+#endif
+
+/* #define SHELL	/* nt use of pcsys routines caused a hang */
+
+#define RANDOM		/* have Berkeley random(3) */
+#define TEXTCOLOR	/* Color text */
+
+#define EXEPATH			/* Allow .exe location to be used as HACKDIR */
+#define TRADITIONAL_GLYPHMAP	/* Store glyph mappings at level change time */
+
+#define PC_LOCKING		/* Prevent overwrites of aborted or in-progress games */
+				/* without first receiving confirmation. */
+
+#define SELF_RECOVER		/* Allow the game itself to recover from an aborted game */
+
+#define NOTSTDC		/* no strerror() */
+
+#define USER_SOUNDS
+
+/*
+ * -----------------------------------------------------------------
+ *  The remaining code shouldn't need modification.
+ * -----------------------------------------------------------------
+ */
+/* #define SHORT_FILENAMES	/* All NT filesystems support long names now */
+
+#ifdef MICRO
+#undef MICRO			/* never define this! */
+#endif
+
+#define NOCWD_ASSUMPTIONS	/* Always define this. There are assumptions that
+                                   it is defined for WIN32.
+				   Allow paths to be specified for HACKDIR,
+				   LEVELDIR, SAVEDIR, BONESDIR, DATADIR,
+				   SCOREDIR, LOCKDIR, CONFIGDIR, and TROUBLEDIR */
+#define NO_TERMS
+#define ASCIIGRAPH
+
+#ifdef OPTIONS_USED
+#undef OPTIONS_USED
+#endif
+#ifdef MSWIN_GRAPHICS
+#define OPTIONS_USED	"guioptions"
+#else
+#define OPTIONS_USED	"ttyoptions"
+#endif
+#define OPTIONS_FILE OPTIONS_USED
+
+#define PORT_HELP	"porthelp"
+
+#if defined(WIN_CE_POCKETPC)
+#	define PORT_CE_PLATFORM "Pocket PC"
+#elif defined(WIN_CE_PS2xx)
+#	define PORT_CE_PLATFORM "Palm-size PC 2.11"
+#elif defined(WIN_CE_HPCPRO)
+#	define PORT_CE_PLATFORM "H/PC Pro 2.11"
+#elif defined(WIN_CE_SMARTPHONE)
+#	define PORT_CE_PLATFORM "Smartphone 2002"
+#endif
+
+#if defined(ARM)
+#	define PORT_CE_CPU "ARM"
+#elif defined(PPC)
+#	define PORT_CE_CPU "PPC"
+#elif defined(ALPHA)
+#	define PORT_CE_CPU "ALPHA"
+#elif defined(SH3)
+#	define PORT_CE_CPU "SH3"
+#elif defined(SH4)
+#	define PORT_CE_CPU "SH4"
+#elif defined(MIPS)
+#	define PORT_CE_CPU "MIPS"
+#elif defined(X86) || defined(_X86_)
+#	define PORT_CE_CPU "X86"
+#else
+#	error Only ARM, PPC, ALPHA, SH3, SH4, MIPS and X86 supported
+#endif
+
+#define RUNTIME_PORT_ID	/* trigger run-time port identification since
+			   Makedefs is bootstrapped on a cross-platform. */
+
+#include <string.h>	/* Provides prototypes of strncmpi(), etc.     */
+#ifdef STRNCMPI
+#define strncmpi(a,b,c) _strnicmp(a,b,c)
+#endif
+
+#ifdef STRCMPI
+#define strcmpi(a,b) _stricmp(a,b)
+#define stricmp(a,b) _stricmp(a,b)
+#endif
+
+#include <stdlib.h>
+
+#define PATHLEN		BUFSZ /* maximum pathlength */
+#define FILENAME	BUFSZ /* maximum filename length (conservative) */
+
+#if defined(_MAX_PATH) && defined(_MAX_FNAME)
+# if (_MAX_PATH < BUFSZ) && (_MAX_FNAME < BUFSZ)
+#undef PATHLEN
+#undef FILENAME
+#define PATHLEN		_MAX_PATH
+#define FILENAME	_MAX_FNAME
+# endif
+#endif
+
+
+#define NO_SIGNAL
+#define index	strchr
+#define rindex	strrchr
+#define USE_STDARG
+#ifdef RANDOM
+/* Use the high quality random number routines. */
+#define Rand()	random()
+#else
+#define Rand()	rand()
+#endif
+
+#define FCMASK	0660	/* file creation mask */
+#define regularize	nt_regularize
+#define HLOCK "NHPERM"
+
+#ifndef M
+#define M(c)		((char) (0x80 | (c)))
+/* #define M(c)		((c) - 128) */
+#endif
+
+#ifndef C
+#define C(c)		(0x1f & (c))
+#endif
+
+#if defined(DLB)
+#define FILENAME_CMP  _stricmp		      /* case insensitive */
+#endif
+
+#if 0
+extern char levels[], bones[], permbones[],
+#endif /* 0 */
+
+/* this was part of the MICRO stuff in the past */
+extern const char *alllevels, *allbones;
+extern char hackdir[];
+#define ABORT C('a')
+#define getuid() 1
+#define getlogin() ((char *)0)
+extern void NDECL(win32_abort);
+#ifdef WIN32CON
+extern void FDECL(nttty_preference_update, (const char *));
+extern void NDECL(toggle_mouse_support);
+#endif
+
+#ifndef alloca
+#define ALLOCA_HACK	/* used in util/panic.c */
+#endif
+
+#ifndef REDO
+#undef	Getchar
+#define Getchar nhgetch
+#endif
+
+#ifdef _MSC_VER
+#if 0
+#pragma warning(disable:4018)	/* signed/unsigned mismatch */
+#pragma warning(disable:4305)	/* init, conv from 'const int' to 'char' */
+#endif
+#pragma warning(disable:4761)	/* integral size mismatch in arg; conv supp*/
+#ifdef YYPREFIX
+#pragma warning(disable:4102)	/* unreferenced label */
+#endif
+#endif
+
+/* UNICODE stuff */
+#define NHSTR_BUFSIZE	255
+#ifdef UNICODE
+	#define NH_W2A(w, a, cb)     ( WideCharToMultiByte(                              \
+												   CP_ACP,                      \
+												   0,                           \
+												   (w),                           \
+												   -1,                          \
+												   (a),                           \
+												   (cb),                          \
+												   NULL,                        \
+												   NULL), (a) )
+
+	#define NH_A2W(a, w, cb)     ( MultiByteToWideChar(                              \
+												   CP_ACP,                      \
+												   0,                           \
+												   (a),                           \
+												   -1,                          \
+												   (w),                           \
+												   (cb)), (w) )
+#else
+	#define NH_W2A(w, a, cb)     (strncpy((a), (w), (cb)))
+
+	#define NH_A2W(a, w, cb)     (strncpy((w), (a), (cb)))
+#endif
+
+extern int FDECL(set_win32_option, (const char *, const char *));
+
+/* Missing definitions */
+extern int		mswin_have_input();
+#define kbhit	mswin_have_input
+
+#define getenv(a) ((char*)NULL)
+
+/* __stdio.h__ */
+#define perror(a)
+#define freopen(a, b, c) fopen(a, b)
+extern int isatty(int);
+
+/* __time.h___ */
+#ifndef _TIME_T_DEFINED
+typedef __int64 time_t;        /* time value */
+#define _TIME_T_DEFINED     /* avoid multiple def's of time_t */
+#endif
+
+#ifndef _TM_DEFINED
+struct tm {
+        int tm_sec;     /* seconds after the minute - [0,59] */
+        int tm_min;     /* minutes after the hour - [0,59] */
+        int tm_hour;    /* hours since midnight - [0,23] */
+        int tm_mday;    /* day of the month - [1,31] */
+        int tm_mon;     /* months since January - [0,11] */
+        int tm_year;    /* years since 1900 */
+        int tm_wday;    /* days since Sunday - [0,6] */
+        int tm_yday;    /* days since January 1 - [0,365] */
+        int tm_isdst;   /* daylight savings time flag - - NOT IMPLEMENTED */
+        };
+#define _TM_DEFINED
+#endif
+
+struct tm * __cdecl localtime(const time_t *);
+time_t __cdecl time(time_t *);
+
+/* __stdio.h__ */
+#ifndef BUFSIZ
+#define BUFSIZ 255
+#endif
+
+#define rewind(stream) (void)fseek( stream, 0L, SEEK_SET )
+
+/* __io.h__ */
+typedef long off_t;
+
+int __cdecl close(int);
+int __cdecl creat(const char *, int);
+int __cdecl eof(int);
+long __cdecl lseek(int, long, int);
+int __cdecl open(const char *, int, ...);
+int __cdecl read(int, void *, unsigned int);
+int __cdecl unlink(const char *);
+int __cdecl write(int, const void *, unsigned int);
+int __cdecl rename(const char *, const char *);
+int __cdecl access(const char *, int);
+
+#ifdef DeleteFile
+#undef DeleteFile
+#endif
+#define DeleteFile(a) unlink(a)
+
+int chdir( const char *dirname );
+char *getcwd( char *buffer, int maxlen );
+
+/* __stdlib.h__ */
+#define abort()  (void)TerminateProcess(GetCurrentProcess(), 0)
+#ifndef strdup
+#define strdup _strdup
+#endif
+
+/* sys/stat.h */
+#define S_IWRITE  GENERIC_WRITE
+#define S_IREAD   GENERIC_READ
+
+
+/* CE 2.xx is missing even more stuff */
+#if defined(WIN_CE_PS2xx) || defined(WIN32_PLATFORM_HPCPRO)
+#define ZeroMemory(p, s)         memset((p), 0, (s))
+
+int __cdecl isupper(int c);
+int __cdecl isdigit(int c);
+int __cdecl isspace(int c);
+int __cdecl isprint(int c);
+
+char* __cdecl _strdup(const char* s);
+char* __cdecl strrchr( const char *string, int c );
+int   __cdecl _stricmp(const char* a, const char* b);
+#endif
+
+/* ARM - the processor; avoids conflict with ARM in hack.h */
+# ifdef ARM
+# undef ARM
+# endif
+
+#endif /* WCECONF_H */
diff -Naurd ../nethack-3.4.0/include/winprocs.h ./include/winprocs.h
--- ../nethack-3.4.0/include/winprocs.h Wed Mar 20 23:42:58 2002
+++ ./include/winprocs.h Mon Feb 24 15:25:05 2003
@@ -157,15 +157,16 @@
 #define WC_FONTSIZ_MENU	 0x100000L	/* 21 supports specification of mnu win font */
 #define WC_FONTSIZ_TEXT	 0x200000L	/* 22 supports specification of txt win font */
 #define WC_SCROLL_MARGIN 0x400000L	/* 23 supports setting scroll margin for map */
-#define WC_SPLASH_SCREEN 0x800000L	/* 24 supports setting scroll margin for map */
+#define WC_SPLASH_SCREEN 0x800000L	/* 24 supports display of splash screen      */
 #define WC_POPUP_DIALOG	 0x1000000L	/* 25 supports queries in pop dialogs        */
-#define WC_LARGE_FONT	 0x2000000L	/* 26 Port supports large font               */
+#define WC_SCROLL_AMOUNT 0x2000000L	/* 26 scroll this amount at scroll margin    */
 #define WC_EIGHT_BIT_IN	 0x4000000L	/* 27 8-bit character input                  */
 #define WC_PERM_INVENT	 0x8000000L	/* 28 8-bit character input                  */
 #define WC_MAP_MODE	 0x10000000L	/* 29 map_mode option                        */
 #define WC_WINDOWCOLORS  0x20000000L	/* 30 background color for message window    */
 #define WC_PLAYER_SELECTION  0x40000000L /* 31 background color for message window    */
-					/* 1 free bit */
+#define WC_MOUSE_SUPPORT 0x80000000L	/* 32 mouse support                          */
+					/* no free bits */
 
 #define ALIGN_LEFT	1
 #define ALIGN_RIGHT	2
@@ -201,7 +202,7 @@
 #endif
 
 struct wc_Opt {
-	char *wc_name;
+	const char *wc_name;
 	unsigned long wc_bit;
 };
 
diff -Naurd ../nethack-3.4.0/src/allmain.c ./src/allmain.c
--- ../nethack-3.4.0/src/allmain.c Wed Mar 20 23:42:59 2002
+++ ./src/allmain.c Mon Feb 24 15:25:05 2003
@@ -100,7 +100,7 @@
 
 		    /* calculate how much time passed. */
 #ifdef STEED
-		    if (u.usteed && flags.mv) {
+		    if (u.usteed && u.umoved) {
 			/* your speed doesn't augment steed's speed */
 			moveamt = mcalcmove(u.usteed);
 		    } else
@@ -221,21 +221,27 @@
 
 		    if(!u.uinvulnerable) {
 			if(Teleportation && !rn2(85)) {
-#ifdef REDO
 			    xchar old_ux = u.ux, old_uy = u.uy;
-#endif
 			    tele();
-#ifdef REDO
 			    if (u.ux != old_ux || u.uy != old_uy) {
+				if (!next_to_u()) {
+				    check_leash(old_ux, old_uy);
+				}
+#ifdef REDO
 				/* clear doagain keystrokes */
 				pushch(0);
 				savech(0);
-			    }
 #endif
+			    }
 			}
+			/* delayed change may not be valid anymore */
+			if ((change == 1 && !Polymorph) ||
+			    (change == 2 && u.ulycn == NON_PM))
+			    change = 0;
 			if(Polymorph && !rn2(100))
 			    change = 1;
-			else if (u.ulycn >= LOW_PM && !rn2(80 - (20 * night())))
+			else if (u.ulycn >= LOW_PM && !Upolyd &&
+				 !rn2(80 - (20 * night())))
 			    change = 2;
 			if (change && !Unchanging) {
 			    if (multi >= 0) {
@@ -278,10 +284,13 @@
 
 		    /* when immobile, count is in turns */
 		    if(multi < 0) {
-			if (++multi == 0)	/* finished yet? */
+			if (++multi == 0) {	/* finished yet? */
 			    unmul((char *)0);
+			    /* if unmul caused a level change, take it now */
+			    if (u.utotype) deferred_goto();
+			}
 		    }
-		}			
+		}
 	    } while (youmonst.movement<NORMAL_SPEED); /* hero can't move loop */
 
 	    /******************************************/
@@ -331,14 +340,14 @@
 #endif
 		occupation = 0;
 	    if(
-#ifdef MICRO
+#if defined(MICRO) || defined(WIN32)
 		   abort_lev ||
 #endif
 		   monster_nearby()) {
 		stop_occupation();
 		reset_eat();
 	    }
-#ifdef MICRO
+#if defined(MICRO) || defined(WIN32)
 	    if (!(++occtime % 7))
 		display_nhwindow(WIN_MAP, FALSE);
 #endif
@@ -403,8 +412,12 @@
 	    flags.botl = 1;
 
 	if (vision_full_recalc) vision_recalc(0);	/* vision! */
-	if (multi && multi%7 == 0)
+	/* when running in non-tport mode, this gets done through domove() */
+	if ((!flags.run || iflags.runmode == RUN_TPORT) &&
+		(multi && (!flags.travel ? !(multi % 7) : !(moves % 7L)))) {
+	    if (flags.time && flags.run) flags.botl = 1;
 	    display_nhwindow(WIN_MAP, FALSE);
+	}
     }
 }
 
diff -Naurd ../nethack-3.4.0/src/apply.c ./src/apply.c
--- ../nethack-3.4.0/src/apply.c Wed Mar 20 23:42:59 2002
+++ ./src/apply.c Mon Feb 24 15:25:05 2003
@@ -34,17 +34,19 @@
 STATIC_PTR int NDECL(set_trap);		/* occupation callback */
 STATIC_DCL int FDECL(use_whip, (struct obj *));
 STATIC_DCL int FDECL(use_pole, (struct obj *));
+STATIC_DCL int FDECL(use_cream_pie, (struct obj *));
 STATIC_DCL int FDECL(use_grapple, (struct obj *));
 STATIC_DCL int FDECL(do_break_wand, (struct obj *));
 STATIC_DCL boolean FDECL(figurine_location_checks,
 				(struct obj *, coord *, BOOLEAN_P));
 STATIC_DCL boolean NDECL(uhave_graystone);
+STATIC_DCL void FDECL(add_class, (char *, CHAR_P));
 
 #ifdef	AMIGA
 void FDECL( amii_speaker, ( struct obj *, char *, int ) );
 #endif
 
-static char no_elbow_room[] = "don't have enough elbow-room to maneuver.";
+static const char no_elbow_room[] = "don't have enough elbow-room to maneuver.";
 
 #ifdef TOURIST
 STATIC_OVL int
@@ -190,7 +192,7 @@
 	return FALSE;
 }
 
-static char hollow_str[] = "a hollow sound.  This must be a secret %s!";
+static const char hollow_str[] = "a hollow sound.  This must be a secret %s!";
 
 /* Strictly speaking it makes no sense for usage of a stethoscope to
    not take any time; however, unless it did, the stethoscope would be
@@ -289,7 +291,7 @@
 	return res;
 }
 
-static char whistle_str[] = "produce a %s whistling sound.";
+static const char whistle_str[] = "produce a %s whistling sound.";
 
 STATIC_OVL void
 use_whistle(obj)
@@ -325,7 +327,7 @@
 			if (mintrap(mtmp) == 2) change_luck(-1);
 		    }
 		}
-		if (pet_cnt > 0) makeknown(MAGIC_WHISTLE);
+		if (pet_cnt > 0) makeknown(obj->otyp);
 	}
 }
 
@@ -398,7 +400,7 @@
 use_leash(obj)
 struct obj *obj;
 {
-	register int x, y;
+	coord cc;
 	register struct monst *mtmp;
 	int spotmon;
 
@@ -407,12 +409,9 @@
 		return;
 	}
 
-	if(!getdir((char *)0)) return;
-
-	x = u.ux + u.dx;
-	y = u.uy + u.dy;
+	if(!get_adjacent_loc((char *)0, (char *)0, u.ux, u.uy, &cc)) return;
 
-	if((x == u.ux) && (y == u.uy)) {
+	if((cc.x == u.ux) && (cc.y == u.uy)) {
 #ifdef STEED
 		if (u.usteed && u.dz > 0) {
 		    mtmp = u.usteed;
@@ -424,7 +423,7 @@
 		return;
 	}
 
-	if(!(mtmp = m_at(x, y))) {
+	if(!(mtmp = m_at(cc.x, cc.y))) {
 		There("is no creature there.");
 		return;
 	}
@@ -528,94 +527,65 @@
 register xchar x, y;
 {
 	register struct obj *otmp;
-	register struct monst *mtmp = fmon;
+	register struct monst *mtmp;
 
-	for(otmp = invent; otmp; otmp = otmp->nobj)
-	    if(otmp->otyp == LEASH && otmp->leashmon != 0) {
-		while(mtmp) {
-		    if(!DEADMONSTER(mtmp) && ((int)mtmp->m_id == otmp->leashmon &&
-			    (dist2(u.ux,u.uy,mtmp->mx,mtmp->my) >
-				dist2(x,y,mtmp->mx,mtmp->my)))
-			) {
-			if(otmp->cursed && !breathless(mtmp->data)) {
-			    if(um_dist(mtmp->mx, mtmp->my, 5)) {
-				pline("%s chokes to death!",Monnam(mtmp));
-				mondied(mtmp);
-			    } else
-				if(um_dist(mtmp->mx, mtmp->my, 3))
-					pline("%s chokes on the leash!",
-						Monnam(mtmp));
-			} else {
-			    if(um_dist(mtmp->mx, mtmp->my, 5)) {
-				pline("%s leash snaps loose!",
-					s_suffix(Monnam(mtmp)));
-				m_unleash(mtmp, FALSE);
-			    } else {
-				if(um_dist(mtmp->mx, mtmp->my, 3)) {
-				    You("pull on the leash.");
-				    if (mtmp->data->msound != MS_SILENT)
-					switch(rn2(3)) {
-					    case 0:  growl(mtmp);	break;
-					    case 1:  yelp(mtmp);	break;
-					    default: whimper(mtmp); break;
-					}
-				}
+	for (otmp = invent; otmp; otmp = otmp->nobj) {
+	    if (otmp->otyp != LEASH || otmp->leashmon == 0) continue;
+	    for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
+		if (DEADMONSTER(mtmp)) continue;
+		if ((int)mtmp->m_id == otmp->leashmon) break; 
+	    }
+	    if (!mtmp) {
+		impossible("leash in use isn't attached to anything?");
+		otmp->leashmon = 0;
+		continue;
+	    }
+	    if (dist2(u.ux,u.uy,mtmp->mx,mtmp->my) >
+		    dist2(x,y,mtmp->mx,mtmp->my)) {
+		if (!um_dist(mtmp->mx, mtmp->my, 3)) {
+		    ;	/* still close enough */
+		} else if (otmp->cursed && !breathless(mtmp->data)) {
+		    if (um_dist(mtmp->mx, mtmp->my, 5) ||
+			    (mtmp->mhp -= rnd(2)) <= 0) {
+			long save_pacifism = u.uconduct.killer;
+
+			Your("leash chokes %s to death!", mon_nam(mtmp));
+			/* hero might not have intended to kill pet, but
+			   that's the result of his actions; gain experience,
+			   lose pacifism, take alignment and luck hit, make
+			   corpse less likely to remain tame after revival */
+			xkilled(mtmp, 0);	/* no "you kill it" message */
+			/* life-saving doesn't ordinarily reset this */
+			if (mtmp->mhp > 0) u.uconduct.killer = save_pacifism;
+		    } else {
+			pline("%s chokes on the leash!", Monnam(mtmp));
+			/* tameness eventually drops to 1 here (never 0) */
+			if (mtmp->mtame && rn2(mtmp->mtame)) mtmp->mtame--;
+		    }
+		} else {
+		    if (um_dist(mtmp->mx, mtmp->my, 5)) {
+			pline("%s leash snaps loose!", s_suffix(Monnam(mtmp)));
+			m_unleash(mtmp, FALSE);
+		    } else {
+			You("pull on the leash.");
+			if (mtmp->data->msound != MS_SILENT)
+			    switch (rn2(3)) {
+			    case 0:  growl(mtmp);   break;
+			    case 1:  yelp(mtmp);    break;
+			    default: whimper(mtmp); break;
 			    }
-			}
 		    }
-		    mtmp = mtmp->nmon;
 		}
 	    }
+	}
 }
 
 #endif /* OVL0 */
 #ifdef OVLB
 
-boolean
-wield_tool(obj)
-struct obj *obj;
-{
-	if(welded(uwep)) {
-		/* Andreas Bormann - ihnp4!decvax!mcvax!unido!ab */
-		if(flags.verbose) {
-			pline("Since your weapon is welded to your %s,",
-				bimanual(uwep) ?
-				(const char *)makeplural(body_part(HAND))
-				: body_part(HAND));
-			pline("you cannot wield that %s.", xname(obj));
-		}
-		return(FALSE);
-	}
-	if (cantwield(youmonst.data)) {
-		You_cant("hold it strongly enough.");
-		return(FALSE);
-	}
-	/* Check shield */
-	if (uarms && bimanual(obj)) {
-		You("cannot wield a two-handed tool while wearing a shield.");
-		return(FALSE);
-	}
-	if(uquiver == obj) setuqwep((struct obj *)0);
-	if(uswapwep == obj) {
-	    (void) doswapweapon();
-	    /* If doswapweapon failed... */
-	    if(uswapwep == obj) return (FALSE);
-	} else {
-	    You("now wield %s.", doname(obj));
-	    setuwep(obj);
-	}
-	if (uwep != obj) return(FALSE); /* rewielded old object after dying */
-	/* applying weapon or tool that gets wielded ends two-weapon combat */
-	if (u.twoweap)
-		untwoweapon();
-	if (obj->oclass != WEAPON_CLASS)
-		unweapon = TRUE;
-	return(TRUE);
-}
-
 #define WEAK	3	/* from eat.c */
 
-static char look_str[] = "look %s.";
+static const char look_str[] = "look %s.";
 
 STATIC_OVL int
 use_mirror(obj)
@@ -875,7 +845,7 @@
 use_candelabrum(obj)
 register struct obj *obj;
 {
-	char *s = obj->spe != 1 ? "candles" : "candle";
+	const char *s = (obj->spe != 1) ? "candles" : "candle";
 
 	if(Underwater) {
 		You("cannot make fire under water.");
@@ -927,7 +897,7 @@
 register struct obj *obj;
 {
 	register struct obj *otmp;
-	char *s = obj->quan != 1 ? "candles" : "candle";
+	const char *s = (obj->quan != 1) ? "candles" : "candle";
 	char qbuf[QBUFSZ];
 
 	if(u.uswallow) {
@@ -971,8 +941,8 @@
 			      (obj->quan > 1L) ? "them" : "it",
 			      (obj->quan > 1L) ? "them" : "it");
 		if (obj->quan < 7L && otmp->spe == 7)
-		    pline("%s now has seven%s %s attached.",
-			  The(xname(otmp)), otmp->lamplit ? " lit" : "", s);
+		    pline("%s now has seven%s candles attached.",
+			  The(xname(otmp)), otmp->lamplit ? " lit" : "");
 		/* candelabrum's light range might increase */
 		if (otmp->lamplit) obj_merge_light_sources(otmp, otmp);
 		/* candles are no longer a separate light source */
@@ -1056,7 +1026,15 @@
 		return FALSE;
 	    if (obj->where == OBJ_MINVENT ? cansee(x,y) : !Blind)
 		pline("%s %s light!", Yname2(obj), otense(obj, "catch"));
-	    begin_burn(obj, TRUE);
+	    if (obj->otyp == POT_OIL) makeknown(obj->otyp);
+	    if (obj->unpaid && costly_spot(u.ux, u.uy) && (obj->where == OBJ_INVENT)) {
+	        /* if it catches while you have it, then it's your tough luck */
+		check_unpaid(obj);
+	        verbalize("That's in addition to the cost of %s %s, of course.",
+				Yname2(obj), obj->quan == 1 ? "itself" : "themselves");
+		bill_dummy_object(obj);
+	    }
+	    begin_burn(obj, FALSE);
 	    return TRUE;
 	}
 	return FALSE;
@@ -1181,7 +1159,7 @@
 	    }
 	}
 
-	if(!obj || (obj != uwep && !wield_tool(obj))) return 0;
+	if (!obj || !wield_tool(obj, "rub")) return 0;
 
 	/* now uwep is obj */
 	if (uwep->otyp == MAGIC_LAMP) {
@@ -1361,7 +1339,7 @@
 	    if (In_sokoban(&u.uz))
 		change_luck(-1);
 
-	    teleds(cc.x, cc.y);
+	    teleds(cc.x, cc.y, TRUE);
 	    nomul(-1);
 	    nomovemsg = "";
 	    morehungry(rnd(25));
@@ -1690,6 +1668,11 @@
 {
 	xchar x,y;
 
+	if (carried(obj) && u.uswallow) {
+		if (!quietly)
+			You("don't have enough room in here.");
+		return FALSE;
+	}
 	x = cc->x; y = cc->y;
 	if (!isok(x,y)) {
 		if (!quietly)
@@ -1719,6 +1702,11 @@
 	xchar x, y;
 	coord cc;
 
+	if (u.uswallow) {
+		/* can't activate a figurine while swallowed */
+		if (!figurine_location_checks(obj, (coord *)0, FALSE))
+			return;
+	}
 	if(!getdir((char *)0)) {
 		flags.move = multi = 0;
 		return;
@@ -1729,12 +1717,13 @@
 	if (!figurine_location_checks(obj, &cc, FALSE)) return;
 	You("%s and it transforms.",
 	    (u.dx||u.dy) ? "set the figurine beside you" :
-	    (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)) ?
+	    (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz) ||
+	     is_pool(cc.x, cc.y)) ?
 		"release the figurine" :
 	    (u.dz < 0 ?
 		"toss the figurine into the air" :
 		"set the figurine on the ground"));
-	(void) make_familiar(obj, u.ux+u.dx, u.uy+u.dy, FALSE);
+	(void) make_familiar(obj, cc.x, cc.y, FALSE);
 	(void) stop_timer(FIG_TRANSFORM, (genericptr_t)obj);
 	useup(obj);
 }
@@ -1751,9 +1740,9 @@
 	char buf[BUFSZ];
 
 	if (Glib) {
-	    dropx(obj);
 	    pline("%s from your %s.", Tobjnam(obj, "slip"),
 		  makeplural(body_part(FINGER)));
+	    dropx(obj);
 	    return;
 	}
 
@@ -1761,9 +1750,9 @@
 		if ((obj->cursed || Fumbling) && !rn2(2)) {
 			check_unpaid(obj);
 			obj->spe--;
-			dropx(obj);
 			pline("%s from your %s.", Tobjnam(obj, "slip"),
 			      makeplural(body_part(FINGER)));
+			dropx(obj);
 			return;
 		}
 		otmp = getobj(lubricables, "grease");
@@ -1826,19 +1815,26 @@
 {
     struct obj *obj;
     boolean do_scratch;
-    const char *streak_color;
+    const char *streak_color, *choices;
     char stonebuf[QBUFSZ];
     static const char scritch[] = "\"scritch, scritch\"";
-    static char allowall[3] = { GOLD_CLASS, ALL_CLASSES, 0 };
+    static const char allowall[3] = { COIN_CLASS, ALL_CLASSES, 0 };
+    static const char justgems[3] = { ALLOW_NONE, GEM_CLASS, 0 };
 #ifndef GOLDOBJ
     struct obj goldobj;
 #endif
 
+    /* in case it was acquired while blinded */
+    if (!Blind) tstone->dknown = 1;
+    /* when the touchstone is fully known, don't bother listing extra
+       junk as likely candidates for rubbing */
+    choices = (tstone->otyp == TOUCHSTONE && tstone->dknown &&
+		objects[TOUCHSTONE].oc_name_known) ? justgems : allowall;
     Sprintf(stonebuf, "rub on the stone%s", plur(tstone->quan));
-    if ((obj = getobj(allowall, stonebuf)) == 0)
+    if ((obj = getobj(choices, stonebuf)) == 0)
 	return;
 #ifndef GOLDOBJ
-    if (obj->oclass == GOLD_CLASS) {
+    if (obj->oclass == COIN_CLASS) {
 	u.ugold += obj->quan;	/* keep botl up to date */
 	goldobj = *obj;
 	dealloc_obj(obj);
@@ -2066,10 +2062,8 @@
     const char *msg_snap = "Snap!";
 
     if (obj != uwep) {
-	if (!wield_tool(obj)) return 0;
+	if (!wield_tool(obj, "lash")) return 0;
 	else res = 1;
-	/* prevent bashing msg */
-	unweapon = FALSE;
     }
     if (!getdir((char *)0)) return res;
 
@@ -2180,7 +2174,7 @@
 	    if (proficient && rn2(proficient + 2)) {
 		if (!mtmp || enexto(&cc, rx, ry, youmonst.data)) {
 		    You("yank yourself out of the pit!");
-		    teleds(cc.x, cc.y);
+		    teleds(cc.x, cc.y, TRUE);
 		    u.utrap = 0;
 		    vision_full_recalc = 1;
 		}
@@ -2221,7 +2215,7 @@
 	    }
 	    if (gotit) {
 		obj_extract_self(otmp);
-		possibly_unwield(mtmp);
+		possibly_unwield(mtmp, FALSE);
 		setmnotwielded(mtmp,otmp);
 
 		switch (rn2(proficient + 1)) {
@@ -2307,9 +2301,9 @@
 
 
 static const char
-	*not_enough_room = "There's not enough room here to use that.",
-	*where_to_hit = "Where do you want to hit?",
-	*cant_see_spot = "won't hit anything if you can't see that spot.";
+	not_enough_room[] = "There's not enough room here to use that.",
+	where_to_hit[] = "Where do you want to hit?",
+	cant_see_spot[] = "won't hit anything if you can't see that spot.";
 
 /* Distance attacks by pole-weapons */
 STATIC_OVL int
@@ -2327,7 +2321,7 @@
 	    return (0);
 	}
 	if (obj != uwep) {
-	    if (!wield_tool(obj)) return(0);
+	    if (!wield_tool(obj, "swing")) return(0);
 	    else res = 1;
 	}
      /* assert(obj == uwep); */
@@ -2359,6 +2353,8 @@
 	if ((mtmp = m_at(cc.x, cc.y)) != (struct monst *)0) {
 	    int oldhp = mtmp->mhp;
 
+	    bhitpos = cc;
+	    check_caitiff(mtmp);
 	    (void) thitmonst(mtmp, uwep);
 	    /* check the monster's HP because thitmonst() doesn't return
 	     * an indication of whether it hit.  Not perfect (what if it's a
@@ -2372,12 +2368,50 @@
 	return (1);
 }
 
+STATIC_OVL int
+use_cream_pie(obj)
+struct obj *obj;
+{
+	boolean wasblind = Blind;
+	boolean wascreamed = u.ucreamed;
+	boolean several = FALSE;
+
+	if (obj->quan > 1L) {
+		several = TRUE;
+		obj = splitobj(obj, 1L);
+	}
+	if (Hallucination)
+		You("give yourself a facial.");
+	else
+		pline("You immerse your %s in %s%s.", body_part(FACE),
+			several ? "one of " : "",
+			several ? makeplural(the(xname(obj))) : the(xname(obj)));
+	if(can_blnd((struct monst*)0, &youmonst, AT_WEAP, obj)) {
+		int blindinc = rnd(25);
+		u.ucreamed += blindinc;
+		make_blinded(Blinded + (long)blindinc, FALSE);
+		if (!Blind || (Blind && wasblind))
+			pline("There's %ssticky goop all over your %s.",
+				wascreamed ? "more " : "",
+				body_part(FACE));
+		else /* Blind  && !wasblind */
+			You_cant("see through all the sticky goop on your %s.",
+				body_part(FACE));
+	}
+	if (obj->unpaid) {
+		verbalize("You used it, you bought it!");
+		bill_dummy_object(obj);
+	}
+	obj_extract_self(obj);
+	delobj(obj);
+	return(0);
+}
 
 STATIC_OVL int
 use_grapple (obj)
 	struct obj *obj;
 {
-	int res = 0, typ, max_range = 4;
+	int res = 0, typ, max_range = 4, tohit;
 	coord cc;
 	struct monst *mtmp;
 	struct obj *otmp;
@@ -2388,7 +2422,7 @@
 	    return (0);
 	}
 	if (obj != uwep) {
-	    if (!wield_tool(obj)) return(0);
+	    if (!wield_tool(obj, "cast")) return(0);
 	    else res = 1;
 	}
      /* assert(obj == uwep); */
@@ -2406,15 +2440,46 @@
 	else if (P_SKILL(typ) == P_SKILLED) max_range = 5;
 	else max_range = 8;
 	if (distu(cc.x, cc.y) > max_range) {
-		pline("Too far!");
-		return (res);
+	    pline("Too far!");
+	    return (res);
 	} else if (!cansee(cc.x, cc.y)) {
-		You(cant_see_spot);
-		return (res);
+	    You(cant_see_spot);
+	    return (res);
+	}
+
+	/* What do you want to hit? */
+	tohit = rn2(5);
+	if (typ != P_NONE && P_SKILL(typ) >= P_SKILLED) {
+	    winid tmpwin = create_nhwindow(NHW_MENU);
+	    anything any;
+	    char buf[BUFSZ];
+	    menu_item *selected;
+
+	    any.a_void = 0;	/* set all bits to zero */
+	    any.a_int = 1;	/* use index+1 (cant use 0) as identifier */
+	    start_menu(tmpwin);
+	    any.a_int++;
+	    Sprintf(buf, "an object on the %s", surface(cc.x, cc.y));
+	    add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
+			 buf, MENU_UNSELECTED);
+	    any.a_int++;
+	    add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
+			"a monster", MENU_UNSELECTED);
+	    any.a_int++;
+	    Sprintf(buf, "the %s", surface(cc.x, cc.y));
+	    add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
+			 buf, MENU_UNSELECTED);
+	    end_menu(tmpwin, "Aim for what?");
+	    tohit = rn2(4);
+	    if (select_menu(tmpwin, PICK_ONE, &selected) > 0 &&
+			rn2(P_SKILL(typ) > P_SKILLED ? 20 : 2))
+		tohit = selected[0].item.a_int - 1;
+	    free((genericptr_t)selected);
+	    destroy_nhwindow(tmpwin);
 	}
 
 	/* What did you hit? */
-	switch (rn2(5)) {
+	switch (tohit) {
 	case 0:	/* Trap */
 	    /* FIXME -- untrap needs to deal with non-adjacent traps */
 	    break;
@@ -2475,6 +2540,7 @@
     register struct monst *mon;
     int dmg, damage;
     boolean affects_objects;
+    boolean shop_damage = FALSE;
     int expltype = EXPL_MAGICAL;
     char confirm[QBUFSZ], the_wand[BUFSZ], buf[BUFSZ];
 
@@ -2562,10 +2628,17 @@
 	if (!isok(x,y)) continue;
 
 	if (obj->otyp == WAN_DIGGING) {
-	    if(dig_check(BY_OBJECT, FALSE, x, y))
+	    if(dig_check(BY_OBJECT, FALSE, x, y)) {
+		if (IS_WALL(levl[x][y].typ) || IS_DOOR(levl[x][y].typ)) {
+		    /* normally, pits and holes don't anger guards, but they
+		     * do if it's a wall or door that's being dug */
+		    watch_dig((struct monst *)0, x, y, TRUE);
+		    if (*in_rooms(x,y,SHOPBASE)) shop_damage = TRUE;
+		}		    
 		digactualhole(x, y, BY_OBJECT,
 			      (rn2(obj->spe) < 3 || !Can_dig_down(&u.uz)) ?
 			       PIT : HOLE);
+	    }
 	    continue;
 	} else if(obj->otyp == WAN_CREATE_MONSTER) {
 	    /* u.ux,u.uy creates it near you--x,y might create it in rock */
@@ -2598,6 +2671,10 @@
 	}
     }
 
+    /* Note: if player fell thru, this call is a no-op.
+       Damage is handled in digactualhole in that case */
+    if (shop_damage) pay_for_damage("dig into", FALSE);
+
     if (obj->otyp == WAN_LIGHT)
 	litroom(TRUE, obj);	/* only needs to be done once */
 
@@ -2621,17 +2698,40 @@
 	return FALSE;
 }
 
+STATIC_OVL void
+add_class(cl, class)
+char *cl;
+char class;
+{
+	char tmp[2];
+	tmp[0] = class;
+	tmp[1] = '\0';
+	Strcat(cl, tmp);
+}
+
 int
 doapply()
 {
 	register struct obj *obj;
 	register int res = 1;
+	char class_list[MAXOCLASSES+2];
 
 	if(check_capacity((char *)0)) return (0);
-	obj = getobj(carrying(POT_OIL) || uhave_graystone()
-		? tools_too : tools, "use or apply");
+
+	if (carrying(POT_OIL) || uhave_graystone())
+		Strcpy(class_list, tools_too);
+	else
+		Strcpy(class_list, tools);
+	if (carrying(CREAM_PIE) || carrying(EUCALYPTUS_LEAF))
+		add_class(class_list, FOOD_CLASS);
+
+	obj = getobj(class_list, "use or apply");
 	if(!obj) return 0;
 
+	if (obj->oartifact && !touch_artifact(obj, &youmonst))
+	    return 1;	/* evading your grasp costs a turn; just be
+			   grateful that you don't drop it as well */
+
 	if (obj->oclass == WAND_CLASS)
 	    return do_break_wand(obj);
 
@@ -2647,6 +2747,9 @@
 			ublindf->otyp == BLINDFOLD ? "wearing a blindfold" :
 						     "wearing lenses");
 		break;
+	case CREAM_PIE:
+		res = use_cream_pie(obj);
+		break;
 	case BULLWHIP:
 		res = use_whip(obj);
 		break;
@@ -2706,6 +2809,27 @@
 	case TIN_WHISTLE:
 		use_whistle(obj);
 		break;
+	case EUCALYPTUS_LEAF:
+		/* MRKR: Every Australian knows that a gum leaf makes an */
+		/*	 excellent whistle, especially if your pet is a  */
+		/*	 tame kangaroo named Skippy.			 */
+		if (obj->blessed) {
+		    use_magic_whistle(obj);
+		    /* sometimes the blessing will be worn off */
+		    if (!rn2(49)) {
+			if (!Blind) {
+			    char buf[BUFSZ];
+
+			    pline("%s %s %s.", Shk_Your(buf, obj),
+				  aobjnam(obj, "glow"), hcolor("brown"));
+			    obj->bknown = 1;
+			}
+			unbless(obj);
+		    }
+		} else {
+		    use_whistle(obj);
+		}
+		break;
 	case STETHOSCOPE:
 		res = use_stethoscope(obj);
 		break;
@@ -2798,9 +2922,12 @@
 		    otmp->blessed = obj->blessed;
 		    otmp->cursed = obj->cursed;
 		    otmp->owt = weight(otmp);
-		    otmp = hold_another_object(otmp,
-					(u.uswallow || Is_airlevel(&u.uz) ||
-					 u.uinwater || Is_waterlevel(&u.uz)) ?
+		    otmp = hold_another_object(otmp, u.uswallow ?
+				       "Oops!  %s out of your reach!" :
+					(Is_airlevel(&u.uz) ||
+					 Is_waterlevel(&u.uz) ||
+					 levl[u.ux][u.uy].typ < IRONBARS ||
+					 levl[u.ux][u.uy].typ >= ICE) ?
 					       "Oops!  %s away from you!" :
 					       "Oops!  %s to the floor!",
 					       The(aobjnam(otmp, "slip")),
@@ -2824,7 +2951,7 @@
 		if (is_pole(obj)) {
 			res = use_pole(obj);
 			break;
-		} else if (is_pick(obj) /* || is_axe(obj) */) {
+		} else if (is_pick(obj) || is_axe(obj)) {
 			res = use_pick_axe(obj);
 			break;
 		}
@@ -2841,7 +2968,8 @@
 /* Keep track of unfixable troubles for purposes of messages saying you feel
  * great.
  */
-int unfixable_trouble_count(is_horn)
+int
+unfixable_trouble_count(is_horn)
 	boolean is_horn;
 {
 	int unfixable_trbl = 0;
diff -Naurd ../nethack-3.4.0/src/artifact.c ./src/artifact.c
--- ../nethack-3.4.0/src/artifact.c Wed Mar 20 23:43:00 2002
+++ ./src/artifact.c Mon Feb 24 15:25:05 2003
@@ -20,8 +20,11 @@
 
 #define get_artifact(o) \
 		(((o)&&(o)->oartifact) ? &artilist[(int) (o)->oartifact] : 0)
+
 STATIC_DCL int FDECL(spec_applies, (const struct artifact *,struct monst *));
 STATIC_DCL int FDECL(arti_invoke, (struct obj*));
+STATIC_DCL boolean FDECL(Mb_hit, (struct monst *magr,struct monst *mdef,
+				  struct obj *,int *,int,BOOLEAN_P,char *));
 
 /* The amount added to the victim's total hit points to insure that the
    victim will be killed even after damage bonus/penalty adjustments.
@@ -248,6 +251,34 @@
 	return((boolean)(arti && (arti->spfx & abil)));
 }
 
+/* used so that callers don't need to known about SPFX_ codes */
+boolean
+confers_luck(obj)
+struct obj *obj;
+{
+    /* might as well check for this too */
+    if (obj->otyp == LUCKSTONE) return TRUE;
+
+    return (obj->oartifact && spec_ability(obj, SPFX_LUCK));
+}
+
+/* used to check whether a monster is getting reflection from an artifact */
+boolean
+arti_reflects(obj)
+struct obj *obj;
+{
+    const struct artifact *arti = get_artifact(obj);
+
+    if (arti) {      
+	/* while being worn */
+	if ((obj->owornmask & ~W_ART) && (arti->spfx & SPFX_REFLECT))
+	    return TRUE;
+	/* just being carried */
+	if (arti->cspfx & SPFX_REFLECT) return TRUE;
+    }
+    return FALSE;
+}
+
 #endif /* OVL0 */
 #ifdef OVLB
 
@@ -439,6 +470,7 @@
 	    /* this assumes that no one else is using xray_range */
 	    if (on) u.xray_range = 3;
 	    else u.xray_range = -1;
+	    vision_full_recalc = 1;
 	}
 	if ((spfx & SPFX_REFLECT) && (wp_mask & W_WEP)) {
 	    if (on) EReflecting |= wp_mask;
@@ -547,8 +579,9 @@
 	} else if (weap->spfx & SPFX_DFLAG1) {
 	    return ((ptr->mflags1 & weap->mtype) != 0L);
 	} else if (weap->spfx & SPFX_DFLAG2) {
-	    return ((ptr->mflags2 & weap->mtype) ||
-		(yours && !Upolyd && (urace.selfmask & weap->mtype)));
+	    return ((ptr->mflags2 & weap->mtype) || (yours &&
+			((!Upolyd && (urace.selfmask & weap->mtype)) ||
+			 ((weap->mtype & M2_WERE) && u.ulycn >= LOW_PM))));
 	} else if (weap->spfx & SPFX_DALIGN) {
 	    return yours ? (u.ualign.type != weap->alignment) :
 			   (ptr->maligntyp == A_NONE ||
@@ -688,6 +721,205 @@
 
 #ifdef OVLB
 
+
+	/*
+	 * Magicbane's intrinsic magic is incompatible with normal
+	 * enchantment magic.  Thus, its effects have a negative
+	 * dependence on spe.  Against low mr victims, it typically
+	 * does "double athame" damage, 2d4.  Occasionally, it will
+	 * cast unbalancing magic which effectively averages out to
+	 * 4d4 damage (3d4 against high mr victims), for spe = 0.
+	 *
+	 * Prior to 3.4.1, the cancel (aka purge) effect always
+	 * included the scare effect too; now it's one or the other.
+	 * Likewise, the stun effect won't be combined with either
+	 * of those two; it will be chosen separately or possibly
+	 * used as a fallback when scare or cancel fails.
+	 *
+	 * [Historical note: a change to artifact_hit() for 3.4.0
+	 * unintentionally made all of Magicbane's special effects
+	 * be blocked if the defender successfully saved against a
+	 * stun attack.  As of 3.4.1, those effects can occur but
+	 * will be slightly less likely than they were in 3.3.x.]
+	 */
+#define MB_MAX_DIEROLL		8	/* rolls above this aren't magical */
+static const char * const mb_verb[2][4] = {
+	{ "probe", "stun", "scare", "cancel" },
+	{ "prod", "amaze", "tickle", "purge" },
+};
+#define MB_INDEX_PROBE		0
+#define MB_INDEX_STUN		1
+#define MB_INDEX_SCARE		2
+#define MB_INDEX_CANCEL		3
+
+/* called when someone is being hit by Magicbane */
+STATIC_OVL boolean
+Mb_hit(magr, mdef, mb, dmgptr, dieroll, vis, hittee)
+struct monst *magr, *mdef;	/* attacker and defender */
+struct obj *mb;			/* Magicbane */
+int *dmgptr;			/* extra damage target will suffer */
+int dieroll;			/* d20 that has already scored a hit */
+boolean vis;			/* whether the action can be seen */
+char *hittee;			/* target's name: "you" or mon_nam(mdef) */
+{
+    struct permonst *old_uasmon;
+    const char *verb;
+    boolean youattack = (magr == &youmonst),
+	    youdefend = (mdef == &youmonst),
+	    resisted = FALSE, do_stun, do_confuse, result;
+    int attack_indx, scare_dieroll = MB_MAX_DIEROLL / 2;
+
+    result = FALSE;		/* no message given yet */
+    /* the most severe effects are less likely at higher enchantment */
+    if (mb->spe >= 3)
+	scare_dieroll /= (1 << (mb->spe / 3));
+    /* if target successfully resisted the artifact damage bonus,
+       reduce overall likelihood of the assorted special effects */
+    if (!spec_dbon_applies) dieroll += 1;
+
+    /* might stun even when attempting a more severe effect, but
+       in that case it will only happen if the other effect fails;
+       extra damage will apply regardless; 3.4.1: sometimes might
+       just probe even when it hasn't been enchanted */
+    do_stun = (max(mb->spe,0) < rn2(spec_dbon_applies ? 11 : 7));
+
+    /* the special effects also boost physical damage; increments are
+       generally cumulative, but since the stun effect is based on a
+       different criterium its damage might not be included; the base
+       damage is either 1d4 (athame) or 2d4 (athame+spec_dbon) depending
+       on target's resistance check against AD_STUN (handled by caller)
+       [note that a successful save against AD_STUN doesn't actually
+       prevent the target from ending up stunned] */
+    attack_indx = MB_INDEX_PROBE;
+    *dmgptr += rnd(4);			/* (2..3)d4 */
+    if (do_stun) {
+	attack_indx = MB_INDEX_STUN;
+	*dmgptr += rnd(4);		/* (3..4)d4 */
+    }
+    if (dieroll <= scare_dieroll) {
+	attack_indx = MB_INDEX_SCARE;
+	*dmgptr += rnd(4);		/* (3..5)d4 */
+    }
+    if (dieroll <= (scare_dieroll / 2)) {
+	attack_indx = MB_INDEX_CANCEL;
+	*dmgptr += rnd(4);		/* (4..6)d4 */
+    }
+
+    /* give the hit message prior to inflicting the effects */
+    verb = mb_verb[!!Hallucination][attack_indx];
+    if (youattack || youdefend || vis) {
+	result = TRUE;
+	pline_The("magic-absorbing blade %s %s!",
+		  vtense((const char *)0, verb), hittee);
+	/* assume probing has some sort of noticeable feedback
+	   even if it is being done by one monster to another */
+	if (attack_indx == MB_INDEX_PROBE && !canspotmon(mdef))
+	    map_invisible(mdef->mx, mdef->my);
+    }
+
+    /* now perform special effects */
+    switch (attack_indx) {
+    case MB_INDEX_CANCEL:
+	old_uasmon = youmonst.data;
+	if (!cancel_monst(mdef, mb, youattack, FALSE, FALSE)) {
+	    resisted = TRUE;
+	} else {
+	    do_stun = FALSE;
+	    if (youdefend) {
+		if (youmonst.data != old_uasmon)
+		    *dmgptr = 0;    /* rehumanized, so no more damage */
+		if (u.uenmax > 0) {
+		    You("lose magical energy!");
+		    u.uenmax--;
+		    if (u.uen > 0) u.uen--;
+		    flags.botl = 1;
+		}
+	    } else {
+		if (mdef->data == &mons[PM_CLAY_GOLEM])
+		    mdef->mhp = 1;	/* cancelled clay golems will die */
+		if (youattack && attacktype(mdef->data, AT_MAGC)) {
+		    You("absorb magical energy!");
+		    u.uenmax++;
+		    u.uen++;
+		    flags.botl = 1;
+		}
+	    }
+	}
+	break;
+
+    case MB_INDEX_SCARE:
+	if (youdefend) {
+	    if (Antimagic) {
+		resisted = TRUE;
+	    } else {
+		nomul(-3);
+		nomovemsg = "";
+		if (magr && magr == u.ustuck && sticks(youmonst.data)) {
+		    u.ustuck = (struct monst *)0;
+		    You("release %s!", mon_nam(magr));
+		}
+	    }
+	} else {
+	    if (rn2(2) && resist(mdef, WEAPON_CLASS, 0, NOTELL))
+		resisted = TRUE;
+	    else
+		monflee(mdef, 3, FALSE, (mdef->mhp > *dmgptr));
+	}
+	if (!resisted) do_stun = FALSE;
+	break;
+
+    case MB_INDEX_STUN:
+	do_stun = TRUE;		/* (this is redundant...) */
+	break;
+
+    case MB_INDEX_PROBE:
+	if (youattack && (mb->spe == 0 || !rn2(3 * abs(mb->spe)))) {
+	    pline_The("%s is insightful.", verb);
+	    /* pre-damage status */
+	    probe_monster(mdef);
+	}
+	break;
+    }
+    /* stun if that was selected and a worse effect didn't occur */
+    if (do_stun) {
+	if (youdefend)
+	    make_stunned((HStun + 3), FALSE);
+	else
+	    mdef->mstun = 1;
+	/* avoid extra stun message below if we used mb_verb["stun"] above */
+	if (attack_indx == MB_INDEX_STUN) do_stun = FALSE;
+    }
+    /* lastly, all this magic can be confusing... */
+    do_confuse = !rn2(12);
+    if (do_confuse) {
+	if (youdefend)
+	    make_confused(HConfusion + 4, FALSE);
+	else
+	    mdef->mconf = 1;
+    }
+
+    if (youattack || youdefend || vis) {
+	(void) upstart(hittee);	/* capitalize */
+	if (resisted) {
+	    pline("%s %s!", hittee, vtense(hittee, "resist"));
+	    shieldeff(youdefend ? u.ux : mdef->mx,
+		      youdefend ? u.uy : mdef->my);
+	}
+	if ((do_stun || do_confuse) && flags.verbose) {
+	    char buf[BUFSZ];
+
+	    buf[0] = '\0';
+	    if (do_stun) Strcat(buf, "stunned");
+	    if (do_stun && do_confuse) Strcat(buf, " and ");
+	    if (do_confuse) Strcat(buf, "confused");
+	    pline("%s %s %s%c", hittee, vtense(hittee, "are"),
+		  buf, (do_stun && do_confuse) ? '!' : '.');
+	}
+    }
+
+    return result;
+}
+  
 /* Function used when someone attacks someone else with an artifact
  * weapon.  Only adds the special (artifact) damage, and returns a 1 if it
  * did something special (in which case the caller won't print the normal
@@ -725,7 +957,9 @@
 	    return FALSE;
 	}
 
-	realizes_damage = (youdefend || vis);
+	realizes_damage = (youdefend || vis || 
+			   /* feel the effect even if not seen */
+			   (youattack && mdef == u.ustuck));
 
 	/* the four basic attacks: fire, cold, shock and missiles */
 	if (attacks(AD_FIRE, otmp)) {
@@ -750,192 +984,34 @@
 	    return realizes_damage;
 	}
 	if (attacks(AD_ELEC, otmp)) {
-	    if (realizes_damage) {
-		if (youattack ? otmp != uwep : !spec_dbon_applies)
-		    pline("%s %s%c", Tobjnam(otmp, "hit"),
+	    if (realizes_damage)
+		pline_The("massive hammer hits%s %s%c",
+			  !spec_dbon_applies ? "" : "!  Lightning strikes",
 			  hittee, !spec_dbon_applies ? '.' : '!');
-		if (spec_dbon_applies)
-		    pline("Lightning strikes %s!", hittee);
-	    }
 	    if (!rn2(5)) (void) destroy_mitem(mdef, RING_CLASS, AD_ELEC);
 	    if (!rn2(5)) (void) destroy_mitem(mdef, WAND_CLASS, AD_ELEC);
 	    return realizes_damage;
 	}
 	if (attacks(AD_MAGM, otmp)) {
-	    if (realizes_damage) {
-		if (youattack ? otmp != uwep : !spec_dbon_applies)
-		    pline("%s %s%c", Tobjnam(otmp, "hit"),
+	    if (realizes_damage)
+		pline_The("imaginary widget hits%s %s%c",
+			  !spec_dbon_applies ? "" :
+				"!  A hail of magic missiles strikes",
 			  hittee, !spec_dbon_applies ? '.' : '!');
-		if (spec_dbon_applies)
-		    pline("A hail of magic missiles strikes %s!", hittee);
-	    }
 	    return realizes_damage;
 	}
 
+	if (attacks(AD_STUN, otmp) && dieroll <= MB_MAX_DIEROLL) {
+	    /* Magicbane's special attacks (possibly modifies hittee[]) */
+	    return Mb_hit(magr, mdef, otmp, dmgptr, dieroll, vis, hittee);
+	}
+
 	if (!spec_dbon_applies) {
 	    /* since damage bonus didn't apply, nothing more to do;  
 	       no further attacks have side-effects on inventory */
 	    return FALSE;
 	}
 
-	/*
-	 * Magicbane's intrinsic magic is incompatible with normal
-	 * enchantment magic.  Thus, its effects have a negative
-	 * dependence on spe.  Against low mr victims, it typically
-	 * does "double athame" damage, 2d4.  Occasionally, it will
-	 * cast unbalancing magic which effectively averages out to
-	 * 4d4 damage (2.5d4 against high mr victims), for spe = 0.
-	 */
-
-#define MB_MAX_DIEROLL		8    /* rolls above this aren't magical */
-#define MB_INDEX_INIT		(-1)
-#define MB_INDEX_PROBE		0
-#define MB_INDEX_STUN		1
-#define MB_INDEX_SCARE		2
-#define MB_INDEX_PURGE		3
-#define MB_RESIST_ATTACK	(resist_index = attack_index)
-#define MB_RESISTED_ATTACK	(resist_index == attack_index)
-#define MB_UWEP_ATTACK		(youattack && (otmp == uwep))
-
-	if (attacks(AD_STUN, otmp) && (dieroll <= MB_MAX_DIEROLL)) {
-		int attack_index = MB_INDEX_INIT;
-		int resist_index = MB_INDEX_INIT;
-		int scare_dieroll = MB_MAX_DIEROLL / 2;
-
-		if (otmp->spe >= 3)
-			scare_dieroll /= (1 << (otmp->spe / 3));
-
-		*dmgptr += rnd(4);			/* 3d4 */
-
-		if (otmp->spe > rn2(10))		/* probe */
-			attack_index = MB_INDEX_PROBE;
-		else {					/* stun */
-			attack_index = MB_INDEX_STUN;
-			*dmgptr += rnd(4);		/* 4d4 */
-
-			if (youdefend)
-				make_stunned((HStun + 3), FALSE);
-			else
-				mdef->mstun = 1;
-		}
-		if (dieroll <= scare_dieroll) {		/* scare */
-			attack_index = MB_INDEX_SCARE;
-			*dmgptr += rnd(4);		/* 5d4 */
-
-			if (youdefend) {
-				if (Antimagic)
-					MB_RESIST_ATTACK;
-				else {
-					nomul(-3);
-					nomovemsg = "";
-					if (magr && magr == u.ustuck
-						&& sticks(youmonst.data)) {
-					    u.ustuck = (struct monst *)0;
-					    You("release %s!", mon_nam(magr));
-					}
-				}
-			} else if (youattack) {
-				if (rn2(2) && resist(mdef,SPBOOK_CLASS,0,0)) {
-				    MB_RESIST_ATTACK;
-				} else {
-				    monflee(mdef, 3, FALSE, TRUE);
-				}
-			}
-		}
-		if (dieroll <= (scare_dieroll / 2)) {	/* purge */
-			struct obj *ospell;
-			struct permonst *old_uasmon = youmonst.data;
-
-			attack_index = MB_INDEX_PURGE;
-			*dmgptr += rnd(4);		/* 6d4 */
-
-			/* Create a fake spell object, ala spell.c */
-			ospell = mksobj(SPE_CANCELLATION, FALSE, FALSE);
-			ospell->blessed = ospell->cursed = 0;
-			ospell->quan = 20L;
-
-			cancel_monst(mdef, ospell, youattack, FALSE, FALSE);
-
-			if (youdefend) {
-				if (old_uasmon != youmonst.data)
-					/* rehumanized, no more damage */
-					*dmgptr = 0;
-				if (Antimagic)
-					MB_RESIST_ATTACK;
-			} else {
-				if (!mdef->mcan)
-					MB_RESIST_ATTACK;
-
-				/* cancelled clay golems will die ... */
-				else if (mdef->data == &mons[PM_CLAY_GOLEM])
-					mdef->mhp = 1;
-			}
-
-			obfree(ospell, (struct obj *)0);
-		}
-
-		if (youdefend || mdef->mhp > 0) {  /* ??? -dkh- */
-			static const char *mb_verb[4] =
-				{"probe", "stun", "scare", "purge"};
-
-			if (youattack || youdefend || vis) {
-				pline_The("magic-absorbing blade %ss %s!",
-					mb_verb[attack_index], hittee);
-
-				if (MB_RESISTED_ATTACK) {
-					pline("%s resist%s!",
-					youdefend ? "You" : Monnam(mdef),
-					youdefend ? "" : "s");
-
-					shieldeff(youdefend ? u.ux : mdef->mx,
-						youdefend ? u.uy : mdef->my);
-				}
-			}
-
-			/* Much ado about nothing.  More magic fanfare! */
-			if (MB_UWEP_ATTACK) {
-				if (attack_index == MB_INDEX_PURGE) {
-				    if (!MB_RESISTED_ATTACK &&
-					attacktype(mdef->data, AT_MAGC)) {
-					You("absorb magical energy!");
-					u.uenmax++;
-					u.uen++;
-					flags.botl = 1;
-				    }
-				} else if (attack_index == MB_INDEX_PROBE) {
-				    if (!rn2(4 * otmp->spe)) {
-					pline_The("probe is insightful!");
-					if (!canspotmon(mdef))
-					    map_invisible(u.ux+u.dx,u.uy+u.dy);
-					/* pre-damage status */
-					probe_monster(mdef);
-				    }
-				}
-			} else if (youdefend && !MB_RESISTED_ATTACK
-				   && (attack_index == MB_INDEX_PURGE)) {
-				You("lose magical energy!");
-				if (u.uenmax > 0) u.uenmax--;
-				if (u.uen > 0) u.uen--;
-					flags.botl = 1;
-			}
-
-			/* all this magic is confusing ... */
-			if (!rn2(12)) {
-			    if (youdefend)
-				make_confused((HConfusion + 4), FALSE);
-			    else
-				mdef->mconf = 1;
-
-			    if (youattack || youdefend || vis)
-				pline("%s %s confused.",
-				      youdefend ? "You" : Monnam(mdef),
-				      youdefend ? "are" : "is");
-			}
-		}
-		return TRUE;
-	}
-	/* end of Magicbane code */
-
 	/* We really want "on a natural 20" but Nethack does it in */
 	/* reverse from AD&D. */
 	if (spec_ability(otmp, SPFX_BEHEAD)) {
@@ -986,7 +1062,7 @@
 		}
 	    } else if (otmp->oartifact == ART_VORPAL_BLADE &&
 			(dieroll == 1 || mdef->data == &mons[PM_JABBERWOCK])) {
-		static const char *behead_msg[2] = {
+		static const char * const behead_msg[2] = {
 		     "%s beheads %s!",
 		     "%s decapitates %s!"
 		};
@@ -1043,7 +1119,7 @@
 			if (vis) {
 			    if(otmp->oartifact == ART_STORMBRINGER)
 				pline_The("%s blade draws the life from %s!",
-				      hcolor(Black),
+				      hcolor(NH_BLACK),
 				      mon_nam(mdef));
 			    else
 				pline("%s draws the life from %s!",
@@ -1070,7 +1146,7 @@
 				    "unholy blade" : "object");
 			else if (otmp->oartifact == ART_STORMBRINGER)
 				pline_The("%s blade drains your life!",
-				      hcolor(Black));
+				      hcolor(NH_BLACK));
 			else
 				pline("%s drains your life!",
 				      The(distant_name(otmp, xname)));
@@ -1095,7 +1171,8 @@
     register struct obj *obj;
 
     obj = getobj(invoke_types, "invoke");
-    if(!obj) return 0;
+    if (!obj) return 0;
+    if (obj->oartifact && !touch_artifact(obj, &youmonst)) return 1;
     return arti_invoke(obj);
 }
 
@@ -1138,7 +1215,7 @@
 	    long creamed = (long)u.ucreamed;
 
 	    if (Upolyd) healamt = (u.mhmax + 1 - u.mh) / 2;
-	    if (healamt || Sick || Blinded > creamed)
+	    if (healamt || Sick || Slimed || Blinded > creamed)
 		You_feel("better.");
 	    else
 		goto nothing_special;
@@ -1268,13 +1345,16 @@
 	  }
 	}
     } else {
-	long cprop = (u.uprops[oart->inv_prop].extrinsic ^= W_ARTI);
-	boolean on = (cprop & W_ARTI) != 0; /* true if invoked prop just set */
+	long eprop = (u.uprops[oart->inv_prop].extrinsic ^= W_ARTI),
+	     iprop = u.uprops[oart->inv_prop].intrinsic;
+	boolean on = (eprop & W_ARTI) != 0; /* true if invoked prop just set */
 
 	if(on && obj->age > monstermoves) {
 	    /* the artifact is tired :-) */
 	    u.uprops[oart->inv_prop].extrinsic ^= W_ARTI;
 	    You_feel("that %s is ignoring you.", the(xname(obj)));
+	    /* can't just keep repeatedly trying */
+	    obj->age += (long) d(3,10);
 	    return 1;
 	} else if(!on) {
 	    /* when turning off property, determine downtime */
@@ -1282,7 +1362,7 @@
 	    obj->age = monstermoves + rnz(100);
 	}
 
-	if(cprop & ~W_ARTI) {
+	if ((eprop & ~W_ARTI) || iprop) {
 nothing_special:
 	    /* you had the property from some other source too */
 	    if (carried(obj))
@@ -1301,15 +1381,13 @@
 	    } else (void) float_down(I_SPECIAL|TIMEOUT, W_ARTI);
 	    break;
 	case INVIS:
-	    if (!See_invisible && !Blind) {
-		newsym(u.ux,u.uy);
-		if (on) {
-		    Your("body takes on a %s transparency...",
-			 Hallucination ? "normal" : "strange");
-		} else {
-		    Your("body seems to unfade...");
-		}
-	    } else goto nothing_special;
+	    if (BInvis || Blind) goto nothing_special;
+	    newsym(u.ux, u.uy);
+	    if (on)
+		Your("body takes on a %s transparency...",
+		     Hallucination ? "normal" : "strange");
+	    else
+		Your("body seems to unfade...");
 	    break;
 	}
     }
@@ -1327,7 +1405,8 @@
 }
 
 /* KMH -- Talking artifacts are finally implemented */
-void arti_speak(obj)
+void
+arti_speak(obj)
     struct obj *obj;
 {
 	register const struct artifact *oart = get_artifact(obj);
diff -Naurd ../nethack-3.4.0/src/attrib.c ./src/attrib.c
--- ../nethack-3.4.0/src/attrib.c Wed Mar 20 23:43:00 2002
+++ ./src/attrib.c Mon Feb 24 15:25:05 2003
@@ -1,11 +1,10 @@
-/*	SCCS Id: @(#)attrib.c	3.4	2000/05/17	*/
+/*	SCCS Id: @(#)attrib.c	3.4	2002/10/07	*/
 /*	Copyright 1988, 1989, 1990, 1992, M. Stephenson		  */
 /* NetHack may be freely redistributed.  See license for details. */
 
 /*  attribute modification routines. */
 
 #include "hack.h"
-#include "artifact.h"
 
 /* #define DEBUG */	/* uncomment for debugging info */
 
@@ -13,10 +12,10 @@
 
 	/* part of the output on gain or loss of attribute */
 static
-const char	*plusattr[] = {
+const char	* const plusattr[] = {
 	"strong", "smart", "wise", "agile", "tough", "charismatic"
 },
-		*minusattr[] = {
+		* const minusattr[] = {
 	"weak", "stupid", "foolish", "clumsy", "fragile", "repulsive"
 };
 
@@ -99,6 +98,7 @@
 
 static long next_check = 600L;	/* arbitrary first setting */
 STATIC_DCL void NDECL(exerper);
+STATIC_DCL void FDECL(postadjabil, (long *));
 
 /* adjust an attribute; return TRUE if change is made, FALSE otherwise */
 boolean
@@ -211,9 +211,8 @@
 	register struct obj *otmp;
 	register long bonchance = 0;
 
-	for(otmp = invent; otmp; otmp=otmp->nobj)
-	    if (otmp->otyp == LUCKSTONE
-		|| (otmp->oartifact && spec_ability(otmp, SPFX_LUCK))) {
+	for (otmp = invent; otmp; otmp = otmp->nobj)
+	    if (confers_luck(otmp)) {
 		if (otmp->cursed) bonchance -= otmp->quan;
 		else if (otmp->blessed) bonchance += otmp->quan;
 		else if (parameter) bonchance += otmp->quan;
@@ -318,9 +317,15 @@
 		pline("exerper: Hunger checks");
 #endif
 		switch (hs) {
-		    case SATIATED:	exercise(A_DEX, FALSE); break;
+		    case SATIATED:	exercise(A_DEX, FALSE);
+					if (Role_if(PM_MONK))
+					    exercise(A_WIS, FALSE);
+					break;
 		    case NOT_HUNGRY:	exercise(A_CON, TRUE); break;
-		    case WEAK:		exercise(A_STR, FALSE); break;
+		    case WEAK:		exercise(A_STR, FALSE);
+					if (Role_if(PM_MONK))	/* fasting */
+					    exercise(A_WIS, TRUE);
+					break;
 		    case FAINTING:
 		    case FAINTED:	exercise(A_CON, FALSE); break;
 		}
@@ -517,6 +522,16 @@
 	(void)encumber_msg();
 }
 
+STATIC_OVL
+void
+postadjabil(ability)
+long *ability;
+{
+	if (!ability) return;
+	if (ability == &(HWarning) || ability == &(HSee_invisible))
+		see_monsters();
+}
+
 void
 adjabil(oldlevel,newlevel)
 int oldlevel, newlevel;
@@ -554,6 +569,7 @@
 	}
 
 	while (abil || rabil) {
+	    long prevabil;
 	    /* Have we finished with the intrinsics list? */
 	    if (!abil || !abil->ability) {
 	    	/* Try the race intrinsics */
@@ -562,7 +578,7 @@
 	    	rabil = 0;
 	    	mask = FROMRACE;
 	    }
-
+		prevabil = *(abil->ability);
 		if(oldlevel < abil->ulevel && newlevel >= abil->ulevel) {
 			/* Abilities gained at level 1 can never be lost
 			 * via level loss, only via means that remove _any_
@@ -587,6 +603,8 @@
 				You_feel("less %s!", abil->gainstr);
 			}
 		}
+	    if (prevabil != *(abil->ability))	/* it changed */
+		postadjabil(abil->ability);
 	    abil++;
 	}
 
diff -Naurd ../nethack-3.4.0/src/ball.c ./src/ball.c
--- ../nethack-3.4.0/src/ball.c Wed Mar 20 23:43:00 2002
+++ ./src/ball.c Mon Feb 24 15:25:05 2003
@@ -38,7 +38,7 @@
 		    } else if (flags.verbose)
 			Your("%s does not protect you.", xname(uarmh));
 		}
-		losehp(dmg, "Crunched in the head by an iron ball",
+		losehp(dmg, "crunched in the head by an iron ball",
 			NO_KILLER_PREFIX);
 	}
 }
@@ -343,19 +343,30 @@
     }
 }
 
-/* return TRUE if ball could be dragged
+/* return TRUE if the caller needs to place the ball and chain down again
  *
  *  Should not be called while swallowed.  Should be called before movement,
  *  because we might want to move the ball or chain to the hero's old position.
+ *
+ * It is called if we are moving.  It is also called if we are teleporting
+ * *if* the ball doesn't move and we thus must drag the chain.  It is not
+ * called for ordinary teleportation.
+ *
+ * allow_drag is only used in the ugly special case where teleporting must
+ * drag the chain, while an identical-looking movement must drag both the ball
+ * and chain.
  */
 boolean
-drag_ball(x, y, bc_control, ballx, bally, chainx, chainy, cause_delay)
+drag_ball(x, y, bc_control, ballx, bally, chainx, chainy, cause_delay,
+    allow_drag)
 xchar x, y;
 int *bc_control;
 xchar *ballx, *bally, *chainx, *chainy;
 boolean *cause_delay;
+boolean allow_drag;
 {
 	struct trap *t = (struct trap *)0;
+	boolean already_in_rock;
 
 	*ballx  = uball->ox;
 	*bally  = uball->oy;
@@ -371,10 +382,11 @@
 
 	/* only need to move the chain? */
 	if (carried(uball) || distmin(x, y, uball->ox, uball->oy) <= 2) {
+	    xchar oldchainx = uchain->ox, oldchainy = uchain->oy;
 	    *bc_control = BC_CHAIN;
 	    move_bc(1, *bc_control, *ballx, *bally, *chainx, *chainy);
 	    if (carried(uball)) {
-		/* move chain only if necessary; assume they didn't teleport */
+		/* move chain only if necessary */
 		if (distmin(x, y, uchain->ox, uchain->oy) > 1) {
 		    *chainx = u.ux;
 		    *chainy = u.uy;
@@ -383,11 +395,31 @@
 	    }
 #define CHAIN_IN_MIDDLE(chx, chy) \
 (distmin(x, y, chx, chy) <= 1 && distmin(chx, chy, uball->ox, uball->oy) <= 1)
+#define IS_CHAIN_ROCK(x,y) \
+(IS_ROCK(levl[x][y].typ) || (IS_DOOR(levl[x][y].typ) && \
+      (levl[x][y].doormask & (D_CLOSED|D_LOCKED))))
+/* Don't ever move the chain into solid rock.  If we have to, then instead
+ * undo the move_bc() and jump to the drag ball code.  Note that this also
+ * means the "cannot carry and drag" message will not appear, since unless we
+ * moved at least two squares there is no possibility of the chain position
+ * being in solid rock.
+ */
+#define SKIP_TO_DRAG { *chainx = oldchainx; *chainy = oldchainy; \
+    move_bc(0, *bc_control, *ballx, *bally, *chainx, *chainy); \
+    goto drag; } 
+	    if (IS_CHAIN_ROCK(u.ux, u.uy) || IS_CHAIN_ROCK(*chainx, *chainy)
+			|| IS_CHAIN_ROCK(uball->ox, uball->oy))
+		already_in_rock = TRUE;
+	    else
+		already_in_rock = FALSE;
+
 	    switch(dist2(x, y, uball->ox, uball->oy)) {
 		/* two spaces diagonal from ball, move chain inbetween */
 		case 8:
 		    *chainx = (uball->ox + x)/2;
 		    *chainy = (uball->oy + y)/2;
+		    if (IS_CHAIN_ROCK(*chainx, *chainy) && !already_in_rock)
+			SKIP_TO_DRAG;
 		    break;
 
 		/* player is distance 2/1 from ball; move chain to one of the
@@ -410,7 +442,47 @@
 			tempy = y;
 			tempy2 = uball->oy;
 		    }
-		    if (dist2(tempx, tempy, uchain->ox, uchain->oy) <
+		    if (IS_CHAIN_ROCK(tempx, tempy) &&
+				!IS_CHAIN_ROCK(tempx2, tempy2) &&
+				!already_in_rock) {
+			if (allow_drag) {
+			    /* Avoid pathological case *if* not teleporting:
+			     *   0			    0_
+			     *   _X  move northeast  ----->  X@
+			     *    @
+			     */
+			    if (dist2(u.ux, u.uy, uball->ox, uball->oy) == 5 &&
+				  dist2(x, y, tempx, tempy) == 1)
+				SKIP_TO_DRAG;
+			    /* Avoid pathological case *if* not teleporting:
+			     *    0			     0
+			     *   _X  move east       ----->  X_
+			     *    @			      @
+			     */
+			    if (dist2(u.ux, u.uy, uball->ox, uball->oy) == 4 &&
+				  dist2(x, y, tempx, tempy) == 2)
+				SKIP_TO_DRAG;
+			}
+			*chainx = tempx2;
+			*chainy = tempy2;
+		    } else if (!IS_CHAIN_ROCK(tempx, tempy) &&
+				IS_CHAIN_ROCK(tempx2, tempy2) &&
+				!already_in_rock) {
+			if (allow_drag) {
+			    if (dist2(u.ux, u.uy, uball->ox, uball->oy) == 5 &&
+				    dist2(x, y, tempx2, tempy2) == 1)
+				SKIP_TO_DRAG;
+			    if (dist2(u.ux, u.uy, uball->ox, uball->oy) == 4 &&
+				  dist2(x, y, tempx2, tempy2) == 2)
+				SKIP_TO_DRAG;
+			}
+			*chainx = tempx;
+			*chainy = tempy;
+		    } else if (IS_CHAIN_ROCK(tempx, tempy) &&
+				IS_CHAIN_ROCK(tempx2, tempy2) &&
+				!already_in_rock) {
+			SKIP_TO_DRAG;
+		    } else if (dist2(tempx, tempy, uchain->ox, uchain->oy) <
 			 dist2(tempx2, tempy2, uchain->ox, uchain->oy) ||
 		       ((dist2(tempx, tempy, uchain->ox, uchain->oy) ==
 			 dist2(tempx2, tempy2, uchain->ox, uchain->oy)) && rn2(2))) {
@@ -428,8 +500,10 @@
 		case 4:
 		    if (CHAIN_IN_MIDDLE(uchain->ox, uchain->oy))
 			break;
-		    *chainx = (x + uchain->ox)/2;
-		    *chainy = (y + uchain->oy)/2;
+		    *chainx = (x + uball->ox)/2;
+		    *chainy = (y + uball->oy)/2;
+		    if (IS_CHAIN_ROCK(*chainx, *chainy) && !already_in_rock)
+			SKIP_TO_DRAG;
 		    break;
 		
 		/* ball is one space diagonal from player.  Check for the
@@ -447,6 +521,8 @@
 			    *chainx = uball->ox;
 			else
 			    *chainy = uball->oy;
+			if (IS_CHAIN_ROCK(*chainx, *chainy) && !already_in_rock)
+			    SKIP_TO_DRAG;
 			break;
 		    }
 		    /* fall through */
@@ -470,11 +546,15 @@
 		default: impossible("bad chain movement");
 		    break;
 	    }
+#undef SKIP_TO_DRAG
+#undef IS_CHAIN_ROCK
 #undef CHAIN_IN_MIDDLE
 	    return TRUE;
 	}
 
-	if (near_capacity() > SLT_ENCUMBER) {
+drag:
+
+	if (near_capacity() > SLT_ENCUMBER && dist2(x, y, u.ux, u.uy) <= 2) {
 	    You("cannot %sdrag the heavy iron ball.",
 			    invent ? "carry all that and also " : "");
 	    nomul(0);
@@ -527,13 +607,25 @@
 	    }
 	}
 
-	*bc_control = BC_BALL|BC_CHAIN;;
+	*bc_control = BC_BALL|BC_CHAIN;
 
 	move_bc(1, *bc_control, *ballx, *bally, *chainx, *chainy);
-	*ballx  = uchain->ox;
-	*bally  = uchain->oy;
-	*chainx = u.ux;
-	*chainy = u.uy;
+	if (dist2(x, y, u.ux, u.uy) > 2) {
+	    /* Awful case: we're still in range of the ball, so we thought we
+	     * could only move the chain, but it turned out that the target
+	     * square for the chain was rock, so we had to drag it instead.
+	     * But we can't drag it either, because we teleported and are more
+	     * than one square from our old position.  Revert to the teleport
+	     * behavior.
+	     */
+	    *ballx = *chainx = x;
+	    *bally = *chainy = y;
+	} else {
+	    *ballx  = uchain->ox;
+	    *bally  = uchain->oy;
+	    *chainx = u.ux;
+	    *chainy = u.uy;
+	}
 	*cause_delay = TRUE;
 	return TRUE;
 }
diff -Naurd ../nethack-3.4.0/src/bones.c ./src/bones.c
--- ../nethack-3.4.0/src/bones.c Wed Mar 20 23:43:00 2002
+++ ./src/bones.c Mon Feb 24 15:25:05 2003
@@ -165,6 +165,9 @@
 	    return FALSE;
 	if (no_bones_level(&u.uz))
 	    return FALSE;		/* no bones for specific levels */
+	if (u.uswallow) {
+	    return FALSE;		/* no bones when swallowed */
+	}
 	if (!Is_branchlev(&u.uz)) {
 	    /* no bones on non-branches with portals */
 	    for(ttmp = ftrap; ttmp; ttmp = ttmp->ntrap)
@@ -194,9 +197,11 @@
 	struct permonst *mptr;
 	struct fruit *f;
 	char c, *bonesid;
+	char whynot[BUFSZ];
 
 	/* caller has already checked `can_make_bones()' */
 
+	clear_bypasses();
 	fd = open_bonesfile(&u.uz, &bonesid);
 	if (fd >= 0) {
 		(void) close(fd);
@@ -308,12 +313,16 @@
 	    levl[x][y].glyph = cmap_to_glyph(S_stone);
 	}
 
-	fd = create_bonesfile(&u.uz, &bonesid);
+	fd = create_bonesfile(&u.uz, &bonesid, whynot);
 	if(fd < 0) {
 #ifdef WIZARD
 		if(wizard)
-			pline("Cannot create bones file - create failed");
+			pline("%s", whynot);
 #endif
+		/* bones file creation problems are silent to the player.
+		 * Keep it that way, but place a clue into the paniclog.
+		 */
+		paniclog("savebones", whynot);
 		return;
 	}
 	c = (char) (strlen(bonesid) + 1);
@@ -397,15 +406,18 @@
 #endif
 		mread(fd, (genericptr_t) &c, sizeof c);	/* length incl. '\0' */
 		mread(fd, (genericptr_t) oldbonesid, (unsigned) c); /* DD.nnn */
-		if (strcmp(bonesid, oldbonesid)) {
+		if (strcmp(bonesid, oldbonesid) != 0) {
+			char errbuf[BUFSZ];
+
+			Sprintf(errbuf, "This is bones level '%s', not '%s'!",
+				oldbonesid, bonesid);
 #ifdef WIZARD
 			if (wizard) {
-				pline("This is bones level '%s', not '%s'!",
-					oldbonesid, bonesid);
+				pline("%s", errbuf);
 				ok = FALSE;	/* won't die of trickery */
 			}
 #endif
-			trickery();
+			trickery(errbuf);
 		} else {
 			register struct monst *mtmp;
 			int mndx;
diff -Naurd ../nethack-3.4.0/src/botl.c ./src/botl.c
--- ../nethack-3.4.0/src/botl.c Wed Mar 20 23:43:01 2002
+++ ./src/botl.c Mon Feb 24 15:25:05 2003
@@ -7,7 +7,7 @@
 #ifdef OVL0
 extern const char *hu_stat[];	/* defined in eat.c */
 
-const char *enc_stat[] = {
+const char * const enc_stat[] = {
 	"",
 	"Burdened",
 	"Stressed",
@@ -45,7 +45,8 @@
 #ifdef OVL1
 
 /* convert experience level (1..30) to rank index (0..8) */
-int xlev_to_rank(xlev)
+int
+xlev_to_rank(xlev)
 int xlev;
 {
 	return (xlev <= 2) ? 0 : (xlev <= 30) ? ((xlev + 2) / 4) : 8;
@@ -53,7 +54,8 @@
 
 #if 0	/* not currently needed */
 /* convert rank index (0..8) to experience level (1..30) */
-int rank_to_xlev(rank)
+int
+rank_to_xlev(rank)
 int rank;
 {
 	return (rank <= 0) ? 1 : (rank <= 8) ? ((rank * 4) - 2) : 30;
@@ -254,7 +256,7 @@
 	if(hp < 0) hp = 0;
 	(void) describe_level(newbot2);
 	Sprintf(nb = eos(newbot2),
-		"%c:%-2ld HP:%d(%d) Pw:%d(%d) AC:%-2d", oc_syms[GOLD_CLASS],
+		"%c:%-2ld HP:%d(%d) Pw:%d(%d) AC:%-2d", oc_syms[COIN_CLASS],
 #ifndef GOLDOBJ
 		u.ugold,
 #else
diff -Naurd ../nethack-3.4.0/src/cmd.c ./src/cmd.c
--- ../nethack-3.4.0/src/cmd.c Wed Mar 20 23:43:01 2002
+++ ./src/cmd.c Mon Feb 24 15:25:05 2003
@@ -22,7 +22,7 @@
  * module you are trying to debug) or things are going to get rather
  * hard to link :-)
  */
-extern void NDECL(wiz_debug_cmd);
+extern int NDECL(wiz_debug_cmd);
 #endif
 
 #ifdef DUMB	/* stuff commented out in extern.h, but needed here */
@@ -115,6 +115,7 @@
 STATIC_PTR int NDECL(wiz_genesis);
 STATIC_PTR int NDECL(wiz_where);
 STATIC_PTR int NDECL(wiz_detect);
+STATIC_PTR int NDECL(wiz_panic);
 STATIC_PTR int NDECL(wiz_polyself);
 STATIC_PTR int NDECL(wiz_level_tele);
 STATIC_PTR int NDECL(wiz_level_change);
@@ -131,14 +132,18 @@
 STATIC_DCL void FDECL(mon_chain, (winid, const char *, struct monst *, long *, long *));
 STATIC_DCL void FDECL(contained, (winid, const char *, long *, long *));
 STATIC_PTR int NDECL(wiz_show_stats);
+#  ifdef PORT_DEBUG
+STATIC_DCL int NDECL(wiz_port_debug);
+#  endif
 # endif
 STATIC_PTR int NDECL(enter_explore_mode);
 STATIC_PTR int NDECL(doattributes);
 STATIC_PTR int NDECL(doconduct); /**/
-STATIC_PTR void NDECL(minimal_enlightenment);
+STATIC_PTR boolean NDECL(minimal_enlightenment);
 
 #ifdef OVLB
 STATIC_DCL void FDECL(enlght_line, (const char *,const char *,const char *));
+STATIC_DCL char *FDECL(enlght_combatinc, (const char *,int,int,char *));
 #ifdef UNIX
 static void NDECL(end_of_input);
 #endif
@@ -147,6 +152,7 @@
 static const char* readchar_queue="";
 
 STATIC_DCL char *NDECL(parse);
+STATIC_DCL boolean FDECL(help_dir, (CHAR_P,const char *));
 
 #ifdef OVL1
 
@@ -435,6 +441,7 @@
 }
 #endif
 
+/* #monster command - use special monster ability while polymorphed */
 STATIC_PTR int
 domonability()
 {
@@ -484,6 +491,8 @@
 }
 
 #ifdef WIZARD
+
+/* ^W command - wish for something */
 STATIC_PTR int
 wiz_wish()	/* Unlimited wishes for debug mode by Paul Polderman */
 {
@@ -499,6 +508,7 @@
 	return 0;
 }
 
+/* ^I command - identify hero's inventory */
 STATIC_PTR int
 wiz_identify()
 {
@@ -507,23 +517,29 @@
 	return 0;
 }
 
-/* reveal the level map and any traps on it */
+/* ^F command - reveal the level map and any traps on it */
 STATIC_PTR int
 wiz_map()
 {
 	if (wizard) {
 	    struct trap *t;
+	    long save_Hconf = HConfusion,
+		 save_Hhallu = HHallucination;
 
+	    HConfusion = HHallucination = 0L;
 	    for (t = ftrap; t != 0; t = t->ntrap) {
 		t->tseen = 1;
 		map_trap(t, TRUE);
 	    }
 	    do_mapping();
+	    HConfusion = save_Hconf;
+	    HHallucination = save_Hhallu;
 	} else
 	    pline("Unavailable command '^F'.");
 	return 0;
 }
 
+/* ^G command - generate monster(s); a count prefix will be honored */
 STATIC_PTR int
 wiz_genesis()
 {
@@ -532,6 +548,7 @@
 	return 0;
 }
 
+/* ^O command - display dungeon layout */
 STATIC_PTR int
 wiz_where()
 {
@@ -540,6 +557,7 @@
 	return 0;
 }
 
+/* ^E command - detect unseen (secret doors, traps, hidden monsters) */
 STATIC_PTR int
 wiz_detect()
 {
@@ -548,6 +566,7 @@
 	return 0;
 }
 
+/* ^V command - level teleport */
 STATIC_PTR int
 wiz_level_tele()
 {
@@ -556,6 +575,7 @@
 	return 0;
 }
 
+/* #monpolycontrol command - choose new form for shapechangers, polymorphees */
 STATIC_PTR int
 wiz_mon_polycontrol()
 {
@@ -565,6 +585,7 @@
     return 0;
 }
 
+/* #levelchange command - adjust hero's experience level */
 STATIC_PTR int
 wiz_level_change()
 {
@@ -590,7 +611,7 @@
 	}
 	if (newlevel < 1) newlevel = 1;
 	while (u.ulevel > newlevel)
-	    losexp((const char *)0);
+	    losexp("#levelchange");
     } else {
 	if (u.ulevel >= MAXULEV) {
 	    You("are already as experienced as you can get.");
@@ -604,6 +625,16 @@
     return 0;
 }
 
+/* #panic command - test program's panic handling */
+STATIC_PTR int
+wiz_panic()
+{
+	if (yn("Do you want to call panic() and end your game?") == 'y')
+		panic("crash test.");
+        return 0;
+}
+
+/* #polyself command - change hero's form */
 STATIC_PTR int
 wiz_polyself()
 {
@@ -611,6 +642,7 @@
         return 0;
 }
 
+/* #seenv command */
 STATIC_PTR int
 wiz_show_seenv()
 {
@@ -652,6 +684,7 @@
 	return 0;
 }
 
+/* #vision command */
 STATIC_PTR int
 wiz_show_vision()
 {
@@ -688,6 +721,7 @@
 	return 0;
 }
 
+/* #wmode command */
 STATIC_PTR int
 wiz_show_wmodes()
 {
@@ -725,13 +759,13 @@
 /* -enlightenment and conduct- */
 static winid en_win;
 static const char
-	*You_ = "You ",
-	*are  = "are ",  *were  = "were ",
-	*have = "have ", *had   = "had ",
-	*can  = "can ",  *could = "could ";
+	You_[] = "You ",
+	are[]  = "are ",  were[]  = "were ",
+	have[] = "have ", had[]   = "had ",
+	can[]  = "can ",  could[] = "could ";
 static const char
-	*have_been  = "have been ",
-	*have_never = "have never ", *never = "never ";
+	have_been[]  = "have been ",
+	have_never[] = "have never ", never[] = "never ";
 
 #define enl_msg(prefix,present,past,suffix) \
 			enlght_line(prefix, final ? past : present, suffix)
@@ -752,6 +786,43 @@
 	putstr(en_win, 0, buf);
 }
 
+/* format increased damage or chance to hit */
+static char *
+enlght_combatinc(inctyp, incamt, final, outbuf)
+const char *inctyp;
+int incamt, final;
+char *outbuf;
+{
+	char numbuf[24];
+	const char *modif, *bonus;
+
+	if (final
+#ifdef WIZARD
+		|| wizard
+#endif
+	  ) {
+	    Sprintf(numbuf, "%s%d",
+		    (incamt > 0) ? "+" : "", incamt);
+	    modif = (const char *) numbuf;
+	} else {
+	    int absamt = abs(incamt);
+
+	    if (absamt <= 3) modif = "small";
+	    else if (absamt <= 6) modif = "moderate";
+	    else if (absamt <= 12) modif = "large";
+	    else modif = "huge";
+	}
+	bonus = (incamt > 0) ? "bonus" : "penalty";
+	/* "bonus to hit" vs "damage bonus" */
+	if (!strcmp(inctyp, "damage")) {
+	    const char *ctmp = inctyp;
+	    inctyp = bonus;
+	    bonus = ctmp;
+	}
+	Sprintf(outbuf, "%s %s %s", an(modif), bonus, inctyp);
+	return outbuf;
+}
+
 void
 enlightenment(final)
 int final;	/* 0 => still in progress; 1 => over, survived; 2 => dead */
@@ -765,7 +836,7 @@
 
 #ifdef ELBERETH
 	if (u.uevent.uhand_of_elbereth) {
-	    static const char *hofe_titles[3] = {
+	    static const char * const hofe_titles[3] = {
 				"the Hand of Elbereth",
 				"the Envoy of Balance",
 				"the Glory of Arioch"
@@ -822,18 +893,6 @@
 			if (u.usick_type & SICK_NONVOMITABLE)
 				you_are("sick from illness");
 		}
-		/* added by JDS */
-		if (u.uhitinc) {
-			Sprintf(buf, "%s%i %s to hit", u.uhitinc > 0 ? "+" : "",
-				u.uhitinc, u.uhitinc > 0 ? "bonus" : "penalty");
-			you_have(buf);
-			
-		}
-		if (u.udaminc) {
-			Sprintf(buf, "%s%i %s to damage", u.udaminc > 0 ? "+" : "",
-				u.udaminc, u.udaminc > 0 ? "bonus" : "penalty");
-			you_have(buf);
-		} /* end JDS portion */
 	}
 	if (Stoned) you_are("turning to stone");
 	if (Slimed) you_are("turning into slime");
@@ -881,7 +940,16 @@
 	if (u.umconf) you_are("going to confuse monsters");
 
 	/*** Appearance and behavior ***/
-	if (Adornment) you_are("adorned");
+	if (Adornment) {
+	    int adorn = 0;
+
+	    if(uleft && uleft->otyp == RIN_ADORNMENT) adorn += uleft->spe;
+	    if(uright && uright->otyp == RIN_ADORNMENT) adorn += uright->spe;
+	    if (adorn < 0)
+		you_are("poorly adorned");
+	    else
+		you_are("adorned");
+	}
 	if (Invisible) you_are("invisible");
 	else if (Invis) you_are("invisible to others");
 	/* ordinarily "visible" is redundant; this is a special case for
@@ -906,7 +974,10 @@
 	else if (Amphibious) you_can("breathe water");
 	if (Passes_walls) you_can("walk through walls");
 #ifdef STEED
-	if (u.usteed) {
+	/* If you die while dismounting, u.usteed is still set.  Since several
+	 * places in the done() sequence depend on u.usteed, just detect this
+	 * special case. */
+	if (u.usteed && (final < 2 || strcmp(killer, "riding accident"))) {
 	    Sprintf(buf, "riding %s", y_monnam(u.usteed));
 	    you_are(buf);
 	}
@@ -925,9 +996,25 @@
 	}
 
 	/*** Physical attributes ***/
+	if (u.uhitinc)
+	    you_have(enlght_combatinc("to hit", u.uhitinc, final, buf));
+	if (u.udaminc)
+	    you_have(enlght_combatinc("damage", u.udaminc, final, buf));
 	if (Slow_digestion) you_have("slower digestion");
 	if (Regeneration) enl_msg("You regenerate", "", "d", "");
-	if (u.uspellprot || Protection) you_are("protected");
+	if (u.uspellprot || Protection) {
+	    int prot = 0;
+
+	    if(uleft && uleft->otyp == RIN_PROTECTION) prot += uleft->spe;
+	    if(uright && uright->otyp == RIN_PROTECTION) prot += uright->spe;
+	    if (HProtection & INTRINSIC) prot += u.ublessed;
+	    prot += u.uspellprot;
+
+	    if (prot < 0)
+		you_are("ineffectively protected");
+	    else
+		you_are("protected");
+	}
 	if (Protection_from_shape_changers)
 		you_are("protected from shape changers");
 	if (Polymorph) you_are("polymorphing");
@@ -937,7 +1024,7 @@
 		you_are(buf);
 	}
 	if (Upolyd) {
-	    if (u.ulycn >= LOW_PM) Strcpy(buf, "in beast form");
+	    if (u.umonnum == u.ulycn) Strcpy(buf, "in beast form");
 	    else Sprintf(buf, "polymorphed into %s", an(youmonst.data->mname));
 #ifdef WIZARD
 	    if (wizard) Sprintf(eos(buf), " (%d)", u.mtimedone);
@@ -1039,16 +1126,18 @@
 /*
  * Courtesy function for non-debug, non-explorer mode players
  * to help refresh them about who/what they are.
+ * Returns FALSE if menu cancelled (dismissed with ESC), TRUE otherwise.
  */
-STATIC_OVL void
+STATIC_OVL boolean
 minimal_enlightenment()
 {
 	winid tmpwin;
 	menu_item *selected;
 	anything any;
+	int genidx, n;
 	char buf[BUFSZ], buf2[BUFSZ];
-	static char fmtstr[] = "%-15s: %-12s";
-	static char deity_fmtstr[] = "%-17s%s";
+	static const char fmtstr[] = "%-15s: %-12s";
+	static const char deity_fmtstr[] = "%-17s%s";
 
 	any.a_void = 0;
 	buf[0] = buf2[0] = '\0';
@@ -1085,10 +1174,11 @@
 		(flags.female && urole.name.f) ? urole.name.f : urole.name.m);
 	    add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
 	}
-	Sprintf(buf, fmtstr, "gender", genders[poly_gender()].adj);
+	/* don't want poly_gender() here; it forces `2' for non-humanoids */
+	genidx = is_neuter(youmonst.data) ? 2 : flags.female;
+	Sprintf(buf, fmtstr, "gender", genders[genidx].adj);
 	add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
-
-	if (Upolyd) {
+	if (Upolyd && (int)u.mfemale != genidx) {
 	    Sprintf(buf, fmtstr, "gender (base)", genders[u.mfemale].adj);
 	    add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
 	}
@@ -1105,7 +1195,7 @@
 		&& u.ualign.type == A_CHAOTIC) ? " (s,c)" :
 	    (u.ualignbase[A_ORIGINAL] == A_CHAOTIC)       ? " (s)" :
 	    (u.ualign.type   == A_CHAOTIC)       ? " (c)" : "");
-    	Sprintf(buf, fmtstr, "chaotic deity", buf2);
+	Sprintf(buf, fmtstr, "Chaotic", buf2);
 	add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
 
 	Sprintf(buf2, deity_fmtstr, align_gname(A_NEUTRAL),
@@ -1113,25 +1203,28 @@
 		&& u.ualign.type == A_NEUTRAL) ? " (s,c)" :
 	    (u.ualignbase[A_ORIGINAL] == A_NEUTRAL)       ? " (s)" :
 	    (u.ualign.type   == A_NEUTRAL)       ? " (c)" : "");
-    	Sprintf(buf, fmtstr, "neutral deity", buf2);
+	Sprintf(buf, fmtstr, "Neutral", buf2);
 	add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
 
 	Sprintf(buf2, deity_fmtstr, align_gname(A_LAWFUL),
-	    (u.ualignbase[A_ORIGINAL] == u.ualign.type && u.ualign.type == A_LAWFUL)  ? " (s,c)" :
+	    (u.ualignbase[A_ORIGINAL] == u.ualign.type &&
+		u.ualign.type == A_LAWFUL)  ? " (s,c)" :
 	    (u.ualignbase[A_ORIGINAL] == A_LAWFUL)        ? " (s)" :
 	    (u.ualign.type   == A_LAWFUL)        ? " (c)" : "");
-    	Sprintf(buf, fmtstr, "lawful  deity", buf2);
+	Sprintf(buf, fmtstr, "Lawful", buf2);
 	add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
 
 	end_menu(tmpwin, "Base Attributes");
-	(void) select_menu(tmpwin, PICK_NONE, &selected);
+	n = select_menu(tmpwin, PICK_NONE, &selected);
 	destroy_nhwindow(tmpwin);
+	return (n != -1);
 }
 
 STATIC_PTR int
 doattributes()
 {
-	minimal_enlightenment();
+	if (!minimal_enlightenment())
+		return 0;
 	if (wizard || discover)
 		enlightenment(0);
 	return 0;
@@ -1409,6 +1502,10 @@
 	{(char *)0, (char *)0, donull, TRUE},
 	{(char *)0, (char *)0, donull, TRUE},
 	{(char *)0, (char *)0, donull, TRUE},
+#ifdef PORT_DEBUG
+	{(char *)0, (char *)0, donull, TRUE},
+#endif
+	{(char *)0, (char *)0, donull, TRUE},
         {(char *)0, (char *)0, donull, TRUE},
 	{(char *)0, (char *)0, donull, TRUE},
 	{(char *)0, (char *)0, donull, TRUE},
@@ -1423,9 +1520,13 @@
 #if defined(WIZARD)
 static const struct ext_func_tab debug_extcmdlist[] = {
 	{"levelchange", "change experience level", wiz_level_change, TRUE},
-	{"light sources", "show mobile light sources", wiz_light_sources, TRUE},
-	{"monpoly_control", "control monster polymorphs", wiz_mon_polycontrol, TRUE},
-	{"poly", "polymorph self", wiz_polyself, TRUE},
+	{"lightsources", "show mobile light sources", wiz_light_sources, TRUE},
+	{"monpolycontrol", "control monster polymorphs", wiz_mon_polycontrol, TRUE},
+	{"panic", "test panic routine (fatal to game)", wiz_panic, TRUE},
+	{"polyself", "polymorph self", wiz_polyself, TRUE},
+#ifdef PORT_DEBUG
+	{"portdebug", "wizard port debug command", wiz_port_debug, TRUE},
+#endif
 	{"seenv", "show seen vectors", wiz_show_seenv, TRUE},
 	{"stats", "show memory statistics", wiz_show_stats, TRUE},
 	{"timeout", "look at timeout queue", wiz_timeout_queue, TRUE},
@@ -1466,9 +1567,9 @@
 }
 
 
-static const char *template = "%-18s %4ld  %6ld";
-static const char *count_str = "                   count  bytes";
-static const char *separator = "------------------ -----  ------";
+static const char template[] = "%-18s %4ld  %6ld";
+static const char count_str[] = "                   count  bytes";
+static const char separator[] = "------------------ -----  ------";
 
 STATIC_OVL void
 count_obj(chain, total_count, total_size, top, recurse)
@@ -1661,6 +1762,7 @@
 	boolean do_walk, do_rush, prefix_seen, bad_command,
 		firsttime = (cmd == 0);
 
+	iflags.menu_requested = FALSE;
 	if (firsttime) {
 		flags.nopick = 0;
 		cmd = parse();
@@ -1738,12 +1840,16 @@
 		    multi = 0;
 		    return;
 	 case CMD_TRAVEL:
-		    flags.travel = 1;
-		    flags.run = 8;
-		    flags.nopick = 1;
-		    do_rush = TRUE;
-		    break;
+		    if (iflags.travelcmd) {
+			    flags.travel = 1;
+			    flags.run = 8;
+			    flags.nopick = 1;
+			    do_rush = TRUE;
+			    break;
+		    }
+		    /*FALLTHRU*/
 	 default:   if (movecmd(*cmd)) {	/* ordinary movement */
+			flags.run = 0;	/* only matters here if it was 8 */
 			do_walk = TRUE;
 		    } else if (movecmd(iflags.num_pad ?
 				       unmeta(*cmd) : lowc(*cmd))) {
@@ -1755,6 +1861,14 @@
 		    }
 		    break;
 	}
+
+	/* some special prefix handling */
+	/* overload 'm' prefix for ',' to mean "request a menu" */
+	if (prefix_seen && cmd[1] == ',') {
+		iflags.menu_requested = TRUE;
+		++cmd;
+	}
+
 	if (do_walk) {
 	    if (multi) flags.mv = TRUE;
 	    domove();
@@ -1820,7 +1934,9 @@
 		}
 	    }
 	    *cp = '\0';
-	    Norep("Unknown command '%s'.", expcmd);
+	    if (!prefix_seen || !iflags.cmdassist ||
+		!help_dir(0, "Invalid direction key!"))
+		Norep("Unknown command '%s'.", expcmd);
 	}
 	/* didn't move */
 	flags.move = FALSE;
@@ -1870,6 +1986,38 @@
 	return !u.dz;
 }
 
+/*
+ * uses getdir() but unlike getdir() it specifically
+ * produces coordinates using the direction from getdir()
+ * and verifies that those coordinates are ok.
+ *
+ * If the call to getdir() returns 0, Never_mind is displayed.
+ * If the resulting coordinates are not okay, emsg is displayed.
+ *
+ * Returns non-zero if coordinates in cc are valid.
+ */
+int get_adjacent_loc(prompt,emsg,x,y,cc)
+const char *prompt, *emsg;
+xchar x,y;
+coord *cc;
+{
+	xchar new_x, new_y;
+	if (!getdir(prompt)) {
+		pline(Never_mind);
+		return 0;
+	}
+	new_x = x + u.dx;
+	new_y = y + u.dy;
+	if (cc && isok(new_x,new_y)) {
+		cc->x = new_x;
+		cc->y = new_y;
+	} else {
+		if (emsg) pline(emsg);
+		return 0;
+	}
+	return 1;
+}
+
 int
 getdir(s)
 const char *s;
@@ -1881,7 +2029,7 @@
 	    dirsym = readchar();
 	else
 #endif
-	    dirsym = yn_function (s ? s : "In what direction?",
+	    dirsym = yn_function ((s && *s != '^') ? s : "In what direction?",
 					(char *)0, '\0');
 #ifdef REDO
 	savech(dirsym);
@@ -1889,14 +2037,86 @@
 	if(dirsym == '.' || dirsym == 's')
 		u.dx = u.dy = u.dz = 0;
 	else if(!movecmd(dirsym) && !u.dz) {
-		if(!index(quitchars, dirsym))
-			pline("What a strange direction!");
+		boolean did_help = FALSE;
+		if(!index(quitchars, dirsym)) {
+		    if (iflags.cmdassist) {
+			did_help = help_dir((s && *s == '^') ? dirsym : 0,
+					    "Invalid direction key!");
+		    }
+		    if (!did_help) pline("What a strange direction!");
+		}
 		return 0;
 	}
 	if(!u.dz && (Stunned || (Confusion && !rn2(5)))) confdir();
 	return 1;
 }
 
+STATIC_OVL boolean
+help_dir(sym, msg)
+char sym;
+const char *msg;
+{
+	char ctrl;
+	winid win;
+	static const char wiz_only_list[] = "EFGIOVW";
+	char buf[BUFSZ], buf2[BUFSZ], *expl;
+
+	win = create_nhwindow(NHW_TEXT);
+	if (!win) return FALSE;
+	if (msg) {
+		Sprintf(buf, "cmdassist: %s", msg);
+		putstr(win, 0, buf);
+		putstr(win, 0, "");
+	}
+	if (letter(sym)) { 
+	    sym = highc(sym);
+	    ctrl = (sym - 'A') + 1;
+	    if ((expl = dowhatdoes_core(ctrl, buf2))
+		&& (!index(wiz_only_list, sym)
+#ifdef WIZARD
+		    || wizard
+#endif
+	                     )) {
+		Sprintf(buf, "Are you trying to use ^%c%s?", sym,
+			index(wiz_only_list, sym) ? "" :
+			" as specified in the Guidebook");
+		putstr(win, 0, buf);
+		putstr(win, 0, "");
+		putstr(win, 0, expl);
+		putstr(win, 0, "");
+		putstr(win, 0, "To use that command, you press");
+		Sprintf(buf,
+			"the <Ctrl> key, and the <%c> key at the same time.", sym);
+		putstr(win, 0, buf);
+		putstr(win, 0, "");
+	    }
+	}
+	if (iflags.num_pad) {
+		putstr(win, 0, "Valid direction keys (with number_pad on) are:");
+		putstr(win, 0, "          7  8  9");
+		putstr(win, 0, "           \\ | / ");
+		putstr(win, 0, "          4- . -6");
+		putstr(win, 0, "           / | \\ ");
+		putstr(win, 0, "          1  2  3");
+	} else {
+		putstr(win, 0, "Valid direction keys are:");
+		putstr(win, 0, "          y  k  u");
+		putstr(win, 0, "           \\ | / ");
+		putstr(win, 0, "          h- . -l");
+		putstr(win, 0, "           / | \\ ");
+		putstr(win, 0, "          b  j  n");
+	};
+	putstr(win, 0, "");
+	putstr(win, 0, "          <  up");
+	putstr(win, 0, "          >  down");
+	putstr(win, 0, "          .  direct at yourself");
+	putstr(win, 0, "");
+	putstr(win, 0, "(Suppress this message with !cmdassist in config file.)");
+	display_nhwindow(win, FALSE);
+	destroy_nhwindow(win);
+	return TRUE;
+}
+
 #endif /* OVL1 */
 #ifdef OVLB
 
@@ -1936,62 +2156,81 @@
     x -= u.ux;
     y -= u.uy;
 
-    if ( abs(x) <= 1 && abs(y) <= 1 ) {
-	x = sgn(x), y = sgn(y);
-    } else {
-	u.tx = u.ux+x;
-	u.ty = u.uy+y;
-	cmd[0] = CMD_TRAVEL;
-	return cmd;
-    }
+    if (iflags.travelcmd) {
+        if (abs(x) <= 1 && abs(y) <= 1 ) {
+            x = sgn(x), y = sgn(y);
+        } else {
+            u.tx = u.ux+x;
+            u.ty = u.uy+y;
+            cmd[0] = CMD_TRAVEL;
+            return cmd;
+        }
 
-    if(x == 0 && y == 0) {
-	/* here */
-	if(IS_FOUNTAIN(levl[u.ux][u.uy].typ) || IS_SINK(levl[u.ux][u.uy].typ)) {
-	    cmd[0]=mod == CLICK_1 ? 'q' : M('d');
-	    return cmd;
-	} else if(IS_THRONE(levl[u.ux][u.uy].typ)) {
-	    cmd[0]=M('s');
-	    return cmd;
-	} else if((u.ux == xupstair && u.uy == yupstair)
-		  || (u.ux == sstairs.sx && u.uy == sstairs.sy && sstairs.up)
-		  || (u.ux == xupladder && u.uy == yupladder)) {
-	    return "<";
-	} else if((u.ux == xdnstair && u.uy == ydnstair)
-		  || (u.ux == sstairs.sx && u.uy == sstairs.sy && !sstairs.up)
-		  || (u.ux == xdnladder && u.uy == ydnladder)) {
-	    return ">";
-	} else if(OBJ_AT(u.ux, u.uy)) {
-	    cmd[0] = Is_container(level.objects[u.ux][u.uy]) ? M('l') : ',';
-	    return cmd;
-	} else {
-	    return "."; /* just rest */
-	}
-    }
+        if(x == 0 && y == 0) {
+            /* here */
+            if(IS_FOUNTAIN(levl[u.ux][u.uy].typ) || IS_SINK(levl[u.ux][u.uy].typ)) {
+                cmd[0]=mod == CLICK_1 ? 'q' : M('d');
+                return cmd;
+            } else if(IS_THRONE(levl[u.ux][u.uy].typ)) {
+                cmd[0]=M('s');
+                return cmd;
+            } else if((u.ux == xupstair && u.uy == yupstair)
+                      || (u.ux == sstairs.sx && u.uy == sstairs.sy && sstairs.up)
+                      || (u.ux == xupladder && u.uy == yupladder)) {
+                return "<";
+            } else if((u.ux == xdnstair && u.uy == ydnstair)
+                      || (u.ux == sstairs.sx && u.uy == sstairs.sy && !sstairs.up)
+                      || (u.ux == xdnladder && u.uy == ydnladder)) {
+                return ">";
+            } else if(OBJ_AT(u.ux, u.uy)) {
+                cmd[0] = Is_container(level.objects[u.ux][u.uy]) ? M('l') : ',';
+                return cmd;
+            } else {
+                return "."; /* just rest */
+            }
+        }
 
-    /* directional commands */
+        /* directional commands */
 
-    dir = xytod(x, y);
+        dir = xytod(x, y);
 
-    if (!m_at(u.ux+x, u.uy+y) && !test_move(u.ux, u.uy, x, y, 1)) {
-	cmd[1] = (iflags.num_pad ? ndir[dir] : sdir[dir]);
-	cmd[2] = 0;
-	if (IS_DOOR(levl[u.ux+x][u.uy+y].typ)) {
-	    /* slight assistance to the player: choose kick/open for them */
-	    if (levl[u.ux+x][u.uy+y].doormask & D_LOCKED) {
-		cmd[0] = C('d');
-		return cmd;
-	    }
-	    if (levl[u.ux+x][u.uy+y].doormask & D_CLOSED) {
-		cmd[0] = 'o';
-		return cmd;
-	    }
-	}
-	if (levl[u.ux+x][u.uy+y].typ <= SCORR) {
-	    cmd[0] = 's';
-	    cmd[1] = 0;
-	    return cmd;
-	}
+	if (!m_at(u.ux+x, u.uy+y) && !test_move(u.ux, u.uy, x, y, TEST_MOVE)) {
+            cmd[1] = (iflags.num_pad ? ndir[dir] : sdir[dir]);
+            cmd[2] = 0;
+            if (IS_DOOR(levl[u.ux+x][u.uy+y].typ)) {
+                /* slight assistance to the player: choose kick/open for them */
+                if (levl[u.ux+x][u.uy+y].doormask & D_LOCKED) {
+                    cmd[0] = C('d');
+                    return cmd;
+                }
+                if (levl[u.ux+x][u.uy+y].doormask & D_CLOSED) {
+                    cmd[0] = 'o';
+                    return cmd;
+                }
+            }
+            if (levl[u.ux+x][u.uy+y].typ <= SCORR) {
+                cmd[0] = 's';
+                cmd[1] = 0;
+                return cmd;
+            }
+        }
+    } else {
+        /* convert without using floating point, allowing sloppy clicking */
+        if(x > 2*abs(y))
+            x = 1, y = 0;
+        else if(y > 2*abs(x))
+            x = 0, y = 1;
+        else if(x < -2*abs(y))
+            x = -1, y = 0;
+        else if(y < -2*abs(x))
+            x = 0, y = -1;
+        else
+            x = sgn(x), y = sgn(y);
+
+        if(x == 0 && y == 0)	/* map click on player to "rest" command */
+            return ".";
+
+        dir = xytod(x, y);
     }
 
     /* move, attack, etc. */
@@ -2142,6 +2381,8 @@
 	/* Keyboard travel command */
 	static char cmd[2];
 	coord cc;
+
+	if (!iflags.travelcmd) return 0;
 	cmd[1]=0;
 	cc.x = u.ux;
 	cc.y = u.uy;
@@ -2157,6 +2398,54 @@
 	return 0;
 }
 
+#ifdef PORT_DEBUG
+# ifdef WIN32CON
+extern void NDECL(win32con_debug_keystrokes);
+# endif
+
+int
+wiz_port_debug()
+{
+	int n, k;
+	winid win;
+	anything any;
+	int item = 'a';
+	int num_menu_selections;
+	struct menu_selection_struct {
+		char *menutext;
+		void NDECL((*fn));
+	} menu_selections[] = {
+#ifdef WIN32CON
+		{"test win32 keystrokes", win32con_debug_keystrokes},
+#endif
+		{(char *)0, (void NDECL((*)))0}		/* array terminator */
+	};
+
+	num_menu_selections = SIZE(menu_selections) - 1;
+	if (num_menu_selections > 0) {
+		menu_item *pick_list;
+		win = create_nhwindow(NHW_MENU);
+		start_menu(win);
+		for (k=0; k < num_menu_selections; ++k) {
+			any.a_int = k+1;
+			add_menu(win, NO_GLYPH, &any, item++, 0, ATR_NONE,
+				menu_selections[k].menutext, MENU_UNSELECTED);
+		}
+		end_menu(win, "Which port debugging feature?");
+		n = select_menu(win, PICK_ONE, &pick_list);
+		destroy_nhwindow(win);
+		if (n > 0) {
+			n = pick_list[0].item.a_int - 1;
+			free((genericptr_t) pick_list);
+			/* execute the function */
+			(*menu_selections[n].fn)();
+		}
+	} else
+		pline("No port-specific debug capability defined.");
+	return 0;
+}
+# endif /*PORT_DEBUG*/
+
 #endif /* OVL0 */
 
 /*cmd.c*/
diff -Naurd ../nethack-3.4.0/src/dbridge.c ./src/dbridge.c
--- ../nethack-3.4.0/src/dbridge.c Wed Mar 20 23:43:01 2002
+++ ./src/dbridge.c Mon Feb 24 15:25:05 2003
@@ -400,7 +400,7 @@
 			    if (enexto(&xy, etmp->ex, etmp->ey, etmp->edata)) {
 				pline("A %s force teleports you away...",
 				      Hallucination ? "normal" : "strange");
-				teleds(xy.x, xy.y);
+				teleds(xy.x, xy.y, FALSE);
 			    }
 			    /* otherwise on top of the drawbridge is the
 			     * only viable spot in the dungeon, so stay there
@@ -531,6 +531,7 @@
 			pline_The("%s passes through %s!",
 			      at_portcullis ? "portcullis" : "drawbridge",
 			      e_nam(etmp));
+		if (is_u(etmp)) spoteffects(FALSE);
 		return;
 	}
 	if (e_missed(etmp, FALSE)) {
diff -Naurd ../nethack-3.4.0/src/decl.c ./src/decl.c
--- ../nethack-3.4.0/src/decl.c Wed Mar 20 23:43:01 2002
+++ ./src/decl.c Mon Feb 24 15:25:05 2003
@@ -261,14 +263,14 @@
 struct tc_gbl_data tc_gbl_data = { 0,0, 0,0 };	/* AS,AE, LI,CO */
 
 char *fqn_prefix[PREFIX_COUNT] = { (char *)0, (char *)0, (char *)0, (char *)0,
-				(char *)0, (char *)0, (char *)0, (char *)0 };
+				(char *)0, (char *)0, (char *)0, (char *)0, (char *)0 };
 
 #ifdef PREFIXES_IN_USE
 char *fqn_prefix_names[PREFIX_COUNT] = { "hackdir", "leveldir", "savedir",
 					"bonesdir", "datadir", "scoredir",
-					"lockdir", "configdir" };
+					"lockdir", "configdir", "troubledir" };
 #endif
-			
+
 /* dummy routine used to force linkage */
 void
 decl_init()
diff -Naurd ../nethack-3.4.0/src/detect.c ./src/detect.c
--- ../nethack-3.4.0/src/detect.c Wed Mar 20 23:43:01 2002
+++ ./src/detect.c Mon Feb 24 15:25:05 2003
@@ -115,7 +115,7 @@
 			/* didn't find it; perhaps a monster is carrying it */
 #ifndef GOLDOBJ
 			if ((mtmp = m_at(x,y)) != 0) {
-				if (oclass == GOLD_CLASS && mtmp->mgold)
+				if (oclass == COIN_CLASS && mtmp->mgold)
 					return FALSE;
 				else for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj)
 					if (o_in(otmp, oclass)) return FALSE;
@@ -169,7 +169,7 @@
     struct obj *temp;
     boolean stale;
 
-    known = stale = clear_stale_map(GOLD_CLASS,
+    known = stale = clear_stale_map(COIN_CLASS,
 				(unsigned)(sobj->blessed ? GOLD : 0));
 
     /* look for gold carried by monsters (might be in a container) */
@@ -186,7 +186,7 @@
 	    if (sobj->blessed && o_material(obj, GOLD)) {
 	    	known = TRUE;
 	    	goto outgoldmap;
-	    } else if (o_in(obj, GOLD_CLASS)) {
+	    } else if (o_in(obj, COIN_CLASS)) {
 		known = TRUE;
 		goto outgoldmap;	/* skip further searching */
 	    }
@@ -197,7 +197,7 @@
 	if (sobj->blessed && o_material(obj, GOLD)) {
 	    known = TRUE;
 	    if (obj->ox != u.ux || obj->oy != u.uy) goto outgoldmap;
-	} else if (o_in(obj, GOLD_CLASS)) {
+	} else if (o_in(obj, COIN_CLASS)) {
 	    known = TRUE;
 	    if (obj->ox != u.ux || obj->oy != u.uy) goto outgoldmap;
 	}
@@ -242,7 +242,7 @@
 		temp->oy = obj->oy;
 	    }
 	    map_object(temp,1);
-	} else if ((temp = o_in(obj, GOLD_CLASS))) {
+	} else if ((temp = o_in(obj, COIN_CLASS))) {
 	    if (temp != obj) {
 		temp->ox = obj->ox;
 		temp->oy = obj->oy;
@@ -269,7 +269,7 @@
 		temp->oy = mtmp->my;
 		map_object(temp,1);
 		break;
-	    } else if ((temp = o_in(obj, GOLD_CLASS))) {
+	    } else if ((temp = o_in(obj, COIN_CLASS))) {
 		temp->ox = mtmp->mx;
 		temp->oy = mtmp->my;
 		map_object(temp,1);
@@ -391,7 +391,7 @@
 }
 
 /*
- * Used for scrolls, potions, and crystal balls.  Returns:
+ * Used for scrolls, potions, spells, and crystal balls.  Returns:
  *
  *	1 - nothing was detected
  *	0 - something was detected
@@ -403,8 +403,9 @@
 {
     register int x, y;
     int is_cursed = (detector && detector->cursed);
-    int do_dknown =
-	(detector && detector->oclass == POTION_CLASS && detector->blessed);
+    int do_dknown = (detector && (detector->oclass == POTION_CLASS ||
+				    detector->oclass == SPBOOK_CLASS) &&
+			detector->blessed);
     int ct = 0, ctu = 0;
     register struct obj *obj, *otmp = (struct obj *)0;
     register struct monst *mtmp;
@@ -448,9 +449,9 @@
 	if ((is_cursed && mtmp->m_ap_type == M_AP_OBJECT &&
 	    (!class || class == objects[mtmp->mappearance].oc_class)) ||
 #ifndef GOLDOBJ
-	    (mtmp->mgold && (!class || class == GOLD_CLASS))) {
+	    (mtmp->mgold && (!class || class == COIN_CLASS))) {
 #else
-	    (findgold(mtmp->minvent) && (!class || class == GOLD_CLASS))) {
+	    (findgold(mtmp->minvent) && (!class || class == COIN_CLASS))) {
 #endif
 	    ct++;
 	    break;
@@ -530,9 +531,9 @@
 	    temp.corpsenm = PM_TENGU;		/* if mimicing a corpse */
 	    map_object(&temp, 1);
 #ifndef GOLDOBJ
-	} else if (mtmp->mgold && (!class || class == GOLD_CLASS)) {
+	} else if (mtmp->mgold && (!class || class == COIN_CLASS)) {
 #else
-	} else if (findgold(mtmp->minvent) && (!class || class == GOLD_CLASS)) {
+	} else if (findgold(mtmp->minvent) && (!class || class == COIN_CLASS)) {
 #endif
 	    struct obj gold;
 
@@ -753,7 +754,7 @@
 	    else	return "near you";
 }
 
-static struct {
+static const struct {
     const char *what;
     d_level *where;
 } level_detects[] = {
diff -Naurd ../nethack-3.4.0/src/dig.c ./src/dig.c
--- ../nethack-3.4.0/src/dig.c Wed Mar 20 23:43:02 2002
+++ ./src/dig.c Mon Feb 24 15:25:05 2003
@@ -13,11 +13,19 @@
 STATIC_DCL boolean NDECL(rm_waslit);
 STATIC_DCL void FDECL(mkcavepos, (XCHAR_P,XCHAR_P,int,BOOLEAN_P,BOOLEAN_P));
 STATIC_DCL void FDECL(mkcavearea, (BOOLEAN_P));
-STATIC_DCL int FDECL(dig_typ, (XCHAR_P,XCHAR_P));
+STATIC_DCL int FDECL(dig_typ, (struct obj *,XCHAR_P,XCHAR_P));
 STATIC_DCL int NDECL(dig);
 STATIC_DCL schar FDECL(fillholetyp, (int, int));
 STATIC_DCL void NDECL(dig_up_grave);
 
+/* Indices returned by dig_typ() */
+#define DIGTYP_UNDIGGABLE 0
+#define DIGTYP_ROCK       1
+#define DIGTYP_STATUE     2
+#define DIGTYP_BOULDER    3
+#define DIGTYP_DOOR       4
+#define DIGTYP_TREE       5
+
 
 STATIC_OVL boolean
 rm_waslit()
@@ -122,16 +130,21 @@
 }
 
 /* When digging into location <x,y>, what are you actually digging into? */
-/* result: 1=>statue, 2=>boulder, 3=>door, 0=>other; used as array index */
-/* KMH -- Added 4=>tree */
 STATIC_OVL int
-dig_typ(x, y)
+dig_typ(otmp, x, y)
+struct obj *otmp;
 xchar x, y;
 {
-	return (sobj_at(STATUE, x, y) ? 1 :
-		sobj_at(BOULDER, x, y) ? 2 :
-		closed_door(x, y) ? 3 :
-		IS_TREE(levl[x][y].typ) ? 4: 0);
+	boolean ispick = is_pick(otmp);
+
+	return (ispick && sobj_at(STATUE, x, y) ? DIGTYP_STATUE :
+		ispick && sobj_at(BOULDER, x, y) ? DIGTYP_BOULDER :
+		closed_door(x, y) ? DIGTYP_DOOR :
+		IS_TREE(levl[x][y].typ) ?
+			(ispick ? DIGTYP_UNDIGGABLE : DIGTYP_TREE) :
+		ispick && IS_ROCK(levl[x][y].typ) &&
+			(!level.flags.arboreal || IS_WALL(levl[x][y].typ)) ?
+			DIGTYP_ROCK : DIGTYP_UNDIGGABLE);
 }
 
 boolean
@@ -153,11 +166,12 @@
 	int		x, y;
 {
 	struct trap *ttmp = t_at(x, y);
+	const char *verb = (madeby == BY_YOU && uwep && is_axe(uwep)) ? "chop" : "dig in";
 
 	if (On_stairs(x, y)) {
 	    if (x == xdnladder || x == xupladder) {
 		if(verbose) pline_The("ladder resists your effort.");
-	    } else if(verbose) pline_The("stairs are too hard to dig in.");
+	    } else if(verbose) pline_The("stairs are too hard to %s.", verb);
 	    return(FALSE);
 	} else if (IS_THRONE(levl[x][y].typ) && madeby != BY_OBJECT) {
 	    if(verbose) pline_The("throne is too hard to break apart.");
@@ -167,20 +181,20 @@
 	    if(verbose) pline_The("altar is too hard to break apart.");
 	    return(FALSE);
 	} else if (Is_airlevel(&u.uz)) {
-	    if(verbose) You("cannot dig in thin air.");
+	    if(verbose) You("cannot %s thin air.", verb);
 	    return(FALSE);
 	} else if (Is_waterlevel(&u.uz)) {
 	    if(verbose) pline_The("water splashes and subsides.");
 	    return(FALSE);
-	} else if ((IS_WALL(levl[x][y].typ) &&
+	} else if ((IS_ROCK(levl[x][y].typ) && levl[x][y].typ != SDOOR &&
 		      (levl[x][y].wall_info & W_NONDIGGABLE) != 0)
 		|| (ttmp &&
 		      (ttmp->ttyp == MAGIC_PORTAL || !Can_dig_down(&u.uz)))) {
-	    if(verbose) pline_The("%s here is too hard to dig in.",
-				  surface(x,y));
+	    if(verbose) pline_The("%s here is too hard to %s.",
+				  surface(x,y), verb);
 	    return(FALSE);
 	} else if (sobj_at(BOULDER, x, y)) {
-	    if(verbose) There("isn't enough room to dig here.");
+	    if(verbose) There("isn't enough room to %s here.", verb);
 	    return(FALSE);
 	} else if (madeby == BY_OBJECT &&
 		    /* the block against existing traps is mainly to
@@ -197,11 +211,14 @@
 {
 	register struct rm *lev;
 	register xchar dpx = digging.pos.x, dpy = digging.pos.y;
+	register boolean ispick = uwep && is_pick(uwep);
+	const char *verb =
+	    (!uwep || is_pick(uwep)) ? "dig into" : "chop through";
 
 	lev = &levl[dpx][dpy];
 	/* perhaps a nymph stole your pick-axe while you were busy digging */
 	/* or perhaps you teleported away */
-	if (u.uswallow || !uwep || !is_pick(uwep) ||
+	if (u.uswallow || !uwep || (!ispick && !is_axe(uwep)) ||
 	    !on_level(&digging.level, &u.uz) ||
 	    ((digging.down ? (dpx != u.ux || dpy != u.uy)
 			   : (distu(dpx,dpy) > 2))))
@@ -210,12 +227,14 @@
 	if (digging.down) {
 	    if(!dig_check(BY_YOU, TRUE, u.ux, u.uy)) return(0);
 	} else { /* !digging.down */
-	    if (IS_ROCK(lev->typ) && !may_dig(dpx,dpy) && !dig_typ(dpx, dpy)) {
-		pline("This wall is too hard to dig into.");
+	    if (IS_TREE(lev->typ) && !may_dig(dpx,dpy) &&
+			dig_typ(uwep, dpx, dpy) == DIGTYP_TREE) {
+		pline("This tree seems to be petrified.");
 		return(0);
 	    }
-	    if (IS_TREE(lev->typ) && !may_dig(dpx,dpy) && dig_typ(dpx, dpy) == 4) {
-		pline("This tree seems to be petrified.");
+	    if (IS_ROCK(lev->typ) && !may_dig(dpx,dpy) &&
+			dig_typ(uwep, dpx, dpy) == DIGTYP_ROCK) {
+		pline("This wall is too hard to %s.", verb);
 		return(0);
 	    }
 	}
@@ -319,6 +338,7 @@
 			if (IS_TREE(lev->typ)) {
 			    digtxt = "You cut down the tree.";
 			    lev->typ = ROOM;
+			    if (!rn2(5)) (void) rnd_treefruit_at(dpx, dpy);
 			} else {
 			    digtxt = "You succeed in cutting away some rock.";
 			    lev->typ = CORR;
@@ -330,7 +350,8 @@
 			}
 			if (level.flags.is_maze_lev) {
 			    lev->typ = ROOM;
-			} else if (level.flags.is_cavernous_lev) {
+			} else if (level.flags.is_cavernous_lev &&
+				   !in_town(dpx, dpy)) {
 			    lev->typ = CORR;
 			} else {
 			    lev->typ = DOOR;
@@ -360,7 +381,7 @@
 		    newsym(dpx, dpy);
 		if(digtxt && !digging.quiet) pline(digtxt); /* after newsym */
 		if(dmgtxt)
-		    pay_for_damage(dmgtxt);
+		    pay_for_damage(dmgtxt, FALSE);
 
 		if(Is_earthlevel(&u.uz) && !rn2(3)) {
 		    register struct monst *mtmp;
@@ -389,19 +410,19 @@
 		digging.level.dlevel = -1;
 		return(0);
 	} else {		/* not enough effort has been spent yet */
-		static const char *d_target[5] = {
-					"rock", "statue", "boulder", "door", "tree"
+		static const char *const d_target[6] = {
+			"", "rock", "statue", "boulder", "door", "tree"
 		};
-		int dig_target = dig_typ(dpx, dpy);
+		int dig_target = dig_typ(uwep, dpx, dpy);
 
-		if (IS_WALL(lev->typ) || dig_target == 3) {
+		if (IS_WALL(lev->typ) || dig_target == DIGTYP_DOOR) {
 		    if(*in_rooms(dpx, dpy, SHOPBASE)) {
-			pline("This %s seems too hard to dig into.",
-			      IS_DOOR(lev->typ) ? "door" : "wall");
+			pline("This %s seems too hard to %s.",
+			      IS_DOOR(lev->typ) ? "door" : "wall", verb);
 			return(0);
 		    }
-		} else if (!IS_ROCK(lev->typ) && !dig_target)
-			return(0); /* statue or boulder got taken */
+		} else if (!IS_ROCK(lev->typ) && dig_target == DIGTYP_ROCK)
+		    return(0); /* statue or boulder got taken */
 		if(!did_dig_msg) {
 		    You("hit the %s with all your might.",
 			d_target[dig_target]);
@@ -475,7 +496,7 @@
 	   breaking bypasses that routine and calls us directly */
 	if (IS_FOUNTAIN(lev->typ)) {
 	    dogushforth(FALSE);
-	    lev->looted |= F_WARNED;		/* force dryup */
+	    SET_FOUNTAIN_WARNED(x,y);		/* force dryup */
 	    dryup(x, y, madeby_u);
 	    return;
 #ifdef SINKS
@@ -483,6 +504,13 @@
 	    breaksink(x, y);
 	    return;
 #endif
+	} else if (lev->typ == DRAWBRIDGE_DOWN ||
+		   (is_drawbridge_wall(x, y) >= 0)) {
+	    int bx = x, by = y;
+	    /* if under the portcullis, the bridge is adjacent */
+	    (void) find_drawbridge(&bx, &by);
+	    destroy_drawbridge(bx, by);
+	    return;
 	}
 
 	if (ttyp != PIT && !Can_dig_down(&u.uz)) {
@@ -510,7 +538,7 @@
 
 	    if(madeby_u) {
 		You("dig a pit in the %s.", surface_type);
-		if (shopdoor) pay_for_damage("ruin");
+		if (shopdoor) pay_for_damage("ruin", FALSE);
 	    } else if (!madeby_obj && canseemon(madeby))
 		pline("%s digs a pit in the %s.", Monnam(madeby), surface_type);
 	    else if (cansee(x, y) && flags.verbose)
@@ -559,13 +587,15 @@
 			impact_drop((struct obj *)0, x, y, 0);
 		    if (oldobjs != newobjs)
 			(void) pickup(1);
-		    if (shopdoor && madeby_u) pay_for_damage("ruin");
+		    if (shopdoor && madeby_u) pay_for_damage("ruin", FALSE);
 
 		} else {
 		    d_level newlevel;
 
 		    if (*u.ushops && madeby_u)
 			shopdig(1); /* shk might snatch pack */
+		    /* handle earlier damage, eg breaking wand of digging */
+		    else if (!madeby_u) pay_for_damage("dig into", TRUE);
 
 		    You("fall through...");
 		    /* Earlier checks must ensure that the destination
@@ -578,7 +608,7 @@
 		    spoteffects(FALSE);
 		}
 	    } else {
-		if (shopdoor && madeby_u) pay_for_damage("ruin");
+		if (shopdoor && madeby_u) pay_for_damage("ruin", FALSE);
 		if (newobjs)
 		    impact_drop((struct obj *)0, x, y, 0);
 		if (mtmp) {
@@ -602,6 +632,7 @@
 			} else {
 			    get_level(&tolevel, depth(&u.uz) + 1);
 			}
+			if (mtmp->isshk) make_angry_shk(mtmp, 0, 0);
 			migrate_to_level(mtmp, ledger_no(&tolevel),
 					 MIGR_RANDOM, (coord *)0);
 		    }
@@ -622,7 +653,8 @@
 	boolean nohole = !Can_dig_down(&u.uz);
 
 	if ((ttmp && (ttmp->ttyp == MAGIC_PORTAL || nohole)) ||
-	   (IS_WALL(lev->typ) && (lev->wall_info & W_NONDIGGABLE) != 0)) {
+	   (IS_ROCK(lev->typ) && lev->typ != SDOOR &&
+	    (lev->wall_info & W_NONDIGGABLE) != 0)) {
 		pline_The("%s here is too hard to dig in.", surface(u.ux,u.uy));
 
 	} else if (is_pool(u.ux, u.uy) || is_lava(u.ux, u.uy)) {
@@ -731,7 +763,6 @@
 {
 	struct obj *otmp;
 
-
 	/* Grave-robbing is frowned upon... */
 	exercise(A_WIS, FALSE);
 	if (Role_if(PM_ARCHEOLOGIST)) {
@@ -777,23 +808,29 @@
 use_pick_axe(obj)
 struct obj *obj;
 {
+	boolean ispick;
 	char dirsyms[12];
 	char qbuf[QBUFSZ];
 	register char *dsp = dirsyms;
 	register int rx, ry;
 	int res = 0;
-	register const char *sdp;
+	register const char *sdp, *verb;
+
 	if(iflags.num_pad) sdp = ndir; else sdp = sdir;	/* DICE workaround */
 
+	/* Check tool */
 	if (obj != uwep) {
-	    if (!wield_tool(obj)) return(0);
+	    if (!wield_tool(obj, "swing")) return 0;
 	    else res = 1;
 	}
+	ispick = is_pick(obj);
+	verb = ispick ? "dig" : "chop";
+
 	if (u.utrap && u.utraptype == TT_WEB) {
-	    pline("%s you can't dig while entangled in a web.",
+	    pline("%s you can't %s while entangled in a web.",
 		  /* res==0 => no prior message;
 		     res==1 => just got "You now wield a pick-axe." message */
-		  !res ? "Unfortunately," : "But");
+		  !res ? "Unfortunately," : "But", verb);
 	    return res;
 	}
 
@@ -801,13 +838,15 @@
 		(void) movecmd(*sdp);	/* sets u.dx and u.dy and u.dz */
 		rx = u.ux + u.dx;
 		ry = u.uy + u.dy;
-		if(u.dz > 0 || (u.dz == 0 && isok(rx, ry) &&
-		    (IS_ROCK(levl[rx][ry].typ) || dig_typ(rx, ry))))
+		/* Include down even with axe, so we have at least one direction */
+		if (u.dz > 0 ||
+		    (u.dz == 0 && isok(rx, ry) &&
+		     dig_typ(obj, rx, ry) != DIGTYP_UNDIGGABLE))
 			*dsp++ = *sdp;
 		sdp++;
 	}
 	*dsp = 0;
-	Sprintf(qbuf, "In what direction do you want to dig? [%s]", dirsyms);
+	Sprintf(qbuf, "In what direction do you want to %s? [%s]", verb, dirsyms);
 	if(!getdir(qbuf))
 		return(res);
 
@@ -825,11 +864,13 @@
 	register int rx, ry;
 	register struct rm *lev;
 	int dig_target;
+	boolean ispick = is_pick(obj);
+	const char *verbing = ispick ? "digging" : "chopping";
 
 	if (u.uswallow && attack(u.ustuck)) {
 		;  /* return(1) */
 	} else if (Underwater) {
-		pline("Turbulence torpedoes your digging attempts.");
+		pline("Turbulence torpedoes your %s attempts.", verbing);
 	} else if(u.dz < 0) {
 		if(Levitation)
 			You("don't have enough leverage.");
@@ -858,8 +899,8 @@
 		lev = &levl[rx][ry];
 		if(MON_AT(rx, ry) && attack(m_at(rx, ry)))
 			return(1);
-		dig_target = dig_typ(rx, ry);
-		if (!IS_ROCK(lev->typ) && !dig_target) {
+		dig_target = dig_typ(obj, rx, ry);
+		if (dig_target == DIGTYP_UNDIGGABLE) {
 			/* ACCESSIBLE or POOL */
 			struct trap *trap = t_at(rx, ry);
 
@@ -874,11 +915,27 @@
 			    /* (maybe `move_into_trap()' would be better) */
 			    nomul(-d(2,2));
 			    nomovemsg = "You pull free.";
-			} else
+			} else if (lev->typ == IRONBARS) {
+			    pline("Clang!");
+			    wake_nearby();
+			} else if (IS_TREE(lev->typ))
+			    You("need an axe to cut down a tree.");
+			else if (IS_ROCK(lev->typ))
+			    You("need a pick to dig rock.");
+			else if (!ispick && (sobj_at(STATUE, rx, ry) ||
+					     sobj_at(BOULDER, rx, ry))) {
+			    boolean vibrate = !rn2(3);
+			    pline("Sparks fly as you whack the %s.%s",
+				sobj_at(STATUE, rx, ry) ? "statue" : "boulder",
+				vibrate ? " The axe-handle vibrates violently!" : "");
+			    if (vibrate) losehp(2, "axing a hard object", KILLED_BY);
+			}
+			else
 			    You("swing your %s through thin air.",
 				aobjnam(obj, (char *)0));
 		} else {
-			static const char *d_action[5] = {
+			static const char * const d_action[6] = {
+						"swinging",
 						"digging",
 						"chipping the statue",
 						"hitting the boulder",
@@ -889,7 +946,8 @@
 			digging.quiet = FALSE;
 			if (digging.pos.x != rx || digging.pos.y != ry ||
 			    !on_level(&digging.level, &u.uz) || digging.down) {
-			    if (flags.autodig && !dig_target && !digging.down &&
+			    if (flags.autodig &&
+				dig_target == DIGTYP_ROCK && !digging.down &&
 				digging.pos.x == u.ux &&
 				digging.pos.y == u.uy &&
 				(moves <= digging.lastdigtime+2 &&
@@ -911,7 +969,7 @@
 					d_action[dig_target]);
 			    digging.chew = FALSE;
 			}
-			set_occupation(dig, "digging", 0);
+			set_occupation(dig, verbing, 0);
 		}
 	} else if (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)) {
 		/* it must be air -- water checked above */
@@ -922,6 +980,10 @@
 		/* Monsters which swim also happen not to be able to dig */
 		You("cannot stay under%s long enough.",
 				is_pool(u.ux, u.uy) ? "water" : " the lava");
+	} else if (!ispick) {
+		Your("%s merely scratches the %s.",
+				aobjnam(obj, (char *)0), surface(u.ux,u.uy));
+		u_wipe_engr(3);
 	} else {
 		if (digging.pos.x != u.ux || digging.pos.y != u.uy ||
 			!on_level(&digging.level, &u.uz) || !digging.down) {
@@ -932,18 +994,18 @@
 		    digging.pos.y = u.uy;
 		    assign_level(&digging.level, &u.uz);
 		    digging.effort = 0;
-		    You("start digging downward.");
+		    You("start %s downward.", verbing);
 		    if (*u.ushops) shopdig(0);
 		} else
-		    You("continue digging downward.");
+		    You("continue %s downward.", verbing);
 		did_dig_msg = FALSE;
-		set_occupation(dig, "digging", 0);
+		set_occupation(dig, verbing, 0);
 	}
 	return(1);
 }
 
 /*
- * Town Watchmen frown on damage to the town walls or fountains.
+ * Town Watchmen frown on damage to the town walls, trees or fountains.
  * It's OK to dig holes in the ground, however.
  * If mtmp is assumed to be a watchman, a watchman is found if mtmp == 0
  * zap == TRUE if wand/spell of digging, FALSE otherwise (chewing)
@@ -954,12 +1016,11 @@
     xchar x, y;
     boolean zap;
 {
-	s_level *slev = Is_special(&u.uz);
 	struct rm *lev = &levl[x][y];
 
-	if (slev && slev->flags.town &&
+	if (in_town(x, y) &&
 	    (closed_door(x, y) || lev->typ == SDOOR ||
-	     IS_WALL(lev->typ) || IS_FOUNTAIN(lev->typ))) {
+	     IS_WALL(lev->typ) || IS_FOUNTAIN(lev->typ) || IS_TREE(lev->typ))) {
 	    if (!mtmp) {
 		for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
 		    if (DEADMONSTER(mtmp)) continue;
@@ -976,10 +1037,13 @@
 		    verbalize("Halt, vandal!  You're under arrest!");
 		    (void) angry_guards(!(flags.soundok));
 		} else {
-		    char *str;
+		    const char *str;
+
 		    if (IS_DOOR(lev->typ))
 			str = "door";
-		    else if (IS_WALL(lev->typ))
+		    else if (IS_TREE(lev->typ))
+			str = "tree";
+		    else if (IS_ROCK(lev->typ))
 			str = "wall";
 		    else
 			str = "fountain";
@@ -1006,9 +1070,6 @@
 	here = &levl[mtmp->mx][mtmp->my];
 	if (here->typ == SDOOR)
 	    cvt_sdoor_to_door(here);	/* ->typ = DOOR */
-	if (IS_TREE(here->typ))
-		/* KMH -- Trees shouldn't create piles */
-		pile = 0;
 
 	/* Eats away door if present & closed or locked */
 	if (closed_door(mtmp->mx, mtmp->my)) {
@@ -1028,11 +1089,10 @@
 	    }
 	    newsym(mtmp->mx, mtmp->my);
 	    return FALSE;
-	} else
-	if (!IS_ROCK(here->typ)) /* no dig */
+	} else if (!IS_ROCK(here->typ) && !IS_TREE(here->typ)) /* no dig */
 	    return FALSE;
 
-	/* Only rock and walls fall through to this point. */
+	/* Only rock, trees, and walls fall through to this point. */
 	if ((here->wall_info & W_NONDIGGABLE) != 0) {
 	    impossible("mdig_tunnel:  %s at (%d,%d) is undiggable",
 		       (IS_WALL(here->typ) ? "wall" : "stone"),
@@ -1048,19 +1108,23 @@
 		add_damage(mtmp->mx, mtmp->my, 0L);
 	    if (level.flags.is_maze_lev) {
 		here->typ = ROOM;
-	    } else if (level.flags.is_cavernous_lev) {
+	    } else if (level.flags.is_cavernous_lev &&
+		       !in_town(mtmp->mx, mtmp->my)) {
 		here->typ = CORR;
 	    } else {
 		here->typ = DOOR;
 		here->doormask = D_NODOOR;
 	    }
-	} else
-	    /* KMH -- Added support for trees */
-	    here->typ = level.flags.arboreal ? ROOM : CORR;
-
-	if (pile && pile < 5)   /* leave behind some rocks? */
-	    (void) mksobj_at((pile == 1) ? BOULDER : ROCK,
+	} else if (IS_TREE(here->typ)) {
+	    here->typ = ROOM;
+	    if (pile && pile < 5)
+		(void) rnd_treefruit_at(mtmp->mx, mtmp->my);
+	} else {
+	    here->typ = CORR;
+	    if (pile && pile < 5)
+		(void) mksobj_at((pile == 1) ? BOULDER : ROCK,
 			     mtmp->mx, mtmp->my, TRUE, FALSE);
+	}
 	newsym(mtmp->mx, mtmp->my);
 	if (!sobj_at(BOULDER, mtmp->mx, mtmp->my))
 	    unblock_point(mtmp->mx, mtmp->my);	/* vision */
@@ -1165,6 +1229,13 @@
 		    } else if (!Blind)
 			pline_The("wall glows then fades.");
 		    break;
+		} else if (IS_TREE(room->typ)) { /* check trees before stone */
+		    if (!(room->wall_info & W_NONDIGGABLE)) {
+			room->typ = ROOM;
+			unblock_point(zx,zy); /* vision */
+		    } else if (!Blind)
+			pline_The("tree shudders but is unharmed.");
+		    break;
 		} else if (room->typ == STONE || room->typ == SCORR) {
 		    if (!(room->wall_info & W_NONDIGGABLE)) {
 			room->typ = CORR;
@@ -1181,13 +1252,16 @@
 			shopwall = TRUE;
 		    }
 		    watch_dig((struct monst *)0, zx, zy, TRUE);
-		    if (level.flags.is_cavernous_lev) {
+		    if (level.flags.is_cavernous_lev && !in_town(zx, zy)) {
 			room->typ = CORR;
 		    } else {
 			room->typ = DOOR;
 			room->doormask = D_NODOOR;
 		    }
 		    digdepth -= 2;
+		} else if (IS_TREE(room->typ)) {
+		    room->typ = ROOM;
+		    digdepth -= 2;
 		} else {	/* IS_ROCK but not IS_WALL or SDOOR */
 		    room->typ = CORR;
 		    digdepth--;
@@ -1199,7 +1273,7 @@
 	} /* while */
 	tmp_at(DISP_END,0);	/* closing call */
 	if (shopdoor || shopwall)
-	    pay_for_damage(shopdoor ? "destroy" : "dig into");
+	    pay_for_damage(shopdoor ? "destroy" : "dig into", FALSE);
 	return;
 }
 
@@ -1477,7 +1551,7 @@
 #endif
 
 #ifdef DEBUG
-void
+int
 wiz_debug_cmd() /* in this case, bury everything at your loc and around */
 {
 	int x, y;
@@ -1485,6 +1559,7 @@
 	for (x = u.ux - 1; x <= u.ux + 1; x++)
 	    for (y = u.uy - 1; y <= u.uy + 1; y++)
 		if (isok(x,y)) bury_objs(x,y);
+	return 0;
 }
 
 #endif /* DEBUG */
diff -Naurd ../nethack-3.4.0/src/display.c ./src/display.c
--- ../nethack-3.4.0/src/display.c Wed Mar 20 23:43:02 2002
+++ ./src/display.c Mon Feb 24 15:25:05 2003
@@ -331,7 +331,8 @@
 	map_background(x,y,show);					\
 }
 
-void map_location(x,y,show)
+void
+map_location(x,y,show)
     int x, y, show;
 {
     _map_location(x,y,show);
@@ -370,7 +371,7 @@
      * the mimic was mimicing.
      */
 
-    if (mon_mimic && sightflags) {
+    if (mon_mimic && (sightflags == PHYSICALLY_SEEN)) {
 	switch (mon->m_ap_type) {
 	    default:
 		impossible("display_monster:  bad m_ap_type value [ = %d ]",
@@ -459,6 +460,9 @@
 
     if (mon_warning(mon)) {
         if (wl > WARNCOUNT - 1) wl = WARNCOUNT - 1;
+	/* 3.4.1: this really ought to be rn2(WARNCOUNT), but value "0"
+	   isn't handled correctly by the what_is routine so avoid it */
+	if (Hallucination) wl = rn1(WARNCOUNT-1,1);
         glyph = warning_to_glyph(wl);
     } else if (MATCH_WARN_OF_MON(mon)) {
 	glyph = mon_to_glyph(mon);
@@ -536,6 +540,13 @@
 	     * underneath if already seen.  Otherwise, show the appropriate
 	     * floor symbol.
 	     *
+	     * Similarly, if the hero digs a hole in a wall or feels a location
+	     * that used to contain an unseen monster.  In these cases,
+	     * there's no reason to assume anything was underneath, so
+	     * just show the appropriate floor symbol.  If something was
+	     * embedded in the wall, the glyph will probably already
+	     * reflect that.  Don't change the symbol in this case.
+	     *
 	     * This isn't quite correct.  If the boulder was on top of some
 	     * other objects they should be seen once the boulder is removed.
 	     * However, we have no way of knowing that what is there now
@@ -551,6 +562,12 @@
 					       cmap_to_glyph(S_stone);
 		    show_glyph(x,y,lev->glyph);
 		}
+	    } else if ((lev->glyph >= cmap_to_glyph(S_stone) &&
+			lev->glyph < cmap_to_glyph(S_room)) ||
+		       glyph_is_invisible(levl[x][y].glyph)) {
+		lev->glyph = lev->waslit ? cmap_to_glyph(S_room) :
+					   cmap_to_glyph(S_stone);
+		show_glyph(x,y,lev->glyph);
 	    }
 	} else {
 	    /* We feel it (I think hallways are the only things left). */
@@ -653,7 +670,7 @@
 	    return;
 	}
 	if (x == u.ux && y == u.uy) {
-	    if (canseeself()) {
+	    if (senseself()) {
 		_map_location(x,y,0);	/* map *under* self */
 		display_self();
 	    } else
@@ -695,7 +712,7 @@
 	if (x == u.ux && y == u.uy) {
 	    feel_location(u.ux, u.uy);		/* forces an update */
 
-	    if (canseeself()) display_self();
+	    if (senseself()) display_self();
 	}
 	else if ((mon = m_at(x,y))
 		&& ((see_it = (tp_sensemon(mon) || MATCH_WARN_OF_MON(mon)
@@ -1046,11 +1063,17 @@
 see_monsters()
 {
     register struct monst *mon;
+
     for (mon = fmon; mon; mon = mon->nmon) {
 	if (DEADMONSTER(mon)) continue;
 	newsym(mon->mx,mon->my);
 	if (mon->wormno) see_wsegs(mon);
     }
+#ifdef STEED
+    /* when mounted, hero's location gets caught by monster loop */
+    if (!u.usteed)
+#endif
+    newsym(u.ux, u.uy);
 }
 
 /*
@@ -1062,16 +1085,19 @@
 set_mimic_blocking()
 {
     register struct monst *mon;
-    for (mon = fmon; mon; mon = mon->nmon)
-	if(!DEADMONSTER(mon) && mon->minvis &&
+
+    for (mon = fmon; mon; mon = mon->nmon) {
+	if (DEADMONSTER(mon)) continue;
+	if (mon->minvis &&
 	   ((mon->m_ap_type == M_AP_FURNITURE &&
-	      (mon->mappearance == S_vcdoor || mon->mappearance == S_hcdoor))||
+	     (mon->mappearance == S_vcdoor || mon->mappearance == S_hcdoor)) ||
 	    (mon->m_ap_type == M_AP_OBJECT && mon->mappearance == BOULDER))) {
 	    if(See_invisible)
 		block_point(mon->mx, mon->my);
 	    else
 		unblock_point(mon->mx, mon->my);
 	}
+    }
 }
 
 /*
@@ -1843,7 +1869,7 @@
 t_warn(lev)
     struct rm *lev;
 {
-    static const char *warn_str = "wall_angle: %s: case %d: seenv = 0x%x";
+    static const char warn_str[] = "wall_angle: %s: case %d: seenv = 0x%x";
     const char *wname;
 
     if (lev->typ == TUWALL) wname = "tuwall";
diff -Naurd ../nethack-3.4.0/src/dlb.c ./src/dlb.c
--- ../nethack-3.4.0/src/dlb.c Wed Mar 20 23:43:02 2002
+++ ./src/dlb.c Mon Feb 24 15:25:05 2003
@@ -9,6 +9,8 @@
 #include <string.h>
 #endif
 
+#define DATAPREFIX 4
+
 #ifdef DLB
 /*
  * Data librarian.  Present a STDIO-like interface to NetHack while
@@ -29,7 +31,7 @@
 } dlb_procs_t;
 
 /* without extern.h via hack.h, these haven't been declared for us */
-extern FILE *FDECL(fopen_datafile, (const char *,const char *,BOOLEAN_P));
+extern FILE *FDECL(fopen_datafile, (const char *,const char *,int));
 
 #ifdef DLBLIB
 /*
@@ -199,7 +201,7 @@
 {
     boolean status = FALSE;
 
-    lp->fdata = fopen_datafile(lib_name, RDBMODE, FALSE);
+    lp->fdata = fopen_datafile(lib_name, RDBMODE, DATAPREFIX);
     if (lp->fdata) {
 	if (readlibdir(lp)) {
 	    status = TRUE;
@@ -460,7 +462,7 @@
     dp = (dlb *) alloc(sizeof(dlb));
     if (do_dlb_fopen(dp, name, mode))
     	dp->fp = (FILE *) 0;
-    else if ((fp = fopen_datafile(name, mode, FALSE)) != 0)
+    else if ((fp = fopen_datafile(name, mode, DATAPREFIX)) != 0)
 	dp->fp = fp;
     else {
 	/* can't find anything */
diff -Naurd ../nethack-3.4.0/src/do.c ./src/do.c
--- ../nethack-3.4.0/src/do.c Wed Mar 20 23:43:02 2002
+++ ./src/do.c Mon Feb 24 15:25:05 2003
@@ -7,19 +7,6 @@
 #include "hack.h"
 #include "lev.h"
 
-#include <errno.h>
-#ifdef _MSC_VER	/* MSC 6.0 defines errno quite differently */
-# if (_MSC_VER >= 600)
-#  define SKIP_ERRNO
-# endif
-#endif
-#ifndef SKIP_ERRNO
-#ifdef _DCC
-const
-#endif
-extern int errno;
-#endif
-
 #ifdef SINKS
 # ifdef OVLB
 STATIC_DCL void FDECL(trycall, (struct obj *));
@@ -42,7 +29,7 @@
 #ifdef OVLB
 
 static NEARDATA const char drop_types[] =
-	{ ALLOW_COUNT, GOLD_CLASS, ALL_CLASSES, 0 };
+	{ ALLOW_COUNT, COIN_CLASS, ALL_CLASSES, 0 };
 
 /* 'd' command: drop one inventory item */
 int
@@ -85,13 +72,17 @@
 	    fills_up = lava ? chance == 0 : chance != 0;
 
 	    if (fills_up) {
+		struct trap *ttmp = t_at(rx, ry);
+
 		if (ltyp == DRAWBRIDGE_UP) {
 		    levl[rx][ry].drawbridgemask &= ~DB_UNDER; /* clear lava */
 		    levl[rx][ry].drawbridgemask |= DB_FLOOR;
 		} else
 		    levl[rx][ry].typ = ROOM;
 
+		if (ttmp) (void) delfloortrap(ttmp);
 		bury_objs(rx, ry);
+		
 		newsym(rx,ry);
 		if (pushing) {
 		    You("push %s into the %s.", the(xname(otmp)), what);
@@ -206,6 +197,14 @@
 	} else if (is_lava(x, y)) {
 		return fire_damage(obj, FALSE, FALSE, x, y);
 	} else if (is_pool(x, y)) {
+		/* Reasonably bulky objects (arbitrary) splash when dropped.
+		 * Stuff dropped near fountains always misses */
+		if (Blind && flags.soundok && ((x == u.ux) && (y == u.uy)) &&
+		    weight(obj) > 9) {
+		    pline("Splash!");
+		    map_background(x, y, 0);
+		    newsym(x, y);
+		}
 		water_damage(obj, FALSE, FALSE);
 	}
 	return FALSE;
@@ -218,15 +217,15 @@
 doaltarobj(obj)  /* obj is an object dropped on an altar */
 	register struct obj *obj;
 {
-	if (Blind || obj->oclass == GOLD_CLASS)
+	if (Blind)
 		return;
 
 	/* KMH, conduct */
 	u.uconduct.gnostic++;
 
-	if (obj->blessed || obj->cursed) {
+	if ((obj->blessed || obj->cursed) && obj->oclass != COIN_CLASS) {
 		There("is %s flash as %s %s the altar.",
-			an(hcolor(obj->blessed ? amber : Black)),
+			an(hcolor(obj->blessed ? NH_AMBER : NH_BLACK)),
 			doname(obj), otense(obj, "hit"));
 		if (!Hallucination) obj->bknown = 1;
 	} else {
@@ -273,7 +272,7 @@
 		pline_The("sink quivers upward for a moment.");
 		break;
 	    case RIN_POISON_RESISTANCE:
-		You("smell rotten %s.", makeplural(pl_fruit));
+		You("smell rotten %s.", makeplural(fruitname(FALSE)));
 		break;
 	    case RIN_AGGRAVATE_MONSTER:
 		pline("Several flies buzz angrily around the sink.");
@@ -358,10 +357,10 @@
 		    break;
 		case RIN_PROTECTION:
 		    pline_The("sink glows %s for a moment.",
-			    hcolor((obj->spe<0) ? Black : silver));
+			    hcolor((obj->spe<0) ? NH_BLACK : NH_SILVER));
 		    break;
 		case RIN_WARNING:
-		    pline_The("sink glows %s for a moment.", hcolor(White));
+		    pline_The("sink glows %s for a moment.", hcolor(NH_WHITE));
 		    break;
 		case RIN_TELEPORTATION:
 		    pline_The("sink momentarily vanishes.");
@@ -483,37 +482,41 @@
 #endif
 	    if (!can_reach_floor()) {
 		if(flags.verbose) You("drop %s.", doname(obj));
-		if (obj->oclass != GOLD_CLASS || obj == invent) freeinv(obj);
+#ifndef GOLDOBJ
+		if (obj->oclass != COIN_CLASS || obj == invent) freeinv(obj);
+#else
+		/* Ensure update when we drop gold objects */
+		if (obj->oclass == COIN_CLASS) flags.botl = 1;
+		freeinv(obj);
+#endif
 		hitfloor(obj);
 		return(1);
 	    }
-	    if (IS_ALTAR(levl[u.ux][u.uy].typ)) {
-		doaltarobj(obj);	/* set bknown */
-	    } else
-		if(flags.verbose) You("drop %s.", doname(obj));
+	    if (!IS_ALTAR(levl[u.ux][u.uy].typ) && flags.verbose)
+		You("drop %s.", doname(obj));
 	}
 	dropx(obj);
 	return(1);
 }
 
-/* Called in several places - should not produce texts */
-/* ship_object() _can_ produce texts--is that comment still correct? */
+/* Called in several places - may produce output */
+/* eg ship_object() and dropy() -> sellobj() both produce output */
 void
 dropx(obj)
 register struct obj *obj;
 {
 #ifndef GOLDOBJ
-	if (obj->oclass != GOLD_CLASS || obj == invent) freeinv(obj);
+	if (obj->oclass != COIN_CLASS || obj == invent) freeinv(obj);
 #else
         /* Ensure update when we drop gold objects */
-        if (obj->oclass == GOLD_CLASS) flags.botl = 1;
-	/* Money is usually not in our inventory */
-	/*if (obj->oclass != GOLD_CLASS || obj == invent)*/ 
-        /* !!!! make sure we don't drop "created" gold not in inventory any more,*/
-        /* or this will crash !!!! */
+        if (obj->oclass == COIN_CLASS) flags.botl = 1;
         freeinv(obj);
 #endif
-	if (!u.uswallow && ship_object(obj, u.ux, u.uy, FALSE)) return;
+	if (!u.uswallow) {
+	    if (ship_object(obj, u.ux, u.uy, FALSE)) return;
+	    if (IS_ALTAR(levl[u.ux][u.uy].typ))
+		doaltarobj(obj); /* set bknown */
+	}
 	dropy(obj);
 }
 
@@ -528,15 +531,39 @@
 	if (!u.uswallow && flooreffects(obj,u.ux,u.uy,"drop")) return;
 	/* uswallow check done by GAN 01/29/87 */
 	if(u.uswallow) {
-	    boolean could_petrify;
+	    boolean could_petrify = FALSE;
+	    boolean could_poly = FALSE;
+	    boolean could_slime = FALSE;
+	    boolean could_grow = FALSE;
+	    boolean could_heal = FALSE;
+
 	    if (obj != uball) {		/* mon doesn't pick up ball */
-		could_petrify = obj->otyp == CORPSE &&
-		    touch_petrifies(&mons[obj->corpsenm]);
+		if (obj->otyp == CORPSE) {
+		    could_petrify = touch_petrifies(&mons[obj->corpsenm]);
+		    could_poly = polyfodder(obj);
+		    could_slime = (obj->corpsenm == PM_GREEN_SLIME);
+		    could_grow = (obj->corpsenm == PM_WRAITH);
+		    could_heal = (obj->corpsenm == PM_NURSE);
+		}
 		(void) mpickobj(u.ustuck,obj);
-		if (could_petrify && is_animal(u.ustuck->data)) {
-		    minstapetrify(u.ustuck, TRUE);
-		    /* Don't leave a cockatrice corpse available in a statue */
-		    if (!u.uswallow) delobj(obj);
+		if (is_animal(u.ustuck->data)) {
+		    if (could_poly || could_slime) {
+			(void) newcham(u.ustuck,
+				       could_poly ? (struct permonst *)0 :
+				       &mons[PM_GREEN_SLIME],
+				       FALSE, could_slime);
+			delobj(obj);	/* corpse is digested */
+		    } else if (could_petrify) {
+			minstapetrify(u.ustuck, TRUE);
+			/* Don't leave a cockatrice corpse in a statue */
+			if (!u.uswallow) delobj(obj);
+		    } else if (could_grow) {
+			(void) grow_up(u.ustuck, (struct monst *)0);
+			delobj(obj);	/* corpse is digested */
+		    } else if (could_heal) {
+			u.ustuck->mhp = u.ustuck->mhpmax;
+			delobj(obj);	/* corpse is digested */
+		    }
 		}
 	    }
 	} else  {
@@ -614,6 +641,7 @@
 	/* Hack: gold is not in the inventory, so make a gold object
 	   and put it at the head of the inventory list. */
 	u_gold = mkgoldobj(u.ugold);	/* removes from u.ugold */
+	u_gold->in_use = TRUE;
 	u.ugold = u_gold->quan;		/* put the gold back */
 	assigninvlet(u_gold);		/* might end up as NOINVSYM */
 	u_gold->nobj = invent;
@@ -668,7 +696,7 @@
 		if (cnt < otmp->quan && !welded(otmp) &&
 			(!otmp->cursed || otmp->otyp != LOADSTONE)) {
 #ifndef GOLDOBJ
-		    if (otmp->oclass == GOLD_CLASS)
+		    if (otmp->oclass == COIN_CLASS)
 			(void) splitobj(otmp, otmp->quan - cnt);
 		    else
 #endif
@@ -682,10 +710,11 @@
 
  drop_done:
 #ifndef GOLDOBJ
-    if (u_gold && invent && invent->oclass == GOLD_CLASS) {
+    if (u_gold && invent && invent->oclass == COIN_CLASS) {
 	/* didn't drop [all of] it */
 	u_gold = invent;
 	invent = u_gold->nobj;
+	u_gold->in_use = FALSE;
 	dealloc_obj(u_gold);
 	update_inventory();
     }
@@ -834,14 +863,14 @@
 currentlevel_rewrite()
 {
 	register int fd;
+	char whynot[BUFSZ];
 
 	/* since level change might be a bit slow, flush any buffered screen
 	 *  output (like "you fall through a trap door") */
 	mark_synch();
 
-	fd = create_levelfile(ledger_no(&u.uz));
-
-	if(fd < 0) {
+	fd = create_levelfile(ledger_no(&u.uz), whynot);
+	if (fd < 0) {
 		/*
 		 * This is not quite impossible: e.g., we may have
 		 * exceeded our quota. If that is the case then we
@@ -849,8 +878,7 @@
 		 * Another possibility is that the directory was not
 		 * writable.
 		 */
-		pline("Cannot create level file for level %d.",
-						ledger_no(&u.uz));
+		pline("%s", whynot);
 		return -1;
 	}
 
@@ -910,6 +938,7 @@
 		familiar = FALSE;
 	boolean new = FALSE;	/* made a new level? */
 	struct monst *mtmp;
+	char whynot[BUFSZ];
 
 	if (dunlev(newlevel) > dunlevs_in_dungeon(newlevel))
 		newlevel->dlevel = dunlevs_in_dungeon(newlevel);
@@ -953,7 +982,7 @@
 
 		    pline("A mysterious force momentarily surrounds you...");
 		    if (on_level(newlevel, &u.uz)) {
-			(void) safe_teleds();
+			(void) safe_teleds(FALSE);
 			(void) next_to_u();
 			return;
 		    } else
@@ -983,6 +1012,7 @@
 	fill_pit(u.ux, u.uy);
 	u.ustuck = 0;				/* idem */
 	u.uinwater = 0;
+	u.uundetected = 0;	/* not hidden, even if means are available */
 	keepdogs(FALSE);
 	if (u.uswallow)				/* idem */
 		u.uswldtim = u.uswallow = 0;
@@ -1044,12 +1074,14 @@
 		new = TRUE;	/* made the level */
 	} else {
 		/* returning to previously visited level; reload it */
-		fd = open_levelfile(new_ledger);
+		fd = open_levelfile(new_ledger, whynot);
 		if (fd < 0) {
-			pline("Cannot open file (#%d) for level %d (errno %d).",
-					(int) new_ledger, depth(&u.uz), errno);
+			pline("%s", whynot);
 			pline("Probably someone removed it.");
+			killer = whynot;
 			done(TRICKED);
+			/* we'll reach here if running in wizard mode */
+			error("Cannot continue this game.");
 		}
 		minit();	/* ZEROCOMP */
 		getlev(fd, hackpid, new_ledger, FALSE);
@@ -1118,13 +1150,13 @@
 			    freeinv(uball);
 			}
 		    }
-		    losehp(rnd(3), "falling downstairs", KILLED_BY);
 #ifdef STEED
-		    if (u.usteed) {
+		    /* falling off steed has its own losehp() call */
+		    if (u.usteed)
 			dismount_steed(DISMOUNT_FELL);
-			if (Punished) unplacebc();
-		    }
+		    else
 #endif
+			losehp(rnd(3), "falling downstairs", KILLED_BY);
 		    selftouch("Falling, you");
 		} else if (u.dz && at_ladder)
 		    You("climb down the ladder.");
@@ -1228,13 +1260,13 @@
 	}
 
 	if (familiar) {
-	    static const char *fam_msgs[4] = {
+	    static const char * const fam_msgs[4] = {
 		"You have a sense of deja vu.",
 		"You feel like you've been here before.",
 		"This place %s familiar...",
 		0	/* no message */
 	    };
-	    static const char *halu_fam_msgs[4] = {
+	    static const char * const halu_fam_msgs[4] = {
 		"Whoa!  Everything %s different.",
 		"You are surrounded by twisty little passages, all alike.",
 		"Gee, this %s like uncle Conan's place...",
@@ -1295,6 +1327,8 @@
 	save_currentstate();
 #endif
 
+	/* assume this will always return TRUE when changing level */
+	(void) in_out_region(u.ux, u.uy);
 	(void) pickup(1);
 }
 
diff -Naurd ../nethack-3.4.0/src/do_name.c ./src/do_name.c
--- ../nethack-3.4.0/src/do_name.c Wed Mar 20 23:43:03 2002
+++ ./src/do_name.c Mon Feb 24 15:25:05 2003
@@ -49,7 +49,7 @@
     int cx, cy, i, c;
     int sidx, tx, ty;
     boolean msg_given = TRUE;	/* clear message window by default */
-    static const char *pick_chars = ".,;:";
+    static const char pick_chars[] = ".,;:";
     const char *cp;
     const char *sdp;
     if(iflags.num_pad) sdp = ndir; else sdp = sdir;	/* DICE workaround */
@@ -275,9 +275,10 @@
 	/* strip leading and trailing spaces; unnames monster if all spaces */
 	(void)mungspaces(buf);
 
-	if (mtmp->iswiz || type_is_pname(mtmp->data))
+	if (mtmp->data->geno & G_UNIQ)
 	    pline("%s doesn't like being called names!", Monnam(mtmp));
-	else (void) christen_monst(mtmp, buf);
+	else
+	    (void) christen_monst(mtmp, buf);
 	return(0);
 }
 
@@ -361,8 +362,12 @@
 	}
 
 	if (obj->owornmask) {
+		boolean save_twoweap = u.twoweap;
+		/* unwearing the old instance will clear dual-wield mode
+		   if this object is either of the two weapons */
 		setworn((struct obj *)0, obj->owornmask);
 		setworn(otmp, otmp->owornmask);
+		u.twoweap = save_twoweap;
 	}
 
 	/* replace obj with otmp */
@@ -421,7 +426,12 @@
 			      (genericptr_t)obj->oextra, lth, name);
 	}
 	if (lth) artifact_exists(obj, name, TRUE);
-	if (obj->oartifact && obj == uswapwep) untwoweapon();
+	if (obj->oartifact) {
+	    /* can't dual-wield with artifact as secondary weapon */
+	    if (obj == uswapwep) untwoweapon();
+	    /* activate warning if you've just named your weapon "Sting" */
+	    if (obj == uwep) set_artifact_intrinsic(obj, TRUE, W_WEP);
+	}
 	if (carried(obj)) update_inventory();
 	return obj;
 }
@@ -460,6 +470,11 @@
 #endif
 		obj = getobj(callable, "call");
 		if (obj) {
+			/* behave as if examining it in inventory;
+			   this might set dknown if it was picked up
+			   while blind and the hero can now see */
+			(void) xname(obj);
+
 			if (!obj->dknown) {
 				You("would never recognize another one.");
 				return 0;
@@ -516,7 +531,7 @@
 #endif /*OVLB*/
 #ifdef OVL0
 
-static const char *ghostnames[] = {
+static const char * const ghostnames[] = {
 	/* these names should have length < PL_NSIZ */
 	/* Capitalize the names for aesthetics -dgk */
 	"Adri", "Andries", "Andreas", "Bert", "David", "Dirk", "Emile",
@@ -703,13 +718,12 @@
 	    name_at_start = (boolean)type_is_pname(mdat);
 	}
 
-	if (name_at_start && !has_adjectives) {
+	if (name_at_start && (article == ARTICLE_YOUR || !has_adjectives)) {
 	    if (mdat == &mons[PM_WIZARD_OF_YENDOR])
 		article = ARTICLE_THE;
 	    else
 		article = ARTICLE_NONE;
-	} else if (mons[monsndx(mdat)].geno & G_UNIQ &&
-		   article == ARTICLE_A) {
+	} else if ((mdat->geno & G_UNIQ) && article == ARTICLE_A) {
 	    article = ARTICLE_THE;
 	}
 
@@ -804,8 +818,17 @@
 y_monnam(mtmp)
 struct monst *mtmp;
 {
-	return x_monnam(mtmp, ARTICLE_YOUR, (char *)0, 
-		mtmp->mnamelth ? SUPPRESS_SADDLE : 0, FALSE);
+	int prefix, suppression_flag;
+
+	prefix = mtmp->mtame ? ARTICLE_YOUR : ARTICLE_THE;
+	suppression_flag = (mtmp->mnamelth
+#ifdef STEED
+			    /* "saddled" is redundant when mounted */
+			    || mtmp == u.usteed
+#endif
+			    ) ? SUPPRESS_SADDLE : 0;
+
+	return x_monnam(mtmp, prefix, (char *)0, suppression_flag, FALSE);
 }
 
 #endif /* OVL0 */
@@ -862,7 +885,7 @@
     return outbuf;
 }
 
-static const char *bogusmons[] = {
+static const char * const bogusmons[] = {
 	"jumbo shrimp", "giant pigmy", "gnu", "killer penguin",
 	"giant cockroach", "giant slug", "maggot", "pterodactyl",
 	"tyrannosaurus rex", "basilisk", "beholder", "nightmare",
@@ -959,7 +982,7 @@
 
 #ifdef OVL2
 
-static NEARDATA const char *hcolors[] = {
+static NEARDATA const char * const hcolors[] = {
 	"ultraviolet", "infrared", "bluish-orange",
 	"reddish-green", "dark white", "light black", "sky blue-pink",
 	"salty", "sweet", "sour", "bitter",
@@ -980,9 +1003,8 @@
 }
 
 /* Aliases for road-runner nemesis
- * See also http://www.geocities.com/EnchantedForest/1141/latin.html
  */
-static const char *coynames[] = {
+static const char * const coynames[] = {
 	"Carnivorous Vulgaris","Road-Runnerus Digestus",
 	"Eatibus Anythingus"  ,"Famishus-Famishus",
 	"Eatibus Almost Anythingus","Eatius Birdius",
@@ -996,7 +1018,8 @@
 	"Nemesis Riduclii","Canis latrans"
 };
 	
-char *coyotename(mtmp, buf)
+char *
+coyotename(mtmp, buf)
 struct monst *mtmp;
 char *buf;
 {
diff -Naurd ../nethack-3.4.0/src/do_wear.c ./src/do_wear.c
--- ../nethack-3.4.0/src/do_wear.c Wed Mar 20 23:43:04 2002
+++ ./src/do_wear.c Mon Feb 24 15:25:05 2003
@@ -17,20 +17,20 @@
 
 static NEARDATA const char see_yourself[] = "see yourself";
 static NEARDATA const char unknown_type[] = "Unknown type of %s (%d)";
-static NEARDATA const char *c_armor  = "armor",
-			   *c_suit   = "suit",
+static NEARDATA const char c_armor[]  = "armor",
+			   c_suit[]   = "suit",
 #ifdef TOURIST
-			   *c_shirt  = "shirt",
+			   c_shirt[]  = "shirt",
 #endif
-			   *c_cloak  = "cloak",
-			   *c_gloves = "gloves",
-			   *c_boots  = "boots",
-			   *c_helmet = "helmet",
-			   *c_shield = "shield",
-			   *c_weapon = "weapon",
-			   *c_sword  = "sword",
-			   *c_axe    = "axe",
-			   *c_that_  = "that";
+			   c_cloak[]  = "cloak",
+			   c_gloves[] = "gloves",
+			   c_boots[]  = "boots",
+			   c_helmet[] = "helmet",
+			   c_shield[] = "shield",
+			   c_weapon[] = "weapon",
+			   c_sword[]  = "sword",
+			   c_axe[]    = "axe",
+			   c_that_[]  = "that";
 
 static NEARDATA const long takeoff_order[] = { WORN_BLINDF, W_WEP,
 	WORN_SHIELD, WORN_GLOVES, LEFT_RING, RIGHT_RING, WORN_CLOAK,
@@ -321,7 +321,7 @@
 			pline("%s for a moment.", Tobjnam(uarmh, "vibrate"));
 		    else
 			pline("%s %s for a moment.",
-			      Tobjnam(uarmh, "glow"), hcolor(Black));
+			      Tobjnam(uarmh, "glow"), hcolor(NH_BLACK));
 		    curse(uarmh);
 		}
 		flags.botl = 1;		/* reveal new alignment or INT & WIS */
@@ -635,7 +635,7 @@
 register struct obj *obj;
 {
     long oldprop = u.uprops[objects[obj->otyp].oc_oprop].extrinsic;
-    int old_attrib;
+    int old_attrib, which;
 
     if (obj == uwep) setuwep((struct obj *) 0);
     if (obj == uswapwep) setuswapwep((struct obj *) 0);
@@ -690,44 +690,31 @@
 		    self_invis_message();
 		}
 		break;
-	case RIN_ADORNMENT:
-		old_attrib = ACURR(A_CHA);
-		ABON(A_CHA) += obj->spe;
-		flags.botl = 1;
-		if (ACURR(A_CHA) != old_attrib ||
-		    (objects[RIN_ADORNMENT].oc_name_known &&
-		     old_attrib != 25 && old_attrib != 3)) {
-			makeknown(RIN_ADORNMENT);
-			obj->known = TRUE;
-		}
-		break;
 	case RIN_LEVITATION:
-		if(!oldprop && !HLevitation) {
-			float_up();
-			makeknown(RIN_LEVITATION);
-			obj->known = TRUE;
-			spoteffects(FALSE);	/* for sinks */
+		if (!oldprop && !HLevitation) {
+		    float_up();
+		    makeknown(RIN_LEVITATION);
+		    spoteffects(FALSE);	/* for sinks */
 		}
 		break;
 	case RIN_GAIN_STRENGTH:
-		old_attrib = ACURR(A_STR);
-		ABON(A_STR) += obj->spe;
-		flags.botl = 1;
-		if (ACURR(A_STR) != old_attrib ||
-		    (objects[RIN_GAIN_STRENGTH].oc_name_known &&
-		     old_attrib != STR19(25) && old_attrib != 3)) {
-			makeknown(RIN_GAIN_STRENGTH);
-			obj->known = TRUE;
-		}
-		break;
+		which = A_STR;
+		goto adjust_attrib;
 	case RIN_GAIN_CONSTITUTION:
-		old_attrib = ACURR(A_CON);
-		ABON(A_CON) += obj->spe;
-		flags.botl = 1;
-		if (ACURR(A_CON) != old_attrib ||
-		    objects[RIN_GAIN_CONSTITUTION].oc_name_known) {
-			makeknown(RIN_GAIN_CONSTITUTION);
-			obj->known = TRUE;
+		which = A_CON;
+		goto adjust_attrib;
+	case RIN_ADORNMENT:
+		which = A_CHA;
+ adjust_attrib:
+		old_attrib = ACURR(which);
+		ABON(which) += obj->spe;
+		if (ACURR(which) != old_attrib ||
+			(objects[obj->otyp].oc_name_known &&
+			    old_attrib != 25 && old_attrib != 3)) {
+		    flags.botl = 1;
+		    makeknown(obj->otyp);
+		    obj->known = 1;
+		    update_inventory();
 		}
 		break;
 	case RIN_INCREASE_ACCURACY:	/* KMH */
@@ -740,11 +727,11 @@
 		rescham();
 		break;
 	case RIN_PROTECTION:
-		flags.botl = 1;
 		if (obj->spe || objects[RIN_PROTECTION].oc_name_known) {
-			makeknown(RIN_PROTECTION);
-			obj->known = TRUE;
-			update_inventory();
+		    flags.botl = 1;
+		    makeknown(RIN_PROTECTION);
+		    obj->known = 1;
+		    update_inventory();
 		}
 		break;
     }
@@ -756,12 +743,13 @@
 boolean gone;
 {
     register long mask = obj->owornmask & W_RING;
-    int old_attrib;
+    int old_attrib, which;
 
     if(!(u.uprops[objects[obj->otyp].oc_oprop].extrinsic & mask))
 	impossible("Strange... I didn't know you had that ring.");
     if(gone) setnotworn(obj);
     else setworn((struct obj *)0, obj->owornmask);
+
     switch(obj->otyp) {
 	case RIN_TELEPORTATION:
 	case RIN_REGENERATION:
@@ -796,40 +784,40 @@
 		}
 
 		if (Invisible && !Blind) {
-			newsym(u.ux,u.uy);
-			pline("Suddenly you cannot see yourself.");
-			makeknown(RIN_SEE_INVISIBLE);
+		    newsym(u.ux,u.uy);
+		    pline("Suddenly you cannot see yourself.");
+		    makeknown(RIN_SEE_INVISIBLE);
 		}
 		break;
 	case RIN_INVISIBILITY:
 		if (!Invis && !BInvis && !Blind) {
-			newsym(u.ux,u.uy);
-			Your("body seems to unfade%s.",
-			    See_invisible ? " completely" : "..");
-			makeknown(RIN_INVISIBILITY);
+		    newsym(u.ux,u.uy);
+		    Your("body seems to unfade%s.",
+			 See_invisible ? " completely" : "..");
+		    makeknown(RIN_INVISIBILITY);
 		}
 		break;
-	case RIN_ADORNMENT:
-		old_attrib = ACURR(A_CHA);
-		ABON(A_CHA) -= obj->spe;
-		if (ACURR(A_CHA) != old_attrib) makeknown(RIN_ADORNMENT);
-		flags.botl = 1;
-		break;
 	case RIN_LEVITATION:
 		(void) float_down(0L, 0L);
 		if (!Levitation) makeknown(RIN_LEVITATION);
 		break;
 	case RIN_GAIN_STRENGTH:
-		old_attrib = ACURR(A_STR);
-		ABON(A_STR) -= obj->spe;
-		if (ACURR(A_STR) != old_attrib) makeknown(RIN_GAIN_STRENGTH);
-		flags.botl = 1;
-		break;
+		which = A_STR;
+		goto adjust_attrib;
 	case RIN_GAIN_CONSTITUTION:
-		old_attrib = ACURR(A_CON);
-		ABON(A_CON) -= obj->spe;
-		flags.botl = 1;
-		if (ACURR(A_CON) != old_attrib) makeknown(RIN_GAIN_CONSTITUTION);
+		which = A_CON;
+		goto adjust_attrib;
+	case RIN_ADORNMENT:
+		which = A_CHA;
+ adjust_attrib:
+		old_attrib = ACURR(which);
+		ABON(which) -= obj->spe;
+		if (ACURR(which) != old_attrib) {
+		    flags.botl = 1;
+		    makeknown(obj->otyp);
+		    obj->known = 1;
+		    update_inventory();
+		}
 		break;
 	case RIN_INCREASE_ACCURACY:	/* KMH */
 		u.uhitinc -= obj->spe;
@@ -837,6 +825,14 @@
 	case RIN_INCREASE_DAMAGE:
 		u.udaminc -= obj->spe;
 		break;
+	case RIN_PROTECTION:
+		/* might have forgotten it due to amnesia */
+		if (obj->spe) {
+		    flags.botl = 1;
+		    makeknown(RIN_PROTECTION);
+		    obj->known = 1;
+		    update_inventory();
+		}
 	case RIN_PROTECTION_FROM_SHAPE_CHAN:
 		/* If you're no longer protected, let the chameleons
 		 * change shape again -dgk
@@ -966,6 +962,7 @@
 static NEARDATA const char clothes[] = {ARMOR_CLASS, 0};
 static NEARDATA const char accessories[] = {RING_CLASS, AMULET_CLASS, TOOL_CLASS, FOOD_CLASS, 0};
 
+/* the 'T' command */
 int
 dotakeoff()
 {
@@ -996,7 +993,8 @@
 			      uskin->otyp >= GRAY_DRAGON_SCALES ?
 				"dragon scales are" : "dragon scale mail is");
 		else
-		    pline("Not wearing any armor.");
+		    pline("Not wearing any armor.%s", iflags.cmdassist ?
+			" Use 'R' command to remove accessories." : "");
 		return 0;
 	}
 	if (armorpieces > 1)
@@ -1016,41 +1014,17 @@
 	    You_cant("take that off.");
 	    return 0;
 	}
-	if (otmp == uarmg && welded(uwep)) {
-	    You("seem unable to take off the gloves while holding your %s.",
-		is_sword(uwep) ? c_sword : c_weapon);
-	    uwep->bknown = TRUE;
-	    return 0;
-	} else if (welded(uwep) && bimanual(uwep) &&
-		   (otmp == uarm
-#ifdef TOURIST
-		    || otmp == uarmu
-#endif
-		    )) {
-	    You("seem unable to take off %s while holding your %s.",
-		the(xname(otmp)), is_sword(uwep) ? c_sword : c_weapon);
-	    uwep->bknown = TRUE;
-	    return 0;
-	}
-	if (otmp == uarmg && Glib) {
-	    You_cant("remove the slippery gloves with your slippery fingers.");
-	    return 0;
-	}
-	if (otmp == uarmf && u.utrap && (u.utraptype == TT_BEARTRAP ||
-					u.utraptype == TT_INFLOOR)) { /* -3. */
-	    if(u.utraptype == TT_BEARTRAP)
-		pline_The("bear trap prevents you from pulling your %s out.",
-		      body_part(FOOT));
-	    else
-		You("are stuck in the %s, and cannot pull your %s out.",
-		    surface(u.ux, u.uy), makeplural(body_part(FOOT)));
-		return(0);
-	}
-	reset_remarm();			/* since you may change ordering */
+
+	reset_remarm();		/* clear takeoff_mask and taking_off */
+	(void) select_off(otmp);
+	if (!takeoff_mask) return 0;
+	reset_remarm();		/* armoroff() doesn't use takeoff_mask */
+
 	(void) armoroff(otmp);
 	return(1);
 }
 
+/* the 'R' command */
 int
 doremring()
 {
@@ -1064,7 +1038,8 @@
 	MOREACC(ublindf);
 
 	if(!Accessories) {
-		pline("Not wearing any accessories.");
+		pline("Not wearing any accessories.%s", iflags.cmdassist ?
+			" Use 'T' command to take off non-accessories." : "");
 		return(0);
 	}
 	if (Accessories != 1) otmp = getobj(accessories, "remove");
@@ -1073,32 +1048,13 @@
 		You("are not wearing that.");
 		return(0);
 	}
-	if(cursed(otmp)) return(0);
-	if(otmp->oclass == RING_CLASS || otmp->otyp == MEAT_RING) {
-		if (nolimbs(youmonst.data)) {
-			pline("It seems to be stuck.");
-			return(0);
-		}
-		if (uarmg && uarmg->cursed) {
-			uarmg->bknown = TRUE;
-			You(
-	    "seem unable to remove your ring without taking off your gloves.");
-			return(0);
-		}
-		if (welded(uwep) && bimanual(uwep)) {
-			uwep->bknown = TRUE;
-			You(
-	       "seem unable to remove the ring while your hands hold your %s.",
-			    is_sword(uwep) ? c_sword : c_weapon);
-			return(0);
-		}
-		if (welded(uwep) && otmp==uright) {
-			uwep->bknown = TRUE;
-			You(
-	 "seem unable to remove the ring while your right hand holds your %s.",
-			    is_sword(uwep) ? c_sword : c_weapon);
-			return(0);
-		}
+
+	reset_remarm();		/* clear takeoff_mask and taking_off */
+	(void) select_off(otmp);
+	if (!takeoff_mask) return 0;
+	reset_remarm();		/* not used by Ring_/Amulet_/Blindf_off() */
+
+	if (otmp == uright || otmp == uleft) {
 		/* Sometimes we want to give the off_msg before removing and
 		 * sometimes after; for instance, "you were wearing a moonstone
 		 * ring (on right hand)" is desired but "you were wearing a
@@ -1107,10 +1063,14 @@
 		 */
 		off_msg(otmp);
 		Ring_off(otmp);
-	} else if(otmp->oclass == AMULET_CLASS) {
+	} else if (otmp == uamul) {
 		Amulet_off();
 		off_msg(otmp);
-	} else Blindf_off(otmp); /* does its own off_msg */
+	} else if (otmp == ublindf) {
+		Blindf_off(otmp);	/* does its own off_msg */
+	} else {
+		impossible("removing strange accessory?");
+	}
 	return(1);
 }
 
@@ -1121,9 +1081,9 @@
 {
 	/* Curses, like chickens, come home to roost. */
 	if((otmp == uwep) ? welded(otmp) : (int)otmp->cursed) {
-		You("can't.  %s to be cursed.",
+		You("can't.  %s cursed.",
 			(is_boots(otmp) || is_gloves(otmp) || otmp->quan > 1L)
-			? "They seem" : "It seems");
+			? "They are" : "It is");
 		otmp->bknown = TRUE;
 		return(1);
 	}
@@ -1219,7 +1179,8 @@
 	    is_suit(otmp) ? c_suit : 0;
     if (which && cantweararm(youmonst.data) &&
 	    /* same exception for cloaks as used in m_dowear() */
-	    (which != c_cloak || youmonst.data->msize != MZ_SMALL)) {
+	    (which != c_cloak || youmonst.data->msize != MZ_SMALL) &&
+	    (racial_exception(&youmonst, otmp) < 1)) {
 	if (noisy) pline_The("%s will not fit on your body.", which);
 	return 0;
     } else if (otmp->owornmask & W_ARMOR) {
@@ -1228,11 +1189,11 @@
     }
 
     if (welded(uwep) && bimanual(uwep) &&
-	(otmp == uarm
+	    (is_suit(otmp)
 #ifdef TOURIST
-	 || otmp == uarmu
+			|| is_shirt(otmp)
 #endif
-	 )) {
+	    )) {
 	if (noisy)
 	    You("cannot do that while holding your %s.",
 		is_sword(uwep) ? c_sword : c_weapon);
@@ -1243,6 +1204,12 @@
 	if (uarmh) {
 	    if (noisy) already_wearing(an(c_helmet));
 	    err++;
+	} else if (Upolyd && has_horns(youmonst.data) && !is_flimsy(otmp)) {
+	    /* (flimsy exception matches polyself handling) */
+	    if (noisy)
+		pline_The("%s won't fit over your horn%s.",
+			  c_helmet, plur(num_horns(youmonst.data)));
+	    err++;
 	} else
 	    *mask = W_ARMH;
     } else if (is_shield(otmp)) {
@@ -1268,6 +1235,13 @@
 	} else if (Upolyd && slithy(youmonst.data)) {
 	    if (noisy) You("have no feet...");	/* not body_part(FOOT) */
 	    err++;
+	} else if (Upolyd && youmonst.data->mlet == S_CENTAUR) {
+	    /* break_armor() pushes boots off for centaurs,
+	       so don't let dowear() put them back on... */
+	    if (noisy) pline("You have too many hooves to wear %s.",
+			     c_boots);	/* makeplural(body_part(FOOT)) yields
+					   "rear hooves" which sounds odd */
+	    err++;
 	} else if (u.utrap && (u.utraptype == TT_BEARTRAP ||
 				u.utraptype == TT_INFLOOR)) {
 	    if (u.utraptype == TT_BEARTRAP) {
@@ -1322,7 +1296,7 @@
 	/* getobj can't do this after setting its allow_all flag; that
 	   happens if you have armor for slots that are covered up or
 	   extra armor for slots that are filled */
-	if (noisy) pline(silly_thing_to, "wear");
+	if (noisy) silly_thing("wear", otmp);
 	err++;
     }
 /* Unnecessary since now only weapons and special items like pick-axes get
@@ -1361,7 +1335,10 @@
 
 	if (otmp->otyp == HELM_OF_OPPOSITE_ALIGNMENT &&
 			qstart_level.dnum == u.uz.dnum) {	/* in quest */
-		You("narrowly avoid losing all chance at your goal.");
+		if (u.ualignbase[A_CURRENT] == u.ualignbase[A_ORIGINAL])
+			You("narrowly avoid losing all chance at your goal.");
+		else	/* converted */
+			You("are suddenly overcome with shame and change your mind.");
 		u.ublessed = 0; /* lose your god's protection */
 		makeknown(otmp->otyp);
 		flags.botl = 1;
@@ -1553,6 +1530,7 @@
 	register struct obj *otmp;
 	int xfl = 0;
 	boolean leftfall, rightfall;
+	const char *otherwep = 0;
 
 	leftfall = (uleft && !uleft->cursed &&
 		    (!uwep || !welded(uwep) || !bimanual(uwep)));
@@ -1561,7 +1539,8 @@
 		/* changed so cursed rings don't fall off, GAN 10/30/86 */
 		Your("%s off your %s.",
 			(leftfall && rightfall) ? "rings slip" : "ring slips",
-			makeplural(body_part(FINGER)));
+			(leftfall && rightfall) ? makeplural(body_part(FINGER)) :
+			body_part(FINGER));
 		xfl++;
 		if (leftfall) {
 			otmp = uleft;
@@ -1577,9 +1556,10 @@
 
 	otmp = uswapwep;
 	if (u.twoweap && otmp) {
+		otherwep = is_sword(otmp) ? c_sword :
+		    makesingular(oclass_names[(int)otmp->oclass]);
 		Your("%s %sslips from your %s.",
-			is_sword(otmp) ? c_sword :
-				makesingular(oclass_names[(int)otmp->oclass]),
+			otherwep,
 			xfl ? "also " : "",
 			makeplural(body_part(HAND)));
 		setuswapwep((struct obj *)0);
@@ -1589,10 +1569,16 @@
 	}
 	otmp = uwep;
 	if (otmp && !welded(otmp)) {
+		const char *thiswep;
+
+		/* nice wording if both weapons are the same type */
+		thiswep = is_sword(otmp) ? c_sword :
+		    makesingular(oclass_names[(int)otmp->oclass]);
+		if (otherwep && strcmp(thiswep, otherwep)) otherwep = 0;
+
 		/* changed so cursed weapons don't fall, GAN 10/30/86 */
-		Your("%s %sslips from your %s.",
-			is_sword(otmp) ? c_sword :
-				makesingular(oclass_names[(int)otmp->oclass]),
+		Your("%s%s %sslips from your %s.",
+			otherwep ? "other " : "", thiswep,
 			xfl ? "also " : "",
 			makeplural(body_part(HAND)));
 		setuwep((struct obj *)0);
@@ -1640,50 +1626,121 @@
 	}
 }
 
+/* used for praying to check and fix levitation trouble */
+struct obj *
+stuck_ring(ring, otyp)
+struct obj *ring;
+int otyp;
+{
+    if (ring != uleft && ring != uright) {
+	impossible("stuck_ring: neither left nor right?");
+	return (struct obj *)0;
+    }
+
+    if (ring && ring->otyp == otyp) {
+	/* reasons ring can't be removed match those checked by select_off();
+	   limbless case has extra checks because ordinarily it's temporary */
+	if (nolimbs(youmonst.data) &&
+		uamul && uamul->otyp == AMULET_OF_UNCHANGING && uamul->cursed)
+	    return uamul;
+	if (welded(uwep) && (ring == uright || bimanual(uwep))) return uwep;
+	if (uarmg && uarmg->cursed) return uarmg;
+	if (ring->cursed) return ring;
+    }
+    /* either no ring or not right type or nothing prevents its removal */
+    return (struct obj *)0;
+}
+
 STATIC_PTR
 int
 select_off(otmp)
 register struct obj *otmp;
 {
+	struct obj *why;
 	char buf[BUFSZ];
 
-	if(!otmp) return(0);
-	if(cursed(otmp)) return(0);
-	if((otmp->oclass==RING_CLASS || otmp->otyp == MEAT_RING)
-				&& nolimbs(youmonst.data))
-		return(0);
-	if(welded(uwep) && (otmp==uarmg || otmp==uright || (otmp==uleft
-			&& bimanual(uwep)))) {
-		You("cannot free a weapon hand to take off the ring.");
-		return(0);
+	if (!otmp) return 0;
+	*buf = '\0';			/* lint suppresion */
+
+	/* special ring checks */
+	if (otmp == uright || otmp == uleft) {
+	    if (nolimbs(youmonst.data)) {
+		pline_The("ring is stuck.");
+		return 0;
+	    }
+	    why = 0;	/* the item which prevents ring removal */
+	    if (welded(uwep) && (otmp == uright || bimanual(uwep))) {
+		Sprintf(buf, "free a weapon %s", body_part(HAND));
+		why = uwep;
+	    } else if (uarmg && uarmg->cursed) {
+		Sprintf(buf, "take off your %s", c_gloves);
+		why = uarmg;
+	    }
+	    if (why) {
+		You("cannot %s to remove the ring.", buf);
+		why->bknown = TRUE;
+		return 0;
+	    }
 	}
-	if(uarmg && uarmg->cursed && (otmp==uright || otmp==uleft)) {
-		uarmg->bknown = TRUE;
-		You("cannot remove your gloves to take off the ring.");
-		return(0);
+	/* special glove checks */
+	if (otmp == uarmg) {
+	    if (welded(uwep)) {
+		You("are unable to take off your %s while wielding that %s.",
+		    c_gloves, is_sword(uwep) ? c_sword : c_weapon);
+		uwep->bknown = TRUE;
+		return 0;
+	    } else if (Glib) {
+		You_cant("take off the slippery %s with your slippery %s.",
+			 c_gloves, makeplural(body_part(FINGER)));
+		return 0;
+	    }
 	}
-	if(otmp == uarmf && u.utrap && (u.utraptype == TT_BEARTRAP ||
-					u.utraptype == TT_INFLOOR)) {
-		return (0);
+	/* special boot checks */
+	if (otmp == uarmf) {
+	    if (u.utrap && u.utraptype == TT_BEARTRAP) {
+		pline_The("bear trap prevents you from pulling your %s out.",
+			  body_part(FOOT));
+		return 0;
+	    } else if (u.utrap && u.utraptype == TT_INFLOOR) {
+		You("are stuck in the %s, and cannot pull your %s out.",
+		    surface(u.ux, u.uy), makeplural(body_part(FOOT)));
+		return 0;
+	    }
 	}
-	if((otmp==uarm
+	/* special suit and shirt checks */
+	if (otmp == uarm
 #ifdef TOURIST
-			|| otmp==uarmu
+			|| otmp == uarmu
 #endif
-					) && uarmc && uarmc->cursed) {
-		Strcpy(buf, the(xname(uarmc)));
-		You("cannot remove %s to take off %s.", buf, the(xname(otmp)));
-		uarmc->bknown = TRUE;
-		return(0);
-	}
+		) {
+	    why = 0;	/* the item which prevents disrobing */
+	    if (uarmc && uarmc->cursed) {
+		Sprintf(buf, "remove your %s", cloak_simple_name(uarmc));
+		why = uarmc;
 #ifdef TOURIST
-	if(otmp==uarmu && uarm && uarm->cursed) {
-		Strcpy(buf, the(xname(uarm)));
-		You("cannot remove %s to take off %s.", buf, the(xname(otmp)));
-		uarm->bknown = TRUE;
-		return(0);
-	}
+	    } else if (otmp == uarmu && uarm && uarm->cursed) {
+		Sprintf(buf, "remove your %s", c_suit);
+		why = uarm;
 #endif
+	    } else if (welded(uwep) && bimanual(uwep)) {
+		Sprintf(buf, "release your %s",
+			is_sword(uwep) ? c_sword :
+			(uwep->otyp == BATTLE_AXE) ? c_axe : c_weapon);
+		why = uwep;
+	    }
+	    if (why) {
+		You("cannot %s to take off %s.", buf, the(xname(otmp)));
+		why->bknown = TRUE;
+		return 0;
+	    }
+	}
+	/* basic curse check */
+	if (otmp == uquiver || (otmp == uswapwep && !u.twoweap)) {
+	    ;	/* some items can be removed even when cursed */
+	} else {
+	    /* otherwise, this is fundamental */
+	    if (cursed(otmp)) return 0;
+	}
 
 	if(otmp == uarm) takeoff_mask |= WORN_ARMOR;
 	else if(otmp == uarmc) takeoff_mask |= WORN_CLOAK;
@@ -1765,6 +1822,8 @@
 	return(otmp);
 }
 
+static const char *disrobing = "";
+
 STATIC_PTR
 int
 take_off()
@@ -1772,13 +1831,13 @@
 	register int i;
 	register struct obj *otmp;
 
-	if(taking_off) {
-	    if(todelay > 0) {
-
+	if (taking_off) {
+	    if (todelay > 0) {
 		todelay--;
 		return(1);	/* still busy */
-	    } else if((otmp = do_takeoff())) off_msg(otmp);
-
+	    } else {
+		if ((otmp = do_takeoff())) off_msg(otmp);
+	    }
 	    takeoff_mask &= ~taking_off;
 	    taking_off = 0L;
 	}
@@ -1793,7 +1852,7 @@
 	todelay = 0;
 
 	if (taking_off == 0L) {
-	  You("finish disrobing.");
+	  You("finish %s.", disrobing);
 	  return 0;
 	} else if (taking_off == W_WEP) {
 	  todelay = 1;
@@ -1846,30 +1905,26 @@
 	 */
 	if (todelay>0) todelay--;
 
-	set_occupation(take_off, "disrobing", 0);
+	set_occupation(take_off, disrobing, 0);
 	return(1);		/* get busy */
 }
 
-#endif /* OVLB */
-#ifdef OVL1
-
 void
 reset_remarm()
 {
 	taking_off = takeoff_mask = 0L;
+	disrobing = nul;
 }
 
-#endif /* OVL1 */
-#ifdef OVLB
-
+/* the 'A' command */
 int
 doddoremarm()
 {
     int result = 0;
 
     if (taking_off || takeoff_mask) {
-	You("continue disrobing.");
-	set_occupation(take_off, "disrobing", 0);
+	You("continue %s.", disrobing);
+	set_occupation(take_off, disrobing, 0);
 	(void) take_off();
 	return 0;
     } else if (!uwep && !uswapwep && !uquiver && !uamul && !ublindf &&
@@ -1883,8 +1938,15 @@
 	    (result = ggetobj("take off", select_off, 0, FALSE, (unsigned *)0)) < -1)
 	result = menu_remarm(result);
 
-    if (takeoff_mask)
+    if (takeoff_mask) {
+	/* default activity for armor and/or accessories,
+	   possibly combined with weapons */
+	disrobing = "disrobing";
+	/* specific activity when handling weapons only */
+	if (!(takeoff_mask & ~(W_WEP|W_SWAPWEP|W_QUIVER)))
+	    disrobing = "disarming";
 	(void) take_off();
+    }
     /* The time to perform the command is already completely accounted for
      * in take_off(); if we return 1, that would add an extra turn to each
      * disrobe.
diff -Naurd ../nethack-3.4.0/src/dog.c ./src/dog.c
--- ../nethack-3.4.0/src/dog.c Wed Mar 20 23:43:03 2002
+++ ./src/dog.c Mon Feb 24 15:25:05 2003
@@ -56,8 +56,20 @@
 	int chance, trycnt = 100;
 
 	do {
-	    if (otmp) {
-		pm = &mons[otmp->corpsenm]; /* Figurine; otherwise spell */
+	    if (otmp) {	/* figurine; otherwise spell */
+		int mndx = otmp->corpsenm;
+		pm = &mons[mndx];
+		/* activating a figurine provides one way to exceed the
+		   maximum number of the target critter created--unless
+		   it has a special limit (erinys, Nazgul) */
+		if ((mvitals[mndx].mvflags & G_EXTINCT) &&
+			mbirth_limit(mndx) != MAXMONNO) {
+		    if (!quietly)
+			/* have just been given "You <do something with>
+			   the figurine and it transforms." message */
+			pline("... into a pile of dust.");
+		    break;	/* mtmp is null */
+		}
 	    } else if (!rn2(3)) {
 		pm = &mons[pet_type()];
 	    } else {
@@ -69,7 +81,7 @@
 		}
 	    }
 
-	    mtmp = makemon(pm, x, y, MM_EDOG);
+	    mtmp = makemon(pm, x, y, MM_EDOG|MM_IGNOREWATER);
 	    if (otmp && !mtmp) { /* monster was genocided or square occupied */
 	 	if (!quietly)
 		   pline_The("figurine writhes and then shatters into pieces!");
@@ -79,6 +91,9 @@
 
 	if (!mtmp) return (struct monst *)0;
 
+	if (is_pool(mtmp->mx, mtmp->my) && minliquid(mtmp))
+		return (struct monst *)0;
+
 	initedog(mtmp);
 	mtmp->msleeping = 0;
 	if (otmp) { /* figurine; resulting monster might not become a pet */
@@ -152,7 +167,7 @@
 	    otmp->dknown = otmp->bknown = otmp->rknown = 1;
 	    otmp->owornmask = W_SADDLE;
 	    otmp->leashmon = mtmp->m_id;
-	    update_mon_intrinsics(mtmp, otmp, TRUE);
+	    update_mon_intrinsics(mtmp, otmp, TRUE, TRUE);
 	}
 #endif
 
@@ -453,7 +468,13 @@
 		   the amulet; if you don't have it, will chase you
 		   only if in range. -3. */
 			(u.uhave.amulet && mtmp->iswiz))
-		&& !mtmp->msleeping && mtmp->mcanmove
+		&& ((!mtmp->msleeping && mtmp->mcanmove)
+#ifdef STEED
+		    /* eg if level teleport or new trap, steed has no control
+		       to avoid following */
+		    || (mtmp == u.usteed)
+#endif
+		    )
 		/* monster won't follow if it hasn't noticed you yet */
 		&& !(mtmp->mstrategy & STRAT_WAITFORU)) {
 		stay_behind = FALSE;
@@ -596,6 +617,7 @@
 	boolean carni = carnivorous(mon->data);
 	boolean herbi = herbivorous(mon->data);
 	struct permonst *fptr = &mons[obj->corpsenm];
+	boolean starving;
 
 	if (is_quest_artifact(obj) || obj_resists(obj, 0, 95))
 	    return (obj->cursed ? TABU : APPORT);
@@ -609,12 +631,17 @@
 
 	    /* Ghouls only eat old corpses... yum! */
 	    if (mon->data == &mons[PM_GHOUL])
-	    	return (obj->otyp == CORPSE && obj->age+50 <= monstermoves) ?
-	       			DOGFOOD : TABU;
+		return (obj->otyp == CORPSE &&
+			peek_at_iced_corpse_age(obj) + 50L <= monstermoves) ?
+				DOGFOOD : TABU;
 
 	    if (!carni && !herbi)
 		    return (obj->cursed ? UNDEF : APPORT);
 
+	    /* a starving pet will eat almost anything */
+	    starving = (mon->mtame && !mon->isminion &&
+			EDOG(mon)->mhpmax_penalty);
+
 	    switch (obj->otyp) {
 		case TRIPE_RATION:
 		case MEATBALL:
@@ -627,7 +654,7 @@
 			return POISON;
 		    return (carni ? CADAVER : MANFOOD);
 		case CORPSE:
-		   if ((peek_at_iced_corpse_age(obj)+50 <= monstermoves
+		   if ((peek_at_iced_corpse_age(obj) + 50L <= monstermoves
 					    && obj->corpsenm != PM_LIZARD
 					    && obj->corpsenm != PM_LICHEN
 					    && mon->data->mlet != S_FUNGUS) ||
@@ -640,24 +667,25 @@
 		    else return (carni ? CADAVER : MANFOOD);
 		case CLOVE_OF_GARLIC:
 		    return (is_undead(mon->data) ? TABU :
-			    (herbi ? ACCFOOD : MANFOOD));
+			    ((herbi || starving) ? ACCFOOD : MANFOOD));
 		case TIN:
 		    return (metallivorous(mon->data) ? ACCFOOD : MANFOOD);
 		case APPLE:
 		case CARROT:
-		    return (herbi ? DOGFOOD : MANFOOD);
+		    return (herbi ? DOGFOOD : starving ? ACCFOOD : MANFOOD);
 		case BANANA:
 		    return ((mon->data->mlet == S_YETI) ? DOGFOOD :
-			    (herbi ? ACCFOOD : MANFOOD));
+			    ((herbi || starving) ? ACCFOOD : MANFOOD));
 		default:
+		    if (starving) return ACCFOOD;
 		    return (obj->otyp > SLIME_MOLD ?
 			    (carni ? ACCFOOD : MANFOOD) :
 			    (herbi ? ACCFOOD : MANFOOD));
 	    }
 	default:
 	    if (obj->otyp == AMULET_OF_STRANGULATION ||
-	    		obj->otyp == RIN_SLOW_DIGESTION)
-	    	return (TABU);
+			obj->otyp == RIN_SLOW_DIGESTION)
+		return TABU;
 	    if (hates_silver(mon->data) &&
 		objects[obj->otyp].oc_material == SILVER)
 		return(TABU);
@@ -783,19 +811,28 @@
  * If the pet wasn't abused and was very tame, it might revive tame.
  */
 void
-wary_dog(mtmp, quietly)
+wary_dog(mtmp, was_dead)
 struct monst *mtmp;
-boolean quietly;
+boolean was_dead;
 {
-    int has_edog;
+    struct edog *edog;
+    boolean quietly = was_dead;
 
+    mtmp->meating = 0;
     if (!mtmp->mtame) return;
-    has_edog = !mtmp->isminion;
-    if (has_edog &&
-		((EDOG(mtmp)->killed_by_u == 1) || (EDOG(mtmp)->abuse > 2))) {
+    edog = !mtmp->isminion ? EDOG(mtmp) : 0;
+
+    /* if monster was starving when it died, undo that now */
+    if (edog && edog->mhpmax_penalty) {
+	mtmp->mhpmax += edog->mhpmax_penalty;
+	mtmp->mhp += edog->mhpmax_penalty;	/* heal it */
+	edog->mhpmax_penalty = 0;
+    }
+
+    if (edog && (edog->killed_by_u == 1 || edog->abuse > 2)) {
 	mtmp->mpeaceful = mtmp->mtame = 0;
-	if (EDOG(mtmp)->abuse >= 0 && EDOG(mtmp)->abuse < 10)
-		if (!rn2(EDOG(mtmp)->abuse + 1)) mtmp->mpeaceful = 1;
+	if (edog->abuse >= 0 && edog->abuse < 10)
+	    if (!rn2(edog->abuse + 1)) mtmp->mpeaceful = 1;
 	if(!quietly && cansee(mtmp->mx, mtmp->my)) {
 	    if (haseyes(youmonst.data)) {
 		if (haseyes(mtmp->data))
@@ -810,10 +847,10 @@
 	    }
 	}
     } else {
-    	/* chance it goes wild anyway - Pet Semetary */
-    	if (!rn2(mtmp->mtame)) {
-    		mtmp->mpeaceful = mtmp->mtame = 0;
-    	}
+	/* chance it goes wild anyway - Pet Semetary */
+	if (!rn2(mtmp->mtame)) {
+	    mtmp->mpeaceful = mtmp->mtame = 0;
+	}
     }
     if (!mtmp->mtame) {
 	newsym(mtmp->mx, mtmp->my);
@@ -823,10 +860,19 @@
     }
 
     /* if its still a pet, start a clean pet-slate now */
-    if (has_edog && mtmp->mtame) {
-	EDOG(mtmp)->revivals++;
-    	EDOG(mtmp)->killed_by_u = 0;
-    	EDOG(mtmp)->abuse = 0;
+    if (edog && mtmp->mtame) {
+	edog->revivals++;
+	edog->killed_by_u = 0;
+	edog->abuse = 0;
+	edog->ogoal.x = edog->ogoal.y = -1;
+	if (was_dead || edog->hungrytime < monstermoves + 500L)
+	    edog->hungrytime = monstermoves + 500L;
+	if (was_dead) {
+	    edog->droptime = 0L;
+	    edog->dropdist = 10000;
+	    edog->whistletime = 0L;
+	    edog->apport = 5;
+	} /* else lifesaved, so retain current values */
     }
 }
 
diff -Naurd ../nethack-3.4.0/src/dogmove.c ./src/dogmove.c
--- ../nethack-3.4.0/src/dogmove.c Wed Mar 20 23:43:03 2002
+++ ./src/dogmove.c Mon Feb 24 15:25:05 2003
@@ -100,7 +100,7 @@
 		mtmp->meating = eaten_stat(mtmp->meating, obj);
 		nutrit = eaten_stat(nutrit, obj);
 	    }
-	} else if (obj->oclass == GOLD_CLASS) {
+	} else if (obj->oclass == COIN_CLASS) {
 	    mtmp->meating = (int)(obj->quan/2000) + 1;
 	    if (mtmp->meating < 0) mtmp->meating = 1;
 	    nutrit = (int)(obj->quan/20);
@@ -191,23 +191,8 @@
 	    delobj(obj);
 
 	if (poly) {
-	    char oldpet[BUFSZ];
-#ifdef STEED
-	    long mw = mtmp->misc_worn_check;
-
-	    mtmp->misc_worn_check &= ~W_SADDLE;
-#endif
-	    Strcpy(oldpet, Monnam(mtmp));
-#ifdef STEED
-	    mtmp->misc_worn_check = mw;
-#endif
-	    if (newcham(mtmp, (struct permonst *)0, FALSE) &&
-			cansee(mtmp->mx, mtmp->my)) {
-		uchar save_mnamelth = mtmp->mnamelth;
-		mtmp->mnamelth = 0;
-		pline("%s turns into %s!", oldpet, a_monnam(mtmp));
-		mtmp->mnamelth = save_mnamelth;
-	    }
+	    (void) newcham(mtmp, (struct permonst *)0, FALSE,
+			   cansee(mtmp->mx, mtmp->my));
 	}
 	/* limit "instant" growth to prevent potential abuse */
 	if (grow && (int) mtmp->m_lev < (int)mtmp->data->mlevel + 15) {
@@ -247,12 +232,15 @@
 		    You_feel("worried about %s.", y_monnam(mtmp));
 		stop_occupation();
 	    } else if (monstermoves > edog->hungrytime + 750 || mtmp->mhp < 1) {
-	    dog_died:
-		if (mtmp->mleashed)
+ dog_died:
+		if (mtmp->mleashed
+#ifdef STEED
+		    && mtmp != u.usteed
+#endif
+		    )
 		    Your("leash goes slack.");
 		else if (cansee(mtmp->mx, mtmp->my))
-		    pline("%s dies%s.", Monnam(mtmp),
-			    (mtmp->mhp >= 1) ? "" : " from hunger");
+		    pline("%s starves.", Monnam(mtmp));
 		else
 		    You_feel("%s for a moment.",
 			Hallucination ? "bummed" : "sad");
@@ -301,7 +289,11 @@
 			&& obj->otyp != SCR_MAIL
 #endif
 									){
-		if (dogfood(mtmp, obj) <= CADAVER)
+		int edible = dogfood(mtmp, obj);
+
+		if (edible <= CADAVER ||
+			/* starving pet is more aggressive about eating */
+			(edog->mhpmax_penalty && edible == ACCFOOD))
 		    return dog_eat(mtmp, obj, omx, omy, FALSE);
 
 		if(can_carry(mtmp, obj) && !obj->cursed &&
@@ -338,12 +330,11 @@
 int after, udist, whappr;
 {
 	register int omx, omy;
-	boolean in_masters_sight;
+	boolean in_masters_sight, dog_has_minvent;
 	register struct obj *obj;
 	xchar otyp;
 	int appr;
 
-
 #ifdef STEED
 	/* Steeds don't move on their own will */
 	if (mtmp == u.usteed)
@@ -354,6 +345,7 @@
 	omy = mtmp->my;
 
 	in_masters_sight = couldsee(omx, omy);
+	dog_has_minvent = (DROPPABLES(mtmp) != 0);
 
 	if (!edog || mtmp->mleashed) {	/* he's not going anywhere... */
 	    gtyp = APPORT;
@@ -368,7 +360,7 @@
 	    gtyp = UNDEF;	/* no goal as yet */
 	    gx = gy = 0;	/* suppress 'used before set' message */
 
-	    if ((min_x = omx - SQSRCHRADIUS) < 0) min_x = 0;
+	    if ((min_x = omx - SQSRCHRADIUS) < 1) min_x = 1;
 	    if ((max_x = omx + SQSRCHRADIUS) >= COLNO) max_x = COLNO - 1;
 	    if ((min_y = omy - SQSRCHRADIUS) < 0) min_y = 0;
 	    if ((max_y = omy + SQSRCHRADIUS) >= ROWNO) max_y = ROWNO - 1;
@@ -379,9 +371,12 @@
 		ny = obj->oy;
 		if (nx >= min_x && nx <= max_x && ny >= min_y && ny <= max_y) {
 		    otyp = dogfood(mtmp, obj);
+		    /* skip inferior goals */
 		    if (otyp > gtyp || otyp == UNDEF)
 			continue;
-		    if (cursed_object_at(nx, ny))
+		    /* avoid cursed items unless starving */
+		    if (cursed_object_at(nx, ny) &&
+			    !(edog->mhpmax_penalty && otyp < MANFOOD))
 			continue;
 		    if (otyp < MANFOOD &&
 			    can_reach_food(mtmp, mtmp->mx, mtmp->my, nx, ny)) {
@@ -391,7 +386,7 @@
 			    gtyp = otyp;
 			}
 		    } else if(gtyp == UNDEF && in_masters_sight &&
-			      !mtmp->minvent &&
+			      !dog_has_minvent &&
 			      (!levl[omx][omy].lit || levl[u.ux][u.uy].lit) &&
 			      (otyp == MANFOOD || m_cansee(mtmp, nx, ny)) &&
 			      edog->apport > rn2(8) &&
@@ -415,7 +410,7 @@
 		if (udist > 1) {
 			if (!IS_ROOM(levl[u.ux][u.uy].typ) || !rn2(4) ||
 			   whappr ||
-			   (mtmp->minvent && rn2(edog->apport)))
+			   (dog_has_minvent && rn2(edog->apport)))
 				appr = 1;
 		}
 		/* if you have dog food it'll follow you more closely */
@@ -539,7 +534,8 @@
 	if (appr == -2) return(0);
 
 	allowflags = ALLOW_M | ALLOW_TRAPS | ALLOW_SSM | ALLOW_SANCT;
-	if (passes_walls(mtmp->data)) allowflags |= (ALLOW_ROCK|ALLOW_WALL);
+	if (passes_walls(mtmp->data)) allowflags |= (ALLOW_ROCK | ALLOW_WALL);
+	if (passes_bars(mtmp->data)) allowflags |= ALLOW_BARS;
 	if (throws_rocks(mtmp->data)) allowflags |= ALLOW_ROCK;
 	if (Conflict && !resist(mtmp, RING_CLASS, 0, 0)) {
 	    allowflags |= ALLOW_U;
@@ -575,10 +571,7 @@
 		if (m_carrying(mtmp, SKELETON_KEY)) allowflags |= BUSTDOOR;
 	}
 	if (is_giant(mtmp->data)) allowflags |= BUSTDOOR;
-	if (tunnels(mtmp->data) && (!needspick(mtmp->data) ||
-					m_carrying(mtmp, PICK_AXE) ||
-					m_carrying(mtmp, DWARVISH_MATTOCK)))
-		allowflags |= ALLOW_DIG;
+	if (tunnels(mtmp->data)) allowflags |= ALLOW_DIG;
 	cnt = mfndpos(mtmp, poss, info, allowflags);
 
 	/* Normally dogs don't step on cursed items, but if they have no
@@ -724,12 +717,22 @@
 		}
 		if (!m_in_out_region(mtmp, nix, niy))
 		    return 1;
-		if(IS_ROCK(levl[nix][niy].typ) && may_dig(nix,niy) &&
+		if (((IS_ROCK(levl[nix][niy].typ) && may_dig(nix,niy)) ||
+		     closed_door(nix, niy)) &&
 		    mtmp->weapon_check != NO_WEAPON_WANTED &&
-		    tunnels(mtmp->data) && needspick(mtmp->data) &&
-			(!(mw_tmp = MON_WEP(mtmp)) || !is_pick(mw_tmp))) {
-		    mtmp->weapon_check = NEED_PICK_AXE;
-		    if (mon_wield_item(mtmp))
+		    tunnels(mtmp->data) && needspick(mtmp->data)) {
+		    if (closed_door(nix, niy)) {
+			if (!(mw_tmp = MON_WEP(mtmp)) ||
+			    !is_pick(mw_tmp) || !is_axe(mw_tmp))
+			    mtmp->weapon_check = NEED_PICK_OR_AXE;
+		    } else if (IS_TREE(levl[nix][niy].typ)) {
+			if (!(mw_tmp = MON_WEP(mtmp)) || !is_axe(mw_tmp))
+			    mtmp->weapon_check = NEED_AXE;
+		    } else if (!(mw_tmp = MON_WEP(mtmp)) || !is_pick(mw_tmp)) {
+			mtmp->weapon_check = NEED_PICK_AXE;
+		    }
+		    if (mtmp->weapon_check >= NEED_PICK_AXE &&
+			mon_wield_item(mtmp))
 			return 0;
 		}
 		/* insert a worm_move() if worms ever begin to eat things */
@@ -757,16 +760,16 @@
 		ny = sgn(omy - u.uy);
 		cc.x = u.ux + nx;
 		cc.y = u.uy + ny;
-		if (goodpos(cc.x, cc.y, mtmp)) goto dognext;
+		if (goodpos(cc.x, cc.y, mtmp, 0)) goto dognext;
 
 		i  = xytod(nx, ny);
 		for (j = (i + 7)%8; j < (i + 1)%8; j++) {
 			dtoxy(&cc, j);
-			if (goodpos(cc.x, cc.y, mtmp)) goto dognext;
+			if (goodpos(cc.x, cc.y, mtmp, 0)) goto dognext;
 		}
 		for (j = (i + 6)%8; j < (i + 2)%8; j++) {
 			dtoxy(&cc, j);
-			if (goodpos(cc.x, cc.y, mtmp)) goto dognext;
+			if (goodpos(cc.x, cc.y, mtmp, 0)) goto dognext;
 		}
 		cc.x = mtmp->mx;
 		cc.y = mtmp->my;
diff -Naurd ../nethack-3.4.0/src/dokick.c ./src/dokick.c
--- ../nethack-3.4.0/src/dokick.c Wed Mar 20 23:43:03 2002
+++ ./src/dokick.c Mon Feb 24 15:25:05 2003
@@ -34,6 +34,7 @@
 	register int dmg = ( ACURRSTR + ACURR(A_DEX) + ACURR(A_CON) )/ 15;
 	int kick_skill = P_NONE;
 	int blessed_foot_damage = 0;
+	boolean trapkilled = FALSE;
 
 	if (uarmf && uarmf->otyp == KICKING_BOOTS)
 	    dmg += 5;
@@ -61,14 +62,7 @@
 
 	if(mon->m_ap_type) seemimic(mon);
 
-	/* it is unchivalrous to attack the defenseless or from behind */
-	if (Role_if(PM_KNIGHT) &&
-		u.ualign.type == A_LAWFUL && u.ualign.record > -10 &&
-		(!mon->mcanmove || mon->msleeping ||
-		(mon->mflee && !mon->mavenge))) {
-	    You_feel("like a caitiff!");
-	    adjalign(-1);
-	}
+	check_caitiff(mon);
 
 	/* squeeze some guilt feelings... */
 	if(mon->mtame) {
@@ -99,7 +93,7 @@
 		/* see if the monster has a place to move into */
 		mdx = mon->mx + u.dx;
 		mdy = mon->my + u.dy;
-		if(goodpos(mdx, mdy, mon)) {
+		if(goodpos(mdx, mdy, mon, 0)) {
 			pline("%s reels from the blow.", Monnam(mon));
 			if (m_in_out_region(mon, mdx, mdy)) {
 			    remove_monster(mon->mx, mon->my);
@@ -107,13 +101,13 @@
 			    place_monster(mon, mdx, mdy);
 			    newsym(mon->mx, mon->my);
 			    set_apparxy(mon);
-			    (void) mintrap(mon);
+			    if (mintrap(mon) == 2) trapkilled = TRUE;
 			}
 		}
 	}
 
 	(void) passive(mon, TRUE, mon->mhp > 0, AT_KICK);
-	if (mon->mhp <= 0) killed(mon);
+	if (mon->mhp <= 0 && !trapkilled) killed(mon);
 
 	/* may bring up a dialog, so put this after all messages */
 	if (kick_skill != P_NONE)	/* exercise proficiency */
@@ -214,6 +208,10 @@
 		} else {
 		    mnexto(mon);
 		    if(mon->mx != x || mon->my != y) {
+			if(glyph_is_invisible(levl[x][y].glyph)) {
+			    unmap_object(x, y);
+			    newsym(x, y);
+			}
 			pline("%s %s, %s evading your %skick.", Monnam(mon),
 				(can_teleport(mon->data) ? "teleports" :
 				 is_floater(mon->data) ? "floats" :
@@ -408,6 +406,37 @@
 				    costly_spot(x, y));
 	insider = (*u.ushops && inside_shop(u.ux, u.uy) &&
 				    *in_rooms(x, y, SHOPBASE) == *u.ushops);
+	isgold = (kickobj->oclass == COIN_CLASS);
+
+	if (IS_ROCK(levl[x][y].typ) || closed_door(x, y)) {
+	    if ((!martial() && rn2(20) > ACURR(A_DEX)) ||
+		    IS_ROCK(levl[u.ux][u.uy].typ) || closed_door(u.ux, u.uy)) {
+		if (Blind)
+		    pline("It doesn't come loose.");
+		else
+		    pline("%s %sn't come loose.",
+			  The(distant_name(kickobj, xname)),
+			  otense(kickobj, "do"));
+		return (!rn2(3) || martial());
+	    }
+	    if (Blind)
+		pline("It comes loose.");
+	    else
+		pline("%s %s loose.",
+		      The(distant_name(kickobj, xname)),
+		      otense(kickobj, "come"));
+	    obj_extract_self(kickobj);
+	    newsym(x, y);
+	    if (costly && (!costly_spot(u.ux, u.uy) ||
+		    !index(u.urooms, *in_rooms(x, y, SHOPBASE))))
+		addtobill(kickobj, FALSE, FALSE, FALSE);
+	    if (!flooreffects(kickobj, u.ux, u.uy, "fall")) {
+		place_object(kickobj, u.ux, u.uy);
+		stackobj(kickobj);
+		newsym(u.ux, u.uy);
+	    }
+	    return 1;
+	}
 
 	/* a box gets a chance of breaking open here */
 	if(Is_box(kickobj)) {
@@ -480,35 +509,6 @@
 	/* fragile objects should not be kicked */
 	if (hero_breaks(kickobj, kickobj->ox, kickobj->oy, FALSE)) return 1;
 
-	if (IS_ROCK(levl[x][y].typ) || closed_door(x, y)) {
-		if ((!martial() && rn2(20) > ACURR(A_DEX))
-				 || IS_ROCK(levl[u.ux][u.uy].typ)
-				 || closed_door(u.ux, u.uy)) {
-			if (Blind) pline("It doesn't come loose.");
-			else pline("%s %sn't come loose.",
-				The(distant_name(kickobj, xname)),
-				otense(kickobj, "do"));
-			return(!rn2(3) || martial());
-		}
-		if (Blind) pline("It comes loose.");
-		else pline("%s %s loose.",
-			   The(distant_name(kickobj, xname)),
-			   otense(kickobj, "come"));
-		obj_extract_self(kickobj);
-		newsym(x, y);
-		if (costly && (!costly_spot(u.ux, u.uy)
-			       || !index(u.urooms, *in_rooms(x, y, SHOPBASE))))
-			addtobill(kickobj, FALSE, FALSE, FALSE);
-		if(!flooreffects(kickobj,u.ux,u.uy,"fall")) {
-		    place_object(kickobj, u.ux, u.uy);
-		    stackobj(kickobj);
-		    newsym(u.ux, u.uy);
-		}
-		return(1);
-	}
-
-	isgold = (kickobj->oclass == GOLD_CLASS);
-
 	/* too heavy to move.  range is calculated as potential distance from
 	 * player, so range == 2 means the object may move up to one square
 	 * from its current position
@@ -543,8 +543,15 @@
 	}
 
 	/* the object might have fallen down a hole */
-	if (kickobj->where == OBJ_MIGRATING)
+	if (kickobj->where == OBJ_MIGRATING) {
+	    if (costly) {
+		if(isgold)
+		    costly_gold(x, y, kickobj->quan);
+		else (void)stolen_value(kickobj, x, y,
+					(boolean)shkp->mpeaceful, FALSE);
+	    }
 	    return 1;
+	}
 
 	bhitroom = *in_rooms(bhitpos.x, bhitpos.y, SHOPBASE);
 	if (costly && (!costly_spot(bhitpos.x, bhitpos.y) ||
@@ -594,7 +601,6 @@
 	register int x, y;
 	int avrg_attrib;
 	register struct monst *mtmp;
-	s_level *slev;
 	boolean no_kick = FALSE;
 	char buf[BUFSZ];
 
@@ -628,6 +634,9 @@
 	} else if (near_capacity() > SLT_ENCUMBER) {
 		Your("load is too heavy to balance yourself for a kick.");
 		no_kick = TRUE;
+	} else if (youmonst.data->mlet == S_LIZARD) {
+		Your("legs cannot kick effectively.");
+		no_kick = TRUE;
 	} else if (u.uinwater && !rn2(2)) {
 		Your("slow motion kick doesn't hit anything.");
 		no_kick = TRUE;
@@ -712,7 +721,8 @@
 		kick_monster(x, y);
 		flags.forcefight = FALSE;
 		/* see comment in attack_checks() */
-		if (!canspotmon(mtmp) &&
+		if (!DEADMONSTER(mtmp) &&
+		    !canspotmon(mtmp) &&
 		    /* check x and y; a monster that evades your kick by
 		       jumping to an unseen square doesn't leave an I behind */
 		    mtmp->mx == x && mtmp->my == y &&
@@ -811,7 +821,9 @@
 			(void) mkgold((long) rn1(201, 300), x, y);
 			i = Luck + 1;
 			if(i > 6) i = 6;
-			while(i--) (void) mkobj_at(GEM_CLASS, x, y, TRUE);
+			while(i--)
+			    (void) mksobj_at(rnd_class(DILITHIUM_CRYSTAL,
+					LUCKSTONE-1), x, y, FALSE, TRUE);
 			if (Blind)
 			    You("kick %s loose!", something);
 			else {
@@ -854,30 +866,46 @@
 		    goto ouch;
 		if(IS_TREE(maploc->typ)) {
 		    struct obj *treefruit;
-		    if (rn2(8)) goto ouch;
-		    /* fruit or trouble ? */
-		    if (!rn2(2) && !(maploc->looted & TREE_LOOTED) &&
+		    /* nothing, fruit or trouble? 75:23.5:1.5% */
+		    if (rn2(3)) {
+			if ( !rn2(6) && !(mvitals[PM_KILLER_BEE].mvflags & G_GONE) )
+			    You_hear("a low buzzing."); /* a warning */
+			goto ouch;
+		    }
+		    if (rn2(15) && !(maploc->looted & TREE_LOOTED) &&
 			  (treefruit = rnd_treefruit_at(x, y))) {
-			treefruit->quan = (long)(8 - rnl(8));
+			long nfruit = 8L-rnl(7), nfall;
+			treefruit->quan = nfruit;
 			if (is_plural(treefruit))
 			    pline("Some %s fall from the tree!", xname(treefruit));
 			else
 			    pline("%s falls from the tree!", An(xname(treefruit)));
-			scatter(x,y,2,MAY_HIT,treefruit);
+			nfall = scatter(x,y,2,MAY_HIT,treefruit);
+			if ( nfall != nfruit ) {
+			    /* scatter left some in the tree */
+			    pline("%ld %s got caught in the branches.",
+				nfruit-nfall, xname(treefruit));
+			}
 			exercise(A_DEX, TRUE);
 			exercise(A_WIS, TRUE);	/* discovered a new food source! */
 			newsym(x, y);
 			maploc->looted |= TREE_LOOTED;
 			return(1);
-		    } else if (!rn2(15) && !(maploc->looted & TREE_SWARM)){
-		    	int cnt = rnl(5);
+		    } else if (!(maploc->looted & TREE_SWARM)) {
+		    	int cnt = rnl(4) + 2;
+			int made = 0;
 		    	coord mm;
 		    	mm.x = x; mm.y = y;
-			pline("You've attracted the tree's former occupants!");
-			while (cnt--)
-			    if (enexto(&mm, mm.x, mm.y, &mons[PM_KILLER_BEE]))
-				(void) makemon(&mons[PM_KILLER_BEE],
-					       mm.x, mm.y, MM_ANGRY);
+			while (cnt--) {
+			    if (enexto(&mm, mm.x, mm.y, &mons[PM_KILLER_BEE])
+				&& makemon(&mons[PM_KILLER_BEE],
+					       mm.x, mm.y, MM_ANGRY))
+				made++;
+			}
+			if ( made )
+			    pline("You've attracted the tree's former occupants!");
+			else
+			    You("smell stale honey.");
 			maploc->looted |= TREE_SWARM;
 			return(1);
 		    }
@@ -902,7 +930,7 @@
 			    You_hear("a gushing sound.");
 			else
 			    pline("A %s ooze gushes up from the drain!",
-					 hcolor(Black));
+					 hcolor(NH_BLACK));
 			(void) makemon(&mons[PM_BLACK_PUDDING],
 					 x, y, NO_MM_FLAGS);
 			exercise(A_DEX, TRUE);
@@ -1011,9 +1039,9 @@
 		unblock_point(x,y);		/* vision */
 		if (shopdoor) {
 		    add_damage(x, y, 400L);
-		    pay_for_damage("break");
+		    pay_for_damage("break", FALSE);
 		}
-		if ((slev = Is_special(&u.uz)) && slev->flags.town)
+		if (in_town(x, y))
 		  for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
 		    if (DEADMONSTER(mtmp)) continue;
 		    if((mtmp->data == &mons[PM_WATCHMAN] ||
@@ -1033,7 +1061,7 @@
 	    if (Blind) feel_location(x,y);	/* we know we hit it */
 	    exercise(A_STR, TRUE);
 	    pline("WHAMMM!!!");
-	    if ((slev = Is_special(&u.uz)) && slev->flags.town)
+	    if (in_town(x, y))
 		for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
 		    if (DEADMONSTER(mtmp)) continue;
 		    if ((mtmp->data == &mons[PM_WATCHMAN] ||
@@ -1155,7 +1183,7 @@
 		    /* set obj->no_charge to 0 */
 		    if (Has_contents(obj))
 			picked_container(obj);	/* does the right thing */
-		    if (obj->oclass != GOLD_CLASS)
+		    if (obj->oclass != COIN_CLASS)
 			obj->no_charge = 0;
 		}
 
@@ -1276,7 +1304,7 @@
 	    /* set otmp->no_charge to 0 */
 	    if(container)
 		picked_container(otmp); /* happens to do the right thing */
-	    if(otmp->oclass != GOLD_CLASS)
+	    if(otmp->oclass != COIN_CLASS)
 		otmp->no_charge = 0;
 	}
 
@@ -1286,7 +1314,8 @@
 
 	/* some things break rather than ship */
 	if (breaktest(otmp)) {
-	    char *result;
+	    const char *result;
+
 	    if (objects[otmp->otyp].oc_material == GLASS
 #ifdef TOURIST
 		|| otmp->otyp == EXPENSIVE_CAMERA
@@ -1311,6 +1340,8 @@
 	otmp->ox = cc.x;
 	otmp->oy = cc.y;
 	otmp->owornmask = (long)toloc;
+	/* boulder from rolling boulder trap, no longer part of the trap */
+	if (otmp->otyp == BOULDER) otmp->otrapped = 0;
 
 	if(impact) {
 	    /* the objs impacted may be in a shop other than
@@ -1359,7 +1390,7 @@
 	    if (nx > 0) {
 		place_object(otmp, nx, ny);
 		stackobj(otmp);
-		scatter(nx, ny, rnd(2), 0, otmp);
+		(void)scatter(nx, ny, rnd(2), 0, otmp);
 	    } else {		/* random location */
 		/* set dummy coordinates because there's no
 		   current position for rloco() to update */
diff -Naurd ../nethack-3.4.0/src/dothrow.c ./src/dothrow.c
--- ../nethack-3.4.0/src/dothrow.c Wed Mar 20 23:43:03 2002
+++ ./src/dothrow.c Mon Feb 24 15:25:05 2003
@@ -21,10 +21,12 @@
 
 
 static NEARDATA const char toss_objs[] =
-	{ ALLOW_COUNT, GOLD_CLASS, ALL_CLASSES, WEAPON_CLASS, 0 };
+	{ ALLOW_COUNT, COIN_CLASS, ALL_CLASSES, WEAPON_CLASS, 0 };
 /* different default choices when wielding a sling (gold must be included) */
 static NEARDATA const char bullets[] =
-	{ ALLOW_COUNT, GOLD_CLASS, ALL_CLASSES, GEM_CLASS, 0 };
+	{ ALLOW_COUNT, COIN_CLASS, ALL_CLASSES, GEM_CLASS, 0 };
+
+struct obj *thrownobj = 0;	/* tracks an object until it lands */
 
 extern boolean notonhead;	/* for long worms */
 
@@ -44,7 +46,7 @@
 	/* ask "in what direction?" */
 #ifndef GOLDOBJ
 	if (!getdir((char *)0)) {
-		if (obj->oclass == GOLD_CLASS) {
+		if (obj->oclass == COIN_CLASS) {
 		    u.ugold += obj->quan;
 		    flags.botl = 1;
 		    dealloc_obj(obj);
@@ -52,7 +54,7 @@
 		return(0);
 	}
 
-	if(obj->oclass == GOLD_CLASS) return(throw_gold(obj));
+	if(obj->oclass == COIN_CLASS) return(throw_gold(obj));
 #else
 	if (!getdir((char *)0)) {
 	    /* obj might need to be merged back into the singular gold object */
@@ -69,7 +71,7 @@
           If the money is in quiver, throw one coin at a time,
           possibly using a sling.
         */
-	if(obj->oclass == GOLD_CLASS && obj != uquiver) return(throw_gold(obj));
+	if(obj->oclass == COIN_CLASS && obj != uquiver) return(throw_gold(obj));
 #endif
 
 	if(!canletgo(obj,"throw"))
@@ -167,8 +169,8 @@
 		otmp = splitobj(obj, 1L);
 	    } else {
 		otmp = obj;
-		if (otmp->owornmask && otmp != uball)
-		    remove_worn_item(otmp);
+		if (otmp->owornmask)
+		    remove_worn_item(otmp, FALSE);
 	    }
 	    freeinv(otmp);
 	    throwit(otmp, wep_mask, twoweap);
@@ -215,7 +217,7 @@
 static void
 autoquiver()
 {
-	register struct obj *otmp, *oammo = 0, *omissile = 0, *omisc = 0;
+	struct obj *otmp, *oammo = 0, *omissile = 0, *omisc = 0, *altammo = 0;
 
 	if (uquiver)
 	    return;
@@ -233,6 +235,8 @@
 			 objects[otmp->otyp].oc_material == GLASS)) {
 		if (uslinging())
 		    oammo = otmp;
+		else if (ammo_and_launcher(otmp, uswapwep))
+		    altammo = otmp;
 		else if (!omisc)
 		    omisc = otmp;
 	    } else if (otmp->oclass == GEM_CLASS) {
@@ -242,6 +246,8 @@
 		if (ammo_and_launcher(otmp, uwep))
 		    /* Ammo matched with launcher (bow and arrow, crossbow and bolt) */
 		    oammo = otmp;
+		else if (ammo_and_launcher(otmp, uswapwep))
+		    altammo = otmp;
 		else
 		    /* Mismatched ammo (no better than an ordinary weapon) */
 		    omisc = otmp;
@@ -263,6 +269,8 @@
 	    setuqwep(oammo);
 	else if (omissile)
 	    setuqwep(omissile);
+	else if (altammo)
+	    setuqwep(altammo);
 	else if (omisc)
 	    setuqwep(omisc);
 
@@ -437,11 +445,13 @@
     if (!isok(x,y)) {
 	You_feel("the spirits holding you back.");
 	return FALSE;
+    } else if (!in_out_region(x, y)) {
+	return FALSE;
     }
 
     if (!Passes_walls || !(may_pass = may_passwall(x, y))) {
 	if (IS_ROCK(levl[x][y].typ) || closed_door(x,y)) {
-	    char *s;
+	    const char *s;
 
 	    pline("Ouch!");
 	    if (IS_TREE(levl[x][y].typ))
@@ -469,6 +479,17 @@
 	    losehp(rnd(2+*range), "touching the edge of the universe", KILLED_BY);
 	    return FALSE;
 	}
+	if ((u.ux - x) && (u.uy - y) &&
+		bad_rock(youmonst.data,u.ux,y) && bad_rock(youmonst.data,x,u.uy)) {
+	    boolean too_much = (invent && (inv_weight() + weight_cap() > 600));
+	    /* Move at a diagonal. */
+	    if (bigmonst(youmonst.data) || too_much) {
+		You("%sget forcefully wedged into a crevice.",
+			too_much ? "and all your belongings " : "");
+		losehp(rnd(2+*range), "wedging into a narrow crevice", KILLED_BY);
+		return FALSE;
+	    }
+	}
     }
 
     if ((mon = m_at(x, y)) != 0) {
@@ -536,7 +557,7 @@
 	/* TODO: Treat walls, doors, iron bars, pools, lava, etc. specially
 	 * rather than just stopping before.
 	 */
-	if (goodpos(x, y, mon) && m_in_out_region(mon, x, y)) {
+	if (goodpos(x, y, mon, 0) && m_in_out_region(mon, x, y)) {
 	    remove_monster(mon->mx, mon->my);
 	    newsym(mon->mx, mon->my);
 	    place_monster(mon, x, y);
@@ -863,6 +884,8 @@
 	    u.dz = 1;
 	}
 
+	thrownobj = obj;
+
 	if(u.uswallow) {
 		mon = u.ustuck;
 		bhitpos.x = mon->mx;
@@ -882,6 +905,7 @@
 	    } else {
 		hitfloor(obj);
 	    }
+	    thrownobj = (struct obj*)0;
 	    return;
 
 	} else if(obj->otyp == BOOMERANG && !Underwater) {
@@ -896,6 +920,7 @@
 			    setworn(obj, wep_mask);
 			    u.twoweap = twoweap;
 			}
+			thrownobj = (struct obj*)0;
 			return;
 		}
 	} else {
@@ -953,8 +978,10 @@
 		boolean obj_gone;
 
 		if (mon->isshk &&
-			obj->where == OBJ_MINVENT && obj->ocarry == mon)
+		    obj->where == OBJ_MINVENT && obj->ocarry == mon) {
+		    thrownobj = (struct obj*)0;
 		    return;		/* alert shk caught it */
+		}
 		(void) snuff_candle(obj);
 		notonhead = (bhitpos.x != mon->mx || bhitpos.y != mon->my);
 		obj_gone = thitmonst(mon, obj);
@@ -1004,12 +1031,16 @@
 				  body_part(ARM));
 			    (void) artifact_hit((struct monst *)0,
 						&youmonst, obj, &dmg, 0);
-			    losehp(dmg, xname(obj), KILLED_BY);
+			    losehp(dmg, xname(obj),
+				obj_is_pname(obj) ? KILLED_BY : KILLED_BY_AN);
 			}
-			if (ship_object(obj, u.ux, u.uy, FALSE))
+			if (ship_object(obj, u.ux, u.uy, FALSE)) {
+		    	    thrownobj = (struct obj*)0;
 			    return;
+			}
 			dropy(obj);
 		    }
+		    thrownobj = (struct obj*)0;
 		    return;
 		}
 
@@ -1032,11 +1063,15 @@
 		    if(*u.ushops)
 			check_shop_obj(obj, bhitpos.x, bhitpos.y, FALSE);
 		    (void) mpickobj(mon, obj);	/* may merge and free obj */
+		    thrownobj = (struct obj*)0;
 		    return;
 		}
 		(void) snuff_candle(obj);
-		if (!mon && ship_object(obj, bhitpos.x, bhitpos.y, FALSE))
+		if (!mon && ship_object(obj, bhitpos.x, bhitpos.y, FALSE)) {
+		    thrownobj = (struct obj*)0;
 		    return;
+		}
+		thrownobj = (struct obj*)0;
 		place_object(obj, bhitpos.x, bhitpos.y);
 		if(*u.ushops && obj != uball)
 		    check_shop_obj(obj, bhitpos.x, bhitpos.y, FALSE);
@@ -1480,19 +1515,17 @@
 /*
  * Unconditionally break an object. Assumes all resistance checks
  * and break messages have been delivered prior to getting here.
- * This routine assumes the cause is the hero if heros_fault is TRUE.
- *
  */
 STATIC_OVL void
-breakobj(obj, x, y, heros_fault, from_invent)
+breakobj(obj, x, y, hero_caused, from_invent)
 struct obj *obj;
 xchar x, y;		/* object location (ox, oy may not be right) */
-boolean heros_fault;
+boolean hero_caused;	/* is this the hero's fault? */
 boolean from_invent;
 {
 	switch (obj->oclass == POTION_CLASS ? POT_WATER : obj->otyp) {
 		case MIRROR:
-			if (heros_fault)
+			if (hero_caused)
 			    change_luck(-2);
 			break;
 		case POT_WATER:		/* really, all potions */
@@ -1519,11 +1552,11 @@
 			break;
 		case EGG:
 			/* breaking your own eggs is bad luck */
-			if (heros_fault && obj->spe && obj->corpsenm >= LOW_PM)
+			if (hero_caused && obj->spe && obj->corpsenm >= LOW_PM)
 			    change_luck((schar) -min(obj->quan, 5L));
 			break;
 	}
-	if (heros_fault) {
+	if (hero_caused) {
 	    if (from_invent) {
 		if (*u.ushops)
 			check_shop_obj(obj, x, y, TRUE);
@@ -1570,6 +1603,7 @@
 		case POT_WATER:		/* really, all potions */
 		case EGG:
 		case CREAM_PIE:
+		case MELON:
 		case ACID_VENOM:
 		case BLINDING_VENOM:
 			return 1;
@@ -1607,6 +1641,7 @@
 				(obj->quan==1) ? "s" : "", to_pieces);
 			break;
 		case EGG:
+		case MELON:
 			pline("Splat!");
 			break;
 		case CREAM_PIE:
@@ -1633,6 +1668,11 @@
 	register struct monst *mon;
 
 	if(!u.dx && !u.dy && !u.dz) {
+#ifndef GOLDOBJ
+		u.ugold += obj->quan;
+		flags.botl = 1;
+		dealloc_obj(obj);
+#endif
 		You("cannot throw gold at yourself.");
 		return(0);
 	}
diff -Naurd ../nethack-3.4.0/src/drawing.c ./src/drawing.c
--- ../nethack-3.4.0/src/drawing.c Wed Mar 20 23:43:04 2002
+++ ./src/drawing.c Mon Feb 24 15:25:05 2003
@@ -46,10 +46,10 @@
 	VENOM_SYM
 };
 
-const char *invisexplain = "remembered, unseen, creature";
+const char invisexplain[] = "remembered, unseen, creature";
 
 /* Object descriptions.  Used in do_look(). */
-const char *objexplain[] = {	/* these match def_oc_syms, above */
+const char * const objexplain[] = {	/* these match def_oc_syms, above */
 /* 0*/	0,
 	"strange object",
 	"weapon",
@@ -71,7 +71,7 @@
 };
 
 /* Object class names.  Used in object_detect(). */
-const char *oclass_names[] = {
+const char * const oclass_names[] = {
 /* 0*/	0,
 	"illegal objects",
 	"weapons",
@@ -161,7 +161,7 @@
  * for blessed genocide, so no text should wholly contain any later
  * text.  They should also always contain obvious names (eg. cat/feline).
  */
-const char *monexplain[MAXMCLASSES] = {
+const char * const monexplain[MAXMCLASSES] = {
     0,
     "ant or other insect",	"blob",			"cockatrice",
     "dog or other canine",	"eye or sphere",	"cat or other feline",
@@ -169,7 +169,7 @@
     "jelly",			"kobold",		"leprechaun",
     "mimic",			"nymph",		"orc",
     "piercer",			"quadruped",		"rodent",
-    "spider",			"trapper or lurker above", "unicorn or horse",
+    "arachnid or centipede",	"trapper or lurker above", "unicorn or horse",
     "vortex",		"worm", "xan or other mythical/fantastic insect",
     "light",			"zruty",
 
@@ -181,7 +181,7 @@
     "pudding or ooze",		"quantum mechanic",	"rust monster or disenchanter",
     "snake",			"troll",		"umber hulk",
     "vampire",			"wraith",		"xorn",
-    "yeti, ape or other large beast", "zombie",
+    "apelike creature",		"zombie",
 
     "human or elf",		"ghost",		"golem",
     "major demon",		"sea monster",		"lizard",
diff -Naurd ../nethack-3.4.0/src/dungeon.c ./src/dungeon.c
--- ../nethack-3.4.0/src/dungeon.c Wed Mar 20 23:43:04 2002
+++ ./src/dungeon.c Mon Feb 24 15:25:05 2003
@@ -486,6 +486,9 @@
 	new_level->flags.maze_like = !!(tlevel->flags & MAZELIKE);
 	new_level->flags.rogue_like = !!(tlevel->flags & ROGUELIKE);
 	new_level->flags.align = ((tlevel->flags & D_ALIGN_MASK) >> 4);
+	if (!new_level->flags.align) 
+	    new_level->flags.align =
+		((pd->tmpdungeon[dgn].flags & D_ALIGN_MASK) >> 4);
 
 	new_level->rndlevs = tlevel->rndlevs;
 	new_level->next    = (s_level *) 0;
diff -Naurd ../nethack-3.4.0/src/eat.c ./src/eat.c
--- ../nethack-3.4.0/src/eat.c Wed Mar 20 23:43:04 2002
+++ ./src/eat.c Mon Feb 24 15:25:05 2003
@@ -33,6 +33,7 @@
 STATIC_DCL int FDECL(eatcorpse, (struct obj *));
 STATIC_DCL void FDECL(start_eating, (struct obj *));
 STATIC_DCL void FDECL(fprefx, (struct obj *));
+STATIC_DCL void FDECL(accessory_has_effect, (struct obj *));
 STATIC_DCL void FDECL(fpostfx, (struct obj *));
 STATIC_DCL int NDECL(bite);
 STATIC_DCL int FDECL(edibility_prompts, (struct obj *));
@@ -70,7 +71,7 @@
 
 /* Gold must come first for getobj(). */
 STATIC_OVL NEARDATA const char allobj[] = {
-	GOLD_CLASS, WEAPON_CLASS, ARMOR_CLASS, POTION_CLASS, SCROLL_CLASS,
+	COIN_CLASS, WEAPON_CLASS, ARMOR_CLASS, POTION_CLASS, SCROLL_CLASS,
 	WAND_CLASS, RING_CLASS, AMULET_CLASS, FOOD_CLASS, TOOL_CLASS,
 	GEM_CLASS, ROCK_CLASS, BALL_CLASS, CHAIN_CLASS, SPBOOK_CLASS, 0 };
 
@@ -253,7 +254,7 @@
 		 */
 		if(food) {
 			You("choke over your %s.", foodword(food));
-			if (food->oclass == GOLD_CLASS) {
+			if (food->oclass == COIN_CLASS) {
 				killer = "a very rich meal";
 			} else {
 				killer = food_xname(food, FALSE);
@@ -316,8 +317,7 @@
 	if (!otmp->oeaten) {
 	    if(((!carried(otmp) && costly_spot(otmp->ox, otmp->oy) &&
 		 !otmp->no_charge)
-		 || otmp->unpaid) &&
-		 (otmp->otyp == CORPSE || objects[otmp->otyp].oc_delay > 1)) {
+		 || otmp->unpaid)) {
 		/* create a dummy duplicate to put on bill */
 		verbalize("You bit it, you bought it!");
 		bill_dummy_object(otmp);
@@ -770,22 +770,41 @@
 register int pm;
 {
 	register int tmp = 0;
+	boolean catch_lycanthropy = FALSE;
 
 	/* in case `afternmv' didn't get called for previously mimicking
 	   gold, clean up now to avoid `eatmbuf' memory leak */
 	if (eatmbuf) (void)eatmdone();
 
 	switch(pm) {
+	    case PM_NEWT:
+		/* MRKR: "eye of newt" may give small magical energy boost */
+		if (rn2(3) || 3 * u.uen <= 2 * u.uenmax) {
+		    int old_uen = u.uen;
+		    u.uen += rnd(3);
+		    if (u.uen > u.uenmax) {
+			if (!rn2(3)) u.uenmax++;
+			u.uen = u.uenmax;
+		    }
+		    if (old_uen != u.uen) {
+			    You_feel("a mild buzz.");
+			    flags.botl = 1;
+		    }
+		}
+		break;
 	    case PM_WRAITH:
 		pluslvl(FALSE);
 		break;
 	    case PM_HUMAN_WERERAT:
+		catch_lycanthropy = TRUE;
 		u.ulycn = PM_WERERAT;
 		break;
 	    case PM_HUMAN_WEREJACKAL:
+		catch_lycanthropy = TRUE;
 		u.ulycn = PM_WEREJACKAL;
 		break;
 	    case PM_HUMAN_WEREWOLF:
+		catch_lycanthropy = TRUE;
 		u.ulycn = PM_WEREWOLF;
 		break;
 	    case PM_NURSE:
@@ -819,22 +838,25 @@
 		/* fall into next case */
 	    case PM_SMALL_MIMIC:
 		tmp += 20;
-		if (youmonst.data->mlet != S_MIMIC) {
+		if (youmonst.data->mlet != S_MIMIC && !Unchanging) {
 		    char buf[BUFSZ];
-		    You_cant("resist the temptation to mimic a pile of gold.");
+		    You_cant("resist the temptation to mimic %s.",
+			Hallucination ? "an orange" : "a pile of gold");
 #ifdef STEED
                     /* A pile of gold can't ride. */
 		    if (u.usteed) dismount_steed(DISMOUNT_FELL);
 #endif
 		    nomul(-tmp);
-		    Sprintf(buf, "You now prefer mimicking %s again.",
-			    an(Upolyd ? youmonst.data->mname : urace.noun));
+		    Sprintf(buf, Hallucination ?
+			"You suddenly dread being peeled and mimick %s again!" :
+			"You now prefer mimicking %s again.",
+			an(Upolyd ? youmonst.data->mname : urace.noun));
 		    eatmbuf = strcpy((char *) alloc(strlen(buf) + 1), buf);
 		    nomovemsg = eatmbuf;
 		    afternmv = eatmdone;
 		    /* ??? what if this was set before? */
 		    youmonst.m_ap_type = M_AP_OBJECT;
-		    youmonst.mappearance = GOLD_PIECE;
+		    youmonst.mappearance = Hallucination ? ORANGE : GOLD_PIECE;
 		    newsym(u.ux,u.uy);
 		    curs_on_u();
 		    /* make gold symbol show up now */
@@ -934,6 +956,14 @@
 	    }
 	    break;
 	}
+
+	if (catch_lycanthropy && defends(AD_WERE, uwep)) {
+	    if (!touch_artifact(uwep, &youmonst)) {
+		dropx(uwep);
+		uwepgone();
+	    }
+	}
+
 	return;
 }
 
@@ -1037,7 +1067,7 @@
 	} else {
 	    if (tin.tin->cursed)
 		pline("It contains some decaying%s%s substance.",
-			Blind ? "" : " ", Blind ? "" : hcolor(green));
+			Blind ? "" : " ", Blind ? "" : hcolor(NH_GREEN));
 	    else
 		pline("It contains spinach.");
 
@@ -1309,8 +1339,12 @@
 }
 
 
+/*
+ * called on "first bite" of (non-corpse) food.
+ * used for non-rotten non-tin non-corpse food
+ */
 STATIC_OVL void
-fprefx(otmp)		/* called on "first bite" of (non-corpse) food */
+fprefx(otmp)
 struct obj *otmp;
 {
 	switch(otmp->otyp) {
@@ -1389,33 +1423,14 @@
 		      Hallucination ? "gnarly!" : "delicious!");
 		break;
 	}
+}
 
-	/* KMH, conduct */
-	switch (objects[otmp->otyp].oc_material) {
-	  case WAX: /* let's assume bees' wax */
-	    u.uconduct.unvegan++;
-	    break;
-
-	  case FLESH:
-	    if (otmp->otyp == EGG) {
-		u.uconduct.unvegan++;
-		break;
-	    }
-	  case LEATHER:
-	  case BONE:
-	  case DRAGON_HIDE:
-	    u.uconduct.unvegan++;
-	    violated_vegetarian();
-	    break;
-
-	  default:
-	    if (otmp->otyp == PANCAKE ||
-			otmp->otyp == FORTUNE_COOKIE || /* eggs */
-		otmp->otyp == CREAM_PIE || otmp->otyp == CANDY_BAR || /* milk */
-			otmp->otyp == LUMP_OF_ROYAL_JELLY)
-		u.uconduct.unvegan++;
-	    break;
-	}
+STATIC_OVL void
+accessory_has_effect(otmp)
+struct obj *otmp;
+{
+	pline("Magic spreads through your body as you digest the %s.",
+	    otmp->oclass == RING_CLASS ? "ring" : "amulet");
 }
 
 STATIC_OVL void
@@ -1433,14 +1448,13 @@
 	    if (u.uhp <= 0) return; /* died from sink fall */
 	}
 	otmp->known = otmp->dknown = 1; /* by taste */
-	if (!rn2(otmp->oclass == RING_CLASS ? 3 : 5))
+	if (!rn2(otmp->oclass == RING_CLASS ? 3 : 5)) {
 	  switch (otmp->otyp) {
 	    default:
 	        if (!objects[typ].oc_oprop) break; /* should never happen */
 
 		if (!(u.uprops[objects[typ].oc_oprop].intrinsic & FROMOUTSIDE))
-		    pline("Magic spreads through your body as you digest the %s.",
-			  otmp->oclass == RING_CLASS ? "ring" : "amulet");
+		    accessory_has_effect(otmp);
 
 		u.uprops[objects[typ].oc_oprop].intrinsic |= FROMOUTSIDE;
 
@@ -1479,35 +1493,44 @@
 		}
 		break;
 	    case RIN_ADORNMENT:
+		accessory_has_effect(otmp);
 		if (adjattrib(A_CHA, otmp->spe, -1))
 		    makeknown(typ);
 		break;
 	    case RIN_GAIN_STRENGTH:
+		accessory_has_effect(otmp);
 		if (adjattrib(A_STR, otmp->spe, -1))
 		    makeknown(typ);
 		break;
 	    case RIN_GAIN_CONSTITUTION:
+		accessory_has_effect(otmp);
 		if (adjattrib(A_CON, otmp->spe, -1))
 		    makeknown(typ);
 		break;
 	    case RIN_INCREASE_ACCURACY:
+		accessory_has_effect(otmp);
 		u.uhitinc += otmp->spe;
 		break;
 	    case RIN_INCREASE_DAMAGE:
+		accessory_has_effect(otmp);
 		u.udaminc += otmp->spe;
 		break;
 	    case RIN_PROTECTION:
+		accessory_has_effect(otmp);
 		HProtection |= FROMOUTSIDE;
 		u.ublessed += otmp->spe;
 		flags.botl = 1;
 		break;
 	    case RIN_FREE_ACTION:
 		/* Give sleep resistance instead */
+		if (!(HSleep_resistance & FROMOUTSIDE))
+		    accessory_has_effect(otmp);
 		if (!Sleep_resistance)
 		    You_feel("wide awake.");
 		HSleep_resistance |= FROMOUTSIDE;
 		break;
 	    case AMULET_OF_CHANGE:
+		accessory_has_effect(otmp);
 		makeknown(typ);
 		change_sex();
 		You("are suddenly very %s!",
@@ -1515,12 +1538,16 @@
 		flags.botl = 1;
 		break;
 	    case AMULET_OF_STRANGULATION: /* bad idea! */
+		/* no message--this gives no permanent effect */
 		choke(otmp);
 		break;
 	    case AMULET_OF_RESTFUL_SLEEP: /* another bad idea! */
+		if (!(HSleeping & FROMOUTSIDE))
+		    accessory_has_effect(otmp);
 		HSleeping = FROMOUTSIDE | rnd(100);
 		break;
-		case RIN_SUSTAIN_ABILITY:
+	    case RIN_SUSTAIN_ABILITY:
+	    case AMULET_OF_UNCHANGING:
 	    case AMULET_OF_LIFE_SAVING:
 	    case AMULET_OF_REFLECTION: /* nice try */
 	    /* can't eat Amulet of Yendor or fakes,
@@ -1528,6 +1555,7 @@
 	     */
 		break;
 	  }
+	}
 }
 
 STATIC_OVL void
@@ -1538,7 +1566,7 @@
 	lesshungry(victual.nmod);
 	victual.piece = (struct obj *)0;
 	victual.eating = 0;
-	if (otmp->oclass == GOLD_CLASS) {
+	if (otmp->oclass == COIN_CLASS) {
 #ifdef GOLDOBJ
 		if (carried(otmp))
 		    useupall(otmp);
@@ -1674,24 +1702,24 @@
 	   ability to detect food that is unfit for consumption
 	   or dangerous and avoid it. */
 
-	char buf[BUFSZ], foodsmell[BUFSZ];
-	char *eat_it_anyway = "Eat it anyway?";
-	boolean cadaver = (otmp->otyp == CORPSE);
-	boolean stoneorslime = FALSE;
-	int material = objects[otmp->otyp].oc_material;
+	char buf[BUFSZ], foodsmell[BUFSZ],
+	     it_or_they[QBUFSZ], eat_it_anyway[QBUFSZ];
+	boolean cadaver = (otmp->otyp == CORPSE),
+		stoneorslime = FALSE;
+	int material = objects[otmp->otyp].oc_material,
+	    mnum = otmp->corpsenm;
 	long rotted = 0L;
-	int mnum;
-
-#ifdef GCC_WARN
-	mnum = 0;
-#endif
 
 	Strcpy(foodsmell, Tobjnam(otmp, "smell"));
+	Strcpy(it_or_they, (otmp->quan == 1L) ? "it" : "they");
+	Sprintf(eat_it_anyway, "Eat %s anyway?",
+		(otmp->quan == 1L) ? "it" : "one");
+
 	if (cadaver || otmp->otyp == EGG || otmp->otyp == TIN) {
-		mnum = otmp->corpsenm;
 		/* These checks must match those in eatcorpse() */
-	  	stoneorslime = (touch_petrifies(&mons[mnum]) &&
-			    !Stone_resistance && !poly_when_stoned(youmonst.data));
+		stoneorslime = (touch_petrifies(&mons[mnum]) &&
+				!Stone_resistance &&
+				!poly_when_stoned(youmonst.data));
 
 		if (mnum == PM_GREEN_SLIME)
 		    stoneorslime = (!Unchanging &&
@@ -1717,28 +1745,28 @@
 
 	if (cadaver && mnum != PM_ACID_BLOB && rotted > 5L && !Sick_resistance) {
 		/* Tainted meat */
-		Sprintf(buf, "%s like it could be tainted! %s",
-		     foodsmell, eat_it_anyway);
+		Sprintf(buf, "%s like %s could be tainted! %s",
+			foodsmell, it_or_they, eat_it_anyway);
 		if (yn_function(buf,ynchars,'n')=='n') return 1;
 		else return 2;
 	}
 	if (stoneorslime) {
-		Sprintf(buf, "%s like it could be something very dangerous! %s",
-		     foodsmell, eat_it_anyway);
+		Sprintf(buf, "%s like %s could be something very dangerous! %s",
+			foodsmell, it_or_they, eat_it_anyway);
 		if (yn_function(buf,ynchars,'n')=='n') return 1;
 		else return 2;
 	}
 	if (otmp->orotten || (cadaver && rotted > 3L)) {
 		/* Rotten */
-		Sprintf(buf, "%s like it could be rotten! %s",
-			foodsmell, eat_it_anyway);
+		Sprintf(buf, "%s like %s could be rotten! %s",
+			foodsmell, it_or_they, eat_it_anyway);
 		if (yn_function(buf,ynchars,'n')=='n') return 1;
 		else return 2;
 	}
 	if (cadaver && poisonous(&mons[mnum]) && !Poison_resistance) {
 		/* poisonous */
-		Sprintf(buf, "%s like it might be poisonous! %s",
-			foodsmell, eat_it_anyway);
+		Sprintf(buf, "%s like %s might be poisonous! %s",
+			foodsmell, it_or_they, eat_it_anyway);
 		if (yn_function(buf,ynchars,'n')=='n') return 1;
 		else return 2;
 	}
@@ -1755,8 +1783,8 @@
 		if (yn_function(buf,ynchars,'n')=='n') return 1;
 		else return 2;
 	}
-	if (Upolyd &&
-	    (u.umonnum == PM_RUST_MONSTER && is_metallic(otmp) && otmp->oerodeproof)) {
+	if (Upolyd && u.umonnum == PM_RUST_MONSTER &&
+	    is_metallic(otmp) && otmp->oerodeproof) {
 		Sprintf(buf, "%s disgusting to you right now. %s",
 			foodsmell, eat_it_anyway);
 		if (yn_function(buf,ynchars,'n')=='n') return 1;
@@ -1777,7 +1805,8 @@
 		else return 2;
 	}
 	if (!u.uconduct.unvegetarian &&
-	    ((material == LEATHER || material == BONE || material == DRAGON_HIDE) ||
+	    ((material == LEATHER || material == BONE ||
+	      material == DRAGON_HIDE) ||
 	     (cadaver && !vegetarian(&mons[mnum])))) {
 		Sprintf(buf, "%s unfamiliar to you. %s",
 			foodsmell, eat_it_anyway);
@@ -1787,8 +1816,8 @@
 
 	if (cadaver && mnum != PM_ACID_BLOB && rotted > 5L && Sick_resistance) {
 		/* Tainted meat with Sick_resistance */
-		Sprintf(buf, "%s like it could be tainted! %s",
-		     foodsmell, eat_it_anyway);
+		Sprintf(buf, "%s like %s could be tainted! %s",
+			foodsmell, it_or_they, eat_it_anyway);
 		if (yn_function(buf,ynchars,'n')=='n') return 1;
 		else return 2;
 	}
@@ -1876,7 +1905,7 @@
 	    victual.canchoke = (u.uhs == SATIATED);
 		/* Note: gold weighs 1 pt. for each 1000 pieces (see */
 		/* pickup.c) so gold and non-gold is consistent. */
-	    if (otmp->oclass == GOLD_CLASS)
+	    if (otmp->oclass == COIN_CLASS)
 		basenutrit = ((otmp->quan > 200000L) ? 2000
 			: (int)(otmp->quan/100L));
 	    else if(otmp->oclass == BALL_CLASS || otmp->oclass == CHAIN_CLASS)
@@ -1887,11 +1916,12 @@
 	    victual.eating = TRUE; /* needed for lesshungry() */
 
 	    material = objects[otmp->otyp].oc_material;
-	    if (material == LEATHER || material == BONE || material == DRAGON_HIDE) {
-	 		u.uconduct.unvegan++;
-	    		violated_vegetarian();
+	    if (material == LEATHER ||
+		material == BONE || material == DRAGON_HIDE) {
+		u.uconduct.unvegan++;
+		violated_vegetarian();
 	    } else if (material == WAX)
-			u.uconduct.unvegan++;
+		u.uconduct.unvegan++;
 	    u.uconduct.food++;
 	    
 	    if (otmp->cursed)
@@ -1906,7 +1936,7 @@
 		    You("seem unaffected by the poison.");
 	    } else if (!otmp->cursed)
 		pline("This %s is delicious!",
-		      otmp->oclass == GOLD_CLASS ? foodword(otmp) :
+		      otmp->oclass == COIN_CLASS ? foodword(otmp) :
 		      singular(otmp, xname));
 
 	    eatspecial();
@@ -1956,6 +1986,26 @@
 	    /* if not used up, eatcorpse sets up reqtime and may modify
 	     * oeaten */
 	} else {
+	    /* No checks for WAX, LEATHER, BONE, DRAGON_HIDE.  These are
+	     * all handled in the != FOOD_CLASS case, above */
+	    switch (objects[otmp->otyp].oc_material) {
+	    case FLESH:
+		u.uconduct.unvegan++;
+		if (otmp->otyp != EGG) {
+		    violated_vegetarian();
+		}
+		break;
+
+	    default:
+		if (otmp->otyp == PANCAKE ||
+		    otmp->otyp == FORTUNE_COOKIE || /* eggs */
+		    otmp->otyp == CREAM_PIE ||
+		    otmp->otyp == CANDY_BAR || /* milk */
+		    otmp->otyp == LUMP_OF_ROYAL_JELLY)
+		    u.uconduct.unvegan++;
+		break;
+	    }
+
 	    victual.reqtime = objects[otmp->otyp].oc_delay;
 	    if (otmp->otyp != FORTUNE_COOKIE &&
 		(otmp->cursed ||
@@ -2367,7 +2417,7 @@
 	for (otmp = level.objects[u.ux][u.uy]; otmp; otmp = otmp->nexthere) {
 		if(corpsecheck ?
 		(otmp->otyp==CORPSE && (corpsecheck == 1 || tinnable(otmp))) :
-		    feeding ? (otmp->oclass != GOLD_CLASS && is_edible(otmp)) :
+		    feeding ? (otmp->oclass != COIN_CLASS && is_edible(otmp)) :
 						otmp->oclass==FOOD_CLASS) {
 			Sprintf(qbuf, "There %s %s here; %s %s?",
 				otense(otmp, "are"),
diff -Naurd ../nethack-3.4.0/src/end.c ./src/end.c
--- ../nethack-3.4.0/src/end.c Wed Mar 20 23:43:05 2002
+++ ./src/end.c Mon Feb 24 15:25:05 2003
@@ -18,7 +18,7 @@
  
 struct valuable_data { long count; int typ; };
 
-struct valuable_data
+static struct valuable_data
 	gems[LAST_GEM+1 - FIRST_GEM + 1], /* 1 extra for glass */
 	amulets[LAST_AMULET+1 - FIRST_AMULET];
 
@@ -37,12 +37,11 @@
 STATIC_DCL void FDECL(disclose,(int,BOOLEAN_P));
 STATIC_DCL void FDECL(get_valuables, (struct obj *));
 STATIC_DCL void FDECL(sort_valuables, (struct valuable_data *,int));
-STATIC_DCL void FDECL(add_artifact_score, (struct obj *));
-STATIC_DCL void FDECL(display_artifact_score, (struct obj *,winid));
+STATIC_DCL void FDECL(artifact_score, (struct obj *,BOOLEAN_P,winid));
 STATIC_DCL void FDECL(savelife, (int));
-STATIC_DCL void FDECL(list_vanquished, (int, BOOLEAN_P));
-STATIC_DCL void FDECL(list_genocided, (int, BOOLEAN_P));
-STATIC_DCL boolean FDECL(should_query_disclose_option, (int, int*));
+STATIC_DCL void FDECL(list_vanquished, (CHAR_P,BOOLEAN_P));
+STATIC_DCL void FDECL(list_genocided, (CHAR_P,BOOLEAN_P));
+STATIC_DCL boolean FDECL(should_query_disclose_option, (int,char *));
 
 #if defined(__BEOS__) || defined(MICRO) || defined(WIN32) || defined(OS2)
 extern void FDECL(nethack_exit,(int));
@@ -81,8 +84,7 @@
 	"quit", "escaped", "ascended"
 };
 
-extern const char *killed_by_prefix[];
-
+extern const char * const killed_by_prefix[];	/* from topten.c */
 
 /*ARGSUSED*/
 void
@@ -186,6 +188,7 @@
 	You("die...");
 	mark_synch();	/* flush buffered screen output */
 	buf[0] = '\0';
+	killer_format = KILLED_BY_AN;
 	/* "killed by the high priest of Crom" is okay, "killed by the high
 	   priest" alone isn't */
 	if ((mtmp->data->geno & G_UNIQ) != 0 && !(mtmp->data == &mons[PM_HIGH_PRIEST] && !mtmp->ispriest)) {
@@ -193,18 +196,19 @@
 		Strcat(buf, "the ");
 	    killer_format = KILLED_BY;
 	}
+	/* _the_ <invisible> <distorted> ghost of Dudley */
+	if (mtmp->data == &mons[PM_GHOST] && mtmp->mnamelth) {
+		Strcat(buf, "the ");
+		killer_format = KILLED_BY;
+	}
 	if (mtmp->minvis)
 		Strcat(buf, "invisible ");
 	if (distorted)
 		Strcat(buf, "hallucinogen-distorted ");
 
 	if(mtmp->data == &mons[PM_GHOST]) {
-		char *gn = NAME(mtmp);
-		if (!distorted && !mtmp->minvis && *gn) {
-			Strcat(buf, "the ");
-			killer_format = KILLED_BY;
-		}
-		Sprintf(eos(buf), (*gn ? "ghost of %s" : "ghost%s"), gn);
+		Strcat(buf, "ghost");
+		if (mtmp->mnamelth) Sprintf(eos(buf), " of %s", NAME(mtmp));
 	} else if(mtmp->isshk) {
 		Sprintf(eos(buf), "%s %s, the shopkeeper",
 			(mtmp->female ? "Ms." : "Mr."), shkname(mtmp));
@@ -290,36 +307,39 @@
 STATIC_OVL boolean
 should_query_disclose_option(category, defquery)
 int category;
-int *defquery;
+char *defquery;
 {
-	int idx;
-	char *dop = index(disclosure_options, category);
-	if (dop && defquery) {
-		idx = (dop - disclosure_options) / sizeof(char);
-		if (idx < 0 || idx > (NUM_DISCLOSURE_OPTIONS - 1)) {
-			impossible(
-				"should_query_disclose_option: bad disclosure index %d %c",
-				idx, category);
-			*defquery = DISCLOSE_PROMPT_DEFAULT_YES;
-			return TRUE;
-		}
-		if (flags.end_disclose[idx] == DISCLOSE_YES_WITHOUT_PROMPT) {
-			*defquery = 'y';
-			return FALSE;
-		} else if (flags.end_disclose[idx] == DISCLOSE_NO_WITHOUT_PROMPT) {
-			*defquery = 'n';
-			return FALSE;
-		} else if (flags.end_disclose[idx] == DISCLOSE_PROMPT_DEFAULT_YES) {
-			*defquery = 'y';
-			return TRUE;
-		} else if (flags.end_disclose[idx] == DISCLOSE_PROMPT_DEFAULT_NO) {
-			*defquery = 'n';
-			return TRUE;
-		}
+    int idx;
+    char *dop = index(disclosure_options, category);
+
+    if (dop && defquery) {
+	idx = dop - disclosure_options;
+	if (idx < 0 || idx > (NUM_DISCLOSURE_OPTIONS - 1)) {
+	    impossible(
+		   "should_query_disclose_option: bad disclosure index %d %c",
+		       idx, category);
+	    *defquery = DISCLOSE_PROMPT_DEFAULT_YES;
+	    return TRUE;
 	}
-	if (defquery)impossible("should_query_disclose_option: bad category %c", category);
-	else impossible("should_query_disclose_option: null defquery");
-	return TRUE;
+	if (flags.end_disclose[idx] == DISCLOSE_YES_WITHOUT_PROMPT) {
+	    *defquery = 'y';
+	    return FALSE;
+	} else if (flags.end_disclose[idx] == DISCLOSE_NO_WITHOUT_PROMPT) {
+	    *defquery = 'n';
+	    return FALSE;
+	} else if (flags.end_disclose[idx] == DISCLOSE_PROMPT_DEFAULT_YES) {
+	    *defquery = 'y';
+	    return TRUE;
+	} else if (flags.end_disclose[idx] == DISCLOSE_PROMPT_DEFAULT_NO) {
+	    *defquery = 'n';
+	    return TRUE;
+	}
+    }
+    if (defquery)
+	impossible("should_query_disclose_option: bad category %c", category);
+    else
+	impossible("should_query_disclose_option: null defquery");
+    return TRUE;
 }
 
 STATIC_OVL void
@@ -327,9 +347,8 @@
 int how;
 boolean taken;
 {
-	char	c = 0;
+	char	c = 0, defquery;
 	char	qbuf[QBUFSZ];
-	int defquery;
 	boolean ask;
 
 	if (invent) {
@@ -341,12 +360,10 @@
 
 	    ask = should_query_disclose_option('i', &defquery);
 	    if (!done_stopprint) {
-		if (ask)
-		   c = yn_function(qbuf, ynqchars, defquery);
-		if ((!ask && defquery == 'y') || (ask && c == 'y')) {
-			/* New dump format by maartenj@cs.vu.nl */
+		c = ask ? yn_function(qbuf, ynqchars, defquery) : defquery;
+		if (c == 'y') {
 			struct obj *obj;
-			
+
 			for (obj = invent; obj; obj = obj->nobj) {
 			    makeknown(obj->otyp);
 			    obj->known = obj->bknown = obj->dknown = obj->rknown = 1;
@@ -354,17 +371,17 @@
 			(void) display_inventory((char *)0, TRUE);
 			container_contents(invent, TRUE, TRUE);
 		}
-		if (ask && c == 'q')  done_stopprint++;
+		if (c == 'q')  done_stopprint++;
 	    }
 	}
 
- 	ask = should_query_disclose_option('a', &defquery);
+	ask = should_query_disclose_option('a', &defquery);
 	if (!done_stopprint) {
-	    if (ask)
-		c = yn_function("Do you want to see your attributes?",ynqchars, defquery);
-	    if ((!ask && defquery == 'y') || (ask && c == 'y'))
+	    c = ask ? yn_function("Do you want to see your attributes?",
+				  ynqchars, defquery) : defquery;
+	    if (c == 'y')
 		enlightenment(how >= PANICKED ? 1 : 2); /* final */
-	    if (ask && c == 'q') done_stopprint++;
+	    if (c == 'q') done_stopprint++;
 	}
 
 	ask = should_query_disclose_option('v', &defquery);
@@ -377,11 +394,11 @@
 
 	ask = should_query_disclose_option('c', &defquery);
 	if (!done_stopprint) {
-	    if (ask)
-		c = yn_function("Do you want to see your conduct?",ynqchars,defquery);
-	    if ((!ask && defquery == 'y') || (ask && c == 'y'))
+	    c = ask ? yn_function("Do you want to see your conduct?",
+				  ynqchars, defquery) : defquery;
+	    if (c == 'y')
 		show_conduct(how >= PANICKED ? 1 : 2);
-	    if (ask && c == 'q') done_stopprint++;
+	    if (c == 'q') done_stopprint++;
 	}
 }
 
@@ -471,52 +488,41 @@
     return;
 }
 
+/* called twice; first to calculate total, then to list relevant items */
 STATIC_OVL void
-add_artifact_score(list)
-struct obj *list;
-{
-    struct obj *otmp;
-
-    for (otmp = list; otmp; otmp = otmp->nobj)
-	if (otmp->oartifact ||
-			otmp->otyp == BELL_OF_OPENING ||
-			otmp->otyp == SPE_BOOK_OF_THE_DEAD ||
-			otmp->otyp == CANDELABRUM_OF_INVOCATION) {
-	    u.urexp += (arti_cost(otmp) * 5 / 2);
-	if (Has_contents(otmp))
-	    add_artifact_score(otmp->cobj);
-    }
-}
-
-STATIC_OVL void
-display_artifact_score(list,endwin)
+artifact_score(list, counting, endwin)
 struct obj *list;
+boolean counting;	/* true => add up points; false => display them */
 winid endwin;
 {
     char pbuf[BUFSZ];
     struct obj *otmp;
+    long value, points;
+    short dummy;	/* object type returned by artifact_name() */
 
     for (otmp = list; otmp; otmp = otmp->nobj) {
 	if (otmp->oartifact ||
 			otmp->otyp == BELL_OF_OPENING ||
 			otmp->otyp == SPE_BOOK_OF_THE_DEAD ||
 			otmp->otyp == CANDELABRUM_OF_INVOCATION) {
-	    short dummy;
-
-	    makeknown(otmp->otyp);
-	    otmp->known = otmp->bknown = otmp->dknown =
-		otmp->rknown = 1;
-	    /* assumes artifacts don't have quan>1 */
-	    Sprintf(pbuf, "%s%s (worth %ld %s and %ld points)",
-		the_unique_obj(otmp) ? "The " : "",
-		otmp->oartifact ? artifact_name(xname(otmp), &dummy) :
-			OBJ_NAME(objects[otmp->otyp]),
-		arti_cost(otmp), currency(2L), 
-		arti_cost(otmp) * 5 / 2);
-	    putstr(endwin, 0, pbuf);
+	    value = arti_cost(otmp);	/* zorkmid value */
+	    points = value * 5 / 2;	/* score value */
+	    if (counting) {
+		u.urexp += points;
+	    } else {
+		makeknown(otmp->otyp);
+		otmp->known = otmp->dknown = otmp->bknown = otmp->rknown = 1;
+		/* assumes artifacts don't have quan > 1 */
+		Sprintf(pbuf, "%s%s (worth %ld %s and %ld points)",
+			the_unique_obj(otmp) ? "The " : "",
+			otmp->oartifact ? artifact_name(xname(otmp), &dummy) :
+				OBJ_NAME(objects[otmp->otyp]),
+			value, currency(value), points);
+		putstr(endwin, 0, pbuf);
+	    }
 	}
 	if (Has_contents(otmp))
-	    display_artifact_score(otmp->cobj,endwin);
+	    artifact_score(otmp->cobj, counting, endwin);
     }
 }
 
@@ -532,6 +538,19 @@
 	struct obj *corpse = (struct obj *)0;
 	long umoney;
 
+	if (how == TRICKED) {
+	    if (killer) {
+		paniclog("trickery", killer);
+		killer = 0;
+	    }
+#ifdef WIZARD
+	    if (wizard) {
+		You("are a very tricky wizard, it seems.");
+		return;
+	    }
+#endif
+	}
+
 	/* kilbuf: used to copy killer in case it comes from something like
 	 *	xname(), which would otherwise get overwritten when we call
 	 *	xname() when listing possessions
@@ -544,12 +563,7 @@
 		killer_format = KILLED_BY;
 	Strcpy(kilbuf, (!killer || how >= PANICKED ? deaths[how] : killer));
 	killer = kilbuf;
-#ifdef WIZARD
-	if (wizard && how == TRICKED) {
-		You("are a very tricky wizard, it seems.");
-		return;
-	}
-#endif
+
 	if (how < PANICKED) u.umortality++;
 	if (Lifesaved && (how <= GENOCIDED)) {
 		pline("But wait...");
@@ -630,7 +644,17 @@
 		u.ugrave_arise = (NON_PM - 1);	/* statue instead of corpse */
 	    else if (u.ugrave_arise == NON_PM &&
 		     !(mvitals[u.umonnum].mvflags & G_NOCORPSE)) {
-		corpse = mk_named_object(CORPSE, &mons[u.umonnum],
+		int mnum = u.umonnum;
+
+		if (!Upolyd) {
+		    /* Base corpse on race when not poly'd since original
+		     * u.umonnum is based on role, and all role monsters
+		     * are human.
+		     */
+		    mnum = (flags.female && urace.femalenum != NON_PM) ?
+			urace.femalenum : urace.malenum;
+		}
+		corpse = mk_named_object(CORPSE, &mons[mnum],
 				       u.ux, u.uy, plname);
 		Sprintf(pbuf, "%s, %s%s", plname,
 			killer_format == NO_KILLER_PREFIX ? "" :
@@ -654,7 +678,7 @@
 
 	if (how != PANICKED) {
 	    /* these affect score and/or bones, but avoid them during panic */
-	    taken = paybill(how != QUIT);
+	    taken = paybill((how == ESCAPED) ? -1 : (how != QUIT));
 	    paygd();
 	    clearpriests();
 	} else	taken = FALSE;	/* lint; assert( !bones_ok ); */
@@ -724,7 +748,8 @@
 	    if(!done_stopprint || flags.tombstone)
 		endwin = create_nhwindow(NHW_TEXT);
 
-	    if(how < GENOCIDED && flags.tombstone) outrip(endwin, how);
+	    if (how < GENOCIDED && flags.tombstone && endwin != WIN_ERR)
+		outrip(endwin, how);
 	} else
 	    done_stopprint = 1; /* just avoid any more output */
 
@@ -769,7 +794,8 @@
 			u.urexp += val->list[i].count
 				  * (long)objects[val->list[i].typ].oc_cost;
 
-	    add_artifact_score(invent);
+	    /* count the points for artifacts */
+	    artifact_score(invent, TRUE, endwin);
 
 	    keepdogs(TRUE);
 	    viz_array[0][0] |= IN_SIGHT; /* need visibility for naming */
@@ -797,7 +823,7 @@
 	    }
 
 	    if (!done_stopprint)
-		display_artifact_score(invent,endwin);
+		artifact_score(invent, FALSE, endwin);	/* list artifacts */
 
 	    /* list valuables here */
 	    for (val = valuables; val->list; val++) {
@@ -942,7 +968,7 @@
 
 STATIC_OVL void
 list_vanquished(defquery, ask)
-int defquery;
+char defquery;
 boolean ask;
 {
     register int i, lev;
@@ -963,11 +989,10 @@
      * includes all dead monsters, not just those killed by the player
      */
     if (ntypes != 0) {
-    	if (ask)
-	    c = yn_function("Do you want an account of creatures vanquished?",
-				ynqchars, defquery);
-	if (ask && c == 'q') done_stopprint++;
-	if ((!ask && defquery == 'y') || (ask && c == 'y')) {
+	c = ask ? yn_function("Do you want an account of creatures vanquished?",
+			      ynqchars, defquery) : defquery;
+	if (c == 'q') done_stopprint++;
+	if (c == 'y') {
 	    klwin = create_nhwindow(NHW_MENU);
 	    putstr(klwin, 0, "Vanquished creatures:");
 	    putstr(klwin, 0, "");
@@ -982,11 +1007,11 @@
 				mons[i].mname);
 			if (nkilled > 1) {
 			    switch (nkilled) {
-	    			case 2:  Sprintf(eos(buf)," (twice)");  break;
-	    			case 3:  Sprintf(eos(buf)," (thrice)");  break;
-	    			default: Sprintf(eos(buf)," (%d time%s)",
-				    		nkilled, plur(nkilled));
-				break;
+				case 2:  Sprintf(eos(buf)," (twice)");  break;
+				case 3:  Sprintf(eos(buf)," (thrice)");  break;
+				default: Sprintf(eos(buf)," (%d time%s)",
+						 nkilled, plur(nkilled));
+					 break;
 			    }
 			}
 		    } else {
@@ -1029,7 +1054,7 @@
 
 STATIC_OVL void
 list_genocided(defquery, ask)
-int defquery;
+char defquery;
 boolean ask;
 {
     register int i;
@@ -1042,11 +1067,10 @@
 
     /* genocided species list */
     if (ngenocided != 0) {
-    	if (ask)
-	    c = yn_function("Do you want a list of species genocided?",
-				ynqchars, defquery);
-	if (ask && c == 'q') done_stopprint++;
-	if ((!ask && defquery == 'y') || (ask && c == 'y')) {
+	c = ask ? yn_function("Do you want a list of species genocided?",
+			      ynqchars, defquery) : defquery;
+	if (c == 'q') done_stopprint++;
+	if (c == 'y') {
 	    klwin = create_nhwindow(NHW_MENU);
 	    putstr(klwin, 0, "Genocided species:");
 	    putstr(klwin, 0, "");
diff -Naurd ../nethack-3.4.0/src/engrave.c ./src/engrave.c
--- ../nethack-3.4.0/src/engrave.c Wed Mar 20 23:43:05 2002
+++ ./src/engrave.c Mon Feb 24 15:25:05 2003
@@ -370,7 +370,7 @@
 	ep->engr_txt = (char *)(ep + 1);
 	Strcpy(ep->engr_txt, s);
 	/* engraving Elbereth shows wisdom */
-	if(!strcmp(s, "Elbereth")) exercise(A_WIS, TRUE);
+	if (!in_mklev && !strcmp(s, "Elbereth")) exercise(A_WIS, TRUE);
 	ep->engr_time = e_time;
 	ep->engr_type = e_type > 0 ? e_type : rnd(N_ENGRAVE-1);
 	ep->engr_lth = strlen(s) + 1;
@@ -530,7 +530,11 @@
 		return(0);
 	}
 	if (IS_GRAVE(levl[u.ux][u.uy].typ)) {
-	    if (!levl[u.ux][u.uy].disturbed) {
+	    if (otmp == &zeroobj) { /* using only finger */
+		You("would only make a small smudge on the %s.",
+			surface(u.ux, u.uy));
+		return(0);
+	    } else if (!levl[u.ux][u.uy].disturbed) {
 		You("disturb the undead!");
 		levl[u.ux][u.uy].disturbed = 1;
 		(void) makemon(&mons[PM_GHOUL], u.ux, u.uy, NO_MM_FLAGS);
@@ -546,7 +550,7 @@
 	    case AMULET_CLASS:
 	    case CHAIN_CLASS:
 	    case POTION_CLASS:
-	    case GOLD_CLASS:
+	    case COIN_CLASS:
 		break;
 
 	    case RING_CLASS:
@@ -706,6 +710,8 @@
 			}
 			if (!Blind)
 			    Strcpy(post_engr_text,
+				IS_GRAVE(levl[u.ux][u.uy].typ) ?
+				"Chips fly out from the headstone." :
 				is_ice(u.ux,u.uy) ?
 				"Ice chips fly up from the ice surface!" :
 				"Gravel flies up from the floor.");
@@ -931,6 +937,10 @@
 				       "write in");
 		eloc = is_ice(u.ux,u.uy) ? "frost" : "dust";
 		break;
+	    case HEADSTONE:
+		everb = (oep && !eow ? "add to the epitaph on" :
+				       "engrave on");
+		break;
 	    case ENGRAVE:
 		everb = (oep && !eow ? "add to the engraving in" :
 				       "engrave in");
@@ -1011,6 +1021,7 @@
 		multi = -(len/10);
 		if (multi) nomovemsg = "You finish writing in the dust.";
 		break;
+	    case HEADSTONE:
 	    case ENGRAVE:
 		multi = -(len/10);
 		if ((otmp->oclass == WEAPON_CLASS) &&
@@ -1181,7 +1192,7 @@
 	    tx = rn1(COLNO-3,2);
 	    ty = rn2(ROWNO);
 	} while (engr_at(tx, ty) ||
-		!goodpos(tx, ty, (struct monst *)0));
+		!goodpos(tx, ty, (struct monst *)0, 0));
 
 	ep->engr_x = tx;
 	ep->engr_y = ty;
diff -Naurd ../nethack-3.4.0/src/exper.c ./src/exper.c
--- ../nethack-3.4.0/src/exper.c Wed Mar 20 23:43:05 2002
+++ ./src/exper.c Mon Feb 24 15:25:05 2003
@@ -49,10 +49,11 @@
 	tmp = 1 + mtmp->m_lev * mtmp->m_lev;
 
 /*	For higher ac values, give extra experience */
-	if((i = find_mac(mtmp)) < 3) tmp += (7 - i) * (i < 0) ? 2 : 1;
+	if ((i = find_mac(mtmp)) < 3) tmp += (7 - i) * ((i < 0) ? 2 : 1);
 
 /*	For very fast monsters, give extra experience */
-	if(ptr->mmove >= 12) tmp += (ptr->mmove >= 18) ? 5 : 3;
+	if (ptr->mmove > NORMAL_SPEED)
+	    tmp += (ptr->mmove > (3*NORMAL_SPEED/2)) ? 5 : 3;
 
 /*	For each "special" attack type give extra experience */
 	for(i = 0; i < NATTK; i++) {
@@ -115,7 +116,14 @@
 {
 	register int num;
 
-	if (resists_drli(&youmonst)) return;
+#ifdef WIZARD
+	/* override life-drain resistance when handling an explicit
+	   wizard mode request to reduce level; never fatal though */
+	if (drainer && !strcmp(drainer, "#levelchange"))
+	    drainer = 0;
+	else
+#endif
+	    if (resists_drli(&youmonst)) return;
 
 	if (u.ulevel > 1) {
 		pline("%s level %d.", Goodbye(), u.ulevel--);
@@ -140,10 +148,10 @@
 
 	if (u.ulevel < urole.xlev)
 	    num = rn1((int)ACURR(A_WIS)/2 + urole.enadv.lornd + urace.enadv.lornd,
-	    		urole.enadv.lofix + urace.enadv.lofix);
+			urole.enadv.lofix + urace.enadv.lofix);
 	else
 	    num = rn1((int)ACURR(A_WIS)/2 + urole.enadv.hirnd + urace.enadv.hirnd,
-	    		urole.enadv.hifix + urace.enadv.hifix);
+			urole.enadv.hifix + urace.enadv.hifix);
 	num = enermod(num);		/* M. Stephenson */
 	u.uenmax -= num;
 	if (u.uenmax < 0) u.uenmax = 0;
@@ -209,17 +217,32 @@
 	flags.botl = 1;
 }
 
+/* compute a random amount of experience points suitable for the hero's
+   experience level:  base number of points needed to reach the current
+   level plus a random portion of what it takes to get to the next level */
 long
-rndexp()
+rndexp(gaining)
+boolean gaining;	/* gaining XP via potion vs setting XP for polyself */
 {
-	long minexp, maxexp, diff, factor;
+	long minexp, maxexp, diff, factor, result;
 
 	minexp = (u.ulevel == 1) ? 0L : newuexp(u.ulevel - 1);
 	maxexp = newuexp(u.ulevel);
 	diff = maxexp - minexp,  factor = 1L;
+	/* make sure that `diff' is an argument which rn2() can handle */
 	while (diff >= (long)LARGEST_INT)
 	    diff /= 2L,  factor *= 2L;
-	return minexp + factor * (long)rn2((int)diff);
+	result = minexp + factor * (long)rn2((int)diff);
+	/* 3.4.1:  if already at level 30, add to current experience
+	   points rather than to threshold needed to reach the current
+	   level; otherwise blessed potions of gain level can result
+	   in lowering the experience points instead of raising them */
+	if (u.ulevel == MAXULEV && gaining) {
+	    result += (u.uexp - minexp);
+	    /* avoid wrapping (over 400 blessed potions needed for that...) */
+	    if (result < u.uexp) result = u.uexp;
+	}
+	return result;
 }
 
 /*exper.c*/
diff -Naurd ../nethack-3.4.0/src/explode.c ./src/explode.c
--- ../nethack-3.4.0/src/explode.c Wed Mar 20 23:43:05 2002
+++ ./src/explode.c Mon Feb 24 15:25:05 2003
@@ -188,7 +188,7 @@
 		}
 		curs_on_u();	/* will flush screen and output */
 
-		if (any_shield) {	/* simulate a shield effect */
+		if (any_shield && flags.sparkle) { /* simulate shield effect */
 		    for (k = 0; k < SHIELD_COUNT; k++) {
 			for (i=0; i<3; i++) for (j=0; j<3; j++) {
 			    if (explmask[i][j] == 1)
@@ -264,8 +264,10 @@
 				      (adtyp == AD_DRST) ? "intoxicated" :
 				      (adtyp == AD_ACID) ? "burned" :
 				       "fried");
-		} else if (cansee(i+x-1, j+y-1))
+		} else if (cansee(i+x-1, j+y-1)) {
+		    if(mtmp->m_ap_type) seemimic(mtmp);
 		    pline("%s is caught in the %s!", Monnam(mtmp), str);
+		}
 
 		idamres += destroy_mitem(mtmp, SCROLL_CLASS, (int) adtyp);
 		idamres += destroy_mitem(mtmp, SPBOOK_CLASS, (int) adtyp);
@@ -314,7 +316,8 @@
 		if (Invulnerable) {
 		    damu = 0;
 		    You("are unharmed!");
-		}
+		} else if (Half_physical_damage && adtyp == AD_PHYS)
+		    damu = (damu+1) / 2;
 		if (adtyp == AD_FIRE) (void) burnarmor(&youmonst);
 		destroy_item(SCROLL_CLASS, (int) adtyp);
 		destroy_item(SPBOOK_CLASS, (int) adtyp);
@@ -344,6 +347,10 @@
 			    killer_format = NO_KILLER_PREFIX;
 			    Sprintf(killer_buf, "caught %sself in %s own %s",
 				    uhim(), uhis(), str);
+			} else if (!strncmpi(str,"tower of flame", 8) ||
+				   !strncmpi(str,"fireball", 8)) {
+			    killer_format = KILLED_BY_AN;
+			    Strcpy(killer_buf, str);
 			} else {
 			    killer_format = KILLED_BY;
 			    Strcpy(killer_buf, str);
@@ -360,7 +367,8 @@
 	if (shopdamage) {
 		pay_for_damage(adtyp == AD_FIRE ? "burn away" :
 			       adtyp == AD_COLD ? "shatter" :
-			       adtyp == AD_DISN ? "disintegrate" : "destroy");
+			       adtyp == AD_DISN ? "disintegrate" : "destroy",
+			       FALSE);
 	}
 
 	/* explosions are noisy */
@@ -392,7 +400,8 @@
  *	MAY_FRACTURE	Stone objects can be fractured (statues, boulders)
  */
 
-void
+/* returns number of scattered objects */
+long
 scatter(sx,sy,blastforce,scflags, obj)
 int sx,sy;				/* location of objects to scatter */
 int blastforce;				/* force behind the scattering	*/
@@ -405,11 +414,11 @@
 	uchar typ;
 	long qtmp;
 	boolean used_up;
-	boolean split_up = FALSE;
 	boolean individual_object = obj ? TRUE : FALSE;
 	struct monst *mtmp;
 	struct scatter_chain *stmp, *stmp2 = 0;
 	struct scatter_chain *schain = (struct scatter_chain *)0;
+	long total = 0L;
 
 	while ((otmp = individual_object ? obj : level.objects[sx][sy]) != 0) {
 	    if (otmp->quan > 1L) {
@@ -417,17 +426,8 @@
 		if (qtmp > LARGEST_INT) qtmp = LARGEST_INT;
 		qtmp = (long)rnd((int)qtmp);
 		otmp = splitobj(otmp, qtmp);
-		if (rn2(qtmp))
-		    split_up = TRUE;
-		else
-		    split_up = FALSE;
-	    } else
-		split_up = FALSE;
-	    if (individual_object) {
- 		if (split_up) {
-		    obj = otmp;
-		} else
-		    obj = (struct obj *)0;
+	    } else {
+		obj = (struct obj *)0; /* all used */
 	    }
 	    obj_extract_self(otmp);
 	    used_up = FALSE;
@@ -439,7 +439,7 @@
 		if (otmp->otyp == BOULDER) {
 		    pline("%s apart.", Tobjnam(otmp, "break"));
 		    fracture_rock(otmp);
-		    place_object(otmp, sx, sy);	/* put fragments on floor */
+		    place_object(otmp, sx, sy);
 		    if ((otmp = sobj_at(BOULDER, sx, sy)) != 0) {
 			/* another boulder here, restack it to the top */
 			obj_extract_self(otmp);
@@ -541,12 +541,16 @@
 		stmp2 = stmp->next;
 		x = stmp->ox; y = stmp->oy;
 		if (stmp->obj) {
+			if ( x!=sx || y!=sy )
+			    total += stmp->obj->quan;
 			place_object(stmp->obj, x, y);
 			stackobj(stmp->obj);
 		}
 		free((genericptr_t)stmp);
 		newsym(x,y);
 	}
+
+	return total;
 }
 
 
diff -Naurd ../nethack-3.4.0/src/files.c ./src/files.c
--- ../nethack-3.4.0/src/files.c Wed Mar 20 23:43:06 2002
+++ ./src/files.c Mon Feb 24 15:25:05 2003
@@ -14,11 +14,25 @@
 #if !defined(MAC) && !defined(O_WRONLY) && !defined(AZTEC_C)
 #include <fcntl.h>
 #endif
-#if defined(UNIX) || defined(VMS)
+
 #include <errno.h>
-# ifndef SKIP_ERRNO
-extern int errno;
+#ifdef _MSC_VER	/* MSC 6.0 defines errno quite differently */
+# if (_MSC_VER >= 600)
+#  define SKIP_ERRNO
+# endif
+#endif
+#ifndef SKIP_ERRNO
+# ifdef _DCC
+const
 # endif
+extern int errno;
+#endif
+
+#if defined(UNIX) && defined(QT_GRAPHICS)
+#include <dirent.h>
+#endif
+
+#if defined(UNIX) || defined(VMS)
 #include <signal.h>
 #endif
 
@@ -34,7 +48,7 @@
 #endif
 
 #ifdef PREFIXES_IN_USE
-#define FQN_NUMBUF 2
+#define FQN_NUMBUF 4
 static char fqn_filename_buffer[FQN_NUMBUF][FQN_MAX_FILENAME];
 #endif
 
@@ -75,6 +89,17 @@
 char SAVEP[SAVESIZE];	/* holds path of directory for save file */
 #endif
 
+#ifdef HOLD_LOCKFILE_OPEN
+struct level_ftrack {
+int fd;					/* file descriptor for level file     */
+int oflag;				/* open flags                         */
+boolean nethack_thinks_it_is_open;	/* Does NetHack think it's open?       */
+} lftrack;
+# if defined(WIN32)
+#include <share.h>
+# endif
+#endif /*HOLD_LOCKFILE_OPEN*/
+
 #ifdef WIZARD
 #define WIZKIT_MAX 128
 static char wizkit[WIZKIT_MAX];
@@ -99,8 +124,10 @@
 #define Delay(a) msleep(a)
 # endif
 #define Close close
+#ifndef WIN_CE
 #define DeleteFile unlink
 #endif
+#endif
 
 #ifdef USER_SOUNDS
 extern char *sounddir;
@@ -116,11 +143,123 @@
 #endif
 STATIC_DCL char *FDECL(make_lockname, (const char *,char *));
 STATIC_DCL FILE *FDECL(fopen_config_file, (const char *));
-STATIC_DCL int FDECL(get_uchars, (FILE *,char *,char *,uchar *,int,const char *));
+STATIC_DCL int FDECL(get_uchars, (FILE *,char *,char *,uchar *,BOOLEAN_P,int,const char *));
 int FDECL(parse_config_line, (FILE *,char *,char *,char *));
 #ifdef NOCWD_ASSUMPTIONS
 STATIC_DCL void FDECL(adjust_prefix, (char *, int));
 #endif
+#ifdef SELF_RECOVER
+STATIC_DCL boolean FDECL(copy_bytes, (int, int));
+#endif
+#ifdef HOLD_LOCKFILE_OPEN
+STATIC_DCL int FDECL(open_levelfile_exclusively, (const char *, int, int));
+#endif
+
+/*
+ * fname_encode()
+ *
+ *   Args:
+ *	legal		zero-terminated list of acceptable file name characters
+ *	quotechar	lead-in character used to quote illegal characters as hex digits
+ *	s		string to encode
+ *	callerbuf	buffer to house result
+ *	bufsz		size of callerbuf
+ *
+ *   Notes:
+ *	The hex digits 0-9 and A-F are always part of the legal set due to
+ *	their use in the encoding scheme, even if not explicitly included in 'legal'.
+ *
+ *   Sample:
+ *	The following call:
+ *	    (void)fname_encode("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
+ *				'%', "This is a % test!", buf, 512);
+ *	results in this encoding:
+ *	    "This%20is%20a%20%25%20test%21"
+ */
+char *
+fname_encode(legal, quotechar, s, callerbuf, bufsz)
+const char *legal;
+char quotechar;
+char *s, *callerbuf;
+int bufsz;
+{
+	char *sp, *op;
+	int cnt = 0;
+	static char hexdigits[] = "0123456789ABCDEF";
+
+	sp = s;
+	op = callerbuf;
+	*op = '\0';
+	
+	while (*sp) {
+		/* Do we have room for one more character or encoding? */
+		if ((bufsz - cnt) <= 4) return callerbuf;
+
+		if (*sp == quotechar) {
+			(void)sprintf(op, "%c%02X", quotechar, *sp);
+			 op += 3;
+			 cnt += 3;
+		} else if ((index(legal, *sp) != 0) || (index(hexdigits, *sp) != 0)) {
+			*op++ = *sp;
+			*op = '\0';
+			cnt++;
+		} else {
+			(void)sprintf(op,"%c%02X", quotechar, *sp);
+			op += 3;
+			cnt += 3;
+		}
+		sp++;
+	}
+	return callerbuf;
+}
+
+/*
+ * fname_decode()
+ *
+ *   Args:
+ *	quotechar	lead-in character used to quote illegal characters as hex digits
+ *	s		string to decode
+ *	callerbuf	buffer to house result
+ *	bufsz		size of callerbuf
+ */
+char *
+fname_decode(quotechar, s, callerbuf, bufsz)
+char quotechar;
+char *s, *callerbuf;
+int bufsz;
+{
+	char *sp, *op;
+	int k,calc,cnt = 0;
+	static char hexdigits[] = "0123456789ABCDEF";
+
+	sp = s;
+	op = callerbuf;
+	*op = '\0';
+	calc = 0;
+
+	while (*sp) {
+		/* Do we have room for one more character? */
+		if ((bufsz - cnt) <= 2) return callerbuf;
+		if (*sp == quotechar) {
+			sp++;
+			for (k=0; k < 16; ++k) if (*sp == hexdigits[k]) break;
+			if (k >= 16) return callerbuf;	/* impossible, so bail */
+			calc = k << 4; 
+			sp++;
+			for (k=0; k < 16; ++k) if (*sp == hexdigits[k]) break;
+			if (k >= 16) return callerbuf;	/* impossible, so bail */
+			calc += k; 
+			sp++;
+			*op++ = calc;
+			*op = '\0';
+		} else {
+			*op++ = *sp++;
+			*op = '\0';
+		}
+		cnt++;
+	}
+	return callerbuf;
+}
 
 #ifndef PREFIXES_IN_USE
 /*ARGSUSED*/
@@ -153,18 +292,60 @@
 #endif
 }
 
+/* reasonbuf must be at least BUFSZ, supplied by caller */
+/*ARGSUSED*/
+int
+validate_prefix_locations(reasonbuf)
+char *reasonbuf;
+{
+#if defined(NOCWD_ASSUMPTIONS)
+	FILE *fp;
+	const char *filename;
+	int prefcnt, failcount = 0;
+	char panicbuf1[BUFSZ], panicbuf2[BUFSZ], *details;
+
+	if (reasonbuf) reasonbuf[0] = '\0';
+	for (prefcnt = 1; prefcnt < PREFIX_COUNT; prefcnt++) {
+		/* don't test writing to configdir or datadir; they're readonly */
+		if (prefcnt == CONFIGPREFIX || prefcnt == DATAPREFIX) continue;
+		filename = fqname("validate", prefcnt, 3);
+		if ((fp = fopen(filename, "w"))) {
+			fclose(fp);
+			(void) unlink(filename);
+		} else {
+			if (reasonbuf) {
+				if (failcount) Strcat(reasonbuf,", ");
+				Strcat(reasonbuf, fqn_prefix_names[prefcnt]);
+			}
+			/* the paniclog entry gets the value of errno as well */
+			Sprintf(panicbuf1,"Invalid %s", fqn_prefix_names[prefcnt]);
+#if defined (NHSTDC) && !defined(NOTSTDC)
+			if (!(details = strerror(errno)))
+#endif
+			details = "";
+			Sprintf(panicbuf2,"\"%s\", (%d) %s",
+				fqn_prefix[prefcnt], errno, details);
+			paniclog(panicbuf1, panicbuf2);
+			failcount++;
+		}	
+	}
+	if (failcount)
+		return 0;
+	else
+#endif
+	return 1;
+}
 
 /* fopen a file, with OS-dependent bells and whistles */
 /* NOTE: a simpler version of this routine also exists in util/dlb_main.c */
 FILE *
-fopen_datafile(filename, mode, use_scoreprefix)
+fopen_datafile(filename, mode, prefix)
 const char *filename, *mode;
-boolean use_scoreprefix;
+int prefix;
 {
 	FILE *fp;
 
-	filename = fqname(filename,
-				use_scoreprefix ? SCOREPREFIX : DATAPREFIX, 0);
+	filename = fqname(filename, prefix, prefix == TROUBLEPREFIX ? 3 : 0);
 #ifdef VMS	/* essential to have punctuation, to avoid logical names */
     {
 	char tmp[BUFSIZ];
@@ -229,19 +410,27 @@
 }
 
 int
-create_levelfile(lev)
+create_levelfile(lev, errbuf)
 int lev;
+char errbuf[];
 {
 	int fd;
 	const char *fq_lock;
 
+	if (errbuf) *errbuf = '\0';
 	set_levelfile_name(lock, lev);
 	fq_lock = fqname(lock, LEVELPREFIX, 0);
 
-#if defined(MICRO)
+#if defined(MICRO) || defined(WIN32)
 	/* Use O_TRUNC to force the file to be shortened if it already
 	 * exists and is currently longer.
 	 */
+# ifdef HOLD_LOCKFILE_OPEN
+	if (lev == 0)
+		fd = open_levelfile_exclusively(fq_lock, lev,
+				O_WRONLY |O_CREAT | O_TRUNC | O_BINARY);
+	else
+# endif
 	fd = open(fq_lock, O_WRONLY |O_CREAT | O_TRUNC | O_BINARY, FCMASK);
 #else
 # ifdef MAC
@@ -249,22 +438,28 @@
 # else
 	fd = creat(fq_lock, FCMASK);
 # endif
-#endif /* MICRO */
+#endif /* MICRO || WIN32 */
 
 	if (fd >= 0)
 	    level_info[lev].flags |= LFILE_EXISTS;
+	else if (errbuf)	/* failure explanation */
+	    Sprintf(errbuf,
+		    "Cannot create file \"%s\" for level %d (errno %d).",
+		    lock, lev, errno);
 
 	return fd;
 }
 
 
 int
-open_levelfile(lev)
+open_levelfile(lev, errbuf)
 int lev;
+char errbuf[];
 {
 	int fd;
 	const char *fq_lock;
 
+	if (errbuf) *errbuf = '\0';
 	set_levelfile_name(lock, lev);
 	fq_lock = fqname(lock, LEVELPREFIX, 0);
 #ifdef MFLOPPY
@@ -275,8 +470,22 @@
 #ifdef MAC
 	fd = macopen(fq_lock, O_RDONLY | O_BINARY, LEVL_TYPE);
 #else
+# ifdef HOLD_LOCKFILE_OPEN
+	if (lev == 0)
+		fd = open_levelfile_exclusively(fq_lock, lev, O_RDONLY | O_BINARY );
+	else
+# endif
 	fd = open(fq_lock, O_RDONLY | O_BINARY, 0);
 #endif
+
+	/* for failure, return an explanation that our caller can use;
+	   settle for `lock' instead of `fq_lock' because the latter
+	   might end up being too big for nethack's BUFSZ */
+	if (fd < 0 && errbuf)
+	    Sprintf(errbuf,
+		    "Cannot open file \"%s\" for level %d (errno %d).",
+		    lock, lev, errno);
+
 	return fd;
 }
 
@@ -291,6 +500,9 @@
 	 */
 	if (lev == 0 || (level_info[lev].flags & LFILE_EXISTS)) {
 		set_levelfile_name(lock, lev);
+#ifdef HOLD_LOCKFILE_OPEN
+		if (lev == 0) really_close();
+#endif
 		(void) unlink(fqname(lock, LEVELPREFIX, 0));
 		level_info[lev].flags &= ~LFILE_EXISTS;
 	}
@@ -316,6 +528,62 @@
 #endif
 }
 
+#ifdef HOLD_LOCKFILE_OPEN
+STATIC_OVL int
+open_levelfile_exclusively(name, lev, oflag)
+const char *name;
+int lev, oflag;
+{
+	int reslt, fd;
+	if (lftrack.fd) {
+		/* check for compatible access */
+		if (lftrack.oflag == oflag) {
+			fd = lftrack.fd;
+			reslt = lseek(fd, 0L, SEEK_SET);
+			if (reslt == -1L)
+			    panic("open_levelfile_exclusively: lseek failed %d", reslt);
+			lftrack.nethack_thinks_it_is_open = TRUE;
+		} else {
+			really_close();
+			fd = sopen(name, oflag,SH_DENYRW, FCMASK);
+			lftrack.fd = fd;
+			lftrack.oflag = oflag;
+			lftrack.nethack_thinks_it_is_open = TRUE;
+		}
+	} else {
+			fd = sopen(name, oflag,SH_DENYRW, FCMASK);
+			lftrack.fd = fd;
+			lftrack.oflag = oflag;
+			if (fd)
+			    lftrack.nethack_thinks_it_is_open = TRUE;
+	}
+	return fd;
+}
+
+void
+really_close()
+{
+	int fd = lftrack.fd;
+	lftrack.nethack_thinks_it_is_open = FALSE;
+	lftrack.fd = 0;
+	lftrack.oflag = 0;
+	(void)_close(fd);
+	return;
+}
+
+close(fd)
+int fd;
+{
+ 	if (lftrack.fd == fd) {
+		really_close();	/* close it, but reopen it to hold it */
+		fd = open_levelfile(0, (char *)0);
+		lftrack.nethack_thinks_it_is_open = FALSE;
+		return 0;
+	}
+	return _close(fd);
+}
+#endif
+	
 /* ----------  END LEVEL FILE HANDLING ----------- */
 
 
@@ -366,18 +634,20 @@
 }
 
 int
-create_bonesfile(lev, bonesid)
+create_bonesfile(lev, bonesid, errbuf)
 d_level *lev;
 char **bonesid;
+char errbuf[];
 {
 	const char *file;
 	int fd;
 
+	if (errbuf) *errbuf = '\0';
 	*bonesid = set_bonesfile_name(bones, lev);
 	file = set_bonestemp_name();
 	file = fqname(file, BONESPREFIX, 0);
 
-#ifdef MICRO
+#if defined(MICRO) || defined(WIN32)
 	/* Use O_TRUNC to force the file to be shortened if it already
 	 * exists and is currently longer.
 	 */
@@ -388,6 +658,12 @@
 # else
 	fd = creat(file, FCMASK);
 # endif
+#endif
+	if (fd < 0 && errbuf) /* failure explanation */
+	    Sprintf(errbuf,
+		    "Cannot create bones \"%s\", id %s (errno %d).",
+		    lock, *bonesid, errno);
+
 # if defined(VMS) && !defined(SECURE)
 	/*
 	   Re-protect bones file with world:read+write+execute+delete access.
@@ -399,7 +675,6 @@
 	 */
 	(void) chmod(file, FCMASK | 007);  /* allow other users full access */
 # endif /* VMS && !SECURE */
-#endif /* MICRO */
 
 	return fd;
 }
@@ -442,7 +717,7 @@
 #endif
 #ifdef WIZARD
 	if (wizard && ret != 0)
-		pline("couldn't rename %s to %s", tempname, fq_bones);
+		pline("couldn't rename %s to %s.", tempname, fq_bones);
 #endif
 }
 
@@ -641,6 +924,104 @@
 	return fd;
 }
 
+/*ARGSUSED*/
+static char*
+plname_from_file(filename)
+const char* filename;
+{
+#ifdef STORE_PLNAME_IN_FILE
+    int fd;
+    char* result = 0;
+
+    Strcpy(SAVEF,filename);
+#ifdef COMPRESS_EXTENSION
+    SAVEF[strlen(SAVEF)-strlen(COMPRESS_EXTENSION)] = '\0';
+#endif
+    uncompress(SAVEF);
+    if ((fd = open_savefile()) >= 0) {
+	if (uptodate(fd, filename)) {
+	    char tplname[PL_NSIZ];
+	    mread(fd, (genericptr_t) tplname, PL_NSIZ);
+	    result = strdup(tplname);
+	}
+	(void) close(fd);
+    }
+    compress(SAVEF);
+
+    return result;
+#else
+# if defined(UNIX) && defined(QT_GRAPHICS)
+    /* Name not stored in save file, so we have to extract it from
+       the filename, which loses information
+       (eg. "/", "_", and "." characters are lost. */
+    int k;
+    int uid;
+    char name[NAME_MAX];
+#ifdef COMPRESS_EXTENSION
+#define EXTSTR COMPRESS_EXTENSION
+#else
+#define EXTSTR ""
+#endif
+    if ( sscanf( filename, "%*[^/]/%d%[^.]" EXTSTR, &uid, name ) == 2 ) {
+#undef EXTSTR
+    /* "_" most likely means " ", which certainly looks nicer */
+	for (k=0; name[k]; k++)
+	    if ( name[k]=='_' )
+		name[k]=' ';
+	return strdup(name);
+    } else
+# endif
+    {
+	return 0;
+    }
+#endif
+}
+
+char**
+get_saved_games()
+{
+#if defined(UNIX) && defined(QT_GRAPHICS)
+    int myuid=getuid();
+    struct dirent **namelist;
+    int n = scandir("save", &namelist, 0, alphasort);;
+    if ( n > 0 ) {
+	int i,j=0;
+	char** result = (char**)alloc((n+1)*sizeof(char*)); /* at most */
+	for (i=0; i<n; i++) {
+	    int uid;
+	    char name[NAME_MAX];
+	    if ( sscanf( namelist[i]->d_name, "%d%s", &uid, name ) == 2 ) {
+		if ( uid == myuid ) {
+		    char filename[BUFSZ];
+		    char* r;
+		    Sprintf(filename,"save/%d%s",uid,name);
+		    r = plname_from_file(filename);
+		    if ( r )
+			result[j++] = r;
+		}
+	    }
+	}
+	result[j++] = 0;
+	return result;
+    } else
+#endif
+    {
+	return 0;
+    }
+}
+
+void
+free_saved_games(saved)
+char** saved;
+{
+    if ( saved ) {
+	int i=0;
+	while (saved[i]) free((genericptr_t)saved[i++]);
+	free((genericptr_t)saved);
+    }
+}
+
+
 /* ----------  END SAVE FILE HANDLING ----------- */
 
 
@@ -909,7 +1290,7 @@
 	lockname = make_lockname(filename, locknambuf);
 	filename = fqname(filename, whichprefix, 0);
 #ifndef NO_FILE_LINKS	/* LOCKDIR should be subsumed by LOCKPREFIX */
-	lockname = fqname(lockname, LOCKPREFIX, 1);
+	lockname = fqname(lockname, LOCKPREFIX, 2);
 #endif
 
 #if defined(UNIX) || defined(VMS)
@@ -1013,7 +1394,7 @@
 	if (nesting == 1) {
 		lockname = make_lockname(filename, locknambuf);
 #ifndef NO_FILE_LINKS	/* LOCKDIR should be subsumed by LOCKPREFIX */
-		lockname = fqname(lockname, LOCKPREFIX, 1);
+		lockname = fqname(lockname, LOCKPREFIX, 2);
 #endif
 
 #if defined(UNIX) || defined(VMS)
@@ -1166,27 +1547,33 @@
 /*
  * Retrieve a list of integers from a file into a uchar array.
  *
- * NOTE:  This routine is unable to read a value of 0.
+ * NOTE: zeros are inserted unless modlist is TRUE, in which case the list
+ *  location is unchanged.  Callers must handle zeros if modlist is FALSE.
  */
 STATIC_OVL int
-get_uchars(fp, buf, bufp, list, size, name)
+get_uchars(fp, buf, bufp, list, modlist, size, name)
     FILE *fp;		/* input file pointer */
     char *buf;		/* read buffer, must be of size BUFSZ */
     char *bufp;		/* current pointer */
     uchar *list;	/* return list */
+    boolean modlist;	/* TRUE: list is being modified in place */
     int  size;		/* return list size */
     const char *name;		/* name of option for error message */
 {
     unsigned int num = 0;
     int count = 0;
+    boolean havenum = FALSE;
 
     while (1) {
 	switch(*bufp) {
 	    case ' ':  case '\0':
 	    case '\t': case '\n':
-		if (num) {
-		    list[count++] =  num;
+		if (havenum) {
+		    /* if modifying in place, don't insert zeros */
+		    if (num || !modlist) list[count] = num;
+		    count++;
 		    num = 0;
+		    havenum = FALSE;
 		}
 		if (count == size || !*bufp) return count;
 		bufp++;
@@ -1195,6 +1582,7 @@
 	    case '0': case '1': case '2': case '3':
 	    case '4': case '5': case '6': case '7':
 	    case '8': case '9':
+		havenum = TRUE;
 		num = num*10 + (*bufp-'0');
 		bufp++;
 		break;
@@ -1290,7 +1678,7 @@
 	} else if (match_varname(buf, "LEVELDIR", 4) ||
 		   match_varname(buf, "LEVELS", 4)) {
 		adjust_prefix(bufp, LEVELPREFIX);
-	} else if (match_varname(buf, "SAVE", 4)) {
+	} else if (match_varname(buf, "SAVEDIR", 4)) {
 		adjust_prefix(bufp, SAVEPREFIX);
 	} else if (match_varname(buf, "BONESDIR", 5)) {
 		adjust_prefix(bufp, BONESPREFIX);
@@ -1302,6 +1690,8 @@
 		adjust_prefix(bufp, LOCKPREFIX);
 	} else if (match_varname(buf, "CONFIGDIR", 4)) {
 		adjust_prefix(bufp, CONFIGPREFIX);
+	} else if (match_varname(buf, "TROUBLEDIR", 4)) {
+		adjust_prefix(bufp, TROUBLEPREFIX);
 #else /*NOCWD_ASSUMPTIONS*/
 # ifdef MICRO
 	} else if (match_varname(buf, "HACKDIR", 4)) {
@@ -1354,30 +1744,35 @@
 	    (void) strncpy(catname, bufp, PL_PSIZ-1);
 
 	} else if (match_varname(buf, "BOULDER", 3)) {
-	    (void) get_uchars(fp, buf, bufp, &iflags.bouldersym, 1, "BOULDER");
+	    (void) get_uchars(fp, buf, bufp, &iflags.bouldersym, TRUE,
+			      1, "BOULDER");
 	} else if (match_varname(buf, "GRAPHICS", 4)) {
-	    len = get_uchars(fp, buf, bufp, translate, MAXPCHARS, "GRAPHICS");
+	    len = get_uchars(fp, buf, bufp, translate, FALSE,
+			     MAXPCHARS, "GRAPHICS");
 	    assign_graphics(translate, len, MAXPCHARS, 0);
 	} else if (match_varname(buf, "DUNGEON", 4)) {
-	    len = get_uchars(fp, buf, bufp, translate, MAXDCHARS, "DUNGEON");
+	    len = get_uchars(fp, buf, bufp, translate, FALSE,
+			     MAXDCHARS, "DUNGEON");
 	    assign_graphics(translate, len, MAXDCHARS, 0);
 	} else if (match_varname(buf, "TRAPS", 4)) {
-	    len = get_uchars(fp, buf, bufp, translate, MAXTCHARS, "TRAPS");
+	    len = get_uchars(fp, buf, bufp, translate, FALSE,
+			     MAXTCHARS, "TRAPS");
 	    assign_graphics(translate, len, MAXTCHARS, MAXDCHARS);
 	} else if (match_varname(buf, "EFFECTS", 4)) {
-	    len = get_uchars(fp, buf, bufp, translate, MAXECHARS, "EFFECTS");
+	    len = get_uchars(fp, buf, bufp, translate, FALSE,
+			     MAXECHARS, "EFFECTS");
 	    assign_graphics(translate, len, MAXECHARS, MAXDCHARS+MAXTCHARS);
 
 	} else if (match_varname(buf, "OBJECTS", 3)) {
 	    /* oc_syms[0] is the RANDOM object, unused */
-	    (void) get_uchars(fp, buf, bufp, &(oc_syms[1]),
+	    (void) get_uchars(fp, buf, bufp, &(oc_syms[1]), TRUE,
 					MAXOCLASSES-1, "OBJECTS");
 	} else if (match_varname(buf, "MONSTERS", 3)) {
 	    /* monsyms[0] is unused */
-	    (void) get_uchars(fp, buf, bufp, &(monsyms[1]),
+	    (void) get_uchars(fp, buf, bufp, &(monsyms[1]), TRUE,
 					MAXMCLASSES-1, "MONSTERS");
 	} else if (match_varname(buf, "WARNINGS", 5)) {
-	    (void) get_uchars(fp, buf, bufp, translate,
+	    (void) get_uchars(fp, buf, bufp, translate, FALSE,
 					WARNCOUNT, "WARNINGS");
 	    assign_warnings(translate);
 #ifdef WIZARD
@@ -1501,6 +1896,7 @@
 		add_sound_mapping(bufp);
 #endif
 #ifdef QT_GRAPHICS
+	/* These should move to wc_ options */
 	} else if (match_varname(buf, "QT_TILEWIDTH", 12)) {
 		extern char *qt_tilewidth;
 		if (qt_tilewidth == NULL)	
@@ -1671,21 +2067,33 @@
 	FILE *fp;
 	char *ep, buf[BUFSZ];
 	struct obj *otmp;
+	boolean bad_items = FALSE, skip = FALSE;
+
 	if (!wizard || !(fp = fopen_wizkit_file())) return;
 
-	while (fgets(buf, 4*BUFSZ, fp)) {
-		if ((ep = index(buf, '\n'))) *ep = '\0';
+	while (fgets(buf, (int)(sizeof buf), fp)) {
+	    ep = index(buf, '\n');
+	    if (skip) {	/* in case previous line was too long */
+		if (ep) skip = FALSE; /* found newline; next line is normal */
+	    } else {
+		if (!ep) skip = TRUE; /* newline missing; discard next fgets */
+		else *ep = '\0';		/* remove newline */
+
 		if (buf[0]) {
 			otmp = readobjnam(buf, (struct obj *)0, FALSE);
 			if (otmp) {
 			    if (otmp != &zeroobj)
 				otmp = addinv(otmp);
 			} else {
-			    raw_printf("Bad wizkit item: \"%.50s\"", buf);
-			    wait_synch();
+			    /* .60 limits output line width to 79 chars */
+			    raw_printf("Bad wizkit item: \"%.60s\"", buf);
+			    bad_items = TRUE;
 			}
 		}
+	    }
 	}
+	if (bad_items)
+	    wait_synch();
 	(void) fclose(fp);
 	return;
 }
diff -Naurd ../nethack-3.4.0/src/fountain.c ./src/fountain.c
--- ../nethack-3.4.0/src/fountain.c Wed Mar 20 23:43:06 2002
+++ ./src/fountain.c Mon Feb 24 15:25:05 2003
@@ -43,9 +43,9 @@
 void
 dowaterdemon() /* Water demon */
 {
-	register struct monst *mtmp;
+    register struct monst *mtmp;
 
-	if(mvitals[PM_WATER_DEMON].mvflags & G_GONE) return;
+    if(!(mvitals[PM_WATER_DEMON].mvflags & G_GONE)) {
 	if((mtmp = makemon(&mons[PM_WATER_DEMON],u.ux,u.uy, NO_MM_FLAGS))) {
 	    if (!Blind)
 		You("unleash %s!", a_monnam(mtmp));
@@ -61,6 +61,8 @@
 	    } else if (t_at(mtmp->mx, mtmp->my))
 		(void) mintrap(mtmp);
 	}
+    } else
+	pline_The("fountain bubbles furiously for a moment, then calms.");
 }
 
 STATIC_OVL void
@@ -68,8 +70,8 @@
 {
 	register struct monst *mtmp;
 
-	if(mvitals[PM_WATER_NYMPH].mvflags & G_GONE) return;
-	if((mtmp = makemon(&mons[PM_WATER_NYMPH],u.ux,u.uy, NO_MM_FLAGS))) {
+	if(!(mvitals[PM_WATER_NYMPH].mvflags & G_GONE) &&
+	   (mtmp = makemon(&mons[PM_WATER_NYMPH],u.ux,u.uy, NO_MM_FLAGS))) {
 		if (!Blind)
 		   You("attract %s!", a_monnam(mtmp));
 		else
@@ -138,7 +140,7 @@
 	else You_feel("a gem here!");
 	(void) mksobj_at(rnd_class(DILITHIUM_CRYSTAL, LUCKSTONE-1),
 			 u.ux, u.uy, FALSE, FALSE);
-	levl[u.ux][u.uy].looted |= F_LOOTED;
+	SET_FOUNTAIN_LOOTED(u.ux,u.uy);
 	newsym(u.ux, u.uy);
 	exercise(A_WIS, TRUE);			/* a discovery! */
 }
@@ -149,12 +151,10 @@
 boolean isyou;
 {
 	if (IS_FOUNTAIN(levl[x][y].typ) &&
-	    (!rn2(3) || (levl[x][y].looted & F_WARNED))) {
-		s_level *slev = Is_special(&u.uz);
-		if(isyou && slev && slev->flags.town &&
-		   !(levl[x][y].looted & F_WARNED)) {
+	    (!rn2(3) || FOUNTAIN_IS_WARNED(x,y))) {
+		if(isyou && in_town(x, y) && !FOUNTAIN_IS_WARNED(x,y)) {
 			struct monst *mtmp;
-			levl[x][y].looted |= F_WARNED;
+			SET_FOUNTAIN_WARNED(x,y);
 			/* Warn about future fountain use. */
 			for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
 			    if (DEADMONSTER(mtmp)) continue;
@@ -177,15 +177,16 @@
 				return;
 		}
 #endif
-		if (cansee(x,y)) pline_The("fountain dries up!");
+		/* replace the fountain with ordinary floor */
 		levl[x][y].typ = ROOM;
 		levl[x][y].looted = 0;
 		levl[x][y].blessedftn = 0;
+		if (cansee(x,y)) pline_The("fountain dries up!");
 		/* The location is seen if the hero/monster is invisible */
 		/* or felt if the hero is blind.			 */
 		newsym(x, y);
 		level.flags.nfountains--;
-		if(isyou && slev && slev->flags.town)
+		if(isyou && in_town(x, y))
 		    (void) angry_guards(FALSE);
 	}
 }
@@ -254,7 +255,9 @@
 
 			pline_The("water is contaminated!");
 			if (Poison_resistance) {
-	   pline("Perhaps it is runoff from the nearby %s farm.", pl_fruit);
+			   pline(
+			      "Perhaps it is runoff from the nearby %s farm.",
+				 fruitname(FALSE));
 			   losehp(rnd(4),"unrefrigerated sip of juice",
 				KILLED_BY_AN);
 			   break;
@@ -287,12 +290,12 @@
 		case 25: /* See invisible */
 
 			if (Blind) {
-			  if (Invisible) {
-			    You("feel very self-conscious.");
-			    pline("Then it passes.");
-			  } else {
-			    You("feel transparent.");
-			  }
+			    if (Invisible) {
+				You("feel transparent.");
+			    } else {
+			    	You("feel very self-conscious.");
+			    	pline("Then it passes.");
+			    }
 			} else {
 			   You("see an image of someone stalking you.");
 			   pline("But it disappears.");
@@ -310,7 +313,7 @@
 
 		case 27: /* Find a gem in the sparkling waters. */
 
-			if (!levl[u.ux][u.uy].looted) {
+			if (!FOUNTAIN_IS_LOOTED(u.ux,u.uy)) {
 				dofindgem();
 				break;
 			}
@@ -359,7 +362,6 @@
 	    && u.ulevel >= 5 && !rn2(6)
 	    && !obj->oartifact
 	    && !exist_artifact(LONG_SWORD, artiname(ART_EXCALIBUR))) {
-		s_level *slev = Is_special(&u.uz);
 
 		if (u.ualign.type != A_LAWFUL) {
 			/* Ha!  Trying to cheat her. */
@@ -386,7 +388,7 @@
 		levl[u.ux][u.uy].looted = 0;
 		if(Invisible) newsym(u.ux, u.uy);
 		level.flags.nfountains--;
-		if(slev && slev->flags.town)
+		if(in_town(u.ux, u.uy))
 		    (void) angry_guards(FALSE);
 		return;
 	} else (void) get_wet(obj);
@@ -423,7 +425,7 @@
 			dowatersnakes();
 			break;
 		case 24: /* Find a gem */
-			if (!levl[u.ux][u.uy].looted) {
+			if (!FOUNTAIN_IS_LOOTED(u.ux,u.uy)) {
 				dofindgem();
 				break;
 			}
@@ -443,7 +445,7 @@
 			if (u.ugold > 10) {
 			    u.ugold -= somegold() / 10;
 			    You("lost some of your gold in the fountain!");
-			    levl[u.ux][u.uy].looted &= ~F_LOOTED;
+			    CLEAR_FOUNTAIN_LOOTED(u.ux,u.uy);
 			    exercise(A_WIS, FALSE);
 			}
 #else
@@ -453,7 +455,7 @@
                             if (money > 10) {
 				/* Amount to loose.  Might get rounded up as fountains don't pay change... */
 			        money = somegold(money) / 10; 
-			        for (otmp = invent; otmp && money > 0; otmp = otmp->nobj) if (otmp->oclass == GOLD_CLASS) {
+			        for (otmp = invent; otmp && money > 0; otmp = otmp->nobj) if (otmp->oclass == COIN_CLASS) {
 				    int denomination = objects[otmp->otyp].oc_cost;
 				    long coin_loss = (money + denomination - 1) / denomination;
                                     coin_loss = min(coin_loss, otmp->quan);
@@ -462,7 +464,7 @@
 				    if (!otmp->quan) delobj(otmp);
 				}
 			        You("lost some of your money in the fountain!");
-			        levl[u.ux][u.uy].looted &= ~F_LOOTED;
+				CLEAR_FOUNTAIN_LOOTED(u.ux,u.uy);
 			        exercise(A_WIS, FALSE);
                             }
 			}
@@ -474,8 +476,8 @@
 		 * surface.  After all, there will have been more people going
 		 * by.	Just like a shopping mall!  Chris Woodbury  */
 
-		    if (levl[u.ux][u.uy].looted) break;
-		    levl[u.ux][u.uy].looted |= F_LOOTED;
+		    if (FOUNTAIN_IS_LOOTED(u.ux,u.uy)) break;
+		    SET_FOUNTAIN_LOOTED(u.ux,u.uy);
 		    (void) mkgold((long)
 			(rnd((dunlevs_in_dungeon(&u.uz)-dunlev(&u.uz)+1)*2)+5),
 			u.ux, u.uy);
diff -Naurd ../nethack-3.4.0/src/hack.c ./src/hack.c
--- ../nethack-3.4.0/src/hack.c Wed Mar 20 23:43:06 2002
+++ ./src/hack.c Mon Feb 24 15:25:05 2003
@@ -12,7 +12,7 @@
 #ifdef SINKS
 STATIC_DCL void NDECL(dosinkfall);
 #endif
-STATIC_DCL void NDECL(findtravelpath);
+STATIC_DCL boolean FDECL(findtravelpath, (BOOLEAN_P));
 STATIC_DCL boolean FDECL(monstinroom, (struct permonst *,int));
 
 STATIC_DCL void FDECL(move_update, (BOOLEAN_P));
@@ -47,7 +47,7 @@
     /* this location might not be safe, if not, move revived monster */
     if (revived) {
 	mtmp = m_at(x,y);
-	if (mtmp && !goodpos(x, y, mtmp) &&
+	if (mtmp && !goodpos(x, y, mtmp, 0) &&
 	    enexto(&cc, x, y, mtmp->data)) {
 	    rloc_to(mtmp, cc.x, cc.y);
 	}
@@ -89,6 +89,7 @@
 	    goto cannot_push;
 	}
 	if (isok(rx,ry) && !IS_ROCK(levl[rx][ry].typ) &&
+	    levl[rx][ry].typ != IRONBARS &&
 	    (!IS_DOOR(levl[rx][ry].typ) || !(u.dx && u.dy) || (
 #ifdef REINCARNATION
 		!Is_rogue_level(&u.uz) &&
@@ -113,17 +114,17 @@
 		    (!mtmp->mtrapped ||
 			 !(ttmp && ((ttmp->ttyp == PIT) ||
 				    (ttmp->ttyp == SPIKED_PIT))))) {
+		if (Blind) feel_location(sx, sy);
 		if (canspotmon(mtmp))
-		    pline("There's %s on the other side.", mon_nam(mtmp));
+		    pline("There's %s on the other side.", a_monnam(mtmp));
 		else {
-		    if (Blind) feel_location(sx, sy);
 		    You_hear("a monster behind %s.", the(xname(otmp)));
 		    map_invisible(rx, ry);
 		}
 		if (flags.verbose)
 		    pline("Perhaps that's why %s cannot move it.",
 #ifdef STEED
-				u.usteed ? mon_nam(u.usteed) :
+				u.usteed ? y_monnam(u.usteed) :
 #endif
 				"you");
 		goto cannot_push;
@@ -180,7 +181,7 @@
 #ifdef STEED
 		    if (u.usteed)
 			pline("%s pushes %s and suddenly it disappears!",
-				Monnam(u.usteed), the(xname(otmp)));
+			      upstart(y_monnam(u.usteed)), the(xname(otmp)));
 		    else
 #endif
 		    You("push %s and suddenly it disappears!",
@@ -221,10 +222,9 @@
 		long lastmovetime;
 		lastmovetime = 0;
 #else
+		/* note: reset to zero after save/restore cycle */
 		static NEARDATA long lastmovetime;
 #endif
-		/* note: this var contains garbage initially and
-		   after a restore */
 #ifdef STEED
 		if (!u.usteed) {
 #endif
@@ -235,7 +235,8 @@
 		  exercise(A_STR, TRUE);
 #ifdef STEED
 		} else 
-		    pline("%s moves %s.", Monnam(u.usteed), the(xname(otmp)));
+		    pline("%s moves %s.",
+			  upstart(y_monnam(u.usteed)), the(xname(otmp)));
 #endif
 		lastmovetime = moves;
 	    }
@@ -255,7 +256,7 @@
 #ifdef STEED
 	  if (u.usteed)
 	    pline("%s tries to move %s, but cannot.",
-		  	Monnam(u.usteed), the(xname(otmp)));
+		  upstart(y_monnam(u.usteed)), the(xname(otmp)));
 	  else
 #endif
 	    You("try to move %s, but in vain.", the(xname(otmp)));
@@ -267,7 +268,7 @@
 		    You("aren't skilled enough to %s %s from %s.",
 			(flags.pickup && !In_sokoban(&u.uz))
 			    ? "pick up" : "push aside",
-			the(xname(otmp)), mon_nam(u.usteed));
+			the(xname(otmp)), y_monnam(u.usteed));
 		} else
 #endif
 		{
@@ -381,12 +382,15 @@
 	digtxt = "chew a hole in the wall.";
 	if (level.flags.is_maze_lev) {
 	    lev->typ = ROOM;
-	} else if (level.flags.is_cavernous_lev) {
+	} else if (level.flags.is_cavernous_lev && !in_town(x, y)) {
 	    lev->typ = CORR;
 	} else {
 	    lev->typ = DOOR;
 	    lev->doormask = D_NODOOR;
 	}
+    } else if (IS_TREE(lev->typ)) {
+	digtxt = "chew through the tree.";
+	lev->typ = ROOM;
     } else if (lev->typ == SDOOR) {
 	if (lev->doormask & D_TRAPPED) {
 	    lev->doormask = D_NODOOR;
@@ -418,7 +422,7 @@
     unblock_point(x, y);	/* vision */
     newsym(x, y);
     if (digtxt) You(digtxt);	/* after newsym */
-    if (dmgtxt) pay_for_damage(dmgtxt);
+    if (dmgtxt) pay_for_damage(dmgtxt, FALSE);
     (void) memset((genericptr_t)&digging, 0, sizeof digging);
     return 0;
 }
@@ -449,6 +453,13 @@
 	if (is_floater(youmonst.data) || (HLevitation & FROMOUTSIDE)) {
 	    You("wobble unsteadily for a moment.");
 	} else {
+	    long save_ELev = ELevitation, save_HLev = HLevitation;
+
+	    /* fake removal of levitation in advance so that final
+	       disclosure will be right in case this turns out to
+	       be fatal; fortunately the fact that rings and boots
+	       are really still worn has no effect on bones data */
+	    ELevitation = HLevitation = 0L;
 	    You("crash to the floor!");
 	    losehp(rn1(8, 25 - (int)ACURR(A_CON)),
 		   fell_on_sink, NO_KILLER_PREFIX);
@@ -460,6 +471,8 @@
 		    losehp(rnd(3), fell_on_sink, NO_KILLER_PREFIX);
 		    exercise(A_CON, FALSE);
 		}
+	    ELevitation = save_ELev;
+	    HLevitation = save_HLev;
 	}
 
 	ELevitation &= ~W_ARTI;
@@ -525,11 +538,13 @@
 #endif /* OVL1 */
 #ifdef OVL3
 
-/* return TRUE if (dx,dy) is an OK place to move */
+/* return TRUE if (dx,dy) is an OK place to move
+ * mode is one of DO_MOVE, TEST_MOVE or TEST_TRAV
+ */
 boolean 
-test_move(ux, uy, dx, dy, test_only)
+test_move(ux, uy, dx, dy, mode)
 int ux, uy, dx, dy;
-boolean test_only;
+int mode;
 {
     int x = ux+dx;
     int y = uy+dy;
@@ -540,93 +555,101 @@
      *  Check for physical obstacles.  First, the place we are going.
      */
     if (IS_ROCK(tmpr->typ) || tmpr->typ == IRONBARS) {
-	if (Blind && !test_only) feel_location(x,y);
+	if (Blind && mode == DO_MOVE) feel_location(x,y);
 	if (Passes_walls && may_passwall(x,y)) {
 	    ;	/* do nothing */
+	} else if (tmpr->typ == IRONBARS) {
+	    if (!(Passes_walls || passes_bars(youmonst.data)))
+		return FALSE;
 	} else if (tunnels(youmonst.data) && !needspick(youmonst.data)) {
 	    /* Eat the rock. */
-	    if (!test_only && still_chewing(x,y)) return FALSE;
+	    if (mode == DO_MOVE && still_chewing(x,y)) return FALSE;
 	} else if (flags.autodig && !flags.run && !flags.nopick &&
 		   uwep && is_pick(uwep)) {
 	/* MRKR: Automatic digging when wielding the appropriate tool */
-	    if (!test_only)
+	    if (mode == DO_MOVE)
 		(void) use_pick_axe2(uwep);
 	    return FALSE;
 	} else {
-	    if ( !test_only ) {
+	    if (mode == DO_MOVE) {
 		if (Is_stronghold(&u.uz) && is_db_wall(x,y))
 		    pline_The("drawbridge is up!");
 		if (Passes_walls && !may_passwall(x,y) && In_sokoban(&u.uz))
-	    		pline_The("Sokoban walls resist your ability.");
+		    pline_The("Sokoban walls resist your ability.");
 	    }
 	    return FALSE;
 	}
     } else if (IS_DOOR(tmpr->typ)) {
 	if (closed_door(x,y)) {
-	    if (Blind && !test_only) feel_location(x,y);
+	    if (Blind && mode == DO_MOVE) feel_location(x,y);
 	    if (Passes_walls)
 		;	/* do nothing */
 	    else if (can_ooze(&youmonst)) {
-		if ( !test_only ) You("ooze under the door.");
+		if (mode == DO_MOVE) You("ooze under the door.");
 	    } else if (tunnels(youmonst.data) && !needspick(youmonst.data)) {
 		/* Eat the door. */
-		if (!test_only && still_chewing(x,y)) return FALSE;
+		if (mode == DO_MOVE && still_chewing(x,y)) return FALSE;
 	    } else {
-		if ( !test_only ) {
+		if (mode == DO_MOVE) {
 		    if (amorphous(youmonst.data))
 			You("try to ooze under the door, but can't squeeze your possessions through.");
 		    else if (x == ux || y == uy) {
 			if (Blind || Stunned || ACURR(A_DEX) < 10 || Fumbling) {
 #ifdef STEED
-			    if (u.usteed)
+			    if (u.usteed) {
 				You_cant("lead %s through that closed door.",
-				      x_monnam(u.usteed,
-					 u.usteed->mnamelth ? ARTICLE_NONE : ARTICLE_THE,
-				 	 (char *)0, SUPPRESS_SADDLE, FALSE));
-		 	    else {
-#else
+				         y_monnam(u.usteed));
+			    } else
+#endif
+			    {
 			        pline("Ouch!  You bump into a door.");
 			        exercise(A_DEX, FALSE);
-#endif
-#ifdef STEED
 			    }
-#endif
 			} else pline("That door is closed.");
 		    }
-		}
+		} else if (mode == TEST_TRAV) goto testdiag;
 		return FALSE;
 	    }
-	} else if (dx && dy && !Passes_walls
-		    && ((tmpr->doormask & ~D_BROKEN)
+	} else {
+	testdiag:
+	    if (dx && dy && !Passes_walls
+		&& ((tmpr->doormask & ~D_BROKEN)
 #ifdef REINCARNATION
-				    || Is_rogue_level(&u.uz)
+		    || Is_rogue_level(&u.uz)
 #endif
-				    || block_door(x,y))) {
-	    /* Diagonal moves into a door are not allowed. */
-	    if ( Blind && !test_only )
-		feel_location(x,y);
-	    return FALSE;
+		    || block_door(x,y))) {
+		/* Diagonal moves into a door are not allowed. */
+		if (Blind && mode == DO_MOVE)
+		    feel_location(x,y);
+		return FALSE;
+	    }
 	}
     }
     if (dx && dy
 	    && bad_rock(youmonst.data,ux,y) && bad_rock(youmonst.data,x,uy)) {
 	/* Move at a diagonal. */
 	if (In_sokoban(&u.uz)) {
-	    if ( !test_only )
+	    if (mode == DO_MOVE)
 		You("cannot pass that way.");
 	    return FALSE;
 	}
 	if (bigmonst(youmonst.data)) {
-	    if ( !test_only )
+	    if (mode == DO_MOVE)
 		Your("body is too large to fit through.");
 	    return FALSE;
 	}
 	if (invent && (inv_weight() + weight_cap() > 600)) {
-	    if ( !test_only )
+	    if (mode == DO_MOVE)
 		You("are carrying too much to get through.");
 	    return FALSE;
 	}
     }
+    /* pick a path that does not require crossing a trap */
+    if (flags.run == 8 && mode != DO_MOVE) {
+	struct trap* t = t_at(x, y);
+
+	if (t && t->tseen) return FALSE;
+    }
 
     ust = &levl[ux][uy];
 
@@ -643,80 +666,164 @@
     }
 
     if (sobj_at(BOULDER,x,y) && (In_sokoban(&u.uz) || !Passes_walls)) {
-	if (!(Blind || Hallucination) && (flags.run >= 2))
+	if (!(Blind || Hallucination) && (flags.run >= 2) && mode != TEST_TRAV)
 	    return FALSE;
-	if (!test_only) {
+	if (mode == DO_MOVE) {
 	    /* tunneling monsters will chew before pushing */
 	    if (tunnels(youmonst.data) && !needspick(youmonst.data) &&
 		!In_sokoban(&u.uz)) {
 		if (still_chewing(x,y)) return FALSE;
 	    } else
 		if (moverock() < 0) return FALSE;
+	} else if (mode == TEST_TRAV) {
+	    struct obj* obj;
+
+	    /* don't pick two boulders in a row, unless there's a way thru */
+	    if (sobj_at(BOULDER,ux,uy) && !In_sokoban(&u.uz)) {
+		if (!Passes_walls &&
+		    !(tunnels(youmonst.data) && !needspick(youmonst.data)) &&
+		    !carrying(PICK_AXE) && !carrying(DWARVISH_MATTOCK) &&
+		    !((obj = carrying(WAN_DIGGING)) &&
+		      !objects[obj->otyp].oc_name_known))
+		    return FALSE;
+	    }
 	}
-	/* test_only will assume you'll be able to push it when you get there... */
+	/* assume you'll be able to push it when you get there... */
     }
 
     /* OK, it is a legal place to move. */
     return TRUE;
 }
 
-static void findtravelpath()
+/*
+ * Find a path from the destination (u.tx,u.ty) back to (u.ux,u.uy).
+ * A shortest path is returned.  If guess is TRUE, consider various
+ * inaccessible locations as valid intermediate path points.
+ * Returns TRUE if a path was found.
+ */
+static boolean
+findtravelpath(guess)
+boolean guess;
 {
-    if ( u.tx != u.ux || u.ty != u.uy ) {
+    if (u.tx != u.ux || u.ty != u.uy) {
 	xchar travel[COLNO][ROWNO];
 	xchar travelstepx[2][COLNO*ROWNO];
 	xchar travelstepy[2][COLNO*ROWNO];
-	int n=1;
-	int set=0;
-	int dia=1;
+	xchar tx, ty, ux, uy;
+	int n = 1;			/* max offset in travelsteps */
+	int set = 0;			/* two sets current and previous */
+	int radius = 1;			/* search radius */
+	int i;
 
-	(void) memset((genericptr_t)travel,0,sizeof(travel));
+	/* If guessing, first find an "obvious" goal location.  The obvious
+	 * goal is the position the player knows of, or might figure out
+	 * (couldsee) that is closest to the target on a straight path.
+	 */
+	if (guess) {
+	    tx = u.ux; ty = u.uy; ux = u.tx; uy = u.ty;
+	} else {
+	    tx = u.tx; ty = u.ty; ux = u.ux; uy = u.uy;
+	}
 
-	travelstepx[0][0] = u.tx;
-	travelstepy[0][0] = u.ty;
-	while ( n ) {
-	    int i;
-	    int nn=0;
-	    for (i=0; i<n; i++) {
+    noguess:
+	(void) memset((genericptr_t)travel, 0, sizeof(travel));
+	travelstepx[0][0] = tx;
+	travelstepy[0][0] = ty;
+
+	while (n != 0) {
+	    int nn = 0;
+
+	    for (i = 0; i < n; i++) {
 		int dir;
 		int x = travelstepx[set][i];
 		int y = travelstepy[set][i];
 		static int ordered[] = { 0, 2, 4, 6, 1, 3, 5, 7 };
-		for (dir=0; dir<8; dir++) {
+
+		for (dir = 0; dir < 8; dir++) {
 		    int nx = x+xdir[ordered[dir]];
 		    int ny = y+ydir[ordered[dir]];
-    /*printf("try %d,%d\n",nx,ny);*/
-		    if ( isok(nx,ny) && test_move( x, y, nx-x, ny-y, 1 ) ) {
-			if ( nx == u.ux && ny == u.uy ) {
-			    u.dx = x-u.ux;
-			    u.dy = y-u.uy;
-	/*printf("found\n");*/
-	/*printf("findtravelpath %d,%d -> %d,%d by %d,%d\n",u.ux,u.uy,u.tx,u.ty,u.dx,u.dy);
-	*/
-			    return;
-			} else {
-	/*printf("%d %d %d",isok(nx,ny), !travel[nx][ny], ACCESSIBLE(levl[nx][ny].typ));*/
-			    if ( !travel[nx][ny] ) {
-				travelstepx[1-set][nn]=nx;
-				travelstepy[1-set][nn]=ny;
-				travel[nx][ny]=dia;
-				nn++;
+
+		    if (!isok(nx, ny)) continue;
+		    if ((!Passes_walls && !can_ooze(&youmonst) &&
+			closed_door(x, y)) || sobj_at(BOULDER, x, y)) {
+			/* closed doors and boulders usually
+			 * cause a delay, so prefer another path */
+			if (travel[x][y] > radius-3) {
+			    travelstepx[1-set][nn] = x;
+			    travelstepy[1-set][nn] = y;
+			    /* don't change travel matrix! */
+			    nn++;
+			    continue;
+			}
+		    }
+		    if (test_move(x, y, nx-x, ny-y, TEST_TRAV) &&
+			(levl[nx][ny].seenv || (!Blind && couldsee(nx, ny)))) {
+			if (nx == ux && ny == uy) {
+			    if (!guess) {
+				u.dx = x-ux;
+				u.dy = y-uy;
+				if (x == u.tx && y == u.ty) {
+				    nomul(0);
+				    /* reset run so domove run checks work */
+				    flags.run = 8;
+				}
+				return TRUE;
 			    }
+			} else if (!travel[nx][ny]) {
+			    travelstepx[1-set][nn] = nx;
+			    travelstepy[1-set][nn] = ny;
+			    travel[nx][ny] = radius;
+			    nn++;
 			}
 		    }
 		}
 	    }
+	    
 	    n = nn;
 	    set = 1-set;
-	    dia++;
+	    radius++;
 	}
 
-	/* give up */
+	/* if guessing, find best location in travel matrix and go there */
+	if (guess) {
+	    int px = tx, py = ty;	/* pick location */
+	    int dist, nxtdist;
+
+	    dist = distmin(ux, uy, tx, ty);
+	    for (tx = 1; tx < COLNO; ++tx)
+		for (ty = 0; ty < ROWNO; ++ty)
+		    if (travel[tx][ty]) {
+			nxtdist = distmin(ux, uy, tx, ty);
+			if (nxtdist < dist && couldsee(tx, ty)) {
+			    px = tx; py = ty; dist = nxtdist;
+			}
+		    }
+
+	    if (px == u.ux && py == u.uy) {
+		/* no guesses, just go in the general direction */
+		u.dx = sgn(u.tx - u.ux);
+		u.dy = sgn(u.ty - u.uy);
+		if (test_move(u.ux, u.uy, u.dx, u.dy, TEST_MOVE))
+		    return TRUE;
+		goto found;
+	    }
+	    tx = px;
+	    ty = py;
+	    ux = u.ux;
+	    uy = u.uy;
+	    set = 0;
+	    n = radius = 1;
+	    guess = FALSE;
+	    goto noguess;
+	}
+	return FALSE;
     }
 
+found:
     u.dx = 0;
     u.dy = 0;
     nomul(0);
+    return FALSE;
 }
 
 void
@@ -731,11 +838,13 @@
 	xchar chainx, chainy, ballx, bally;	/* ball&chain new positions */
 	int bc_control;				/* control for ball&chain */
 	boolean cause_delay = FALSE;	/* dragging ball will skip a move */
+	const char *predicament;
 
 	u_wipe_engr(rnd(5));
 
-	if ( flags.travel )
-	    findtravelpath();
+	if (flags.travel)
+	    if (!findtravelpath(FALSE))
+		(void) findtravelpath(TRUE);
 
 	if(((wtcap = near_capacity()) >= OVERLOADED
 	    || (wtcap > SLT_ENCUMBER &&
@@ -821,7 +930,10 @@
 			nomul(0);
 			return;
 		}
-		if((trap = t_at(x, y)) && trap->tseen) {
+		if (((trap = t_at(x, y)) && trap->tseen) ||
+		    (Blind && !Levitation && !Flying &&
+		     !is_clinger(youmonst.data) &&
+		     (is_pool(x, y) || is_lava(x, y)) && levl[x][y].seenv)) {
 			if(flags.run >= 2) {
 				nomul(0);
 				flags.move = 0;
@@ -952,13 +1064,20 @@
 	if (flags.forcefight ||
 	    /* remembered an 'I' && didn't use a move command */
 	    (glyph_is_invisible(levl[x][y].glyph) && !flags.nopick)) {
+		boolean expl = (Upolyd && attacktype(youmonst.data, AT_EXPL));
 	    	char buf[BUFSZ];
 		Sprintf(buf,"a vacant spot on the %s", surface(x,y));
-		You("attack %s.",
-		    !Underwater ? "thin air" : is_pool(x,y) ? "empty water" : buf);
+		You("%s %s.",
+		    expl ? "explode at" : "attack",
+		    !Underwater ? "thin air" :
+		    is_pool(x,y) ? "empty water" : buf);
 		unmap_object(x, y); /* known empty -- remove 'I' if present */
 		newsym(x, y);
 		nomul(0);
+		if (expl) {
+		    u.mh = -1;		/* dead in the current form */
+		    rehumanize();
+		}
 		return;
 	}
 	if (glyph_is_invisible(levl[x][y].glyph)) {
@@ -968,10 +1087,7 @@
 	/* not attacking an animal, so we try to move */
 #ifdef STEED
 	if (u.usteed && !u.usteed->mcanmove && (u.dx || u.dy)) {
-		pline("%s won't move!",
-			upstart(x_monnam(u.usteed,
-					 u.usteed->mnamelth ? ARTICLE_NONE : ARTICLE_THE,
-				 	 (char *)0, SUPPRESS_SADDLE, FALSE)));
+		pline("%s won't move!", upstart(y_monnam(u.usteed)));
 		nomul(0);
 		return;
 	} else
@@ -1003,10 +1119,8 @@
 		    } else if (flags.verbose) {
 #ifdef STEED
 			if (u.usteed)
-			    	Norep("%s is still in a pit.",
-				      upstart(x_monnam(u.usteed,
-					 u.usteed->mnamelth ? ARTICLE_NONE : ARTICLE_THE,
-				 	 (char *)0, SUPPRESS_SADDLE, FALSE)));
+			    Norep("%s is still in a pit.",
+				  upstart(y_monnam(u.usteed)));
 			else
 #endif
 			Norep( (Hallucination && !rn2(5)) ?
@@ -1015,14 +1129,11 @@
 		    }
 		} else if (u.utraptype == TT_LAVA) {
 		    if(flags.verbose) {
-			char *predicament = "stuck in the lava";
+			predicament = "stuck in the lava";
 #ifdef STEED
 			if (u.usteed)
-			    	Norep("%s is %s.",
-				      upstart(x_monnam(u.usteed,
-					 u.usteed->mnamelth ? ARTICLE_NONE : ARTICLE_THE,
-				 	 (char *)0, SUPPRESS_SADDLE, FALSE)),
-					 predicament);
+			    Norep("%s is %s.", upstart(y_monnam(u.usteed)),
+				  predicament);
 			else
 #endif
 			Norep("You are %s.", predicament);
@@ -1033,9 +1144,7 @@
 #ifdef STEED
 			    if (u.usteed)
 				You("lead %s to the edge of the lava.",
-				      x_monnam(u.usteed,
-					 u.usteed->mnamelth ? ARTICLE_NONE : ARTICLE_THE,
-				 	 (char *)0, SUPPRESS_SADDLE, FALSE));
+				    y_monnam(u.usteed));
 			    else
 #endif
 			     You("pull yourself to the edge of the lava.");
@@ -1051,14 +1160,11 @@
 		    }
 		    if(--u.utrap) {
 			if(flags.verbose) {
-			    char *predicament = "stuck to the web";
+			    predicament = "stuck to the web";
 #ifdef STEED
 			    if (u.usteed)
-			    	Norep("%s is %s.",
-				      upstart(x_monnam(u.usteed,
-					 u.usteed->mnamelth ? ARTICLE_NONE : ARTICLE_THE,
-				 	 (char *)0, SUPPRESS_SADDLE, FALSE)),
-					 predicament);
+				Norep("%s is %s.", upstart(y_monnam(u.usteed)),
+				      predicament);
 			    else
 #endif
 			    Norep("You are %s.", predicament);
@@ -1066,10 +1172,8 @@
 		    } else {
 #ifdef STEED
 			if (u.usteed)
-				pline("%s breaks out of the web.",
-				      upstart(x_monnam(u.usteed,
-					 u.usteed->mnamelth ? ARTICLE_NONE : ARTICLE_THE,
-				 	 (char *)0, SUPPRESS_SADDLE, FALSE)));
+			    pline("%s breaks out of the web.",
+				  upstart(y_monnam(u.usteed)));
 			else
 #endif
 			You("disentangle yourself.");
@@ -1077,39 +1181,33 @@
 		} else if (u.utraptype == TT_INFLOOR) {
 		    if(--u.utrap) {
 			if(flags.verbose) {
-			    char *predicament = "stuck in the";
+			    predicament = "stuck in the";
 #ifdef STEED
 			    if (u.usteed)
-			    	Norep("%s is %s %s.",
-				      upstart(x_monnam(u.usteed,
-					 u.usteed->mnamelth ? ARTICLE_NONE : ARTICLE_THE,
-				 	 (char *)0, SUPPRESS_SADDLE, FALSE)),
-					 predicament, surface(u.ux, u.uy));
+				Norep("%s is %s %s.",
+				      upstart(y_monnam(u.usteed)),
+				      predicament, surface(u.ux, u.uy));
 			    else
 #endif
-			    Norep("You are %s %s.", predicament, surface(u.ux, u.uy));
+			    Norep("You are %s %s.", predicament,
+				  surface(u.ux, u.uy));
 			}
 		    } else {
 #ifdef STEED
 			if (u.usteed)
-				pline("%s finally wiggles free.",
-				      upstart(x_monnam(u.usteed,
-					 u.usteed->mnamelth ? ARTICLE_NONE : ARTICLE_THE,
-				 	 (char *)0, SUPPRESS_SADDLE, FALSE)));
+			    pline("%s finally wiggles free.",
+				  upstart(y_monnam(u.usteed)));
 			else
 #endif
 			You("finally wiggle free.");
 		    }
 		} else {
 		    if(flags.verbose) {
-			char *predicament = "caught in a bear trap";
+			predicament = "caught in a bear trap";
 #ifdef STEED
 			if (u.usteed)
-			    	Norep("%s is %s.",
-				      upstart(x_monnam(u.usteed,
-					 u.usteed->mnamelth ? ARTICLE_NONE : ARTICLE_THE,
-				 	 (char *)0, SUPPRESS_SADDLE, FALSE)),
-					 predicament);
+			    Norep("%s is %s.", upstart(y_monnam(u.usteed)),
+				  predicament);
 			else
 #endif
 			Norep("You are %s.", predicament);
@@ -1119,7 +1217,7 @@
 		return;
 	}
 
-	if ( !test_move( u.ux, u.uy, x-u.ux, y-u.uy, 0 ) ) {
+	if (!test_move(u.ux, u.uy, x-u.ux, y-u.uy, DO_MOVE)) {
 	    flags.move = 0;
 	    nomul(0);
 	    return;
@@ -1128,7 +1226,7 @@
 	/* Move ball and chain.  */
 	if (Punished)
 	    if (!drag_ball(x,y, &bc_control, &ballx, &bally, &chainx, &chainy,
-			&cause_delay))
+			&cause_delay, TRUE))
 		return;
 
 	/* Check regions entering/leaving */
@@ -1182,6 +1280,13 @@
 		    sobj_at(BOULDER, trap->tx, trap->ty)) {
 		/* can't swap places with pet pinned in a pit by a boulder */
 		u.ux = u.ux0,  u.uy = u.uy0;	/* didn't move after all */
+	    } else if (u.ux0 != x && u.uy0 != y &&
+		       bad_rock(mtmp->data, x, u.uy0) &&
+		       bad_rock(mtmp->data, u.ux0, y) &&
+		       (bigmonst(mtmp->data) || (curr_mon_load(mtmp) > 600))) {
+		/* can't swap places when pet won't fit thru the opening */
+		u.ux = u.ux0,  u.uy = u.uy0;	/* didn't move after all */
+		You("stop.  %s won't fit through.", upstart(y_monnam(mtmp)));
 	    } else {
 		char pnambuf[BUFSZ];
 
@@ -1271,6 +1376,21 @@
 	    nomul(-2);
 	    nomovemsg = "";
 	}
+
+	if (flags.run && iflags.runmode != RUN_TPORT) {
+	    /* display every step or every 7th step depending upon mode */
+	    if (iflags.runmode != RUN_LEAP || !(moves % 7L)) {
+		if (flags.time) flags.botl = 1;
+		curs_on_u();
+		delay_output();
+		if (iflags.runmode == RUN_CRAWL) {
+		    delay_output();
+		    delay_output();
+		    delay_output();
+		    delay_output();
+		}
+	    }
+	}
 }
 
 void
@@ -1278,10 +1398,18 @@
 {
 	/* a special clue-msg when on the Invocation position */
 	if(invocation_pos(u.ux, u.uy) && !On_stairs(u.ux, u.uy)) {
+	    char buf[BUFSZ];
 	    struct obj *otmp = carrying(CANDELABRUM_OF_INVOCATION);
 
-	    You_feel("a strange vibration under your %s.",
-		    makeplural(body_part(FOOT)));
+	    nomul(0);		/* stop running or travelling */
+#ifdef STEED
+	    if (u.usteed) Sprintf(buf, "beneath %s", y_monnam(u.usteed));
+	    else
+#endif
+	    if (Levitation || Flying) Strcpy(buf, "beneath you");
+	    else Sprintf(buf, "under your %s", makeplural(body_part(FOOT)));
+
+	    You_feel("a strange vibration %s.", buf);
 	    if (otmp && otmp->spe == 7 && otmp->lamplit)
 		pline("%s %s!", The(xname(otmp)),
 		    Blind ? "throbs palpably" : "glows with a strange light");
@@ -1366,7 +1494,7 @@
 			      Amonnam(mtmp), ceiling(u.ux,u.uy));
 			if(mtmp->mtame) /* jumps to greet you, not attack */
 			    ;
-			else if(uarmh)
+			else if(uarmh && is_metallic(uarmh))
 			    pline("Its blow glances off your helmet.");
 			else if (u.uac + 3 <= rnd(20))
 			    You("are almost hit by %s!",
@@ -1480,6 +1608,31 @@
 	return(ptr);
 }
 
+/* is (x,y) in a town? */
+boolean
+in_town(x, y)
+register int x, y;
+{
+	s_level *slev = Is_special(&u.uz);
+	register struct mkroom *sroom;
+	boolean has_subrooms = FALSE;
+
+	if (!slev || !slev->flags.town) return FALSE;
+
+	/*
+	 * See if (x,y) is in a room with subrooms, if so, assume it's the
+	 * town.  If there are no subrooms, the whole level is in town.
+	 */
+	for (sroom = &rooms[0]; sroom->hx > 0; sroom++) {
+	    if (sroom->nsubrooms > 0) {
+		has_subrooms = TRUE;
+		if (inside_room(sroom, x, y)) return TRUE;
+	    }
+	}
+
+	return !has_subrooms;
+}
+
 STATIC_OVL void
 move_update(newlev)
 register boolean newlev;
@@ -1690,8 +1843,8 @@
 	if (!can_reach_floor()) {
 #ifdef STEED
 		if (u.usteed && P_SKILL(P_RIDING) < P_BASIC)
-			You("aren't skilled enough to reach from %s.",
-					mon_nam(u.usteed));
+		    You("aren't skilled enough to reach from %s.",
+			y_monnam(u.usteed));
 		else
 #endif
 		You("cannot reach the %s.", surface(u.ux,u.uy));
@@ -1865,7 +2018,8 @@
 }
 
 /* called when a non-movement, multi-turn action has completed */
-void unmul(msg_override)
+void
+unmul(msg_override)
 const char *msg_override;
 {
 	multi = 0;	/* caller will usually have done this already */
@@ -1992,14 +2146,14 @@
 	   of invent for easier manipulation by askchain & co, but it's also
 	   retained in u.ugold in order to keep the status line accurate; we
 	   mustn't add its weight in twice under that circumstance */
-	wt = (otmp && otmp->oclass == GOLD_CLASS) ? 0 :
+	wt = (otmp && otmp->oclass == COIN_CLASS) ? 0 :
 		(int)((u.ugold + 50L) / 100L);
 #endif
 	while (otmp) {
 #ifndef GOLDOBJ
 		if (otmp->otyp != BOULDER || !throws_rocks(youmonst.data))
 #else
-		if (otmp->oclass == GOLD_CLASS)
+		if (otmp->oclass == COIN_CLASS)
 			wt += (int)(((long)otmp->quan + 50L) / 100L);
 		else if (otmp->otyp != BOULDER || !throws_rocks(youmonst.data))
 #endif
@@ -2075,12 +2229,13 @@
 /* Intended use is for your or some monsters inventory, */
 /* now that u.gold/m.gold is gone.*/
 /* Counting money in a container might be possible too. */
-long money_cnt(otmp)
+long
+money_cnt(otmp)
 struct obj *otmp;
 {
         while(otmp) {
 	        /* Must change when silver & copper is implemented: */
- 	        if (otmp->oclass == GOLD_CLASS) return otmp->quan;
+ 	        if (otmp->oclass == COIN_CLASS) return otmp->quan;
   	        otmp = otmp->nobj;
 	}
 	return 0;
diff -Naurd ../nethack-3.4.0/src/hacklib.c ./src/hacklib.c
--- ../nethack-3.4.0/src/hacklib.c Wed Mar 20 23:43:06 2002
+++ ./src/hacklib.c Mon Feb 24 15:25:05 2003
@@ -18,6 +18,7 @@
 	char *		upstart		(char *)
 	char *		mungspaces	(char *)
 	char *		eos		(char *)
+	char *		strkitten	(char *,char)
 	char *		s_suffix	(const char *)
 	char *		xcrypt		(const char *, char *)
 	boolean		onlyspace	(const char *)
@@ -130,6 +131,19 @@
     return s;
 }
 
+/* strcat(s, {c,'\0'}); */
+char *
+strkitten(s, c)		/* append a character to a string (in place) */
+    char *s;
+    char c;
+{
+    char *p = eos(s);
+
+    *p++ = c;
+    *p = '\0';
+    return s;
+}
+
 char *
 s_suffix(s)		/* return a name converted to possessive */
     const char *s;
diff -Naurd ../nethack-3.4.0/src/invent.c ./src/invent.c
--- ../nethack-3.4.0/src/invent.c Wed Mar 20 23:43:07 2002
+++ ./src/invent.c Mon Feb 24 15:25:05 2003
@@ -1,9 +1,8 @@
-/*	SCCS Id: @(#)invent.c	3.4	2002/02/23	*/
+/*	SCCS Id: @(#)invent.c	3.4	2003/01/24	*/
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /* NetHack may be freely redistributed.  See license for details. */
 
 #include "hack.h"
-#include "artifact.h"
 
 #define NOINVSYM	'#'
 #define CONTAINED_SYM	'>'	/* designator for inside a container */
@@ -55,7 +54,7 @@
 
 #ifdef GOLDOBJ
         /* There is only one of these in inventory... */        
-        if (otmp->oclass == GOLD_CLASS) {
+        if (otmp->oclass == COIN_CLASS) {
 	    otmp->invlet = GOLD_SYM;
 	    return;
 	}
@@ -179,7 +178,7 @@
 #ifdef GOLDOBJ
                 /* temporary special case for gold objects!!!! */
 #endif
-		if (otmp->oclass == GOLD_CLASS) otmp->owt = weight(otmp);
+		if (otmp->oclass == COIN_CLASS) otmp->owt = weight(otmp);
 		else otmp->owt += obj->owt;
 		if(!otmp->onamelth && obj->onamelth)
 			otmp = *potmp = oname(otmp, ONAME(obj));
@@ -245,7 +244,7 @@
 addinv_core1(obj)
 struct obj *obj;
 {
-	if (obj->oclass == GOLD_CLASS) {
+	if (obj->oclass == COIN_CLASS) {
 #ifndef GOLDOBJ
 		u.ugold += obj->quan;
 #else
@@ -287,8 +286,7 @@
 addinv_core2(obj)
 struct obj *obj;
 {
-	if (obj->otyp == LUCKSTONE ||
-	    (obj->oartifact && spec_ability(obj, SPFX_LUCK))) {
+	if (confers_luck(obj)) {
 		/* new luckstone must be in inventory by this point
 		 * for correct calculation */
 		set_moreluck();
@@ -312,7 +310,7 @@
 	addinv_core1(obj);
 #ifndef GOLDOBJ
 	/* if handed gold, we're done */
-	if (obj->oclass == GOLD_CLASS)
+	if (obj->oclass == COIN_CLASS)
 	    return obj;
 #endif
 
@@ -365,10 +363,12 @@
 #endif /* OVL1 */
 #ifdef OVLB
 
-/* Add an item to the inventory unless we're fumbling, and give a message.
+/* Add an item to the inventory unless we're fumbling or it refuses to be
+ * held (via touch_artifact), and give a message.
  * If there aren't any free inventory slots, we'll drop it instead.
  * If both success and failure messages are NULL, then we're just doing the
- * fumbling/slot-limit checking for a silent grab.
+ * fumbling/slot-limit checking for a silent grab.  In any case,
+ * touch_artifact will print its own messages if they are warranted.
  */
 struct obj *
 hold_another_object(obj, drop_fmt, drop_arg, hold_msg)
@@ -378,39 +378,62 @@
 	char buf[BUFSZ];
 
 	if (!Blind) obj->dknown = 1;	/* maximize mergibility */
-	if (Fumbling) {
+	if (obj->oartifact) {
+	    /* place_object may change these */
+	    boolean crysknife = (obj->otyp == CRYSKNIFE);
+	    int oerode = obj->oerodeproof;
+	    boolean wasUpolyd = Upolyd;
+
+	    /* in case touching this object turns out to be fatal */
+	    place_object(obj, u.ux, u.uy);
+
+	    if (!touch_artifact(obj, &youmonst)) {
+		obj_extract_self(obj);	/* remove it from the floor */
+		dropy(obj);		/* now put it back again :-) */
+		return obj;
+	    } else if (wasUpolyd && !Upolyd) {
+		/* loose your grip if you revert your form */
 		if (drop_fmt) pline(drop_fmt, drop_arg);
+		obj_extract_self(obj);
 		dropy(obj);
+		return obj;
+	    }
+	    obj_extract_self(obj);
+	    if (crysknife) {
+		obj->otyp = CRYSKNIFE;
+		obj->oerodeproof = oerode;
+	    }
+	}
+	if (Fumbling) {
+	    if (drop_fmt) pline(drop_fmt, drop_arg);
+	    dropy(obj);
 	} else {
-		long oquan = obj->quan;
-		int prev_encumbr = near_capacity();	/* before addinv() */
-		/* encumbrance only matters if it would now become worse
-		   than max( current_value, stressed ) */
-		if (prev_encumbr < MOD_ENCUMBER) prev_encumbr = MOD_ENCUMBER;
-		if (drop_arg) {
-			/* addinv() may redraw the entire inventory, overwriting
-			 * drop_arg when it comes from something like doname()
-			 */
-			Strcpy(buf, drop_arg);
-			drop_arg = buf;
-		}
-		obj = addinv(obj);
-		if (inv_cnt() > 52
+	    long oquan = obj->quan;
+	    int prev_encumbr = near_capacity();	/* before addinv() */
+
+	    /* encumbrance only matters if it would now become worse
+	       than max( current_value, stressed ) */
+	    if (prev_encumbr < MOD_ENCUMBER) prev_encumbr = MOD_ENCUMBER;
+	    /* addinv() may redraw the entire inventory, overwriting
+	       drop_arg when it comes from something like doname() */
+	    if (drop_arg) drop_arg = strcpy(buf, drop_arg);
+
+	    obj = addinv(obj);
+	    if (inv_cnt() > 52
 		    || ((obj->otyp != LOADSTONE || !obj->cursed)
 			&& near_capacity() > prev_encumbr)) {
-			if (drop_fmt) pline(drop_fmt, drop_arg);
-			/* undo any merge which took place */
-			if (obj->quan > oquan) {
-			    obj = splitobj(obj, oquan);
-			}
-			dropx(obj);
-		} else {
-			if (flags.autoquiver && !uquiver &&
-			    (is_missile(obj) ||
-			     (uwep && ammo_and_launcher(obj, uwep))))
-			    setuqwep(obj);
-			if (hold_msg || drop_fmt) prinv(hold_msg, obj, oquan);
-		}
+		if (drop_fmt) pline(drop_fmt, drop_arg);
+		/* undo any merge which took place */
+		if (obj->quan > oquan) obj = splitobj(obj, oquan);
+		dropx(obj);
+	    } else {
+		if (flags.autoquiver && !uquiver && !obj->owornmask &&
+			(is_missile(obj) ||
+			    ammo_and_launcher(obj, uwep) ||
+			    ammo_and_launcher(obj, uswapwep)))
+		    setuqwep(obj);
+		if (hold_msg || drop_fmt) prinv(hold_msg, obj, oquan);
+	    }
 	}
 	return obj;
 }
@@ -455,9 +478,10 @@
 freeinv_core(obj)
 struct obj *obj;
 {
-	if (obj->oclass == GOLD_CLASS) {
+	if (obj->oclass == COIN_CLASS) {
 #ifndef GOLDOBJ
 		u.ugold -= obj->quan;
+		obj->in_use = FALSE;
 #endif
 		flags.botl = 1;
 		return;
@@ -484,8 +508,7 @@
 
 	if (obj->otyp == LOADSTONE) {
 		curse(obj);
-	} else if (obj->otyp == LUCKSTONE ||
-		    (obj->oartifact && spec_ability(obj, SPFX_LUCK))) {
+	} else if (confers_luck(obj)) {
 		set_moreluck();
 		flags.botl = 1;
 	} else if (obj->otyp == FIGURINE && obj->timed) {
@@ -633,7 +656,7 @@
 {
 	register struct obj *obj = level.objects[x][y];
 	while(obj) {
-	    if (obj->oclass == GOLD_CLASS) return obj;
+	    if (obj->oclass == COIN_CLASS) return obj;
 	    obj = obj->nexthere;
 	}
 	return((struct obj *)0);
@@ -733,6 +756,7 @@
 	boolean usegold = FALSE;	/* can't use gold because its illegal */
 	boolean allowall = FALSE;
 	boolean allownone = FALSE;
+	boolean useboulder = FALSE;
 	xchar foox = 0;
 	long cnt;
 	boolean prezero = FALSE;
@@ -740,14 +764,16 @@
 
 	if(*let == ALLOW_COUNT) let++, allowcnt = 1;
 #ifndef GOLDOBJ
-	if(*let == GOLD_CLASS) let++,
+	if(*let == COIN_CLASS) let++,
 		usegold = TRUE, allowgold = (u.ugold ? TRUE : FALSE);
 #else
-	if(*let == GOLD_CLASS) let++, usegold = TRUE;
+	if(*let == COIN_CLASS) let++, usegold = TRUE;
 #endif
 
 	/* Equivalent of an "ugly check" for gold */
-	if (usegold && !strcmp(word, "eat") && !metallivorous(youmonst.data))
+	if (usegold && !strcmp(word, "eat") &&
+	    (!metallivorous(youmonst.data)
+	     || youmonst.data == &mons[PM_RUST_MONSTER]))
 #ifndef GOLDOBJ
 		usegold = allowgold = FALSE;
 #else
@@ -764,9 +790,14 @@
 	 */
 	if(allowall && !strcmp(word, "read")) allowall = FALSE;
 
+	/* another ugly check: show boulders (not statues) */
+	if(*let == WEAPON_CLASS &&
+	   !strcmp(word, "throw") && throws_rocks(youmonst.data))
+	    useboulder = TRUE;
+
 	if(allownone) *bp++ = '-';
 #ifndef GOLDOBJ
-	if(allowgold) *bp++ = def_oc_syms[GOLD_CLASS];
+	if(allowgold) *bp++ = def_oc_syms[COIN_CLASS];
 #endif
 	if(bp > buf && bp[-1] == '-') *bp++ = ' ';
 	ap = altlets;
@@ -782,6 +813,7 @@
 #ifdef GOLDOBJ
 		|| (usegold && otmp->invlet == GOLD_SYM)
 #endif
+		|| (useboulder && otmp->otyp == BOULDER)
 		) {
 		register int otyp = otmp->otyp;
 		bp[foo++] = otmp->invlet;
@@ -797,10 +829,12 @@
 		|| (putting_on(word) &&
 		     (otmp->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL)))
 							/* already worn */
+#if 0	/* 3.4.1 -- include currently wielded weapon among the choices */
 		|| (!strcmp(word, "wield") &&
 		    (otmp->owornmask & W_WEP))
+#endif
 		|| (!strcmp(word, "ready") &&
-		    (otmp->owornmask & (W_WEP | W_SWAPWEP | W_QUIVER)))
+		    (otmp == uwep || (otmp == uswapwep && u.twoweap)))
 		    ) {
 			foo--;
 			foox++;
@@ -829,17 +863,22 @@
 		      otyp != OIL_LAMP && otyp != MAGIC_LAMP &&
 		      otyp != BRASS_LANTERN) ||
 		     (otmp->oclass == GEM_CLASS && !is_graystone(otmp))))
+		|| (!strncmp(word, "rub on the stone", 16) &&
+		    *let == GEM_CLASS &&	/* using known touchstone */
+		    otmp->dknown && objects[otyp].oc_name_known)
 		|| ((!strcmp(word, "use or apply") ||
 			!strcmp(word, "untrap with")) &&
 		     /* Picks, axes, pole-weapons, bullwhips */
 		    ((otmp->oclass == WEAPON_CLASS && !is_pick(otmp) &&
-		      !is_pole(otmp) && otyp != BULLWHIP)
-		|| (otmp->oclass == POTION_CLASS &&
+		      !is_axe(otmp) && !is_pole(otmp) && otyp != BULLWHIP) ||
+		     (otmp->oclass == POTION_CLASS &&
 		     /* only applicable potion is oil, and it will only
 			be offered as a choice when already discovered */
 		     (otyp != POT_OIL || !otmp->dknown ||
-		      !objects[POT_OIL].oc_name_known))
-		|| (otmp->oclass == GEM_CLASS && !is_graystone(otmp))))
+		      !objects[POT_OIL].oc_name_known)) ||
+		     (otmp->oclass == FOOD_CLASS &&
+		      otyp != CREAM_PIE && otyp != EUCALYPTUS_LEAF) ||
+		     (otmp->oclass == GEM_CLASS && !is_graystone(otmp))))
 		|| (!strcmp(word, "invoke") &&
 		    (!otmp->oartifact && !objects[otyp].oc_unique &&
 		     (otyp != FAKE_AMULET_OF_YENDOR || otmp->known) &&
@@ -927,7 +966,7 @@
 		if(ilet == '-') {
 			return(allownone ? &zeroobj : (struct obj *) 0);
 		}
-		if(ilet == def_oc_syms[GOLD_CLASS]) {
+		if(ilet == def_oc_syms[COIN_CLASS]) {
 			if (!usegold) {
 			    You("cannot %s gold.", word);
 			    return(struct obj *)0;
@@ -981,7 +1020,7 @@
 		     * counts for other things since the throw code will
 		     * split off a single item anyway */
 #ifdef GOLDOBJ
-		    if (ilet != def_oc_syms[GOLD_CLASS])
+		    if (ilet != def_oc_syms[COIN_CLASS])
 #endif
 			allowcnt = 1;
 		    if(cnt == 0 && prezero) return((struct obj *)0);
@@ -1016,10 +1055,10 @@
 	}
 	if(!allowall && let && !index(let,otmp->oclass)
 #ifdef GOLDOBJ
-	   && !(usegold && otmp->oclass == GOLD_CLASS)
+	   && !(usegold && otmp->oclass == COIN_CLASS)
 #endif
 	   ) {
-		pline(silly_thing_to, word);
+		silly_thing(word, otmp);
 		return((struct obj *)0);
 	}
 	if(allowcnt == 2) {	/* cnt given */
@@ -1038,6 +1077,39 @@
 	return(otmp);
 }
 
+void
+silly_thing(word, otmp)
+const char *word;
+struct obj *otmp;
+{
+	int otyp = otmp->otyp;
+	boolean domsg = FALSE;
+	const char *s1, *s2, *s3;
+	const char *what = (otmp->quan > 1L) ? "one of those" : "that";
+	if ((!strcmp(word, "wear") || !strcmp(word, "take off")) &&
+		(otmp->oclass == RING_CLASS ||
+		(otmp->oclass == FOOD_CLASS && otmp->otyp == MEAT_RING) ||
+		(otmp->oclass == TOOL_CLASS &&
+		 (otyp == BLINDFOLD || otyp == TOWEL || otyp == LENSES)))) {
+			if (!strcmp(word, "wear")) {
+	    			s1 = "P"; s2 = "put"; s3 = " on"; domsg = TRUE;
+			} else {
+				s1 = "R"; s2 = "remove"; s3 = ""; domsg = TRUE;
+			}
+	} else if ((!strcmp(word, "put on") || !strcmp(word, "remove")) &&
+		(otmp->oclass == ARMOR_CLASS)) {
+			if (!strcmp(word, "remove")) {
+	    			s1 = "T"; s2 = "take"; s3 = " off"; domsg = TRUE;
+			} else {
+	    			s1 = "W"; s2 = "wear"; s3 = ""; domsg = TRUE;
+			}
+	}
+	if (domsg)
+		pline("Use the '%s' command to %s %s%s.", s1, s2, what, s3);
+	else
+		pline(silly_thing_to, word);
+}
+
 #endif /* OVL1 */
 #ifdef OVLB
 
@@ -1093,12 +1165,14 @@
 	int FDECL((*ckfn),(OBJ_P)) = (int FDECL((*),(OBJ_P))) 0;
 	boolean FDECL((*filter),(OBJ_P)) = (boolean FDECL((*),(OBJ_P))) 0;
 	boolean takeoff, ident, allflag, m_seen;
+	int itemcount;
 #ifndef GOLDOBJ
 	int oletct, iletct, allowgold, unpaid, oc_of_sym;
 #else
 	int oletct, iletct, unpaid, oc_of_sym;
 #endif
 	char sym, *ip, olets[MAXOCLASSES+5], ilets[MAXOCLASSES+5];
+	char extra_removeables[3+1];	/* uwep,uswapwep,uquiver */
 	char buf[BUFSZ], qbuf[QBUFSZ];
 
 	if (resultflags) *resultflags = 0;
@@ -1128,7 +1202,7 @@
 #ifndef GOLDOBJ
 					(allowgold != 0),
 #endif
-					filter);
+					filter, &itemcount);
 	unpaid = count_unpaid(invent);
 
 	if (ident && !iletct) {
@@ -1160,20 +1234,31 @@
 		break;
 	}
 
+	extra_removeables[0] = '\0';
+	if (takeoff) {
+	    /* arbitrary types of items can be placed in the weapon slots
+	       [any duplicate entries in extra_removeables[] won't matter] */
+	    if (uwep) (void)strkitten(extra_removeables, uwep->oclass);
+	    if (uswapwep) (void)strkitten(extra_removeables, uswapwep->oclass);
+	    if (uquiver) (void)strkitten(extra_removeables, uquiver->oclass);
+	}
+
 	ip = buf;
 	olets[oletct = 0] = '\0';
 	while ((sym = *ip++) != '\0') {
 	    if (sym == ' ') continue;
 	    oc_of_sym = def_char_to_objclass(sym);
-	    if (takeoff && !(uwep && oc_of_sym == uwep->oclass) &&
-		    (oc_of_sym != MAXOCLASSES)) {
-		if (!index(removeables, oc_of_sym)) {
+	    if (takeoff && oc_of_sym != MAXOCLASSES) {
+		if (index(extra_removeables, oc_of_sym)) {
+		    ;	/* skip rest of takeoff checks */
+		} else if (!index(removeables, oc_of_sym)) {
 		    pline("Not applicable.");
 		    return 0;
 		} else if (oc_of_sym == ARMOR_CLASS && !wearing_armor()) {
 		    You("are not wearing any armor.");
 		    return 0;
-		} else if (oc_of_sym == WEAPON_CLASS && !uwep && !uswapwep && !uquiver) {
+		} else if (oc_of_sym == WEAPON_CLASS &&
+			!uwep && !uswapwep && !uquiver) {
 		    You("are not wielding anything.");
 		    return 0;
 		} else if (oc_of_sym == RING_CLASS && !uright && !uleft) {
@@ -1188,7 +1273,7 @@
 		}
 	    }
 
-	    if (oc_of_sym == GOLD_CLASS && !combo) {
+	    if (oc_of_sym == COIN_CLASS && !combo) {
 #ifndef GOLDOBJ
 		if (allowgold == 1)
 		    (*fn)(mkgoldobj(u.ugold));
@@ -1271,7 +1356,7 @@
 register const char *olets, *word;	/* olets is an Obj Class char array */
 register int FDECL((*fn),(OBJ_P)), FDECL((*ckfn),(OBJ_P));
 {
-	register struct obj *otmp, *otmp2;
+	struct obj *otmp, *otmp2, *otmpo;
 	register char sym, ilet;
 	register int cnt = 0, dud = 0, tmp;
 	boolean takeoff, nodot, ident, ininv;
@@ -1288,7 +1373,7 @@
 	 */
 nextclass:
 	ilet = 'a'-1;
-	if (*objchn && (*objchn)->oclass == GOLD_CLASS)
+	if (*objchn && (*objchn)->oclass == COIN_CLASS)
 		ilet--;		/* extra iteration */
 	for (otmp = *objchn; otmp; otmp = otmp2) {
 		if(ilet == 'z') ilet = 'A'; else ilet++;
@@ -1306,6 +1391,7 @@
 		}
 		else	sym = 'y';
 
+		otmpo = otmp;
 		if (sym == '#') {
 		 /* Number was entered; split the object unless it corresponds
 		    to 'none' or 'all'.  2 special cases: cursed loadstones and
@@ -1328,7 +1414,13 @@
 			allflag = 1;
 		case 'y':
 			tmp = (*fn)(otmp);
-			if(tmp < 0) goto ret;
+			if(tmp < 0) {
+			    if (otmp != otmpo) {
+				/* split occurred, merge again */
+				(void) merged(&otmpo, &otmp);
+			    }
+			    goto ret;
+			}
 			cnt += tmp;
 			if(--mx == 0) goto ret;
 		case 'n':
@@ -1454,7 +1546,7 @@
 register struct obj *obj;
 {
 #ifndef GOLDOBJ
-	if (obj->oclass == GOLD_CLASS)
+	if (obj->oclass == COIN_CLASS)
 		return GOLD_SYM;
 #endif
 	if (!flags.invlet_constant) {
@@ -1516,7 +1608,7 @@
 		(dot && use_invlet ? obj->invlet : let),
 		(txt ? txt : doname(obj)), cost, currency(cost));
 #ifndef GOLDOBJ
-    } else if (obj && obj->oclass == GOLD_CLASS) {
+    } else if (obj && obj->oclass == COIN_CLASS) {
 	Sprintf(li, "%ld gold piece%s%s", obj->quan, plur(obj->quan),
 		(dot ? "." : ""));
 #endif
@@ -1637,6 +1729,7 @@
 		    ret = message_menu(lets[0],
 			  want_reply ? PICK_ONE : PICK_NONE,
 			  xprname(otmp, (char *)0, lets[0], TRUE, 0L, 0L));
+		    if (out_cnt) *out_cnt = -1L;	/* select all */
 		    break;
 		}
 	    }
@@ -1732,22 +1825,23 @@
     int count = 0;
 
     while (list) {
+	if (Role_if(PM_PRIEST)) list->bknown = TRUE;
 	switch(type) {
 	    case BUC_BLESSED:
-		if (list->oclass != GOLD_CLASS && list->bknown && list->blessed)
+		if (list->oclass != COIN_CLASS && list->bknown && list->blessed)
 		    count++;
 		break;
 	    case BUC_CURSED:
-		if (list->oclass != GOLD_CLASS && list->bknown && list->cursed)
+		if (list->oclass != COIN_CLASS && list->bknown && list->cursed)
 		    count++;
 		break;
 	    case BUC_UNCURSED:
-		if (list->oclass != GOLD_CLASS &&
+		if (list->oclass != COIN_CLASS &&
 			list->bknown && !list->blessed && !list->cursed)
 		    count++;
 		break;
 	    case BUC_UNKNOWN:
-		if (list->oclass != GOLD_CLASS && !list->bknown)
+		if (list->oclass != COIN_CLASS && !list->bknown)
 		    count++;
 		break;
 	    default:
@@ -1864,7 +1958,7 @@
 	char c = '\0';
 	int n, i = 0;
 	char *extra_types, types[BUFSZ];
-	int class_count, oclass, unpaid_count;
+	int class_count, oclass, unpaid_count, itemcount;
 	boolean billx = *u.ushops && doinvbill(0);
 	menu_item *pick_list;
 	boolean traditional = TRUE;
@@ -1899,7 +1993,7 @@
 #ifndef GOLDOBJ
 					      (u.ugold != 0),
 #endif
-					      (boolean FDECL((*),(OBJ_P))) 0);
+					      (boolean FDECL((*),(OBJ_P))) 0, &itemcount);
 	    if (unpaid_count) {
 		Strcat(types, "u");
 		class_count++;
@@ -1955,7 +2049,7 @@
 	}
 	if (traditional) {
 	    oclass = def_char_to_objclass(c); /* change to object class */
-	    if (oclass == GOLD_CLASS) {
+	    if (oclass == COIN_CLASS) {
 		return doprgold();
 	    } else if (index(types, c) > index(types, '\033')) {
 		You("have no such objects.");
@@ -2083,9 +2177,14 @@
 
 	if (Blind) {
 		boolean drift = Is_airlevel(&u.uz) || Is_waterlevel(&u.uz);
-		You("try to feel what is %s%s.",
-		    drift ? "floating here" : "lying here on the ",
-		    drift ?	""	    : surface(u.ux, u.uy));
+		if (dfeature && !strncmp(dfeature, "altar ", 6)) {
+		    /* don't say "altar" twice, dfeature has more info */
+		    You("try to feel what is here.");
+		} else {
+		    You("try to feel what is %s%s.",
+			drift ? "floating here" : "lying here on the ",
+			drift ? ""		: surface(u.ux, u.uy));
+		}
 		if (dfeature && !drift && !strcmp(dfeature, surface(u.ux,u.uy)))
 			dfeature = 0;		/* ice already identifed */
 		if (!can_reach_floor()) {
@@ -2186,16 +2285,12 @@
 mergable(otmp, obj)	/* returns TRUE if obj  & otmp can be merged */
 	register struct obj *otmp, *obj;
 {
-#ifndef GOLDOBJ
-	if (obj->otyp != otmp->otyp || obj->unpaid != otmp->unpaid ||
-#else
 	if (obj->otyp != otmp->otyp) return FALSE;
-       
-        /* Coins of the same kind will always merge. */
-        if (obj->oclass == GOLD_CLASS) return TRUE;
-
-        if (obj->unpaid != otmp->unpaid ||
+#ifdef GOLDOBJ
+	/* coins of the same kind will always merge */
+	if (obj->oclass == COIN_CLASS) return TRUE;
 #endif
+	if (obj->unpaid != otmp->unpaid ||
 	    obj->spe != otmp->spe || obj->dknown != otmp->dknown ||
 	    (obj->bknown != otmp->bknown && !Role_if(PM_PRIEST)) ||
 	    obj->cursed != otmp->cursed || obj->blessed != otmp->blessed ||
@@ -2682,7 +2777,7 @@
 		 * gold in their inventory, so it won't merge.
 		 */
 		m_gold = zeroobj;
-		m_gold.otyp = GOLD_PIECE;  m_gold.oclass = GOLD_CLASS;
+		m_gold.otyp = GOLD_PIECE;  m_gold.oclass = COIN_CLASS;
 		m_gold.quan = mon->mgold;  m_gold.dknown = 1;
 		m_gold.where = OBJ_FREE;
 		/* we had better not merge and free this object... */
diff -Naurd ../nethack-3.4.0/src/lock.c ./src/lock.c
--- ../nethack-3.4.0/src/lock.c Wed Mar 20 23:43:07 2002
+++ ./src/lock.c Mon Feb 24 15:25:05 2003
@@ -226,7 +226,8 @@
 pick_lock(pick) /* pick a lock with a given object */
 	register struct	obj	*pick;
 {
-	int x, y, picktyp, c, ch;
+	int picktyp, c, ch;
+	coord cc;
 	struct rm	*door;
 	struct obj	*otmp;
 	char qbuf[QBUFSZ];
@@ -270,12 +271,10 @@
 		impossible("picking lock with object %d?", picktyp);
 		return(0);
 	}
-	if(!getdir((char *)0)) return(0);
-
 	ch = 0;		/* lint suppression */
-	x = u.ux + u.dx;
-	y = u.uy + u.dy;
-	if (x == u.ux && y == u.uy) {	/* pick lock on a container */
+
+	if(!get_adjacent_loc((char *)0, "Invalid location!", u.ux, u.uy, &cc)) return 0;
+	if (cc.x == u.ux && cc.y == u.uy) {	/* pick lock on a container */
 	    const char *verb;
 	    boolean it;
 	    int count;
@@ -295,7 +294,7 @@
 
 	    count = 0;
 	    c = 'n';			/* in case there are no boxes here */
-	    for(otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere)
+	    for(otmp = level.objects[cc.x][cc.y]; otmp; otmp = otmp->nexthere)
 		if (Is_box(otmp)) {
 		    ++count;
 		    if (!can_reach_floor()) {
@@ -354,8 +353,8 @@
 	} else {			/* pick the lock in a door */
 	    struct monst *mtmp;
 
-	    door = &levl[x][y];
-	    if ((mtmp = m_at(x, y)) && canseemon(mtmp)
+	    door = &levl[cc.x][cc.y];
+	    if ((mtmp = m_at(cc.x, cc.y)) && canseemon(mtmp)
 			&& mtmp->m_ap_type != M_AP_FURNITURE
 			&& mtmp->m_ap_type != M_AP_OBJECT) {
 #ifdef TOURIST
@@ -368,7 +367,7 @@
 		return(0);
 	    }
 	    if(!IS_DOOR(door->typ)) {
-		if (is_drawbridge_wall(x,y) >= 0)
+		if (is_drawbridge_wall(cc.x,cc.y) >= 0)
 		    You("%s no lock on the drawbridge.",
 				Blind ? "feel" : "see");
 		else
@@ -490,7 +489,7 @@
 int
 doopen()		/* try to open a door */
 {
-	register int x, y;
+	coord cc;
 	register struct rm *door;
 	struct monst *mtmp;
 
@@ -504,13 +503,11 @@
 	    return 0;
 	}
 
-	if(!getdir((char *)0)) return(0);
+	if(!get_adjacent_loc((char *)0, (char *)0, u.ux, u.uy, &cc)) return(0);
 
-	x = u.ux + u.dx;
-	y = u.uy + u.dy;
-	if((x == u.ux) && (y == u.uy)) return(0);
+	if((cc.x == u.ux) && (cc.y == u.uy)) return(0);
 
-	if ((mtmp = m_at(x,y))				&&
+	if ((mtmp = m_at(cc.x,cc.y))			&&
 		mtmp->m_ap_type == M_AP_FURNITURE	&&
 		(mtmp->mappearance == S_hcdoor ||
 			mtmp->mappearance == S_vcdoor)	&&
@@ -520,10 +517,10 @@
 	    return(1);
 	}
 
-	door = &levl[x][y];
+	door = &levl[cc.x][cc.y];
 
 	if(!IS_DOOR(door->typ)) {
-		if (is_db_wall(x,y)) {
+		if (is_db_wall(cc.x,cc.y)) {
 		    There("is no obvious way to open the drawbridge.");
 		    return(0);
 		}
@@ -542,7 +539,7 @@
 	    default:	   mesg = " is locked"; break;
 	    }
 	    pline("This door%s.", mesg);
-	    if (Blind) feel_location(x,y);
+	    if (Blind) feel_location(cc.x,cc.y);
 	    return(0);
 	}
 
@@ -557,14 +554,14 @@
 	    if(door->doormask & D_TRAPPED) {
 		b_trapped("door", FINGER);
 		door->doormask = D_NODOOR;
-		if (*in_rooms(x, y, SHOPBASE)) add_damage(x, y, 0L);
+		if (*in_rooms(cc.x, cc.y, SHOPBASE)) add_damage(cc.x, cc.y, 0L);
 	    } else
 		door->doormask = D_ISOPEN;
 	    if (Blind)
-		feel_location(x,y);	/* the hero knows she opened it  */
+		feel_location(cc.x,cc.y);	/* the hero knows she opened it  */
 	    else
-		newsym(x,y);
-	    unblock_point(x,y);		/* vision: new see through there */
+		newsym(cc.x,cc.y);
+	    unblock_point(cc.x,cc.y);		/* vision: new see through there */
 	} else {
 	    exercise(A_STR, TRUE);
 	    pline_The("door resists!");
@@ -847,6 +844,8 @@
 		}
 		unblock_point(x,y);
 		newsym(x,y);
+		/* force vision recalc before printing more messages */
+		if (vision_full_recalc) vision_recalc(0);
 		loudness = 20;
 	    } else res = FALSE;
 	    break;
@@ -872,12 +871,12 @@
 chest_shatter_msg(otmp)
 struct obj *otmp;
 {
-	const char *disposition, *article = (otmp->quan > 1L) ? "A" : "The";
+	const char *disposition;
 	const char *thing;
 	long save_Blinded;
 
 	if (otmp->oclass == POTION_CLASS) {
-		You("%s a %s shatter!", Blind ? "hear" : "see", bottlename());
+		You("%s %s shatter!", Blind ? "hear" : "see", an(bottlename()));
 		if (!breathless(youmonst.data) || haseyes(youmonst.data))
 			potionbreathe(otmp);
 		return;
@@ -904,7 +903,7 @@
 	default:	disposition = "is destroyed";
 		break;
 	}
-	pline("%s %s %s!", article, thing, disposition);
+	pline("%s %s!", An(thing), disposition);
 }
 
 #endif /* OVLB */
diff -Naurd ../nethack-3.4.0/src/makemon.c ./src/makemon.c
--- ../nethack-3.4.0/src/makemon.c Wed Mar 20 23:43:08 2002
+++ ./src/makemon.c Mon Feb 24 15:25:05 2003
@@ -407,13 +407,6 @@
 		    case PM_HORNED_DEVIL:
 			(void)mongets(mtmp, rn2(4) ? TRIDENT : BULLWHIP);
 			break;
-		    case PM_ICE_DEVIL:
-			if (!rn2(4)) (void)mongets(mtmp, SPEAR);
-			break;
-		    case PM_ASMODEUS:
-			(void)mongets(mtmp, WAN_COLD);
-			(void)mongets(mtmp, WAN_FIRE);
-			break;
 		    case PM_DISPATER:
 			(void)mongets(mtmp, WAN_STRIKING);
 			break;
@@ -642,6 +635,16 @@
 		mkmonmoney(mtmp, (long) d(level_difficulty(), 30));
 #endif
 		break;
+	    case S_DEMON:
+	    	/* moved here from m_initweap() because these don't
+		   have AT_WEAP so m_initweap() is not called for them */
+		if (ptr == &mons[PM_ICE_DEVIL] && !rn2(4)) {
+			(void)mongets(mtmp, SPEAR);
+		} else if (ptr == &mons[PM_ASMODEUS]) {
+			(void)mongets(mtmp, WAN_COLD);
+			(void)mongets(mtmp, WAN_FIRE);
+		}
+		break;
 	    default:
 		break;
 	}
@@ -763,6 +766,7 @@
 	boolean byyou = (x == u.ux && y == u.uy);
 	boolean allow_minvent = ((mmflags & NO_MINVENT) == 0);
 	boolean countbirth = ((mmflags & MM_NOCOUNTBIRTH) == 0);
+	unsigned gpflags = (mmflags & MM_IGNOREWATER) ? MM_IGNOREWATER : 0;
 	uchar lim;
 
 	/* if caller wants random location, do it here */
@@ -774,12 +778,12 @@
 		do {
 			x = rn1(COLNO-3,2);
 			y = rn2(ROWNO);
-		} while(!goodpos(x, y, ptr ? &fakemon : (struct monst *)0) ||
+		} while(!goodpos(x, y, ptr ? &fakemon : (struct monst *)0, gpflags) ||
 			(!in_mklev && tryct++ < 50 && cansee(x, y)));
 	} else if (byyou && !in_mklev) {
 		coord bypos;
 
-		if(enexto(&bypos, u.ux, u.uy, ptr)) {
+		if(enexto_core(&bypos, u.ux, u.uy, ptr, gpflags)) {
 			x = bypos.x;
 			y = bypos.y;
 		} else
@@ -816,7 +820,7 @@
 			    return((struct monst *) 0);	/* no more monsters! */
 			}
 			fakemon.data = ptr;	/* set up for goodpos */
-		} while(!goodpos(x, y, &fakemon) && tryct++ < 50);
+		} while(!goodpos(x, y, &fakemon, gpflags) && tryct++ < 50);
 		mndx = monsndx(ptr);
 	}
 	/* if it's unique, don't ever make it again */
@@ -830,8 +834,8 @@
 	 * the caller manually decrement mvitals if the monster is created
 	 * under circumstances where one would not logically expect the
 	 * creation to reduce the supply of wild monsters.  Monster cloning
- 	 * might be one such case, but we go against logic there in order to
-	 * reduce the possibility of abuse.
+ 	 * might be one case that requires that in order to reduce the
+	 * possibility of abuse, but currently doesn't.
 	 */
 	if (mvitals[mndx].born < 255 && countbirth) mvitals[mndx].born++;
 	lim = mbirth_limit(mndx);
@@ -893,7 +897,7 @@
 	if (In_sokoban(&u.uz) && !mindless(ptr))  /* know about traps here */
 	    mtmp->mtrapseen = (1L << (PIT - 1)) | (1L << (HOLE - 1));
 	if (ptr->msound == MS_LEADER)		/* leader knows about portal */
-	    mtmp->mtrapseen |= (1 << (MAGIC_PORTAL-1));
+	    mtmp->mtrapseen |= (1L << (MAGIC_PORTAL-1));
 
 	place_monster(mtmp, x, y);
 	mtmp->mcansee = mtmp->mcanmove = TRUE;
@@ -955,7 +959,7 @@
 			mtmp->cham = CHAM_ORDINARY;
 		else {
 			mtmp->cham = mcham;
-			(void) newcham(mtmp, rndmonst(), FALSE);
+			(void) newcham(mtmp, rndmonst(), FALSE, FALSE);
 		}
 	} else if (mndx == PM_WIZARD_OF_YENDOR) {
 		mtmp->iswiz = TRUE;
@@ -1346,6 +1350,12 @@
 	if (mtmp->mhp <= 0)
 	    return ((struct permonst *)0);
 
+	/* note:  none of the monsters with special hit point calculations
+	   have both little and big forms */
+	oldtype = monsndx(ptr);
+	newtype = little_to_big(oldtype);
+	if (newtype == PM_PRIEST && mtmp->female) newtype = PM_PRIESTESS;
+
 	/* growth limits differ depending on method of advancement */
 	if (victim) {		/* killed a monster */
 	    /*
@@ -1362,6 +1372,9 @@
 	    else if (is_home_elemental(ptr))
 		hp_threshold *= 3;
 	    lev_limit = 3 * (int)ptr->mlevel / 2;	/* same as adj_lev() */
+	    /* If they can grow up, be sure the level is high enough for that */
+	    if (oldtype != newtype && mons[newtype].mlevel > lev_limit)
+		lev_limit = (int)mons[newtype].mlevel;
 	    /* number of hit points to gain; unlike for the player, we put
 	       the limit at the bottom of the next level rather than the top */
 	    max_increase = rnd((int)victim->m_lev + 1);
@@ -1386,11 +1399,6 @@
 	else if (lev_limit < 5) lev_limit = 5;	/* arbitrary */
 	else if (lev_limit > 49) lev_limit = (ptr->mlevel > 49 ? 50 : 49);
 
-	/* note:  none of the monsters with special hit point calculations
-	   have both little and big forms */
-	oldtype = monsndx(ptr);
-	newtype = little_to_big(oldtype);
-	if (newtype == PM_PRIEST && mtmp->female) newtype = PM_PRIESTESS;
 	if ((int)++mtmp->m_lev >= mons[newtype].mlevel && newtype != oldtype) {
 	    ptr = &mons[newtype];
 	    if (mvitals[newtype].mvflags & G_GENOD) {	/* allow G_EXTINCT */
@@ -1435,7 +1443,7 @@
 	    if (mtmp->data->mlet == S_DEMON) {
 		/* demons never get blessed objects */
 		if (otmp->blessed) curse(otmp);
-	    } else if(is_lminion(mtmp->data)) {
+	    } else if(is_lminion(mtmp)) {
 		/* lawful minions don't get cursed, bad, or rusting objects */
 		otmp->cursed = FALSE;
 		if(otmp->spe < 0) otmp->spe = 0;
@@ -1597,7 +1605,7 @@
 
 static NEARDATA char syms[] = {
 	MAXOCLASSES, MAXOCLASSES+1, RING_CLASS, WAND_CLASS, WEAPON_CLASS,
-	FOOD_CLASS, GOLD_CLASS, SCROLL_CLASS, POTION_CLASS, ARMOR_CLASS,
+	FOOD_CLASS, COIN_CLASS, SCROLL_CLASS, POTION_CLASS, ARMOR_CLASS,
 	AMULET_CLASS, TOOL_CLASS, ROCK_CLASS, GEM_CLASS, SPBOOK_CLASS,
 	S_MIMIC_DEF, S_MIMIC_DEF, S_MIMIC_DEF,
 };
@@ -1692,7 +1700,7 @@
 		if (s_sym >= MAXOCLASSES) {
 			ap_type = M_AP_FURNITURE;
 			appear = s_sym == MAXOCLASSES ? S_upstair : S_dnstair;
-		} else if (s_sym == GOLD_CLASS) {
+		} else if (s_sym == COIN_CLASS) {
 			ap_type = M_AP_OBJECT;
 			appear = GOLD_PIECE;
 		} else {
diff -Naurd ../nethack-3.4.0/src/mapglyph.c ./src/mapglyph.c
--- ../nethack-3.4.0/src/mapglyph.c Wed Mar 20 23:43:08 2002
+++ ./src/mapglyph.c Mon Feb 24 15:25:05 2003
@@ -7,6 +7,7 @@
 #include "wintty.h"	/* for prototype of has_color() only */
 #endif
 #include "color.h"
+#define HI_DOMESTIC CLR_WHITE	/* monst.c */
 
 int explcolors[] = {
 	CLR_BLACK,	/* dark    */
@@ -64,7 +65,9 @@
 unsigned *ospecial;
 {
 	register int offset;
+#if defined(TEXTCOLOR) || defined(ROGUE_COLOR)
 	int color = NO_COLOR;
+#endif
 	uchar ch;
 	unsigned special = 0;
 
@@ -126,7 +129,7 @@
 #ifdef ROGUE_COLOR
 	if (HAS_ROGUE_IBM_GRAPHICS && iflags.use_color) {
 	    switch(objects[offset].oc_class) {
-		case GOLD_CLASS: color = CLR_YELLOW; break;
+		case COIN_CLASS: color = CLR_YELLOW; break;
 		case FOOD_CLASS: color = CLR_RED; break;
 		default: color = CLR_BRIGHT_BLUE; break;
 	    }
@@ -194,7 +197,15 @@
 		color = NO_COLOR;
 	} else
 #endif
+	{
 	    mon_color(glyph);
+	    /* special case the hero for `showrace' option */
+#ifdef TEXTCOLOR
+	    if (iflags.use_color && x == u.ux && y == u.uy &&
+		    iflags.showrace && !Upolyd)
+		color = HI_DOMESTIC;
+#endif
+	}
     }
 
 #ifdef TEXTCOLOR
@@ -210,21 +221,11 @@
 # endif
 	color = NO_COLOR;
 #endif
-    if (ochar)
-	*ochar = (int)ch;
-    else
-    	impossible("glyphmap(): Invalid output character buffer.");
-
-    if (ospecial)
-	*ospecial = special;
-    else
-    	impossible("glyphmap(): Invalid special feature return buffer.");
 
+    *ochar = (int)ch;
+    *ospecial = special;
 #ifdef TEXTCOLOR
-    if (ocolor)
-	*ocolor = color;
-    else
-    	impossible("glyphmap(): Invalid color  buffer.");
+    *ocolor = color;
 #endif
     return;
 }
diff -Naurd ../nethack-3.4.0/src/mcastu.c ./src/mcastu.c
--- ../nethack-3.4.0/src/mcastu.c Wed Mar 20 23:43:08 2002
+++ ./src/mcastu.c Mon Feb 24 15:25:05 2003
@@ -40,7 +40,7 @@
 
 #ifdef OVL0
 
-extern const char *flash_types[];	/* from zap.c */
+extern const char * const flash_types[];	/* from zap.c */
 
 /* feedback when frustrated monster couldn't cast a spell */
 STATIC_OVL
@@ -91,7 +91,7 @@
     case 17:
     case 16:
     case 15:
-	return MGC_SUMMON_MONS;	/* also aggravates */
+	return MGC_SUMMON_MONS;
     case 14:
     case 13:
 	return MGC_AGGRAVATION;
@@ -181,7 +181,7 @@
 	 * attacking casts spells only a small portion of the time that an
 	 * attacking monster does.
 	 */
-	if (mattk->adtyp == AD_SPEL || mattk->adtyp == AD_CLRC) {
+	if ((mattk->adtyp == AD_SPEL || mattk->adtyp == AD_CLRC) && ml) {
 	    int cnt = 40;
 
 	    do {
@@ -355,7 +355,7 @@
 	} else
 	    impossible("bad wizard cloning?");
 	break;
-    case MGC_SUMMON_MONS:		/* also aggravates */
+    case MGC_SUMMON_MONS:
     {
 	int count;
 
@@ -542,9 +542,12 @@
 	boolean success;
 	int i;
 	coord bypos;
+	int quan;
 
+	quan = (mtmp->m_lev < 2) ? 1 : rnd((int)mtmp->m_lev / 2);
+	if (quan < 3) quan = 3;
 	success = pm ? TRUE : FALSE;
-	for (i = 0; i <= (int) mtmp->m_lev; i++) {
+	for (i = 0; i <= quan; i++) {
 	    if (!enexto(&bypos, mtmp->mux, mtmp->muy, mtmp->data))
 		break;
 	    if ((pm = mkclass(let,0)) != 0 &&
diff -Naurd ../nethack-3.4.0/src/mhitm.c ./src/mhitm.c
--- ../nethack-3.4.0/src/mhitm.c Wed Mar 20 23:43:08 2002
+++ ./src/mhitm.c Mon Feb 24 15:25:05 2003
@@ -242,7 +242,7 @@
 		    magr->weapon_check = NEED_HTH_WEAPON;
 		    if (mon_wield_item(magr) != 0) return 0;
 		}
-		possibly_unwield(magr);
+		possibly_unwield(magr, FALSE);
 		otmp = MON_WEP(magr);
 
 		if (otmp) {
@@ -306,8 +306,12 @@
 		break;
 
 	    case AT_EXPL:
-		strike = 1;	/* automatic hit */
 		res[i] = explmm(magr, mdef, mattk);
+		if (res[i] == MM_MISS) { /* cancelled--no attack */
+		    strike = 0;
+		    attk = 0;
+		} else
+		    strike = 1;	/* automatic hit */
 		break;
 
 	    case AT_ENGL:
@@ -537,6 +541,9 @@
 {
 	int result;
 
+	if (magr->mcan)
+	    return MM_MISS;
+
 	if(cansee(magr->mx, magr->my))
 		pline("%s explodes!", Monnam(magr));
 	else	noises(magr, mattk);
@@ -563,19 +570,21 @@
 	register struct monst	*magr, *mdef;
 	register struct attack	*mattk;
 {
-	struct	permonst *pa = magr->data, *pd = mdef->data;
-	int	tmp = d((int)mattk->damn,(int)mattk->damd);
 	struct obj *obj;
 	char buf[BUFSZ];
-	int protector =
-	    mattk->aatyp == AT_TENT ? 0 :
-	    mattk->aatyp == AT_KICK ? W_ARMF : W_ARMG;
-	int num;
+	struct permonst *pa = magr->data, *pd = mdef->data;
+	int armpro, num, tmp = d((int)mattk->damn, (int)mattk->damd);
+	boolean cancelled;
 
-	if (touch_petrifies(pd) && !resists_ston(magr) &&
-	   (mattk->aatyp != AT_WEAP || !otmp) &&
-	   (mattk->aatyp != AT_GAZE && mattk->aatyp != AT_EXPL) &&
-	   !(magr->misc_worn_check & protector)) {
+	if (touch_petrifies(pd) && !resists_ston(magr)) {
+	    long protector = attk_protection((int)mattk->aatyp),
+		 wornitems = magr->misc_worn_check;
+
+	    /* wielded weapon gives same protection as gloves here */
+	    if (otmp != 0) wornitems |= W_ARMG;
+
+	    if (protector == 0L ||
+		  (protector != ~0L && (wornitems & protector) != protector)) {
 		if (poly_when_stoned(pa)) {
 		    mon_to_stone(magr);
 		    return MM_HIT; /* no damage during the polymorph */
@@ -586,8 +595,13 @@
 		else if (magr->mtame && !vis)
 		    You(brief_feeling, "peculiarly sad");
 		return MM_AGR_DIED;
+	    }
 	}
 
+	/* cancellation factor is the same as when attacking the hero */
+	armpro = magic_negation(mdef);
+	cancelled = magr->mcan || !((rn2(3) >= armpro) || !rn2(50));
+
 	switch(mattk->adtyp) {
 	    case AD_DGST:
 		/* eating a Rider or its corpse is fatal */
@@ -641,18 +655,24 @@
 		    pline("%s %s for a moment.", Monnam(mdef),
 			  makeplural(stagger(mdef->data, "stagger")));
 		mdef->mstun = 1;
-		/* fall through */
+		goto physical;
+	    case AD_LEGS:
+		if (magr->mcan) {
+		    tmp = 0;
+		    break;
+		}
+		goto physical;
 	    case AD_WERE:
 	    case AD_HEAL:
-	    case AD_LEGS:
 	    case AD_PHYS:
-		if (mattk->aatyp == AT_KICK && thick_skinned(pd))
-			tmp = 0;
-		else if(mattk->aatyp == AT_WEAP) {
+ physical:
+		if (mattk->aatyp == AT_KICK && thick_skinned(pd)) {
+		    tmp = 0;
+		} else if(mattk->aatyp == AT_WEAP) {
 		    if(otmp) {
 			if (otmp->otyp == CORPSE &&
 				touch_petrifies(&mons[otmp->corpsenm]))
-			    goto do_stone_goto_label;
+			    goto do_stone;
 			tmp += dmgval(otmp, mdef);
 			if (otmp->oartifact) {
 			    (void)artifact_hit(magr,mdef, otmp, &tmp, dieroll);
@@ -673,15 +693,13 @@
 		}
 		break;
 	    case AD_FIRE:
-		if (magr->mcan) {
+		if (cancelled) {
 		    tmp = 0;
 		    break;
 		}
 		if (vis)
 		    pline("%s is %s!", Monnam(mdef),
-			  mdef->data == &mons[PM_WATER_ELEMENTAL] ? "boiling" :
-			  mattk->aatyp == AT_HUGS ?
-				"being roasted" : "on fire");
+			  on_fire(mdef->data, mattk));
 		if (pd == &mons[PM_STRAW_GOLEM] ||
 		    pd == &mons[PM_PAPER_GOLEM]) {
 			if (vis) pline("%s burns completely!", Monnam(mdef));
@@ -706,7 +724,7 @@
 		tmp += destroy_mitem(mdef, POTION_CLASS, AD_FIRE);
 		break;
 	    case AD_COLD:
-		if (magr->mcan) {
+		if (cancelled) {
 		    tmp = 0;
 		    break;
 		}
@@ -722,7 +740,7 @@
 		tmp += destroy_mitem(mdef, POTION_CLASS, AD_COLD);
 		break;
 	    case AD_ELEC:
-		if (magr->mcan) {
+		if (cancelled) {
 		    tmp = 0;
 		    break;
 		}
@@ -755,7 +773,8 @@
 		if (!rn2(6)) erode_obj(MON_WEP(mdef), TRUE, TRUE);
 		break;
 	    case AD_RUST:
-		if (!magr->mcan && pd == &mons[PM_IRON_GOLEM]) {
+		if (magr->mcan) break;
+		if (pd == &mons[PM_IRON_GOLEM]) {
 			if (vis) pline("%s falls to pieces!", Monnam(mdef));
 			mondied(mdef);
 			if (mdef->mhp > 0) return 0;
@@ -765,15 +784,19 @@
 							0 : MM_AGR_DIED));
 		}
 		hurtmarmor(mdef, AD_RUST);
+		mdef->mstrategy &= ~STRAT_WAITFORU;
 		tmp = 0;
 		break;
 	    case AD_CORR:
+		if (magr->mcan) break;
 		hurtmarmor(mdef, AD_CORR);
+		mdef->mstrategy &= ~STRAT_WAITFORU;
 		tmp = 0;
 		break;
 	    case AD_DCAY:
-		if (!magr->mcan && (pd == &mons[PM_WOOD_GOLEM] ||
-		    pd == &mons[PM_LEATHER_GOLEM])) {
+		if (magr->mcan) break;
+		if (pd == &mons[PM_WOOD_GOLEM] ||
+		    pd == &mons[PM_LEATHER_GOLEM]) {
 			if (vis) pline("%s falls to pieces!", Monnam(mdef));
 			mondied(mdef);
 			if (mdef->mhp > 0) return 0;
@@ -783,12 +806,14 @@
 							0 : MM_AGR_DIED));
 		}
 		hurtmarmor(mdef, AD_DCAY);
+		mdef->mstrategy &= ~STRAT_WAITFORU;
 		tmp = 0;
 		break;
 	    case AD_STON:
-do_stone_goto_label:
+		if (magr->mcan) break;
+ do_stone:
 		/* may die from the acid if it eats a stone-curing corpse */
-		if (munstone(mdef, FALSE)) goto label2;
+		if (munstone(mdef, FALSE)) goto post_stone;
 		if (poly_when_stoned(pd)) {
 			mon_to_stone(mdef);
 			tmp = 0;
@@ -797,7 +822,7 @@
 		if (!resists_ston(mdef)) {
 			if (vis) pline("%s turns to stone!", Monnam(mdef));
 			monstone(mdef);
-label2:			if (mdef->mhp > 0) return 0;
+ post_stone:		if (mdef->mhp > 0) return 0;
 			else if (mdef->mtame && !vis)
 			    You(brief_feeling, "peculiarly sad");
 			return (MM_DEF_DIED | (grow_up(magr,mdef) ?
@@ -806,11 +831,12 @@
 		tmp = (mattk->adtyp == AD_STON ? 0 : 1);
 		break;
 	    case AD_TLPT:
-		if (!magr->mcan && tmp < mdef->mhp && !tele_restrict(mdef)) {
+		if (!cancelled && tmp < mdef->mhp && !tele_restrict(mdef)) {
 		    char mdef_Monnam[BUFSZ];
 		    /* save the name before monster teleports, otherwise
 		       we'll get "it" in the suddenly disappears message */
 		    if (vis) Strcpy(mdef_Monnam, Monnam(mdef));
+		    mdef->mstrategy &= ~STRAT_WAITFORU;
 		    rloc(mdef);
 		    if (vis && !canspotmon(mdef)
 #ifdef STEED
@@ -821,30 +847,33 @@
 		}
 		break;
 	    case AD_SLEE:
-		if (!magr->mcan && !mdef->msleeping &&
+		if (!cancelled && !mdef->msleeping &&
 			sleep_monst(mdef, rnd(10), -1)) {
 		    if (vis) {
 			Strcpy(buf, Monnam(mdef));
 			pline("%s is put to sleep by %s.", buf, mon_nam(magr));
 		    }
+		    mdef->mstrategy &= ~STRAT_WAITFORU;
 		    slept_monst(mdef);
 		}
 		break;
 	    case AD_PLYS:
-		if(!magr->mcan && mdef->mcanmove) {
+		if(!cancelled && mdef->mcanmove) {
 		    if (vis) {
 			Strcpy(buf, Monnam(mdef));
 			pline("%s is frozen by %s.", buf, mon_nam(magr));
 		    }
 		    mdef->mcanmove = 0;
 		    mdef->mfrozen = rnd(10);
+		    mdef->mstrategy &= ~STRAT_WAITFORU;
 		}
 		break;
 	    case AD_SLOW:
-		if (!magr->mcan && vis && mdef->mspeed != MSLOW) {
+		if (!cancelled && mdef->mspeed != MSLOW) {
 		    unsigned int oldspeed = mdef->mspeed;
 
 		    mon_adjust_speed(mdef, -1, (struct obj *)0);
+		    mdef->mstrategy &= ~STRAT_WAITFORU;
 		    if (mdef->mspeed != oldspeed && vis)
 			pline("%s slows down.", Monnam(mdef));
 		}
@@ -857,6 +886,7 @@
 		if (!magr->mcan && !mdef->mconf && !magr->mspec_used) {
 		    if (vis) pline("%s looks confused.", Monnam(mdef));
 		    mdef->mconf = 1;
+		    mdef->mstrategy &= ~STRAT_WAITFORU;
 		}
 		break;
 	    case AD_BLND:
@@ -869,6 +899,7 @@
 		    if ((rnd_tmp += mdef->mblinded) > 127) rnd_tmp = 127;
 		    mdef->mblinded = rnd_tmp;
 		    mdef->mcansee = 0;
+		    mdef->mstrategy &= ~STRAT_WAITFORU;
 		}
 		tmp = 0;
 		break;
@@ -877,6 +908,7 @@
 		    if (vis) pline("%s looks %sconfused.",
 				    Monnam(mdef), mdef->mconf ? "more " : "");
 		    mdef->mconf = 1;
+		    mdef->mstrategy &= ~STRAT_WAITFORU;
 		}
 		tmp = 0;
 		break;
@@ -884,6 +916,7 @@
 		if (!night() && (pa == &mons[PM_GREMLIN])) break;
 		if (!magr->mcan && !rn2(10)) {
 		    mdef->mcan = 1;	/* cancelled regardless of lifesave */
+		    mdef->mstrategy &= ~STRAT_WAITFORU;
 		    if (is_were(pd) && pd->mlet != S_HUMAN)
 			were_change(mdef);
 		    if (pd == &mons[PM_CLAY_GOLEM]) {
@@ -926,6 +959,7 @@
 		    add_to_minv(magr, gold);
                 }
 #endif
+		mdef->mstrategy &= ~STRAT_WAITFORU;
 		if (vis) {
 		    Strcpy(buf, Monnam(magr));
 		    pline("%s steals some gold from %s.", buf, mon_nam(mdef));
@@ -937,7 +971,7 @@
 		}
 		break;
 	    case AD_DRLI:
-		if (rn2(2) && !resists_drli(mdef)) {
+		if (!cancelled && !rn2(3) && !resists_drli(mdef)) {
 			tmp = d(2,6);
 			if (vis)
 			    pline("%s suddenly seems weaker!", Monnam(mdef));
@@ -953,13 +987,13 @@
 #endif
 	    case AD_SITM:	/* for now these are the same */
 	    case AD_SEDU:
+		if (magr->mcan) break;
 		/* find an object to steal, non-cursed if magr is tame */
-		for (obj = mdef->minvent; obj; obj = obj->nobj) {
+		for (obj = mdef->minvent; obj; obj = obj->nobj)
 		    if (!magr->mtame || !obj->cursed)
 			break;
-		}
 
-		if (!magr->mcan && obj) {
+		if (obj) {
 			char onambuf[BUFSZ], mdefnambuf[BUFSZ];
 
 			/* make a special x_monnam() call that never omits
@@ -979,7 +1013,7 @@
 				if (otmp->owornmask & W_WEP)
 				    setmnotwielded(mdef,otmp);
 				otmp->owornmask = 0L;
-				update_mon_intrinsics(mdef, otmp, FALSE);
+				update_mon_intrinsics(mdef, otmp, FALSE, FALSE);
 			}
 			/* add_to_minv() might free otmp [if it merges] */
 			if (vis)
@@ -990,7 +1024,8 @@
 				pline("%s steals %s from %s!", buf,
 				    onambuf, mdefnambuf);
 			}
-			possibly_unwield(mdef);
+			possibly_unwield(mdef, FALSE);
+			mdef->mstrategy &= ~STRAT_WAITFORU;
 			mselftouch(mdef, (const char *)0, FALSE);
 			if (mdef->mhp <= 0)
 				return (MM_DEF_DIED | (grow_up(magr,mdef) ?
@@ -1007,7 +1042,7 @@
 	    case AD_DRST:
 	    case AD_DRDX:
 	    case AD_DRCO:
-		if (!magr->mcan && !rn2(8)) {
+		if (!cancelled && !rn2(8)) {
 		    if (vis)
 			pline("%s %s was poisoned!", s_suffix(Monnam(magr)),
 			      mpoisons_subj(magr, mattk));
@@ -1055,18 +1090,25 @@
 			          s_suffix(Monnam(mdef)));
 		break;
 	    case AD_SLIM:
-	    	if (!rn2(4) && mdef->data != &mons[PM_FIRE_VORTEX] &&
-	    			mdef->data != &mons[PM_FIRE_ELEMENTAL] &&
-	    			mdef->data != &mons[PM_SALAMANDER] &&
-	    			mdef->data != &mons[PM_GREEN_SLIME]) {
-	    	    if (vis) pline("%s turns into slime.", Monnam(mdef));
-	    	    (void) newcham(mdef, &mons[PM_GREEN_SLIME], FALSE);
-	    	    tmp = 0;
-	    	}
-	    	break;
+		if (cancelled) break;	/* physical damage only */
+		if (!rn2(4) && mdef->data != &mons[PM_FIRE_VORTEX] &&
+				mdef->data != &mons[PM_FIRE_ELEMENTAL] &&
+				mdef->data != &mons[PM_SALAMANDER] &&
+				mdef->data != &mons[PM_GREEN_SLIME]) {
+		    (void) newcham(mdef, &mons[PM_GREEN_SLIME], FALSE, vis);
+		    mdef->mstrategy &= ~STRAT_WAITFORU;
+		    tmp = 0;
+		}
+		break;
 	    case AD_STCK:
+		if (cancelled) tmp = 0;
+		break;
 	    case AD_WRAP: /* monsters cannot grab one another, it's too hard */
-	    case AD_ENCH: /* There's no msomearmor() function, so just do damage */
+		if (magr->mcan) tmp = 0;
+		break;
+	    case AD_ENCH:
+		/* there's no msomearmor() function, so just do damage */
+	     /* if (cancelled) break; */
 		break;
 	    default:	tmp = 0;
 			break;
@@ -1082,6 +1124,23 @@
 	    }
 	    monkilled(mdef, "", (int)mattk->adtyp);
 	    if (mdef->mhp > 0) return 0; /* mdef lifesaved */
+
+	    if (mattk->adtyp == AD_DGST) {
+		/* various checks similar to dog_eat and meatobj.
+		 * after monkilled() to provide better message ordering */
+		if (mdef->cham != CHAM_ORDINARY) {
+		    (void) newcham(magr, (struct permonst *)0, FALSE, TRUE);
+		} else if (mdef->data == &mons[PM_GREEN_SLIME]) {
+		    (void) newcham(magr, &mons[PM_GREEN_SLIME], FALSE, TRUE);
+		} else if (mdef->data == &mons[PM_WRAITH]) {
+		    (void) grow_up(magr, (struct monst *)0);
+		    /* don't grow up twice */
+		    return (MM_DEF_DIED | (magr->mhp > 0 ? 0 : MM_AGR_DIED));
+		} else if (mdef->data == &mons[PM_NURSE]) {
+		    magr->mhp = magr->mhpmax;
+		}
+	    }
+
 	    return (MM_DEF_DIED | (grow_up(magr,mdef) ? 0 : MM_AGR_DIED));
 	}
 	return(MM_HIT);
@@ -1336,6 +1395,49 @@
 	return (mdead | mhit);
 }
 
+/* "aggressive defense"; what type of armor prevents specified attack
+   from touching its target? */
+long
+attk_protection(aatyp)
+int aatyp;
+{
+    long w_mask = 0L;
+
+    switch (aatyp) {
+    case AT_NONE:
+    case AT_SPIT:
+    case AT_EXPL:
+    case AT_BOOM:
+    case AT_GAZE:
+    case AT_BREA:
+    case AT_MAGC:
+	w_mask = ~0L;		/* special case; no defense needed */
+	break;
+    case AT_CLAW:
+    case AT_TUCH:
+    case AT_WEAP:
+	w_mask = W_ARMG;	/* caller needs to check for weapon */
+	break;
+    case AT_KICK:
+	w_mask = W_ARMF;
+	break;
+    case AT_BUTT:
+	w_mask = W_ARMH;
+	break;
+    case AT_HUGS:
+	w_mask = (W_ARMC|W_ARMG); /* attacker needs both to be protected */
+	break;
+    case AT_BITE:
+    case AT_STNG:
+    case AT_ENGL:
+    case AT_TENT:
+    default:
+	w_mask = 0L;		/* no defense available */
+	break;
+    }
+    return w_mask;
+}
+
 #endif /* OVLB */
 
 /*mhitm.c*/
diff -Naurd ../nethack-3.4.0/src/mhitu.c ./src/mhitu.c
--- ../nethack-3.4.0/src/mhitu.c Wed Mar 20 23:43:08 2002
+++ ./src/mhitu.c Mon Feb 24 15:25:05 2003
@@ -316,7 +316,7 @@
 		/* Might be attacking your image around the corner, or
 		 * invisible, or you might be blind....
 		 */
-
+	
 	if(!ranged) nomul(0);
 	if(mtmp->mhp <= 0 || (Underwater && !is_swimmer(mtmp->data)))
 	    return(0);
@@ -356,6 +356,7 @@
 		u.uundetected = 0;
 		if (is_hider(youmonst.data)) {
 		    coord cc; /* maybe we need a unexto() function? */
+		    struct obj *obj;
 
 		    You("fall from the %s!", ceiling(u.ux,u.uy));
 		    if (enexto(&cc, u.ux, u.uy, youmonst.data)) {
@@ -363,7 +364,7 @@
 			newsym(mtmp->mx,mtmp->my);
 			place_monster(mtmp, u.ux, u.uy);
 			if(mtmp->wormno) worm_move(mtmp);
-			teleds(cc.x, cc.y);
+			teleds(cc.x, cc.y, TRUE);
 			set_apparxy(mtmp);
 			newsym(u.ux,u.uy);
 		    } else {
@@ -377,7 +378,8 @@
 		    if (youmonst.data->mlet != S_PIERCER)
 			return(0);	/* trappers don't attack */
 
-		    if (which_armor(mtmp, WORN_HELMET)) {
+		    obj = which_armor(mtmp, WORN_HELMET);
+		    if (obj && is_metallic(obj)) {
 			Your("blow glances off %s helmet.",
 			               s_suffix(mon_nam(mtmp)));
 		    } else {
@@ -436,15 +438,15 @@
 		return(0);
 	}
 
-	/* player might be mimicking gold */
-	if (youmonst.m_ap_type == M_AP_OBJECT
-		&& youmonst.mappearance == GOLD_PIECE
-		&& !range2 && foundyou && !u.uswallow) {
+	/* player might be mimicking an object */
+	if (youmonst.m_ap_type == M_AP_OBJECT && !range2 && foundyou && !u.uswallow) {
 	    if (!youseeit)
-		 pline("%s %s!", Something, likes_gold(mtmp->data) ?
+		 pline("%s %s!", Something,
+			(likes_gold(mtmp->data) && youmonst.mappearance == GOLD_PIECE) ?
 			"tries to pick you up" : "disturbs you");
-	    else pline("Wait, %s!  That gold is really %s named %s!",
+	    else pline("Wait, %s!  That %s is really %s named %s!",
 			m_monnam(mtmp),
+			mimic_obj_name(&youmonst),
 			an(mons[u.umonnum].mname),
 			plname);
 	    if (multi < 0) {	/* this should always be the case */
@@ -452,7 +454,7 @@
 		Sprintf(buf, "You appear to be %s again.",
 			Upolyd ? (const char *) an(youmonst.data->mname) :
 			    (const char *) "yourself");
-		unmul(buf);	/* immediately stop mimicking gold */
+		unmul(buf);	/* immediately stop mimicking */
 	    }
 	    return 0;
 	}
@@ -477,7 +479,7 @@
 	   && mtmp->data != &mons[PM_BALROG]
 	   && mtmp->data != &mons[PM_SUCCUBUS]
 	   && mtmp->data != &mons[PM_INCUBUS])
-	    if(!mtmp->mcan && !rn2(13))	msummon(mdat);
+	    if(!mtmp->mcan && !rn2(13))	msummon(mtmp);
 
 /*	Special lycanthrope handling code */
 	if(!mtmp->cham && is_were(mdat) && !range2) {
@@ -787,6 +789,51 @@
 	return FALSE;
 }
 
+/* armor that sufficiently covers the body might be able to block magic */
+int
+magic_negation(mon)
+struct monst *mon;
+{
+	struct obj *armor;
+	int armpro = 0;
+
+	armor = (mon == &youmonst) ? uarm : which_armor(mon, W_ARM);
+	if (armor && armpro < objects[armor->otyp].a_can)
+	    armpro = objects[armor->otyp].a_can;
+	armor = (mon == &youmonst) ? uarmc : which_armor(mon, W_ARMC);
+	if (armor && armpro < objects[armor->otyp].a_can)
+	    armpro = objects[armor->otyp].a_can;
+	armor = (mon == &youmonst) ? uarmh : which_armor(mon, W_ARMH);
+	if (armor && armpro < objects[armor->otyp].a_can)
+	    armpro = objects[armor->otyp].a_can;
+
+	/* armor types for shirt, gloves, shoes, and shield don't currently
+	   provide any magic cancellation but we might as well be complete */
+#ifdef TOURIST
+	armor = (mon == &youmonst) ? uarmu : which_armor(mon, W_ARMU);
+	if (armor && armpro < objects[armor->otyp].a_can)
+	    armpro = objects[armor->otyp].a_can;
+#endif
+	armor = (mon == &youmonst) ? uarmg : which_armor(mon, W_ARMG);
+	if (armor && armpro < objects[armor->otyp].a_can)
+	    armpro = objects[armor->otyp].a_can;
+	armor = (mon == &youmonst) ? uarmf : which_armor(mon, W_ARMF);
+	if (armor && armpro < objects[armor->otyp].a_can)
+	    armpro = objects[armor->otyp].a_can;
+	armor = (mon == &youmonst) ? uarms : which_armor(mon, W_ARMS);
+	if (armor && armpro < objects[armor->otyp].a_can)
+	    armpro = objects[armor->otyp].a_can;
+
+#ifdef STEED
+	/* this one is really a stretch... */
+	armor = (mon == &youmonst) ? 0 : which_armor(mon, W_SADDLE);
+	if (armor && armpro < objects[armor->otyp].a_can)
+	    armpro = objects[armor->otyp].a_can;
+#endif
+
+	return armpro;
+}
+
 /*
  * hitmu: monster hits you
  *	  returns 2 if monster dies (e.g. "yellow light"), 1 otherwise
@@ -840,13 +887,7 @@
 /*	Use uncancelled when the cancellation factor takes into account certain
  *	armor's special magic protection.  Otherwise just use !mtmp->mcan.
  */
-	armpro = 0;
-	if (uarm && armpro < objects[uarm->otyp].a_can)
-		armpro = objects[uarm->otyp].a_can;
-	if (uarmc && armpro < objects[uarmc->otyp].a_can)
-		armpro = objects[uarmc->otyp].a_can;
-	if (uarmh && armpro < objects[uarmh->otyp].a_can)
-		armpro = objects[uarmh->otyp].a_can;
+	armpro = magic_negation(&youmonst);
 	uncancelled = !mtmp->mcan && ((rn2(3) >= armpro) || !rn2(50));
 
 	permdmg = 0;
@@ -912,11 +953,7 @@
 	    case AD_FIRE:
 		hitmsg(mtmp, mattk);
 		if (uncancelled) {
-		    pline("You're %s!",
-			  youmonst.data == &mons[PM_WATER_ELEMENTAL] ?
-				"boiling" :
-			  mattk->aatyp == AT_HUGS ? "being roasted" :
-			  "on fire");
+		    pline("You're %s!", on_fire(youmonst.data, mattk));
 		    if (youmonst.data == &mons[PM_STRAW_GOLEM] ||
 		        youmonst.data == &mons[PM_PAPER_GOLEM]) {
 			    You("roast!");
@@ -990,12 +1027,9 @@
 dopois:
 		hitmsg(mtmp, mattk);
 		if (uncancelled && !rn2(8)) {
-			Sprintf(buf, "%s %s",
-				!canspotmon(mtmp) ? "Its" :
-				Hallucination ? s_suffix(rndmonnam()) :
-				                s_suffix(mdat->mname),
-				mpoisons_subj(mtmp, mattk));
-			poisoned(buf, ptmp, mdat->mname, 30);
+		    Sprintf(buf, "%s %s",
+			    s_suffix(Monnam(mtmp)), mpoisons_subj(mtmp, mattk));
+		    poisoned(buf, ptmp, mdat->mname, 30);
 		}
 		break;
 	    case AD_DRIN:
@@ -1058,14 +1092,15 @@
 	    case AD_PLYS:
 		hitmsg(mtmp, mattk);
 		if (uncancelled && multi >= 0 && !rn2(3)) {
-	    	if (Free_action) You("momentarily stiffen.");            
-	    	else {
-	    	    if (Blind) You("are frozen!");
-	    	    else You("are frozen by %s!", mon_nam(mtmp));
-	    	    nomovemsg = 0;	/* default: "you can move again" */
-	    	    nomul(-rnd(10));
-	    	    exercise(A_DEX, FALSE);
-	    	}
+		    if (Free_action) {
+			You("momentarily stiffen.");            
+		    } else {
+			if (Blind) You("are frozen!");
+			else You("are frozen by %s!", mon_nam(mtmp));
+			nomovemsg = 0;	/* default: "you can move again" */
+			nomul(-rnd(10));
+			exercise(A_DEX, FALSE);
+		    }
 		}
 		break;
 	    case AD_DRLI:
@@ -1081,6 +1116,7 @@
 		/* This case is too obvious to ignore, but Nethack is not in
 		 * general very good at considering height--most short monsters
 		 * still _can_ attack you when you're flying or mounted.
+		 * [FIXME: why can't a flying attacker overcome this?]
 		 */
 		  if (
 #ifdef STEED
@@ -1089,9 +1125,11 @@
 				    Levitation || Flying) {
 		    pline("%s tries to reach your %s %s!", Monnam(mtmp),
 			  sidestr, body_part(LEG));
+		    dmg = 0;
 		  } else if (mtmp->mcan) {
 		    pline("%s nuzzles against your %s %s!", Monnam(mtmp),
 			  sidestr, body_part(LEG));
+		    dmg = 0;
 		  } else {
 		    if (uarmf) {
 			if (rn2(2) && (uarmf->otyp == LOW_BOOTS ||
@@ -1104,6 +1142,7 @@
 			else {
 			    pline("%s scratches your %s boot!", Monnam(mtmp),
 				sidestr);
+			    dmg = 0;
 			    break;
 			}
 		    } else pline("%s pricks your %s %s!", Monnam(mtmp),
@@ -1125,7 +1164,7 @@
 			    You_hear("%s hissing!", s_suffix(mon_nam(mtmp)));
 			if(!rn2(10) ||
 			    (flags.moonphase == NEW_MOON && !have_lizard())) {
-do_stone:
+ do_stone:
 			    if (!Stoned && !Stone_resistance
 				    && !(poly_when_stoned(youmonst.data) &&
 					polymon(PM_STONE_GOLEM))) {
@@ -1158,8 +1197,9 @@
 		    } else if(u.ustuck == mtmp) {
 			if (is_pool(mtmp->mx,mtmp->my) && !Swimming
 			    && !Amphibious) {
-			    boolean moat = (levl[u.ux][u.uy].typ != POOL) &&
-				(levl[u.ux][u.uy].typ != WATER) &&
+			    boolean moat =
+				(levl[mtmp->mx][mtmp->my].typ != POOL) &&
+				(levl[mtmp->mx][mtmp->my].typ != WATER) &&
 				!Is_medusa_level(&u.uz) &&
 				!Is_waterlevel(&u.uz);
 
@@ -1235,11 +1275,6 @@
 			if (!is_animal(mtmp->data) && !tele_restrict(mtmp))
 			    rloc(mtmp);
 			if (is_animal(mtmp->data) && *buf) {
-			    /* set mavenge bit for animals so knights won't
-			       suffer an alignment penalty during retaliation;
-			       note that only happens when the thief succeeds
-			       in getting something (*buf != 0) */
-			    mtmp->mavenge = 1;
 			    if (canseemon(mtmp))
 				pline("%s tries to %s away with %s.",
 				      Monnam(mtmp),
@@ -1304,6 +1339,11 @@
 		hurtarmor(AD_DCAY);
 		break;
 	    case AD_HEAL:
+		/* a cancelled nurse is just an ordinary monster */
+		if (mtmp->mcan) {
+		    hitmsg(mtmp, mattk);
+		    break;
+		}
 		if(!uwep
 #ifdef TOURIST
 		   && !uarmu
@@ -1596,7 +1636,7 @@
 
 		i = number_leashed();
 		if (i > 0) {
-		    char *s = (i > 1) ? "leashes" : "leash";
+		    const char *s = (i > 1) ? "leashes" : "leash";
 		    pline_The("%s %s loose.", s, vtense(s, "snap"));
 		    unleash_all();
 		}
@@ -2350,7 +2390,7 @@
 			/* obj == uarmh */
 			hairbuf);
 	}
-	remove_worn_item(obj);
+	remove_worn_item(obj, TRUE);
 }
 #endif  /* SEDUCE */
 
@@ -2394,15 +2434,16 @@
 		goto assess_dmg;
 	    case AD_STON: /* cockatrice */
 	    {
-		int protector =
-		    mattk->aatyp == AT_TENT ? 0 :
-		    mattk->aatyp == AT_KICK ? W_ARMF : W_ARMG;
-		if (!resists_ston(mtmp) &&
-		    (mattk->aatyp != AT_WEAP || !MON_WEP(mtmp)) &&
-		    mattk->aatyp != AT_GAZE && mattk->aatyp != AT_EXPL &&
-		    mattk->aatyp != AT_MAGC &&
-		    !(mtmp->misc_worn_check & protector)) {
-		    if(poly_when_stoned(mtmp->data)) {
+		long protector = attk_protection((int)mattk->aatyp),
+		     wornitems = mtmp->misc_worn_check;
+
+		/* wielded weapon gives same protection as gloves here */
+		if (MON_WEP(mtmp) != 0) wornitems |= W_ARMG;
+
+		if (!resists_ston(mtmp) && (protector == 0L ||
+			(protector != ~0L &&
+			    (wornitems & protector) != protector))) {
+		    if (poly_when_stoned(mtmp->data)) {
 			mon_to_stone(mtmp);
 			return (1);
 		    }
diff -Naurd ../nethack-3.4.0/src/minion.c ./src/minion.c
--- ../nethack-3.4.0/src/minion.c Wed Mar 20 23:43:09 2002
+++ ./src/minion.c Mon Feb 24 15:25:05 2003
@@ -7,12 +7,25 @@
 #include "epri.h"
 
 void
-msummon(ptr)		/* ptr summons a monster */
-register struct permonst *ptr;
+msummon(mon)		/* mon summons a monster */
+struct monst *mon;
 {
+	register struct permonst *ptr;
 	register int dtype = NON_PM, cnt = 0;
-	aligntyp atyp = (ptr->maligntyp==A_NONE) ? A_NONE : sgn(ptr->maligntyp);
+	aligntyp atyp;
+	struct monst *mtmp;
 
+	if (mon) {
+	    ptr = mon->data;
+	    atyp = (ptr->maligntyp==A_NONE) ? A_NONE : sgn(ptr->maligntyp);
+	    if (mon->ispriest || mon->data == &mons[PM_ALIGNED_PRIEST]
+		|| mon->data == &mons[PM_ANGEL])
+		atyp = EPRI(mon)->shralign;
+	} else {
+	    ptr = &mons[PM_WIZARD_OF_YENDOR];
+	    atyp = (ptr->maligntyp==A_NONE) ? A_NONE : sgn(ptr->maligntyp);
+	}
+	    
 	if (is_dprince(ptr) || (ptr == &mons[PM_WIZARD_OF_YENDOR])) {
 	    dtype = (!rn2(20)) ? dprince(atyp) :
 				 (!rn2(4)) ? dlord(atyp) : ndemon(atyp);
@@ -25,10 +38,26 @@
 	    dtype = (!rn2(20)) ? dlord(atyp) :
 				 (!rn2(6)) ? ndemon(atyp) : monsndx(ptr);
 	    cnt = 1;
-	} else if (is_lminion(ptr)) {
+	} else if (is_lminion(mon)) {
 	    dtype = (is_lord(ptr) && !rn2(20)) ? llord() :
 		     (is_lord(ptr) || !rn2(6)) ? lminion() : monsndx(ptr);
 	    cnt = (!rn2(4) && !is_lord(&mons[dtype])) ? 2 : 1;
+	} else if (ptr == &mons[PM_ANGEL]) {
+	    /* non-lawful angels can also summon */
+	    if (!rn2(6)) {
+		switch (atyp) { /* see summon_minion */
+		case A_NEUTRAL:
+		    dtype = PM_AIR_ELEMENTAL + rn2(4);
+		    break;
+		case A_CHAOTIC:
+		case A_NONE:
+		    dtype = ndemon(atyp);
+		    break;
+		}
+	    } else {
+		dtype = PM_ANGEL;
+	    }
+	    cnt = (!rn2(4) && !is_lord(&mons[dtype])) ? 2 : 1;
 	}
 
 	if (dtype == NON_PM) return;
@@ -45,10 +74,13 @@
 	}
 
 	while (cnt > 0) {
-	    (void)makemon(&mons[dtype], u.ux, u.uy, NO_MM_FLAGS);
+	    mtmp = makemon(&mons[dtype], u.ux, u.uy, NO_MM_FLAGS);
+	    if (mtmp && (dtype == PM_ANGEL)) {
+		/* alignment should match the summoner */
+		EPRI(mtmp)->shralign = atyp;
+	    }
 	    cnt--;
 	}
-	return;
 }
 
 void
@@ -110,11 +142,12 @@
 demon_talk(mtmp)		/* returns 1 if it won't attack. */
 register struct monst *mtmp;
 {
-	long	demand, offer;
+	long cash, demand, offer;
 
 	if (uwep && uwep->oartifact == ART_EXCALIBUR) {
 	    pline("%s looks very angry.", Amonnam(mtmp));
 	    mtmp->mpeaceful = mtmp->mtame = 0;
+	    set_malign(mtmp);
 	    newsym(mtmp->mx, mtmp->my);
 	    return 0;
 	}
@@ -132,28 +165,38 @@
 	    return(1);
 	}
 #ifndef GOLDOBJ
-	demand = (u.ugold * (rnd(80) + 20 * Athome)) /
+	cash = u.ugold;
 #else
-	demand = (money_cnt(invent) * (rnd(80) + 20 * Athome)) /
+	cash = money_cnt(invent);
 #endif
+	demand = (cash * (rnd(80) + 20 * Athome)) /
 	    (100 * (1 + (sgn(u.ualign.type) == sgn(mtmp->data->maligntyp))));
-	if (!demand)		/* you have no gold */
-	    return mtmp->mpeaceful = 0;
-	else {
+
+	if (!demand) {		/* you have no gold */
+	    mtmp->mpeaceful = 0;
+	    set_malign(mtmp);
+	    return 0;
+	} else {
+	    /* make sure that the demand is unmeetable if the monster
+	       has the Amulet, preventing monster from being satisified
+	       and removed from the game (along with said Amulet...) */
+	    if (mon_has_amulet(mtmp))
+		demand = cash + (long)rn1(1000,40);
+
 	    pline("%s demands %ld %s for safe passage.",
 		  Amonnam(mtmp), demand, currency(demand));
 
 	    if ((offer = bribe(mtmp)) >= demand) {
 		pline("%s vanishes, laughing about cowardly mortals.",
 		      Amonnam(mtmp));
+	    } else if (offer > 0L && (long)rnd(40) > (demand - offer)) {
+		pline("%s scowls at you menacingly, then vanishes.",
+		      Amonnam(mtmp));
 	    } else {
-		if ((long)rnd(40) > (demand - offer)) {
-		    pline("%s scowls at you menacingly, then vanishes.",
-			  Amonnam(mtmp));
-		} else {
-		    pline("%s gets angry...", Amonnam(mtmp));
-		    return mtmp->mpeaceful = 0;
-		}
+		pline("%s gets angry...", Amonnam(mtmp));
+		mtmp->mpeaceful = 0;
+		set_malign(mtmp);
+		return 0;
 	    }
 	}
 	mongone(mtmp);
diff -Naurd ../nethack-3.4.0/src/mklev.c ./src/mklev.c
--- ../nethack-3.4.0/src/mklev.c Wed Mar 20 23:43:09 2002
+++ ./src/mklev.c Mon Feb 24 15:25:05 2003
@@ -35,7 +35,7 @@
 STATIC_DCL void FDECL(makeniche,(int));
 STATIC_DCL void NDECL(make_niches);
 
-STATIC_PTR int FDECL(do_comp,(const genericptr,const genericptr));
+STATIC_PTR int FDECL( CFDECLSPEC do_comp,(const genericptr,const genericptr));
 
 STATIC_DCL void FDECL(dosdoor,(XCHAR_P,XCHAR_P,struct mkroom *,int));
 STATIC_DCL void FDECL(join,(int,int,BOOLEAN_P));
@@ -55,7 +55,7 @@
 
 /* Args must be (const genericptr) so that qsort will always be happy. */
 
-STATIC_PTR int
+STATIC_PTR int CFDECLSPEC
 do_comp(vx,vy)
 const genericptr vx;
 const genericptr vy;
diff -Naurd ../nethack-3.4.0/src/mkmaze.c ./src/mkmaze.c
--- ../nethack-3.4.0/src/mkmaze.c Wed Mar 20 23:43:09 2002
+++ ./src/mkmaze.c Mon Feb 24 15:25:05 2003
@@ -288,13 +288,18 @@
 boolean oneshot;
 d_level *lev;
 {
-    if (bad_location(x, y, nlx, nly, nhx, nhy)) return FALSE;
-    if (oneshot) {
-	/* must make due with the only location possible */
-	/* avoid failure due to a misplaced trap */
-	/* it might still fail if there's a dungeon feature here */
-	struct trap *t = t_at(x,y);
-	if (t) deltrap(t);
+    if (bad_location(x, y, nlx, nly, nhx, nhy)) {
+	if (!oneshot) {
+	    return FALSE;		/* caller should try again */
+	} else {
+	    /* Must make do with the only location possible;
+	       avoid failure due to a misplaced trap.
+	       It might still fail if there's a dungeon feature here. */
+	    struct trap *t = t_at(x,y);
+
+	    if (t && t->ttyp != MAGIC_PORTAL) deltrap(t);
+	    if (bad_location(x, y, nlx, nly, nhx, nhy)) return FALSE;
+	}
     }
     switch (rtype) {
     case LR_TELE:
@@ -412,7 +417,7 @@
 	croom = &rooms[0]; /* only one room on the medusa level */
 	for (tryct = rnd(4); tryct; tryct--) {
 	    x = somex(croom); y = somey(croom);
-	    if (goodpos(x, y, (struct monst *)0)) {
+	    if (goodpos(x, y, (struct monst *)0, 0)) {
 		otmp = mk_tt_object(STATUE, x, y);
 		while (otmp && (poly_when_stoned(&mons[otmp->corpsenm]) ||
 				pm_resistance(&mons[otmp->corpsenm],MR_STONE))) {
diff -Naurd ../nethack-3.4.0/src/mkobj.c ./src/mkobj.c
--- ../nethack-3.4.0/src/mkobj.c Wed Mar 20 23:43:10 2002
+++ ./src/mkobj.c Mon Feb 24 15:25:05 2003
@@ -1,9 +1,8 @@
-/*	SCCS Id: @(#)mkobj.c	3.4	2001/12/03	*/
+/*	SCCS Id: @(#)mkobj.c	3.4	2002/10/07	*/
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /* NetHack may be freely redistributed.  See license for details. */
 
 #include "hack.h"
-#include "artifact.h"
 #include "prop.h"
 
 STATIC_DCL void FDECL(mkbox_cnts,(struct obj *));
@@ -17,6 +16,8 @@
 #endif
 #endif /* OVL1 */
 
+extern struct obj *thrownobj;		/* defined in dothrow.c */
+
 /*#define DEBUG_EFFECTS*/	/* show some messages for debugging */
 
 struct icp {
@@ -46,7 +47,7 @@
 {18, POTION_CLASS},
 {18, SCROLL_CLASS},
 {12, SPBOOK_CLASS},
-{ 7, GOLD_CLASS},
+{ 7, COIN_CLASS},
 { 6, WAND_CLASS},
 { 5, RING_CLASS},
 { 1, AMULET_CLASS}
@@ -175,7 +176,7 @@
 		if (!(otmp = mkobj(iprobs->iclass, TRUE))) continue;
 
 		/* handle a couple of special cases */
-		if (otmp->oclass == GOLD_CLASS) {
+		if (otmp->oclass == COIN_CLASS) {
 		    /* 2.5 x level's usual amount; weight adjusted below */
 		    otmp->quan = (long)(rnd(level_difficulty()+2) * rnd(75));
 		    otmp->owt = weight(otmp);
@@ -609,7 +610,7 @@
 						    mkobj(SPBOOK_CLASS,FALSE));
 		}
 		break;
-	case GOLD_CLASS:
+	case COIN_CLASS:
 		break;	/* do nothing */
 	default:
 		impossible("impossible mkobj %d, sym '%c'.", otmp->otyp,
@@ -679,10 +680,12 @@
 bless(otmp)
 register struct obj *otmp;
 {
+#ifdef GOLDOBJ
+	if (otmp->oclass == COIN_CLASS) return;
+#endif
 	otmp->cursed = 0;
 	otmp->blessed = 1;
-	if (otmp->otyp == LUCKSTONE
-		|| (otmp->oartifact && spec_ability(otmp, SPFX_LUCK)))
+	if (carried(otmp) && confers_luck(otmp))
 	    set_moreluck();
 	else if (otmp->otyp == BAG_OF_HOLDING)
 	    otmp->owt = weight(otmp);
@@ -696,8 +699,7 @@
 register struct obj *otmp;
 {
 	otmp->blessed = 0;
-	if (otmp->otyp == LUCKSTONE
-		|| (otmp->oartifact && spec_ability(otmp, SPFX_LUCK)))
+	if (carried(otmp) && confers_luck(otmp))
 	    set_moreluck();
 	else if (otmp->otyp == BAG_OF_HOLDING)
 	    otmp->owt = weight(otmp);
@@ -707,20 +709,29 @@
 curse(otmp)
 register struct obj *otmp;
 {
+#ifdef GOLDOBJ
+	if (otmp->oclass == COIN_CLASS) return;
+#endif
 	otmp->blessed = 0;
 	otmp->cursed = 1;
-	if (otmp->otyp == LUCKSTONE
-		|| (otmp->oartifact && spec_ability(otmp, SPFX_LUCK)))
+	/* welded two-handed weapon interferes with some armor removal */
+	if (otmp == uwep && bimanual(uwep)) reset_remarm();
+	/* rules at top of wield.c state that twoweapon cannot be done
+	   with cursed alternate weapon */
+	if (otmp == uswapwep && u.twoweap)
+	    drop_uswapwep();
+	/* some cursed items need immediate updating */
+	if (carried(otmp) && confers_luck(otmp))
 	    set_moreluck();
 	else if (otmp->otyp == BAG_OF_HOLDING)
 	    otmp->owt = weight(otmp);
 	else if (otmp->otyp == FIGURINE) {
 		if (otmp->corpsenm != NON_PM
-	    	    && !dead_species(otmp->corpsenm,TRUE)
+		    && !dead_species(otmp->corpsenm,TRUE)
 		    && (carried(otmp) || mcarried(otmp)))
 			attach_fig_transform_timeout(otmp);
 	}
- 	return;
+	return;
 }
 
 void
@@ -728,13 +739,12 @@
 register struct obj *otmp;
 {
 	otmp->cursed = 0;
-	if (otmp->otyp == LUCKSTONE
-		|| (otmp->oartifact && spec_ability(otmp, SPFX_LUCK)))
+	if (carried(otmp) && confers_luck(otmp))
 	    set_moreluck();
 	else if (otmp->otyp == BAG_OF_HOLDING)
-		otmp->owt = weight(otmp);
+	    otmp->owt = weight(otmp);
 	else if (otmp->otyp == FIGURINE && otmp->timed)
-		(void) stop_timer(FIG_TRANSFORM, (genericptr_t) otmp);
+	    (void) stop_timer(FIG_TRANSFORM, (genericptr_t) otmp);
 	return;
 }
 
@@ -830,7 +840,7 @@
 		return wt;
 	} else if (obj->oclass == FOOD_CLASS && obj->oeaten) {
 		return eaten_stat((int)obj->quan * wt, obj);
-	} else if (obj->oclass == GOLD_CLASS)
+	} else if (obj->oclass == COIN_CLASS)
 		return (int)((obj->quan + 50L) / 100L);
 	else if (obj->otyp == HEAVY_IRON_BALL && obj->owt != 0)
 		return((int)(obj->owt));	/* kludge for "very" heavy iron ball */
@@ -1475,6 +1485,8 @@
     if (obj_sheds_light(obj))
 	del_light_source(LS_OBJECT, (genericptr_t) obj);
 
+    if (obj == thrownobj) thrownobj = (struct obj*)0;
+
     free((genericptr_t) obj);
 }
 
diff -Naurd ../nethack-3.4.0/src/mon.c ./src/mon.c
--- ../nethack-3.4.0/src/mon.c Wed Mar 20 23:43:10 2002
+++ ./src/mon.c Mon Feb 24 15:25:05 2003
@@ -254,6 +254,16 @@
 	if (mtmp->mnamelth)
 	    obj = oname(obj, NAME(mtmp));
 
+	/* Avoid "It was hidden under a green mold corpse!" 
+	 *  during Blind combat. An unseen monster referred to as "it"
+	 *  could be killed and leave a corpse.  If a hider then hid
+	 *  underneath it, you could be told the corpse type of a
+	 *  monster that you never knew was there without this.
+	 *  The code in hitmu() substitutes the word "something"
+	 *  if the corpses obj->dknown is 0.
+	 */
+	if (Blind && !sensemon(mtmp)) obj->dknown = 0;
+
 #ifdef INVISIBLE_OBJECTS
 	/* Invisible monster ==> invisible corpse */
 	obj->oinvis = mtmp->minvis;
@@ -276,7 +286,7 @@
 	if(!Blind && uwep &&
 	    (warnlevel > lastwarnlev || moves > lastwarntime + warnDelay)) {
 	    Your("%s %s!", aobjnam(uwep, "glow"),
-		hcolor(light_blue));
+		hcolor(NH_LIGHT_BLUE));
 	    lastwarnlev = warnlevel;
 	    lastwarntime = moves;
 	}
@@ -370,7 +380,9 @@
 	if (!is_clinger(mtmp->data) && !likes_lava(mtmp->data)) {
 	    if (!resists_fire(mtmp)) {
 		if (cansee(mtmp->mx,mtmp->my))
-		    pline("%s burns to a crisp.", Monnam(mtmp));
+		    pline("%s %s.", Monnam(mtmp),
+			  mtmp->data == &mons[PM_WATER_ELEMENTAL] ?
+			  "boils away" : "burns to a crisp");
 		mondead(mtmp);
 	    }
 	    else {
@@ -400,6 +412,12 @@
 	    if (cansee(mtmp->mx,mtmp->my)) {
 		    pline("%s drowns.", Monnam(mtmp));
 	    }
+	    if (u.ustuck && u.uswallow && u.ustuck == mtmp) {
+	    /* This can happen after a purple worm plucks you off a
+		flying steed while you are over water. */
+		pline("%s sinks as water rushes in and flushes you out.",
+			Monnam(mtmp));
+	    }
 	    mondead(mtmp);
 	    if (mtmp->mhp > 0) {
 		rloc(mtmp);
@@ -457,12 +475,19 @@
     for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
 	if (DEADMONSTER(mtmp)) continue;
 
+	/* must check non-moving monsters once/turn in case
+	 * they managed to end up in liquid */
+	if (mtmp->data->mmove == 0) {
+	    if (vision_full_recalc) vision_recalc(0);
+	    if (minliquid(mtmp)) continue;
+	}
+
 	/* regenerate hit points */
 	mon_regen(mtmp, FALSE);
 
 	/* possibly polymorph shapechangers and lycanthropes */
 	if (mtmp->cham && !rn2(6))
-	    (void) newcham(mtmp, (struct permonst *)0, FALSE);
+	    (void) newcham(mtmp, (struct permonst *)0, FALSE, FALSE);
 	were_change(mtmp);
 
 	/* gradually time out temporary problems */
@@ -642,7 +667,8 @@
 			delobj(otmp);
 			ptr = mtmp->data;
 			if (poly) {
-			    if (newcham(mtmp, (struct permonst *)0, FALSE))
+			    if (newcham(mtmp, (struct permonst *)0,
+					FALSE, FALSE))
 				ptr = mtmp->data;
 			} else if (grow) {
 			    ptr = grow_up(mtmp, (struct monst *)0);
@@ -727,7 +753,8 @@
 		delobj(otmp);		/* munch */
 		ptr = mtmp->data;
 		if (poly) {
-		    if (newcham(mtmp, (struct permonst *)0, FALSE)) ptr = mtmp->data;
+		    if (newcham(mtmp, (struct permonst *)0, FALSE, FALSE))
+			ptr = mtmp->data;
 		} else if (grow) {
 		    ptr = grow_up(mtmp, (struct monst *)0);
 		} else if (heal) {
@@ -766,21 +793,21 @@
 	register struct monst *mtmp;
 {
     register struct obj *gold;
+    int mat_idx;
 
     if ((gold = g_at(mtmp->mx, mtmp->my)) != 0) {
+	mat_idx = objects[gold->otyp].oc_material;
 #ifndef GOLDOBJ
 	mtmp->mgold += gold->quan;
 	delobj(gold);
-	if (cansee(mtmp->mx, mtmp->my) ) {
-	    if (flags.verbose && !mtmp->isgd)
-		pline("%s picks up some gold.", Monnam(mtmp));
 #else
         obj_extract_self(gold);
         add_to_minv(mtmp, gold);
+#endif
 	if (cansee(mtmp->mx, mtmp->my) ) {
 	    if (flags.verbose && !mtmp->isgd)
-		pline("%s picks up some money.", Monnam(mtmp));
-#endif
+		pline("%s picks up some %s.", Monnam(mtmp),
+			mat_idx == GOLD ? "gold" : "money");
 	    newsym(mtmp->mx, mtmp->my);
 	}
     }
@@ -934,6 +961,7 @@
 	register uchar ntyp;
 	uchar nowtyp;
 	boolean wantpool,poolok,lavaok,nodiag;
+	boolean rockok = FALSE, treeok = FALSE, thrudoor;
 	int maxx, maxy;
 
 	x = mon->mx;
@@ -945,6 +973,27 @@
 	poolok = is_flyer(mdat) || is_clinger(mdat) ||
 		 (is_swimmer(mdat) && !wantpool);
 	lavaok = is_flyer(mdat) || is_clinger(mdat) || likes_lava(mdat);
+	thrudoor = ((flag & (ALLOW_WALL|BUSTDOOR)) != 0L);
+	if (flag & ALLOW_DIG) {
+	    struct obj *mw_tmp;
+
+	    /* need to be specific about what can currently be dug */
+	    if (!needspick(mdat)) {
+		rockok = treeok = TRUE;
+	    } else if ((mw_tmp = MON_WEP(mon)) && mw_tmp->cursed &&
+		       mon->weapon_check == NO_WEAPON_WANTED) {
+		rockok = is_pick(mw_tmp);
+		treeok = is_axe(mw_tmp);
+	    } else {
+		rockok = (m_carrying(mon, PICK_AXE) ||
+			  (m_carrying(mon, DWARVISH_MATTOCK) &&
+			   !which_armor(mon, W_ARMS)));
+		treeok = (m_carrying(mon, AXE) ||
+			  (m_carrying(mon, BATTLE_AXE) &&
+			   !which_armor(mon, W_ARMS)));
+	    }
+	    thrudoor |= rockok || treeok;
+	}
 
 nexttry:	/* eels prefer the water, but if there is no water nearby,
 		   they will crawl over land */
@@ -961,14 +1010,13 @@
 	    if(nx == x && ny == y) continue;
 	    if(IS_ROCK(ntyp = levl[nx][ny].typ) &&
 	       !((flag & ALLOW_WALL) && may_passwall(nx,ny)) &&
-	       !((flag & ALLOW_DIG) && may_dig(nx,ny))) continue;
+	       !((IS_TREE(ntyp) ? treeok : rockok) && may_dig(nx,ny))) continue;
 	    /* KMH -- Added iron bars */
-	    if (ntyp == IRONBARS &&
-	    	!((flag & ALLOW_WALL) && may_passwall(nx,ny))) continue;
+	    if (ntyp == IRONBARS && !(flag & ALLOW_BARS)) continue;
 	    if(IS_DOOR(ntyp) && !amorphous(mdat) &&
 	       ((levl[nx][ny].doormask & D_CLOSED && !(flag & OPENDOOR)) ||
-		(levl[nx][ny].doormask & D_LOCKED && !(flag & UNLOCKDOOR))
-	       ) && !(flag & (ALLOW_WALL|ALLOW_DIG|BUSTDOOR))) continue;
+		(levl[nx][ny].doormask & D_LOCKED && !(flag & UNLOCKDOOR))) &&
+	       !thrudoor) continue;
 	    if(nx != x && ny != y && (nodiag ||
 #ifdef REINCARNATION
 	       ((IS_DOOR(nowtyp) &&
@@ -1288,21 +1336,17 @@
 			pline("%s medallion begins to glow!",
 				s_suffix(Monnam(mtmp)));
 			makeknown(AMULET_OF_LIFE_SAVING);
-			pline("%s looks much better!", Monnam(mtmp));
+			if (attacktype(mtmp->data, AT_EXPL)
+			    || attacktype(mtmp->data, AT_BOOM))
+				pline("%s reconstitutes!", Monnam(mtmp));
+			else
+				pline("%s looks much better!", Monnam(mtmp));
 			pline_The("medallion crumbles to dust!");
 		}
 		m_useup(mtmp, lifesave);
 		mtmp->mcanmove = 1;
 		mtmp->mfrozen = 0;
 		if (mtmp->mtame && !mtmp->isminion) {
-			struct edog *edog = EDOG(mtmp);
-			if (edog->hungrytime < moves+500)
-				edog->hungrytime = moves+500;
-			if (edog->mhpmax_penalty) {
-				/* was starving */
-				mtmp->mhpmax += edog->mhpmax_penalty;
-				edog->mhpmax_penalty = 0;
-			}
 			wary_dog(mtmp, FALSE);
 		}
 		if (mtmp->mhpmax <= 0) mtmp->mhpmax = 10;
@@ -1419,13 +1463,13 @@
 	    	else if(mdat->mattk[i].damd)
 	    	    tmp = d((int)mdat->mlevel+1, (int)mdat->mattk[i].damd);
 	    	else tmp = 0;
-		if (Half_physical_damage) tmp = (tmp+1) / 2;
 		if (was_swallowed && magr) {
 		    if (magr == &youmonst) {
 			There("is an explosion in your %s!",
 			      body_part(STOMACH));
 			Sprintf(killer_buf, "%s explosion",
 				s_suffix(mdat->mname));
+			if (Half_physical_damage) tmp = (tmp+1) / 2;
 			losehp(tmp, killer_buf, KILLED_BY_AN);
 		    } else {
 			if (flags.soundok) You_hear("an explosion.");
@@ -1473,7 +1517,8 @@
 	mondead(mdef);
 	if (mdef->mhp > 0) return;	/* lifesaved */
 
-	if (corpse_chance(mdef, (struct monst *)0, FALSE))
+	if (corpse_chance(mdef, (struct monst *)0, FALSE) &&
+	    (accessible(mdef->mx, mdef->my) || is_pool(mdef->mx, mdef->my)))
 		(void) make_corpse(mdef);
 }
 
@@ -1500,7 +1545,7 @@
 monstone(mdef)
 register struct monst *mdef;
 {
-	struct obj *otmp, *obj;
+	struct obj *otmp, *obj, *oldminvent;
 	xchar x = mdef->mx, y = mdef->my;
 	boolean wasinside = FALSE;
 
@@ -1515,12 +1560,12 @@
 
 	if ((int)mdef->data->msize > MZ_TINY ||
 		    !rn2(2 + ((int) (mdef->data->geno & G_FREQ) > 2))) {
-		otmp = mkcorpstat(STATUE, KEEPTRAITS(mdef) ? mdef : 0,
-				  mdef->data, x, y, FALSE);
-		if (mdef->mnamelth) otmp = oname(otmp, NAME(mdef));
+		oldminvent = 0;
 		/* some objects may end up outside the statue */
 		while ((obj = mdef->minvent) != 0) {
 		    obj_extract_self(obj);
+		    if (obj->owornmask)
+			update_mon_intrinsics(mdef, obj, FALSE, TRUE);
 		    obj_no_longer_held(obj);
 		    if (obj->owornmask & W_WEP)
 			setmnotwielded(mdef,obj);
@@ -1534,9 +1579,20 @@
 			place_object(obj, x, y);
 		    } else {
 			if (obj->lamplit) end_burn(obj, TRUE);
-			(void) add_to_container(otmp, obj);
+			obj->nobj = oldminvent;
+			oldminvent = obj;
 		    }
 		}
+		/* defer statue creation until after inventory removal
+		   so that saved monster traits won't retain any stale
+		   item-conferred attributes */
+		otmp = mkcorpstat(STATUE, KEEPTRAITS(mdef) ? mdef : 0,
+				  mdef->data, x, y, FALSE);
+		if (mdef->mnamelth) otmp = oname(otmp, NAME(mdef));
+		while ((obj = oldminvent) != 0) {
+		    oldminvent = obj->nobj;
+		    (void) add_to_container(otmp, obj);
+		}
 #ifndef GOLDOBJ
 		if (mdef->mgold) {
 			struct obj *au;
@@ -1707,8 +1763,9 @@
 		redisp = TRUE;
 	}
 #endif
-	if(!accessible(x, y) && !is_pool(x, y)) {
-	    /* might be mimic in wall or corpse in lava */
+	if((!accessible(x, y) && !is_pool(x, y)) ||
+	   (x == u.ux && y == u.uy)) {
+	    /* might be mimic in wall or corpse in lava or on player's spot */
 	    redisp = TRUE;
 	    if(wasinside) spoteffects(TRUE);
 	} else if(x != u.ux || y != u.uy) {
@@ -1803,7 +1860,7 @@
 	/* it's a golem, and not a stone golem */
 	if(canseemon(mtmp))
 	    pline("%s solidifies...", Monnam(mtmp));
-	if (newcham(mtmp, &mons[PM_STONE_GOLEM], FALSE)) {
+	if (newcham(mtmp, &mons[PM_STONE_GOLEM], FALSE, FALSE)) {
 	    if(canseemon(mtmp))
 		pline("Now it's %s.", an(mtmp->data->mname));
 	} else {
@@ -1862,7 +1919,7 @@
 	newx = x;
 	newy = y;
 
-	if (!goodpos(newx, newy, mtmp)) {
+	if (!goodpos(newx, newy, mtmp, 0)) {
 		/* actually we have real problems if enexto ever fails.
 		 * migrating_mons that need to be placed will cause
 		 * no end of trouble.
@@ -2025,6 +2082,10 @@
 	mtmp->meating = 0;	/* assume there's no salvagable food left */
 	setmangry(mtmp);
 	if(mtmp->m_ap_type) seemimic(mtmp);
+	else if (flags.forcefight && !flags.mon_moving && mtmp->mundetected) {
+	    mtmp->mundetected = 0;
+	    newsym(mtmp->mx, mtmp->my);
+	}
 }
 
 /* Wake up nearby monsters. */
@@ -2061,16 +2122,21 @@
 seemimic(mtmp)
 register struct monst *mtmp;
 {
+	unsigned old_app = mtmp->mappearance;
+	uchar old_ap_type = mtmp->m_ap_type;
+
+	mtmp->m_ap_type = M_AP_NOTHING;
+	mtmp->mappearance = 0;
+
 	/*
 	 *  Discovered mimics don't block light.
 	 */
-	if ((mtmp->m_ap_type == M_AP_FURNITURE &&
-		(mtmp->mappearance==S_hcdoor || mtmp->mappearance==S_vcdoor))||
-	    (mtmp->m_ap_type == M_AP_OBJECT && mtmp->mappearance == BOULDER))
-	    unblock_point(mtmp->mx,mtmp->my);
+	if (((old_ap_type == M_AP_FURNITURE &&
+	      (old_app == S_hcdoor || old_app == S_vcdoor)) ||
+	     (old_ap_type == M_AP_OBJECT && old_app == BOULDER)) &&
+	    !does_block(mtmp->mx, mtmp->my, &levl[mtmp->mx][mtmp->my]))
+	    unblock_point(mtmp->mx, mtmp->my);
 
-	mtmp->m_ap_type = M_AP_NOTHING;
-	mtmp->mappearance = 0;
 	newsym(mtmp->mx,mtmp->my);
 }
 
@@ -2086,7 +2152,8 @@
 		mcham = (int) mtmp->cham;
 		if (mcham) {
 			mtmp->cham = CHAM_ORDINARY;
-			(void) newcham(mtmp, &mons[cham_to_pm[mcham]], FALSE);
+			(void) newcham(mtmp, &mons[cham_to_pm[mcham]],
+				       FALSE, FALSE);
 		}
 		if(is_were(mtmp->data) && mtmp->data->mlet != S_HUMAN)
 			new_were(mtmp);
@@ -2129,7 +2196,7 @@
 	    mcham = (int) mon->cham;
 	    if (mcham) {
 		mon->cham = CHAM_ORDINARY;
-		(void) newcham(mon, &mons[cham_to_pm[mcham]], FALSE);
+		(void) newcham(mon, &mons[cham_to_pm[mcham]], FALSE, FALSE);
 	    } else if (is_were(mon->data) && !is_human(mon->data)) {
 		new_were(mon);
 	    }
@@ -2249,14 +2316,23 @@
 
 /* make a chameleon look like a new monster; returns 1 if it actually changed */
 int
-newcham(mtmp, mdat, polyspot)
+newcham(mtmp, mdat, polyspot, msg)
 struct monst *mtmp;
 struct permonst *mdat;
 boolean polyspot;	/* change is the result of wand or spell of polymorph */
+boolean msg;		/* "The oldmon turns into a newmon!" */
 {
 	int mhp, hpn, hpd;
 	int mndx, tryct;
 	struct permonst *olddata = mtmp->data;
+	char oldname[BUFSZ];
+
+	if (msg) {
+	    /* like Monnam() but never mention saddle */
+	    Strcpy(oldname, x_monnam(mtmp, ARTICLE_THE, (char *)0,
+				     SUPPRESS_SADDLE, FALSE));
+	    oldname[0] = highc(oldname[0]);
+	}
 
 	/* mdat = 0 -> caller wants a random monster shape */
 	tryct = 0;
@@ -2363,6 +2439,9 @@
 					mtmp->mhp = 1;  /* almost dead */
 				}
 				expels(mtmp, olddata, FALSE);
+			} else {
+				/* update swallow glyphs for new monster */
+				swallowed(0);
 			}
 		} else if (!sticks(mdat) && !sticks(youmonst.data))
 			unstuck(mtmp);
@@ -2385,11 +2464,20 @@
 
 	newsym(mtmp->mx,mtmp->my);
 
+	if (msg) {
+	    uchar save_mnamelth = mtmp->mnamelth;
+	    mtmp->mnamelth = 0;
+	    pline("%s turns into %s!", oldname,
+		  mdat == &mons[PM_GREEN_SLIME] ? "slime" :
+		  x_monnam(mtmp, ARTICLE_A, (char*)0, SUPPRESS_SADDLE, FALSE));
+	    mtmp->mnamelth = save_mnamelth;
+	}
+
+	possibly_unwield(mtmp, polyspot);	/* might lose use of weapon */
 	mon_break_armor(mtmp, polyspot);
 	if (!(mtmp->misc_worn_check & W_ARMG))
 	    mselftouch(mtmp, "No longer petrify-resistant, ",
 			!flags.mon_moving);
-	possibly_unwield(mtmp);
 	m_dowear(mtmp, FALSE);
 
 	/* This ought to re-test can_carry() on each item in the inventory
@@ -2430,6 +2518,11 @@
 can_be_hatched(mnum)
 int mnum;
 {
+    /* ranger quest nemesis has the oviparous bit set, making it
+       be possible to wish for eggs of that unique monster; turn
+       such into ordinary eggs rather than forbidding them outright */
+    if (mnum == PM_SCORPIUS) mnum = PM_SCORPION;
+
     mnum = little_to_big(mnum);
     /*
      * Queen bees lay killer bee eggs (usually), but killer bees don't
@@ -2535,7 +2628,7 @@
 	    mndx = monsndx(mtmp->data);
 	    if ((mvitals[mndx].mvflags & G_GENOD) || kill_cham[mtmp->cham]) {
 		if (mtmp->cham && !kill_cham[mtmp->cham])
-		    (void) newcham(mtmp, (struct permonst *)0, FALSE);
+		    (void) newcham(mtmp, (struct permonst *)0, FALSE, FALSE);
 		else
 		    mondead(mtmp);
 	    }
@@ -2634,6 +2727,28 @@
 	    mtmp->mpeaceful = 1;
 	}
 }
+
+void
+mimic_hit_msg(mtmp, otyp)
+struct monst *mtmp;
+short otyp;
+{
+	short ap = mtmp->mappearance;
+
+	switch(mtmp->m_ap_type) {
+	    case M_AP_NOTHING:			
+	    case M_AP_FURNITURE:
+	    case M_AP_MONSTER:
+		break;
+	    case M_AP_OBJECT:
+		if (otyp == SPE_HEALING || otyp == SPE_EXTRA_HEALING) {
+		    pline("%s seems a more vivid %s than before.",
+				The(simple_typename(ap)),
+				c_obj_colors[objects[ap].oc_color]);
+		}
+		break;
+	}
+}
 #endif /* OVLB */
 
 /*mon.c*/
diff -Naurd ../nethack-3.4.0/src/mondata.c ./src/mondata.c
--- ../nethack-3.4.0/src/mondata.c Wed Mar 20 23:43:10 2002
+++ ./src/mondata.c Mon Feb 24 15:25:05 2003
@@ -6,10 +6,6 @@
 #include "eshk.h"
 #include "epri.h"
 
-/* fake attack and damage types */
-#define AT_ANY (-1)
-#define AD_ANY (-1)
-
 /*	These routines provide basic data for any type of monster. */
 
 #ifdef OVLB
@@ -251,6 +247,16 @@
 		(ptr->mlet==S_IMP && ptr != &mons[PM_TENGU])));
 }
 
+/* true iff the type of monster pass through iron bars */
+boolean
+passes_bars(mptr)
+struct permonst *mptr;
+{
+    return (boolean) (passes_walls(mptr) || amorphous(mptr) ||
+		      is_whirly(mptr) || verysmall(mptr) ||
+		      (slithy(mptr) && !bigmonst(mptr)));
+}
+
 #endif /* OVL0 */
 #ifdef OVL1
 
@@ -295,6 +301,28 @@
 		attacktype(ptr,AT_HUGS)));
 }
 
+/* number of horns this type of monster has on its head */
+int
+num_horns(ptr)
+struct permonst *ptr;
+{
+    switch (monsndx(ptr)) {
+    case PM_HORNED_DEVIL:	/* ? "more than one" */
+    case PM_MINOTAUR:
+    case PM_ASMODEUS:
+    case PM_BALROG:
+	return 2;
+    case PM_WHITE_UNICORN:
+    case PM_GRAY_UNICORN:
+    case PM_BLACK_UNICORN:
+    case PM_KI_RIN:
+	return 1;
+    default:
+	break;
+    }
+    return 0;
+}
+
 struct attack *
 dmgtype_fromattack(ptr, dtyp, atyp)
 struct permonst *ptr;
@@ -359,7 +387,7 @@
 		/* ought to switch this to use `fmt_ptr' */
 	    panic("monsndx - could not index monster (%lx)",
 		  (unsigned long)ptr);
-	    return FALSE;		/* will not get here */
+	    return NON_PM;		/* will not get here */
 	}
 
 	return(i);
@@ -521,6 +549,11 @@
 	{PM_KOBOLD, PM_LARGE_KOBOLD}, {PM_LARGE_KOBOLD, PM_KOBOLD_LORD},
 	{PM_GNOME, PM_GNOME_LORD}, {PM_GNOME_LORD, PM_GNOME_KING},
 	{PM_DWARF, PM_DWARF_LORD}, {PM_DWARF_LORD, PM_DWARF_KING},
+	{PM_MIND_FLAYER, PM_MASTER_MIND_FLAYER},
+	{PM_ORC, PM_ORC_CAPTAIN}, {PM_HILL_ORC, PM_ORC_CAPTAIN},
+	{PM_MORDOR_ORC, PM_ORC_CAPTAIN}, {PM_URUK_HAI, PM_ORC_CAPTAIN},
+	{PM_SEWER_RAT, PM_GIANT_RAT},
+	{PM_CAVE_SPIDER, PM_GIANT_SPIDER},
 	{PM_OGRE, PM_OGRE_LORD}, {PM_OGRE_LORD, PM_OGRE_KING},
 	{PM_ELF, PM_ELF_LORD}, {PM_WOODLAND_ELF, PM_ELF_LORD},
 	{PM_GREEN_ELF, PM_ELF_LORD}, {PM_GREY_ELF, PM_ELF_LORD},
@@ -605,6 +638,19 @@
 	return montype;
 }
 
+/*
+ * Return the permonst ptr for the race of the monster.
+ * Returns correct pointer for non-polymorphed and polymorphed
+ * player.  It does not return a pointer to player role character.
+ */
+const struct permonst *
+raceptr(mtmp)
+struct monst *mtmp;
+{
+    if (mtmp == &youmonst && !Upolyd) return(&mons[urace.malenum]);
+    else return(mtmp->data);
+}
+
 static const char *levitate[4]	= { "float", "Float", "wobble", "Wobble" };
 static const char *flys[4]	= { "fly", "Fly", "flutter", "Flutter" };
 static const char *flyl[4]	= { "fly", "Fly", "stagger", "Stagger" };
@@ -653,6 +699,45 @@
 
 }
 
+/* return a phrase describing the effect of fire attack on a type of monster */
+const char *
+on_fire(mptr, mattk)
+struct permonst *mptr;
+struct attack *mattk;
+{
+    const char *what;
+
+    switch (monsndx(mptr)) {
+    case PM_FLAMING_SPHERE:
+    case PM_FIRE_VORTEX:
+    case PM_FIRE_ELEMENTAL:
+	what = "already on fire";
+	break;
+    case PM_WATER_ELEMENTAL:
+    case PM_FOG_CLOUD:
+    case PM_STEAM_VORTEX:
+	what = "boiling";
+	break;
+    case PM_ICE_VORTEX:
+    case PM_GLASS_GOLEM:
+	what = "melting";
+	break;
+    case PM_STONE_GOLEM:
+    case PM_CLAY_GOLEM:
+    case PM_GOLD_GOLEM:
+    case PM_AIR_ELEMENTAL:
+    case PM_EARTH_ELEMENTAL:
+    case PM_DUST_VORTEX:
+    case PM_ENERGY_VORTEX:
+	what = "heating up";
+	break;
+    default:
+	what = (mattk->aatyp == AT_HUGS) ? "being roasted" : "on fire";
+	break;
+    }
+    return what;
+}
+
 #endif /* OVLB */
 
 /*mondata.c*/
diff -Naurd ../nethack-3.4.0/src/monmove.c ./src/monmove.c
--- ../nethack-3.4.0/src/monmove.c Wed Mar 20 23:43:11 2002
+++ ./src/monmove.c Mon Feb 24 15:25:05 2003
@@ -1,10 +1,11 @@
-/*	SCCS Id: @(#)monmove.c	3.4	2000/08/16	*/
+/*	SCCS Id: @(#)monmove.c	3.4	2002/04/06	*/
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /* NetHack may be freely redistributed.  See license for details. */
 
 #include "hack.h"
 #include "mfndpos.h"
 #include "artifact.h"
+#include "epri.h"
 
 extern boolean notonhead;
 
@@ -48,10 +49,9 @@
 watch_on_duty(mtmp)
 register struct monst *mtmp;
 {
-	register s_level *slev = Is_special(&u.uz);
 	int	x, y;
 
-	if(slev && slev->flags.town && mtmp->mpeaceful &&
+	if(mtmp->mpeaceful && in_town(u.ux+u.dx, u.uy+u.dy) &&
 	   mtmp->mcansee && m_canseeu(mtmp) && !rn2(3)) {
 
 	    if(picking_lock(&x, &y) && IS_DOOR(levl[x][y].typ) &&
@@ -131,9 +131,9 @@
 struct monst *mtmp;
 {
 	if (mtmp->isshk || mtmp->isgd || mtmp->iswiz || !mtmp->mcansee ||
-			mtmp->mpeaceful || mtmp->data->mlet == S_HUMAN ||
-			is_lminion(mtmp->data) || is_rider(mtmp->data) ||
-			mtmp->data == &mons[PM_MINOTAUR])
+	    mtmp->mpeaceful || mtmp->data->mlet == S_HUMAN ||
+	    is_lminion(mtmp) || mtmp->data == &mons[PM_ANGEL] ||
+	    is_rider(mtmp->data) || mtmp->data == &mons[PM_MINOTAUR])
 		return(FALSE);
 
 	return (boolean)(sobj_at(SCR_SCARE_MONSTER, x, y)
@@ -491,7 +491,7 @@
 		/* arbitrary distance restriction to keep monster far away
 		   from you from having cast dozens of sticks-to-snakes
 		   or similar spells by the time you reach it */
-		if (dist2(mtmp->mx, mtmp->my, u.ux, u.uy) <= 64 && !mtmp->mspec_used) {
+		if (dist2(mtmp->mx, mtmp->my, u.ux, u.uy) <= 49 && !mtmp->mspec_used) {
 		    struct attack *a;
 
 		    for (a = &mdat->mattk[0]; a < &mdat->mattk[NATTK]; a++) {
@@ -625,12 +625,10 @@
 	/* Not necessary if m_move called from this file, but necessary in
 	 * other calls of m_move (ex. leprechauns dodging)
 	 */
-	can_tunnel = tunnels(ptr) &&
 #ifdef REINCARNATION
-		!Is_rogue_level(&u.uz) &&
+	if (!Is_rogue_level(&u.uz))
 #endif
-		(!needspick(ptr) || m_carrying(mtmp, PICK_AXE) ||
-		(m_carrying(mtmp, DWARVISH_MATTOCK) && !which_armor(mtmp, W_ARMS)));
+	    can_tunnel = tunnels(ptr);
 	can_open = !(nohands(ptr) || verysmall(ptr));
 	can_unlock = ((can_open && m_carrying(mtmp, SKELETON_KEY)) ||
 		      mtmp->iswiz || is_rider(ptr));
@@ -822,7 +820,7 @@
 			 (mtoo->mappearance && !mtoo->iswiz) ||
 			 !mtoo->data->mmove)) continue;
 
-		    if(((likegold && otmp->oclass == GOLD_CLASS) ||
+		    if(((likegold && otmp->oclass == COIN_CLASS) ||
 		       (likeobjs && index(practical, otmp->oclass) &&
 			(otmp->otyp != CORPSE || (ptr->mlet == S_NYMPH
 			   && !is_rider(&mons[otmp->corpsenm])))) ||
@@ -875,9 +873,10 @@
 	}
       }
 
+	/* don't tunnel if hostile and close enough to prefer a weapon */
 	if (can_tunnel && needspick(ptr) &&
-		(mw_tmp = MON_WEP(mtmp)) != 0 && !is_pick(mw_tmp) &&
-		mw_tmp->cursed && mtmp->weapon_check == NO_WEAPON_WANTED)
+	    ((!mtmp->mpeaceful || Conflict) &&
+	     dist2(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy) <= 8))
 	    can_tunnel = FALSE;
 
 	nix = omx;
@@ -890,6 +889,7 @@
 	/* unicorn may not be able to avoid hero on a noteleport level */
 	if (is_unicorn(ptr) && !level.flags.noteleport) flag |= NOTONL;
 	if (passes_walls(ptr)) flag |= (ALLOW_WALL | ALLOW_ROCK);
+	if (passes_bars(ptr)) flag |= ALLOW_BARS;
 	if (can_tunnel) flag |= ALLOW_DIG;
 	if (is_human(ptr) || ptr == &mons[PM_MINOTAUR]) flag |= ALLOW_SSM;
 	if (is_undead(ptr) && ptr->mlet != S_GHOST) flag |= NOGARLIC;
@@ -951,11 +951,20 @@
 	    if (mmoved==1 && (u.ux != nix || u.uy != niy) && itsstuck(mtmp))
 		return(3);
 
-	    if(IS_ROCK(levl[nix][niy].typ) && may_dig(nix,niy) &&
-		    mmoved==1 && can_tunnel && needspick(ptr) &&
-		    (!(mw_tmp = MON_WEP(mtmp)) || !is_pick(mw_tmp))) {
-		mtmp->weapon_check = NEED_PICK_AXE;
-		if (mon_wield_item(mtmp))
+	    if (((IS_ROCK(levl[nix][niy].typ) && may_dig(nix,niy)) ||
+		 closed_door(nix, niy)) &&
+		mmoved==1 && can_tunnel && needspick(ptr)) {
+		if (closed_door(nix, niy)) {
+		    if (!(mw_tmp = MON_WEP(mtmp)) ||
+			!is_pick(mw_tmp) || !is_axe(mw_tmp))
+			mtmp->weapon_check = NEED_PICK_OR_AXE;
+		} else if (IS_TREE(levl[nix][niy].typ)) {
+		    if (!(mw_tmp = MON_WEP(mtmp)) || !is_axe(mw_tmp))
+			mtmp->weapon_check = NEED_AXE;
+		} else if (!(mw_tmp = MON_WEP(mtmp)) || !is_pick(mw_tmp)) {
+		    mtmp->weapon_check = NEED_PICK_AXE;
+		}
+		if (mtmp->weapon_check >= NEED_PICK_AXE && mon_wield_item(mtmp))
 		    return(3);
 	    }
 	    /* If ALLOW_U is set, either it's trying to attack you, or it
@@ -1048,10 +1057,10 @@
 
 		    if(here->doormask & (D_LOCKED|D_CLOSED) && amorphous(ptr)) {
 			if (flags.verbose && canseemon(mtmp))
-			    pline("%s %ss under the door.", Monnam(mtmp),
+			    pline("%s %s under the door.", Monnam(mtmp),
 				  (ptr == &mons[PM_FOG_CLOUD] ||
 				   ptr == &mons[PM_YELLOW_LIGHT])
-				  ? "flow" : "ooze");
+				  ? "flows" : "oozes");
 		    } else if(here->doormask & D_LOCKED && can_unlock) {
 			if(btrapped) {
 			    here->doormask = D_NODOOR;
@@ -1110,6 +1119,12 @@
 			if (*in_rooms(mtmp->mx, mtmp->my, SHOPBASE))
 			    add_damage(mtmp->mx, mtmp->my, 0L);
 		    }
+		} else if (levl[mtmp->mx][mtmp->my].typ == IRONBARS) {
+			if (flags.verbose && canseemon(mtmp))
+			    Norep("%s %s %s the iron bars.", Monnam(mtmp),
+				  /* pluralization fakes verb conjugation */
+				  makeplural(locomotion(ptr, "pass")),
+				  passes_walls(ptr) ? "through" : "between");
 		}
 
 		/* possibly dig */
@@ -1187,6 +1202,9 @@
 			(is_pool(mtmp->mx, mtmp->my) && !Is_waterlevel(&u.uz));
 		newsym(mtmp->mx, mtmp->my);
 	    }
+	    if (mtmp->isshk) {
+		after_shk_move(mtmp);
+	    }
 	}
 	return(mmoved);
 }
@@ -1307,7 +1325,7 @@
 		int typ = obj->otyp;
 
 #ifdef GOLDOBJ
-                if (typ == GOLD_CLASS && obj->quan > 100L) return FALSE;
+                if (typ == COIN_CLASS && obj->quan > 100L) return FALSE;
 #endif
 		if (obj->oclass != GEM_CLASS &&
 		    !(typ >= ARROW && typ <= BOOMERANG) &&
diff -Naurd ../nethack-3.4.0/src/monst.c ./src/monst.c
--- ../nethack-3.4.0/src/monst.c Wed Mar 20 23:43:11 2002
+++ ./src/monst.c Mon Feb 24 15:25:05 2003
@@ -1194,7 +1194,7 @@
 	  NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
 	SIZ(1500, 500, 0, MS_ROAR, MZ_HUGE), 0, 0,
 	M1_FLY|M1_THICK_HIDE|M1_NOHANDS|M1_CARNIVORE,
-	M2_HOSTILE|M2_STRONG|M2_GREEDY|M2_JEWELS, 0, CLR_BRIGHT_CYAN),
+	M2_HOSTILE|M2_STRONG|M2_GREEDY|M2_JEWELS, 0, DRAGON_SILVER),
 #if 0	/* DEFERRED */
     MON("baby shimmering dragon", S_DRAGON,
 	LVL(12, 9, 2, 10, 0), G_GENO,
@@ -1271,7 +1271,7 @@
 	M1_FLY|M1_THICK_HIDE|M1_NOHANDS|M1_SEE_INVIS|M1_OVIPAROUS|
 	  M1_CARNIVORE,
 	M2_HOSTILE|M2_STRONG|M2_NASTY|M2_GREEDY|M2_JEWELS|M2_MAGIC,
-	0, CLR_BRIGHT_CYAN),
+	0, DRAGON_SILVER),
 #if 0	/* DEFERRED */
     MON("shimmering dragon", S_DRAGON,
 	LVL(15, 9, -1, 20, 4), (G_GENO|1),
@@ -2060,7 +2060,7 @@
 	M1_BREATHLESS|M1_WALLWALK|M1_THICK_HIDE|M1_METALLIVORE,
 	M2_HOSTILE|M2_STRONG, 0, CLR_BROWN),
 /*
- * Yeti, apes and other large beasts
+ * Apelike beasts
  */
     MON("monkey", S_YETI,
 	LVL(2, 12, 6, 0, 0), (G_GENO|1),
@@ -3138,7 +3138,7 @@
 	LVL(20, 12, 0, 30, -20), (G_NOGEN|G_UNIQ),
 	A(ATTK(AT_WEAP, AD_PHYS, 2, 6), ATTK(AT_WEAP, AD_PHYS, 2, 6),
 	  ATTK(AT_CLAW, AD_SAMU, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK),
-	SIZ(WT_HUMAN, 400, 0, MS_LEADER, MZ_HUMAN), 0, 0,
+	SIZ(WT_HUMAN, 400, 0, MS_LEADER, MZ_HUMAN), MR_STONE, 0,
 	M1_HUMANOID|M1_OMNIVORE,
 	M2_NOPOLY|M2_HUMAN|M2_PEACEFUL|M2_STRONG|M2_MALE|M2_GREEDY|
 	  M2_JEWELS|M2_COLLECT|M2_MAGIC,
@@ -3189,8 +3189,8 @@
 	A(ATTK(AT_WEAP, AD_PHYS, 8, 4), ATTK(AT_WEAP, AD_PHYS, 4, 6),
 	  ATTK(AT_MAGC, AD_SPEL, 0, 0), ATTK(AT_CLAW, AD_SAMU, 2, 6),
 	  NO_ATTK, NO_ATTK),
-	SIZ(WT_HUMAN, 400, 0, MS_NEMESIS, MZ_LARGE), MR_FIRE|MR_POISON, 0,
-	M1_FLY|M1_SEE_INVIS|M1_POIS,
+	SIZ(WT_HUMAN, 400, 0, MS_NEMESIS, MZ_LARGE),
+	MR_FIRE|MR_POISON|MR_STONE, 0, M1_FLY|M1_SEE_INVIS|M1_POIS,
 	M2_NOPOLY|M2_DEMON|M2_STALK|M2_HOSTILE|M2_STRONG|M2_NASTY|M2_COLLECT,
 	M3_WANTSARTI|M3_WAITFORU|M3_INFRAVISION|M3_INFRAVISIBLE, CLR_RED),
     MON("Thoth Amon", S_HUMAN,
@@ -3198,7 +3198,7 @@
 	A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_MAGC, AD_SPEL, 0, 0),
 	  ATTK(AT_MAGC, AD_SPEL, 0, 0), ATTK(AT_CLAW, AD_SAMU, 1, 4),
 	  NO_ATTK, NO_ATTK),
-	SIZ(WT_HUMAN, 400, 0, MS_NEMESIS, MZ_HUMAN), MR_POISON, 0,
+	SIZ(WT_HUMAN, 400, 0, MS_NEMESIS, MZ_HUMAN), MR_POISON|MR_STONE, 0,
 	M1_HUMANOID|M1_OMNIVORE,
 	M2_NOPOLY|M2_HUMAN|M2_PNAME|M2_STRONG|M2_MALE|M2_STALK|M2_HOSTILE|
 	  M2_NASTY|M2_COLLECT|M2_MAGIC,
@@ -3233,7 +3233,7 @@
 	LVL(18, 12, 0, 0, -15), (G_NOGEN|G_UNIQ),
 	A(ATTK(AT_WEAP, AD_PHYS, 4, 8), ATTK(AT_WEAP, AD_PHYS, 4, 8),
 	  ATTK(AT_CLAW, AD_SAMU, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK),
-	SIZ(1900, 700, 0, MS_NEMESIS, MZ_HUGE), 0, 0,
+	SIZ(1900, 700, 0, MS_NEMESIS, MZ_HUGE), MR_STONE, 0,
 	M1_HUMANOID|M1_OMNIVORE,
 	M2_NOPOLY|M2_GIANT|M2_STRONG|M2_ROCKTHROW|M2_STALK|M2_HOSTILE|
 	  M2_NASTY|M2_MALE|M2_JEWELS|M2_COLLECT,
@@ -3243,7 +3243,8 @@
 	A(ATTK(AT_BREA, AD_FIRE, 8, 6), ATTK(AT_BITE, AD_PHYS, 4, 8),
 	  ATTK(AT_MAGC, AD_SPEL, 0, 0), ATTK(AT_CLAW, AD_PHYS, 2, 4),
 	  ATTK(AT_CLAW, AD_SAMU, 2, 4), NO_ATTK ),
-	SIZ(WT_DRAGON, 1600, 0, MS_NEMESIS, MZ_GIGANTIC), MR_FIRE, MR_FIRE,
+	SIZ(WT_DRAGON, 1600, 0, MS_NEMESIS, MZ_GIGANTIC),
+	MR_FIRE|MR_STONE, MR_FIRE,
 	M1_FLY|M1_THICK_HIDE|M1_NOHANDS|M1_CARNIVORE|M1_SEE_INVIS,
 	M2_NOPOLY|M2_PNAME|M2_HOSTILE|M2_STRONG|M2_NASTY|M2_STALK|
 	  M2_GREEDY|M2_JEWELS|M2_MAGIC,
@@ -3253,7 +3254,8 @@
 	A(ATTK(AT_CLAW, AD_PHYS, 16, 2), ATTK(AT_CLAW, AD_PHYS, 16, 2),
 	  ATTK(AT_MAGC, AD_CLRC, 0, 0), ATTK(AT_CLAW, AD_SAMU, 1, 4),
 	  NO_ATTK, NO_ATTK),
-	SIZ(WT_HUMAN, 400, 0, MS_NEMESIS, MZ_HUMAN), MR_POISON, MR_POISON,
+	SIZ(WT_HUMAN, 400, 0, MS_NEMESIS, MZ_HUMAN),
+	MR_POISON|MR_STONE, MR_POISON,
 	M1_HUMANOID|M1_HERBIVORE|M1_SEE_INVIS,
 	M2_NOPOLY|M2_HUMAN|M2_PNAME|M2_HOSTILE|M2_STRONG|M2_NASTY|
 	  M2_STALK|M2_COLLECT|M2_MAGIC,
@@ -3263,8 +3265,8 @@
 	A(ATTK(AT_WEAP, AD_PHYS, 8, 4), ATTK(AT_WEAP, AD_PHYS, 4, 6),
 	  ATTK(AT_MAGC, AD_SPEL, 0, 0), ATTK(AT_CLAW, AD_SAMU, 2, 6),
 	  NO_ATTK, NO_ATTK),
-	SIZ(WT_HUMAN, 400, 0, MS_NEMESIS, MZ_LARGE), MR_FIRE|MR_POISON, 0,
-	M1_FLY|M1_SEE_INVIS|M1_POIS,
+	SIZ(WT_HUMAN, 400, 0, MS_NEMESIS, MZ_LARGE),
+	MR_FIRE|MR_POISON|MR_STONE, 0, M1_FLY|M1_SEE_INVIS|M1_POIS,
 	M2_NOPOLY|M2_DEMON|M2_PNAME|M2_HOSTILE|M2_STRONG|M2_STALK|
 	  M2_NASTY|M2_COLLECT,
 	M3_WANTSARTI|M3_WAITFORU|M3_INFRAVISION|M3_INFRAVISIBLE, CLR_RED),
@@ -3272,7 +3274,7 @@
 	LVL(15, 12, 10, 0, -15), (G_NOGEN|G_UNIQ),
 	A(ATTK(AT_CLAW, AD_PHYS, 2, 6), ATTK(AT_CLAW, AD_SAMU, 2, 6),
 	  ATTK(AT_STNG, AD_DISE, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK),
-	SIZ(750, 350, 0, MS_NEMESIS, MZ_HUMAN), MR_POISON, MR_POISON,
+	SIZ(750, 350, 0, MS_NEMESIS, MZ_HUMAN), MR_POISON|MR_STONE, MR_POISON,
 	M1_ANIMAL|M1_NOHANDS|M1_OVIPAROUS|M1_POIS|M1_CARNIVORE,
 	M2_NOPOLY|M2_PNAME|M2_HOSTILE|M2_STRONG|M2_STALK|M2_NASTY|
 	  M2_COLLECT|M2_MAGIC,
@@ -3281,7 +3283,7 @@
 	LVL(15, 12, 0, 30, 18), (G_NOGEN|G_UNIQ),
 	A(ATTK(AT_WEAP, AD_DRST, 2, 6), ATTK(AT_WEAP, AD_PHYS, 2, 8),
 	  ATTK(AT_CLAW, AD_SAMU, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK),
-	SIZ(WT_HUMAN, 400, 0, MS_NEMESIS, MZ_HUMAN), 0, 0,
+	SIZ(WT_HUMAN, 400, 0, MS_NEMESIS, MZ_HUMAN), MR_STONE, 0,
 	M1_HUMANOID|M1_OMNIVORE,
 	M2_NOPOLY|M2_HUMAN|M2_STRONG|M2_HOSTILE|M2_STALK|M2_NASTY|
 	  M2_COLLECT|M2_MAGIC,
@@ -3293,7 +3295,7 @@
 	LVL(15, 12, 0, 40, -13), (G_NOGEN|G_UNIQ|G_NOCORPSE),
 	A(ATTK(AT_WEAP, AD_PHYS, 2, 6), ATTK(AT_WEAP, AD_PHYS, 2, 6),
 	  ATTK(AT_CLAW, AD_SAMU, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK),
-	SIZ(WT_HUMAN, 400, 0, MS_NEMESIS, MZ_HUMAN), 0, 0,
+	SIZ(WT_HUMAN, 400, 0, MS_NEMESIS, MZ_HUMAN), MR_STONE, 0,
 	M1_HUMANOID|M1_OMNIVORE,
 	M2_NOPOLY|M2_HUMAN|M2_PNAME|M2_HOSTILE|M2_STRONG|M2_STALK|
 	  M2_NASTY|M2_MALE|M2_COLLECT|M2_MAGIC,
@@ -3307,7 +3309,7 @@
 	LVL(15, 12, 2, 50, 12), (G_NOGEN|G_UNIQ),
 	A(ATTK(AT_WEAP, AD_PHYS, 2,10), ATTK(AT_WEAP, AD_PHYS, 2,10),
 	  ATTK(AT_CLAW, AD_SAMU, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK),
-	SIZ(2250, 850, 0, MS_NEMESIS, MZ_HUGE), MR_FIRE, MR_FIRE,
+	SIZ(2250, 850, 0, MS_NEMESIS, MZ_HUGE), MR_FIRE|MR_STONE, MR_FIRE,
 	M1_HUMANOID|M1_OMNIVORE,
 	M2_NOPOLY|M2_GIANT|M2_MALE|M2_PNAME|M2_HOSTILE|M2_STALK|
 	  M2_STRONG|M2_NASTY|M2_ROCKTHROW|M2_JEWELS|M2_COLLECT,
@@ -3317,7 +3319,7 @@
 	A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_WEAP, AD_PHYS, 1, 6),
 	  ATTK(AT_CLAW, AD_SAMU, 1, 4), ATTK(AT_MAGC, AD_SPEL, 0, 0),
 	  NO_ATTK, NO_ATTK),
-	SIZ(WT_HUMAN, 400, 0, MS_NEMESIS, MZ_HUMAN), 0, 0,
+	SIZ(WT_HUMAN, 400, 0, MS_NEMESIS, MZ_HUMAN), MR_STONE, 0,
 	M1_HUMANOID|M1_OMNIVORE,
 	M2_NOPOLY|M2_HUMAN|M2_STRONG|M2_HOSTILE|M2_STALK|M2_NASTY|
 	  M2_COLLECT|M2_MAGIC,
diff -Naurd ../nethack-3.4.0/src/mplayer.c ./src/mplayer.c
--- ../nethack-3.4.0/src/mplayer.c Wed Mar 20 23:43:11 2002
+++ ./src/mplayer.c Mon Feb 24 15:25:05 2003
@@ -305,7 +305,7 @@
 		do {
 		    x = rn1(COLNO-4, 2);
 		    y = rnd(ROWNO-2);
-		} while(!goodpos(x, y, &fakemon) && tryct++ <= 50);
+		} while(!goodpos(x, y, &fakemon, 0) && tryct++ <= 50);
 
 		/* if pos not found in 50 tries, don't bother to continue */
 		if(tryct > 50) return;
diff -Naurd ../nethack-3.4.0/src/mthrowu.c ./src/mthrowu.c
--- ../nethack-3.4.0/src/mthrowu.c Wed Mar 20 23:43:11 2002
+++ ./src/mthrowu.c Mon Feb 24 15:25:05 2003
@@ -186,9 +186,9 @@
 	    if (ismimic) seemimic(mtmp);
 	    mtmp->msleeping = 0;
 	    if (vis) hit(distant_name(otmp,mshot_xname), mtmp, exclam(damage));
-	    else if (verbose) pline("It is hit%s", exclam(damage));
+	    else if (verbose) pline("%s is hit%s", Monnam(mtmp), exclam(damage));
 
-	    if (otmp->opoisoned) {
+	    if (otmp->opoisoned && is_poisonable(otmp)) {
 		if (resists_poison(mtmp)) {
 		    if (vis) pline_The("poison doesn't seem to affect %s.",
 				   mon_nam(mtmp));
@@ -221,9 +221,12 @@
 	    if (mtmp->mhp < 1) {
 		if (vis || verbose)
 		    pline("%s is %s!", Monnam(mtmp),
-			(nonliving(mtmp->data) || !vis)
+			(nonliving(mtmp->data) || !canspotmon(mtmp))
 			? "destroyed" : "killed");
-		if (!flags.mon_moving) xkilled(mtmp,0);
+		/* don't blame hero for unknown rolling boulder trap */
+		if (!flags.mon_moving &&
+		    (otmp->otyp != BOULDER || range >= 0 || !otmp->otrapped))
+		    xkilled(mtmp,0);
 		else mondied(mtmp);
 	    }
 
@@ -299,16 +302,26 @@
 	    }
 	    dx = rn2(3)-1;
 	    dy = rn2(3)-1;
-	    /* pre-check validity of new direction */
-	    if((!dx && !dy)
-	       || !isok(bhitpos.x+dx,bhitpos.y+dy)
-	       /* missile hits the wall */
-	       || IS_ROCK(levl[bhitpos.x+dx][bhitpos.y+dy].typ)) {
+	    /* check validity of new direction */
+	    if (!dx && !dy) {
 		(void) drop_throw(singleobj, 0, bhitpos.x, bhitpos.y);
 		return;
 	    }
 	}
 
+	/* pre-check for doors, walls and boundaries.
+	   Also need to pre-check for bars regardless of direction;
+	   the random chance for small objects hitting bars is
+	   skipped when reaching them at point blank range */
+	if (!isok(bhitpos.x+dx,bhitpos.y+dy)
+	    || IS_ROCK(levl[bhitpos.x+dx][bhitpos.y+dy].typ)
+	    || closed_door(bhitpos.x+dx, bhitpos.y+dy)
+	    || (levl[bhitpos.x + dx][bhitpos.y + dy].typ == IRONBARS &&
+		hits_bars(&singleobj, bhitpos.x, bhitpos.y, 0, 0))) {
+	    (void) drop_throw(singleobj, 0, bhitpos.x, bhitpos.y);
+	    return;
+	}
+
 	/* Note: drop_throw may destroy singleobj.  Since obj must be destroyed
 	 * early to avoid the dagger bug, anyone who modifies this code should
 	 * be careful not to use either one after it's been freed.
@@ -377,7 +390,8 @@
 			    if (dam < 1) dam = 1;
 			    hitu = thitu(hitv, dam, singleobj, (char *)0);
 		    }
-		    if (hitu && singleobj->opoisoned) {
+		    if (hitu && singleobj->opoisoned &&
+			is_poisonable(singleobj)) {
 			char onmbuf[BUFSZ], knmbuf[BUFSZ];
 			struct obj otmp;
 			unsigned save_ocknown;
@@ -433,12 +447,18 @@
 			|| !isok(bhitpos.x+dx,bhitpos.y+dy)
 			/* missile hits the wall */
 			|| IS_ROCK(levl[bhitpos.x+dx][bhitpos.y+dy].typ)
+			/* missile hit closed door */
+			|| closed_door(bhitpos.x+dx, bhitpos.y+dy)
+			/* missile might hit iron bars */
+			|| (levl[bhitpos.x+dx][bhitpos.y+dy].typ == IRONBARS &&
+			hits_bars(&singleobj, bhitpos.x, bhitpos.y, !rn2(5), 0))
 #ifdef SINKS
 			/* Thrown objects "sink" */
 			|| IS_SINK(levl[bhitpos.x][bhitpos.y].typ)
 #endif
 								) {
-		    (void) drop_throw(singleobj, 0, bhitpos.x, bhitpos.y);
+		    if (singleobj) /* hits_bars might have destroyed it */
+			(void) drop_throw(singleobj, 0, bhitpos.x, bhitpos.y);
 		    break;
 		}
 		tmp_at(bhitpos.x, bhitpos.y);
@@ -469,10 +489,10 @@
 		obj->owt = weight(obj);
 	} else {
 		obj_extract_self(obj);
-		possibly_unwield(mon);
+		possibly_unwield(mon, FALSE);
 		if (obj->owornmask) {
 		    mon->misc_worn_check &= ~obj->owornmask;
-		    update_mon_intrinsics(mon, obj, FALSE);
+		    update_mon_intrinsics(mon, obj, FALSE, FALSE);
 		}
 		obfree(obj, (struct obj*) 0);
 	}
@@ -743,6 +763,83 @@
 	return((struct obj *) 0);
 }
 
+/* TRUE iff thrown/kicked/rolled object doesn't pass through iron bars */
+boolean
+hits_bars(obj_p, x, y, always_hit, whodidit)
+struct obj **obj_p;	/* *obj_p will be set to NULL if object breaks */
+int x, y;
+int always_hit;	/* caller can force a hit for items which would fit through */
+int whodidit;	/* 1==hero, 0=other, -1==just check whether it'll pass thru */
+{
+    struct obj *otmp = *obj_p;
+    int obj_type = otmp->otyp;
+    boolean hits = always_hit;
+
+    if (!hits)
+	switch (otmp->oclass) {
+	case WEAPON_CLASS:
+	    {
+		int oskill = objects[obj_type].oc_skill;
+
+		hits = (oskill != -P_BOW  && oskill != -P_CROSSBOW &&
+			oskill != -P_DART && oskill != -P_SHURIKEN &&
+			oskill != P_SPEAR && oskill != P_JAVELIN &&
+			oskill != P_KNIFE);	/* but not dagger */
+		break;
+	    }
+	case ARMOR_CLASS:
+		hits = (objects[obj_type].oc_armcat != ARM_GLOVES);
+		break;
+	case TOOL_CLASS:
+		hits = (obj_type != SKELETON_KEY &&
+			obj_type != LOCK_PICK &&
+#ifdef TOURIST
+			obj_type != CREDIT_CARD &&
+#endif
+			obj_type != TALLOW_CANDLE &&
+			obj_type != WAX_CANDLE &&
+			obj_type != LENSES &&
+			obj_type != TIN_WHISTLE &&
+			obj_type != MAGIC_WHISTLE);
+		break;
+	case ROCK_CLASS:	/* includes boulder */
+		if (obj_type != STATUE ||
+			mons[otmp->corpsenm].msize > MZ_TINY) hits = TRUE;
+		break;
+	case FOOD_CLASS:
+		if (obj_type == CORPSE &&
+			mons[otmp->corpsenm].msize > MZ_TINY) hits = TRUE;
+		else
+		    hits = (obj_type == MEAT_STICK ||
+			    obj_type == HUGE_CHUNK_OF_MEAT);
+		break;
+	case SPBOOK_CLASS:
+	case WAND_CLASS:
+	case BALL_CLASS:
+	case CHAIN_CLASS:
+		hits = TRUE;
+		break;
+	default:
+		break;
+	}
+
+    if (hits && whodidit != -1) {
+	if (whodidit ? hero_breaks(otmp, x, y, FALSE) : breaks(otmp, x, y))
+	    *obj_p = otmp = 0;		/* object is now gone */
+	    /* breakage makes its own noises */
+	else if (obj_type == BOULDER || obj_type == HEAVY_IRON_BALL)
+	    pline("Whang!");
+	else if (otmp->oclass == COIN_CLASS ||
+		objects[obj_type].oc_material == GOLD ||
+		objects[obj_type].oc_material == SILVER)
+	    pline("Clink!");
+	else
+	    pline("Clonk!");
+    }
+
+    return hits;
+}
+
 #endif /* OVL0 */
 
 /*mthrowu.c*/
diff -Naurd ../nethack-3.4.0/src/muse.c ./src/muse.c
--- ../nethack-3.4.0/src/muse.c Wed Mar 20 23:43:11 2002
+++ ./src/muse.c Mon Feb 24 15:25:05 2003
@@ -445,10 +445,19 @@
 		nomore(MUSE_WAN_TELEPORTATION_SELF);
 		nomore(MUSE_WAN_TELEPORTATION);
 		if(obj->otyp == WAN_TELEPORTATION && obj->spe > 0) {
+		    /* use the TELEP_TRAP bit to determine if they know
+		     * about noteleport on this level or not.  Avoids
+		     * ineffective re-use of teleportation.  This does
+		     * mean if the monster leaves the level, they'll know
+		     * about teleport traps.
+		     */
+		    if (!level.flags.noteleport ||
+			!(mtmp->mtrapseen & (1 << (TELEP_TRAP-1)))) {
 			m.defensive = obj;
 			m.has_defense = (mon_has_amulet(mtmp))
 				? MUSE_WAN_TELEPORTATION
 				: MUSE_WAN_TELEPORTATION_SELF;
+		    }
 		}
 		nomore(MUSE_SCR_TELEPORTATION);
 		if(obj->otyp == SCR_TELEPORTATION && mtmp->mcansee
@@ -456,8 +465,12 @@
 		   && (!obj->cursed ||
 		       (!(mtmp->isshk && inhishop(mtmp))
 			    && !mtmp->isgd && !mtmp->ispriest))) {
+		    /* see WAN_TELEPORTATION case above */
+		    if (!level.flags.noteleport ||
+			!(mtmp->mtrapseen & (1 << (TELEP_TRAP-1)))) {
 			m.defensive = obj;
 			m.has_defense = MUSE_SCR_TELEPORTATION;
+		    }
 		}
 
 	    if (mtmp->data != &mons[PM_PESTILENCE]) {
@@ -563,6 +576,9 @@
 		if (tele_restrict(mtmp)) {	/* mysterious force... */
 		    if (vismon && how)		/* mentions 'teleport' */
 			makeknown(how);
+		    /* monster learns that teleportation isn't useful here */
+		    if (level.flags.noteleport)
+			mtmp->mtrapseen |= (1 << (TELEP_TRAP-1));
 		    return 2;
 		}
 		if ((
@@ -584,6 +600,9 @@
 		otmp->spe--;
 		m_using = TRUE;
 		mbhit(mtmp,rn1(8,6),mbhitm,bhito,otmp);
+		/* monster learns that teleportation isn't useful here */
+		if (level.flags.noteleport)
+		    mtmp->mtrapseen |= (1 << (TELEP_TRAP-1));
 		m_using = FALSE;
 		return 2;
 	case MUSE_SCR_TELEPORTATION:
@@ -882,6 +901,7 @@
 {
 	struct permonst *pm = mtmp->data;
 	int difficulty = monstr[(monsndx(pm))];
+	int trycnt = 0;
 
 	if(is_animal(pm) || attacktype(pm, AT_EXPL) || mindless(mtmp->data)
 			|| pm->mlet == S_GHOST
@@ -889,9 +909,12 @@
 			|| pm->mlet == S_KOP
 # endif
 		) return 0;
+    try_again:
 	switch (rn2(8 + (difficulty > 3) + (difficulty > 6) +
 				(difficulty > 8))) {
 		case 6: case 9:
+			if (level.flags.noteleport && ++trycnt < 2)
+			    goto try_again;
 			if (!rn2(3)) return WAN_TELEPORTATION;
 			/* else FALLTHRU */
 		case 0: case 1:
@@ -1130,7 +1153,7 @@
 		break;
 	case WAN_CANCELLATION:
 	case SPE_CANCELLATION:
-		cancel_monst(mtmp, otmp, FALSE, TRUE, FALSE);
+		(void) cancel_monst(mtmp, otmp, FALSE, TRUE, FALSE);
 		break;
 	}
 	if (reveal_invis) {
@@ -1760,13 +1783,13 @@
 	case MUSE_WAN_POLYMORPH:
 		mzapmsg(mtmp, otmp, TRUE);
 		otmp->spe--;
-		(void) newcham(mtmp, muse_newcham_mon(mtmp), TRUE);
+		(void) newcham(mtmp, muse_newcham_mon(mtmp), TRUE, FALSE);
 		if (oseen) makeknown(WAN_POLYMORPH);
 		return 2;
 	case MUSE_POT_POLYMORPH:
 		mquaffmsg(mtmp, otmp);
 		if (vismon) pline("%s suddenly mutates!", Monnam(mtmp));
-		(void) newcham(mtmp, muse_newcham_mon(mtmp), FALSE);
+		(void) newcham(mtmp, muse_newcham_mon(mtmp), FALSE, FALSE);
 		if (oseen) makeknown(POT_POLYMORPH);
 		m_useup(mtmp, otmp);
 		return 2;
@@ -1784,7 +1807,7 @@
 		if (mtmp->wormno) worm_move(mtmp);
 		newsym(trapx, trapy);
 
-		(void) newcham(mtmp, (struct permonst *)0, FALSE);
+		(void) newcham(mtmp, (struct permonst *)0, FALSE, FALSE);
 		return 2;
 	case MUSE_BULLWHIP:
 		/* attempt to disarm hero */
@@ -2011,6 +2034,11 @@
 		makeknown(SHIELD_OF_REFLECTION);
 	    }
 	    return TRUE;
+	} else if (arti_reflects(MON_WEP(mon))) {
+	    /* due to wielded artifact weapon */
+	    if (str)
+		pline(str, s_suffix(mon_nam(mon)), "weapon");
+	    return TRUE;
 	} else if ((orefl = which_armor(mon, W_AMUL)) &&
 				orefl->otyp == AMULET_OF_REFLECTION) {
 	    if (str) {
@@ -2100,6 +2128,10 @@
     int nutrit = (obj->otyp == CORPSE) ? dog_nutrition(mon, obj) : 0;
     /* also sets meating */
 
+    /* give a "<mon> is slowing down" message and also remove
+       intrinsic speed (comparable to similar effect on the hero) */
+    mon_adjust_speed(mon, -3, (struct obj *)0);
+
     if (canseemon(mon)) {
 	long save_quan = obj->quan;
 
diff -Naurd ../nethack-3.4.0/src/music.c ./src/music.c
--- ../nethack-3.4.0/src/music.c Wed Mar 20 23:43:12 2002
+++ ./src/music.c Mon Feb 24 15:25:05 2003
@@ -409,7 +409,7 @@
 		    if ((damage = zapyourself(instr, TRUE)) != 0) {
 			char buf[BUFSZ];
 			Sprintf(buf, "using a magical horn on %sself", uhim());
-			losehp(damage, buf, NO_KILLER_PREFIX);
+			losehp(damage, buf, KILLED_BY);
 		    }
 		} else {
 		    buzz((instr->otyp == FROST_HORN) ? AD_COLD-1 : AD_FIRE-1,
diff -Naurd ../nethack-3.4.0/src/objects.c ./src/objects.c
--- ../nethack-3.4.0/src/objects.c Wed Mar 20 23:43:12 2002
+++ ./src/objects.c Mon Feb 24 15:25:05 2003
@@ -321,40 +321,44 @@
 /* suits of armor */
 /*
  * There is code in polyself.c that assumes (1) and (2).
- * There is code in objnam.c, mon.c, read.c that assumes (2).
+ * There is code in obj.h, objnam.c, mon.c, read.c that assumes (2).
  *
  *	(1) The dragon scale mails and the dragon scales are together.
  *	(2) That the order of the dragon scale mail and dragon scales is the
  *	    the same defined in monst.c.
  */
-#define DRGN_ARMR(name,power,cost,ac,color) \
-	ARMOR(name,(char *)0,1,0,1,power,0,5,40,cost,ac,0,ARM_SUIT,DRAGON_HIDE,color)
-DRGN_ARMR("gray dragon scale mail",   ANTIMAGIC,  1200, 1, CLR_GRAY),
-DRGN_ARMR("silver dragon scale mail", REFLECTING, 1200, 1, SILVER),
+#define DRGN_ARMR(name,mgc,power,cost,ac,color) \
+	ARMOR(name,(char *)0,1,mgc,1,power,0,5,40,cost,ac,0,ARM_SUIT,DRAGON_HIDE,color)
+/* 3.4.1: dragon scale mail reclassified as "magic" since magic is
+   needed to create them */
+DRGN_ARMR("gray dragon scale mail",   1, ANTIMAGIC,  1200, 1, CLR_GRAY),
+DRGN_ARMR("silver dragon scale mail", 1, REFLECTING, 1200, 1, DRAGON_SILVER),
 #if 0	/* DEFERRED */
-DRGN_ARMR("shimmering dragon scale mail", DISPLACED, 1200, 1, CLR_CYAN),
+DRGN_ARMR("shimmering dragon scale mail", 1, DISPLACED, 1200, 1, CLR_CYAN),
 #endif
-DRGN_ARMR("red dragon scale mail",    FIRE_RES,    900, 1, CLR_RED),
-DRGN_ARMR("white dragon scale mail",  COLD_RES,    900, 1, CLR_WHITE),
-DRGN_ARMR("orange dragon scale mail", SLEEP_RES,   900, 1, CLR_ORANGE),
-DRGN_ARMR("black dragon scale mail",  DISINT_RES, 1200, 1, CLR_BLACK),
-DRGN_ARMR("blue dragon scale mail",   SHOCK_RES,   900, 1, CLR_BLUE),
-DRGN_ARMR("green dragon scale mail",  POISON_RES,  900, 1, CLR_GREEN),
-DRGN_ARMR("yellow dragon scale mail", ACID_RES,    900, 1, CLR_YELLOW),
+DRGN_ARMR("red dragon scale mail",    1, FIRE_RES,    900, 1, CLR_RED),
+DRGN_ARMR("white dragon scale mail",  1, COLD_RES,    900, 1, CLR_WHITE),
+DRGN_ARMR("orange dragon scale mail", 1, SLEEP_RES,   900, 1, CLR_ORANGE),
+DRGN_ARMR("black dragon scale mail",  1, DISINT_RES, 1200, 1, CLR_BLACK),
+DRGN_ARMR("blue dragon scale mail",   1, SHOCK_RES,   900, 1, CLR_BLUE),
+DRGN_ARMR("green dragon scale mail",  1, POISON_RES,  900, 1, CLR_GREEN),
+DRGN_ARMR("yellow dragon scale mail", 1, ACID_RES,    900, 1, CLR_YELLOW),
 
 /* For now, only dragons leave these. */
-DRGN_ARMR("gray dragon scales",   ANTIMAGIC,  700, 7, CLR_GRAY),
-DRGN_ARMR("silver dragon scales", REFLECTING, 700, 7, SILVER),
+/* 3.4.1: dragon scales left classified as "non-magic"; they confer
+   magical properties but are produced "naturally" */
+DRGN_ARMR("gray dragon scales",   0, ANTIMAGIC,  700, 7, CLR_GRAY),
+DRGN_ARMR("silver dragon scales", 0, REFLECTING, 700, 7, DRAGON_SILVER),
 #if 0	/* DEFERRED */
-DRGN_ARMR("shimmering dragon scales", DISPLACED,  700, 7, CLR_CYAN),
+DRGN_ARMR("shimmering dragon scales", 0, DISPLACED,  700, 7, CLR_CYAN),
 #endif
-DRGN_ARMR("red dragon scales",    FIRE_RES,   500, 7, CLR_RED),
-DRGN_ARMR("white dragon scales",  COLD_RES,   500, 7, CLR_WHITE),
-DRGN_ARMR("orange dragon scales", SLEEP_RES,  500, 7, CLR_ORANGE),
-DRGN_ARMR("black dragon scales",  DISINT_RES, 700, 7, CLR_BLACK),
-DRGN_ARMR("blue dragon scales",   SHOCK_RES,  500, 7, CLR_BLUE),
-DRGN_ARMR("green dragon scales",  POISON_RES, 500, 7, CLR_GREEN),
-DRGN_ARMR("yellow dragon scales", ACID_RES,   500, 7, CLR_YELLOW),
+DRGN_ARMR("red dragon scales",    0, FIRE_RES,   500, 7, CLR_RED),
+DRGN_ARMR("white dragon scales",  0, COLD_RES,   500, 7, CLR_WHITE),
+DRGN_ARMR("orange dragon scales", 0, SLEEP_RES,  500, 7, CLR_ORANGE),
+DRGN_ARMR("black dragon scales",  0, DISINT_RES, 700, 7, CLR_BLACK),
+DRGN_ARMR("blue dragon scales",   0, SHOCK_RES,  500, 7, CLR_BLUE),
+DRGN_ARMR("green dragon scales",  0, POISON_RES, 500, 7, CLR_GREEN),
+DRGN_ARMR("yellow dragon scales", 0, ACID_RES,   500, 7, CLR_YELLOW),
 #undef DRGN_ARMR
 
 ARMOR("plate mail", (char *)0,
@@ -647,6 +651,7 @@
 	1, 0, 0, 20, 100,  50,	6,  3, WHACK,  P_PICK_AXE, IRON, HI_METAL),
 WEPTOOL("grappling hook", "iron hook",
 	0, 0, 0,  5,  30,  50,  2,  6, WHACK,  P_FLAIL, IRON, HI_METAL),
+/* 3.4.1: unicorn horn left classified as "magic" */
 WEPTOOL("unicorn horn", (char *)0,
 	1, 1, 1,  0,  20, 100, 12, 12, PIERCE, P_UNICORN_HORN, BONE, CLR_WHITE),
 
@@ -875,7 +880,7 @@
 /* coins ... - so far, gold is all there is */
 #define COIN(name,prob,metal,worth) OBJECT( \
 		OBJ(name,(char *)0), BITS(0,1,0,0,0,0,0,0,0,0,0,P_NONE,metal), 0, \
-		GOLD_CLASS, prob, 0, 1, worth, 0, 0, 0, 0, 0, HI_GOLD )
+		COIN_CLASS, prob, 0, 1, worth, 0, 0, 0, 0, 0, HI_GOLD )
 	COIN("gold piece",      1000, GOLD,1),
 #undef COIN
 
@@ -921,6 +926,10 @@
 GEM("worthless piece of green glass", "green",   77, 1, 0, 6, 5, GLASS, CLR_GREEN),
 GEM("worthless piece of violet glass", "violet", 77, 1, 0, 6, 5, GLASS, CLR_MAGENTA),
 
+/* Placement note: there is a wishable subrange for
+ * "gray stones" in the o_ranges[] array in objnam.c
+ * that is currently everything between luckstones and flint (inclusive).
+ */
 ROCK("luckstone", "gray",	0, 10,  10, 60, 3, 3, 1, 10, 7, MINERAL, CLR_GRAY),
 ROCK("loadstone", "gray",	0, 10, 500,  1, 3, 3, 1, 10, 6, MINERAL, CLR_GRAY),
 ROCK("touchstone", "gray",	0,  8,  10, 45, 3, 3, 1, 10, 6, MINERAL, CLR_GRAY),
diff -Naurd ../nethack-3.4.0/src/objnam.c ./src/objnam.c
--- ../nethack-3.4.0/src/objnam.c Wed Mar 20 23:43:12 2002
+++ ./src/objnam.c Mon Feb 24 15:25:05 2003
@@ -101,7 +101,7 @@
 	if (Role_if(PM_SAMURAI) && Japanese_item_name(otyp))
 		actualn = Japanese_item_name(otyp);
 	switch(ocl->oc_class) {
-	case GOLD_CLASS:
+	case COIN_CLASS:
 		Strcpy(buf, "coin");
 		break;
 	case POTION_CLASS:
@@ -209,6 +209,24 @@
 	return str;
 }
 
+/* convert player specified fruit name into corresponding fruit juice name
+   ("slice of pizza" -> "pizza juice" rather than "slice of pizza juice") */
+char *
+fruitname(juice)
+boolean juice;	/* whether or not to append " juice" to the name */
+{
+    char *buf = nextobuf();
+    const char *fruit_nam = strstri(pl_fruit, " of ");
+
+    if (fruit_nam)
+	fruit_nam += 4;		/* skip past " of " */
+    else
+	fruit_nam = pl_fruit;	/* use it as is */
+
+    Sprintf(buf, "%s%s", makesingular(fruit_nam), juice ? " juice" : "");
+    return buf;
+}
+
 #endif /* OVLB */
 #ifdef OVL1
 
@@ -231,12 +249,11 @@
 	buf[0] = '\0';
 	/*
 	 * clean up known when it's tied to oc_name_known, eg after AD_DRIN
-	 * This is only required for unique objects and the Fake AoY since the
-	 * article printed for the object is tied to the combination of the two
+	 * This is only required for unique objects since the article
+	 * printed for the object is tied to the combination of the two
 	 * and printing the wrong article gives away information.
 	 */
-	if (!nn && ocl->oc_uses_known &&
-	    (ocl->oc_unique || typ == FAKE_AMULET_OF_YENDOR)) obj->known = 0;
+	if (!nn && ocl->oc_uses_known && ocl->oc_unique) obj->known = 0;
 	if (!Blind) obj->dknown = TRUE;
 	if (Role_if(PM_PRIEST)) obj->bknown = TRUE;
 	if (obj_is_pname(obj))
@@ -343,7 +360,7 @@
 			Sprintf(eos(buf), " of %s meat", mons[obj->corpsenm].mname);
 		}
 		break;
-	    case GOLD_CLASS:
+	    case COIN_CLASS:
 	    case CHAIN_CLASS:
 		Strcpy(buf, actualn);
 		break;
@@ -573,7 +590,7 @@
 #endif
 
 	if (obj->bknown &&
-	    obj->oclass != GOLD_CLASS &&
+	    obj->oclass != COIN_CLASS &&
 	    (obj->otyp != POT_WATER || !objects[POT_WATER].oc_name_known
 		|| (!obj->cursed && !obj->blessed))) {
 	    /* allow 'blessed clear potion' if we don't know it's holy water;
@@ -780,6 +797,10 @@
 not_fully_identified(otmp)
 register struct obj *otmp;
 {
+#ifdef GOLDOBJ
+    /* gold doesn't have any interesting attributes [yet?] */
+    if (otmp->oclass == COIN_CLASS) return FALSE;	/* always fully ID'd */
+#endif
     /* check fundamental ID hallmarks first */
     if (!otmp->known || !otmp->dknown ||
 #ifdef MAIL
@@ -868,6 +889,7 @@
 	    strcmp(str, "iron bars") &&
 	    strcmp(str, "ice")) {
 		if (index(vowels, *str) &&
+		    strncmp(str, "one-", 4) &&
 		    strncmp(str, "useful", 6) &&
 		    strncmp(str, "unicorn", 7) &&
 		    strncmp(str, "uranium", 7) &&
@@ -1007,6 +1029,19 @@
 	return buf;
 }
 
+/* various singular words that vtense would otherwise categorize as plural */
+static const char * const special_subjs[] = {
+	"erinys",
+	"manes",		/* this one is ambiguous */
+	"Cyclops",
+	"Hippocrates",
+	"Pelias",
+	"aklys",
+	"amnesia",
+	"paralysis",
+	0
+};
+
 /* return form of the verb (input plural) for present tense 3rd person subj */
 char *
 vtense(subj, verb)
@@ -1015,8 +1050,8 @@
 {
 	char *buf = nextobuf();
 	int len;
-	const char *spot;
-	const char *sp;
+	const char *sp, *spot;
+	const char * const *spec;
 
 	/*
 	 * verb is given in plural (without trailing s).  Return as input
@@ -1032,6 +1067,7 @@
 	    spot = (const char *)0;
 	    for (sp = subj; (sp = index(sp, ' ')) != 0; ++sp) {
 		if (!strncmp(sp, " of ", 4) ||
+		    !strncmp(sp, " from ", 6) ||
 		    !strncmp(sp, " called ", 8) ||
 		    !strncmp(sp, " named ", 7) ||
 		    !strncmp(sp, " labeled ", 9)) {
@@ -1039,23 +1075,33 @@
 		    break;
 		}
 	    }
-	    len = strlen(subj);
+	    len = (int) strlen(subj);
 	    if (!spot) spot = subj + len - 1;
 
 	    /*
-	     * plural: anything that ends in 's', but not '*us'.
+	     * plural: anything that ends in 's', but not '*us' or '*ss'.
 	     * Guess at a few other special cases that makeplural creates.
 	     */
-	    if ((*spot == 's' && spot != subj && *(spot-1) != 'u') ||
+	    if ((*spot == 's' && spot != subj &&
+			(*(spot-1) != 'u' && *(spot-1) != 's')) ||
 		((spot - subj) >= 4 && !strncmp(spot-3, "eeth", 4)) ||
 		((spot - subj) >= 3 && !strncmp(spot-3, "feet", 4)) ||
 		((spot - subj) >= 2 && !strncmp(spot-1, "ia", 2)) ||
 		((spot - subj) >= 2 && !strncmp(spot-1, "ae", 2))) {
-		Strcpy(buf, verb);
-		return buf;
+		/* check for special cases to avoid false matches */
+		len = (int)(spot - subj) + 1;
+		for (spec = special_subjs; *spec; spec++)
+		    if (!strncmpi(*spec, subj, len)) goto sing;
+
+		return strcpy(buf, verb);
 	    }
+	    /*
+	     * 2nd person singular behaves as if plural.
+	     */
+	    if (!strcmpi(subj, "you")) return strcpy(buf, verb);
 	}
 
+ sing:
 	len = strlen(verb);
 	spot = verb + len - 1;
 
@@ -1452,27 +1498,32 @@
 				Strcpy(p-3, "fe");
 				return bp;
 			}
-
 			if(!BSTRCMP(bp, p-6, "staves")) {
 				Strcpy(p-3, "ff");
 				return bp;
 			}
-
 			if (!BSTRCMPI(bp, p-6, "leaves")) {
 				Strcpy(p-3, "f");
 				return bp;
 			}
+			if (!BSTRCMP(bp, p-8, "vortices")) {
+				Strcpy(p-4, "ex");
+				return bp;
+			}
 
 			/* note: nurses, axes but boxes */
-			if(!BSTRCMP(bp, p-5, "boxes")) {
-				p[-2] = 0;
+			if (!BSTRCMP(bp, p-5, "boxes") ||
+			    !BSTRCMP(bp, p-4, "ches")) {
+				p[-2] = '\0';
 				return bp;
 			}
+
 			if (!BSTRCMP(bp, p-6, "gloves") ||
 			    !BSTRCMP(bp, p-6, "lenses") ||
 			    !BSTRCMP(bp, p-5, "shoes") ||
 			    !BSTRCMP(bp, p-6, "scales"))
 				return bp;
+
 		} else if (!BSTRCMP(bp, p-5, "boots") ||
 			   !BSTRCMP(bp, p-9, "gauntlets") ||
 			   !BSTRCMP(bp, p-6, "tricks") ||
@@ -1486,15 +1537,24 @@
 #ifdef WIZARD
 			   !BSTRCMP(bp, p-9, "iron bars") ||
 #endif
-			   !BSTRCMP(bp, p-5, "aklys"))
+			   !BSTRCMP(bp, p-5, "aklys") ||
+			   !BSTRCMP(bp, p-6, "fungus"))
 				return bp;
 	mins:
-		p[-1] = 0;
+		p[-1] = '\0';
+
 	} else {
+
 		if(!BSTRCMP(bp, p-5, "teeth")) {
 			Strcpy(p-5, "tooth");
 			return bp;
 		}
+
+		if (!BSTRCMP(bp, p-5, "fungi")) {
+			Strcpy(p-5, "fungus");
+			return bp;
+		}
+
 		/* here we cannot find the plural suffix */
 	}
 	return bp;
@@ -1507,6 +1567,15 @@
 const char *o_str;	/* from objects[], so is in canonical form */
 boolean retry_inverted;	/* optional extra "of" handling */
 {
+	/* special case: wizards can wish for traps.  The object is "beartrap"
+	 * and the trap is "bear trap", so to let wizards wish for both we
+	 * must not fuzzymatch.
+	 */
+#ifdef WIZARD
+	if (wizard && !strcmp(o_str, "beartrap"))
+	    return !strncmpi(o_str, u_str, 8);
+#endif
+
 	/* ignore spaces & hyphens and upper/lower case when comparing */
 	if (fuzzymatch(u_str, o_str, " -", TRUE)) return TRUE;
 
@@ -1659,7 +1728,8 @@
 	(void)mungspaces(bp);
 	/* allow wishing for "nothing" to preserve wishless conduct...
 	   [now requires "wand of nothing" if that's what was really wanted] */
-	if (!strcmpi(bp, "nothing") || !strcmpi(bp, "nil")) return no_wish;
+	if (!strcmpi(bp, "nothing") || !strcmpi(bp, "nil") ||
+	    !strcmpi(bp, "none")) return no_wish;
 	/* save the [nearly] unmodified choice string */
 	Strcpy(fruitbuf, bp);
 
@@ -1902,6 +1972,9 @@
 		}
 		as++;
 	}
+	/* can't use spellings list for this one due to shuffling */
+	if (!strcmpi(bp, "grey spellbook"))
+		*(bp + 2) = 'a';
     }
 
 	/* dragon scales - assumes order of dragons */
@@ -2015,6 +2088,8 @@
 		oclass = GEM_CLASS;
 		dn = actualn = bp;
 		goto srch;
+	} else if (!strcmpi(bp, "looking glass")) {
+		;	/* avoid false hit on "* glass" */
 	} else if (!BSTRCMPI(bp, p-6, " glass") || !strcmpi(bp, "glass")) {
 		register char *g = bp;
 		if (strstri(g, "broken")) return (struct obj *)0;
@@ -2027,7 +2102,7 @@
 			typ = LAST_GEM + rnd(9);
 			if (objects[typ].oc_class == GEM_CLASS) goto typfnd;
 			else typ = 0;	/* somebody changed objects[]? punt */
-		} else if (g > bp) {	/* try to construct canonical form */
+		} else {		/* try to construct canonical form */
 			char tbuf[BUFSZ];
 			Strcpy(tbuf, "worthless piece of ");
 			Strcat(tbuf, g);  /* assume it starts with the color */
@@ -2615,6 +2690,17 @@
     return "cloak";
 }
 
+const char *
+mimic_obj_name(mtmp)
+struct monst *mtmp;
+{
+	if (mtmp->m_ap_type == M_AP_OBJECT && mtmp->mappearance != STRANGE_OBJECT) {
+		int idx = objects[mtmp->mappearance].oc_descr_idx;
+		if (mtmp->mappearance == GOLD_PIECE) return "gold";
+		return obj_descr[idx].oc_name;
+	}
+	return "whatcha-may-callit";
+}
 #endif /* OVLB */
 
 /*objnam.c*/
diff -Naurd ../nethack-3.4.0/src/options.c ./src/options.c
--- ../nethack-3.4.0/src/options.c Wed Mar 20 23:43:12 2002
+++ ./src/options.c Mon Feb 24 15:25:05 2003
@@ -17,6 +17,12 @@
 
 #define WINTYPELEN 16
 
+#ifdef DEFAULT_WC_TILED_MAP
+#define PREFER_TILED TRUE
+#else
+#define PREFER_TILED FALSE
+#endif
+
 /*
  *  NOTE:  If you add (or delete) an option, please update the short
  *  options help (option_help()), the long options help (dat/opthelp),
@@ -38,7 +44,7 @@
 #else
 	{"altmeta", (boolean *)0, TRUE, DISP_IN_GAME},
 #endif
-	{"ascii_map",     &iflags.wc_ascii_map, TRUE, SET_IN_GAME},	/*WC*/
+	{"ascii_map",     &iflags.wc_ascii_map, !PREFER_TILED, SET_IN_GAME},	/*WC*/
 #ifdef MFLOPPY
 	{"asksavedisk", &flags.asksavedisk, FALSE, SET_IN_GAME},
 #else
@@ -62,7 +68,8 @@
 #else
 	{"checkspace", (boolean *)0, FALSE, SET_IN_FILE},
 #endif
-# ifdef MICRO
+	{"cmdassist", &iflags.cmdassist, TRUE, SET_IN_GAME},
+# if defined(MICRO) || defined(WIN32)
 	{"color",         &iflags.wc_color,TRUE, SET_IN_GAME},		/*WC*/
 # else	/* systems that support multiple terminals, many monochrome */
 	{"color",         &iflags.wc_color, FALSE, SET_IN_GAME},	/*WC*/
@@ -103,9 +110,10 @@
 #else
 	{"ignintr", (boolean *)0, FALSE, SET_IN_FILE},
 #endif
-	{"large_font", &iflags.wc_large_font, FALSE, SET_IN_FILE},	/*WC*/
+	{"large_font", &iflags.obsolete, FALSE, SET_IN_FILE},	/* OBSOLETE */
 	{"legacy", &flags.legacy, TRUE, DISP_IN_GAME},
 	{"lit_corridor", &flags.lit_corridor, FALSE, SET_IN_GAME},
+	{"lootabc", &iflags.lootabc, FALSE, SET_IN_GAME},
 #ifdef MAC_GRAPHICS_ENV
 	{"Macgraphics", &iflags.MACgraphics, TRUE, SET_IN_GAME},
 #else
@@ -122,11 +130,7 @@
 #else
 	{"menu_tab_sep", (boolean *)0, FALSE, SET_IN_FILE},
 #endif
-#ifdef TTY_GRAPHICS
-	{"msg_window", &iflags.prevmsg_window, FALSE, SET_IN_GAME},
-#else
-	{"msg_window", (boolean *)0, FALSE, SET_IN_FILE},
-#endif
+	{"mouse_support", &iflags.wc_mouse_support, TRUE, DISP_IN_GAME},	/*WC*/
 #ifdef NEWS
 	{"news", &iflags.news, TRUE, DISP_IN_GAME},
 #else
@@ -144,7 +148,7 @@
 	{"prayconfirm", &flags.prayconfirm, TRUE, SET_IN_GAME},
 	{"preload_tiles", &iflags.wc_preload_tiles, TRUE, DISP_IN_GAME},	/*WC*/
 	{"pushweapon", &flags.pushweapon, FALSE, SET_IN_GAME},
-#if defined(MICRO) && !defined(AMIGA) && !defined(MSWIN_GRAPHICS)
+#if defined(MICRO) && !defined(AMIGA)
 	{"rawio", &iflags.rawio, FALSE, DISP_IN_GAME},
 #else
 	{"rawio", (boolean *)0, FALSE, SET_IN_FILE},
@@ -161,6 +165,7 @@
 #else
 	{"showexp", (boolean *)0, FALSE, SET_IN_FILE},
 #endif
+	{"showrace", &iflags.showrace, FALSE, SET_IN_GAME},
 #ifdef SCORE_ON_BOTL
 	{"showscore", &flags.showscore, FALSE, SET_IN_GAME},
 #else
@@ -172,7 +177,7 @@
 	{"sparkle", &flags.sparkle, TRUE, SET_IN_GAME},
 	{"standout", &flags.standout, FALSE, SET_IN_GAME},
 	{"splash_screen",     &iflags.wc_splash_screen, TRUE, DISP_IN_GAME},	/*WC*/
-	{"tiled_map",     &iflags.wc_tiled_map, FALSE, DISP_IN_GAME},	/*WC*/
+	{"tiled_map",     &iflags.wc_tiled_map, PREFER_TILED, DISP_IN_GAME},	/*WC*/
 	{"time", &flags.time, FALSE, SET_IN_GAME},
 #ifdef TIMED_DELAY
 	{"timed_delay", &flags.nap, TRUE, SET_IN_GAME},
@@ -181,6 +186,7 @@
 #endif
 	{"tombstone",&flags.tombstone, TRUE, SET_IN_GAME},
 	{"toptenwin",&flags.toptenwin, FALSE, SET_IN_GAME},
+	{"travel", &iflags.travelcmd, TRUE, SET_IN_GAME},
 	{"use_inverse",   &iflags.wc_inverse, FALSE, SET_IN_GAME},		/*WC*/
 	{"verbose", &flags.verbose, TRUE, SET_IN_GAME},
 	{(char *)0, (boolean *)0, FALSE, 0}
@@ -202,10 +208,6 @@
 						8, DISP_IN_GAME },
 	{ "align_message", "message window alignment", 20, DISP_IN_GAME }, 	/*WC*/
 	{ "align_status", "status window alignment", 20, DISP_IN_GAME }, 	/*WC*/
-#ifdef MAC
-	{ "background", "the color of the background (black or white)",
-						6, SET_IN_FILE },
-#endif
 	{ "boulder",  "the symbol to use for displaying boulders",
 						1, SET_IN_GAME },
 	{ "catname",  "the name of your (first) cat (e.g., catname:Tabby)",
@@ -258,6 +260,11 @@
 						MAXMCLASSES, SET_IN_FILE },
 	{ "msghistory", "number of top line messages to save",
 						5, DISP_IN_GAME },
+# ifdef TTY_GRAPHICS
+	{"msg_window", "the type of message window required",1, SET_IN_GAME},
+# else
+	{"msg_window", "the type of message window required", 1, SET_IN_FILE},
+# endif
 	{ "name",     "your character's name (e.g., name:Merlin-W)",
 						PL_NSIZ, DISP_IN_GAME },
 	{ "objects",  "the symbols to use for objects",
@@ -283,8 +290,12 @@
 						PL_CSIZ, DISP_IN_GAME },
 	{ "role",     "your starting role (e.g., Barbarian, Valkyrie)",
 						PL_CSIZ, DISP_IN_GAME },
+	{ "runmode", "display updating frequency when `running' or `travelling'",
+						sizeof "teleport", SET_IN_GAME },
 	{ "scores",   "the parts of the score list you wish to see",
 						32, SET_IN_GAME },
+	{ "scroll_amount", "scroll the map this amount when scroll_margin is reached",
+						20, DISP_IN_GAME }, /*WC*/
 	{ "scroll_margin", "scroll map when this far from the edge", 20, DISP_IN_GAME }, /*WC*/
 #ifdef MSDOS
 	{ "soundcard", "type of sound card to use", 20, SET_IN_FILE },
@@ -296,9 +307,6 @@
 	{ "tile_file", "name of tile file", 70, DISP_IN_GAME},	/*WC*/
 	{ "traps",    "the symbols to use in drawing traps",
 						MAXTCHARS+1, SET_IN_FILE },
-#ifdef MAC
-	{"use_stone", "use stone background patterns", 8, SET_IN_FILE },
-#endif
 	{ "vary_msgcount", "show more old messages at a time", 20, DISP_IN_GAME }, /*WC*/
 #ifdef MSDOS
 	{ "video",    "method of video updating", 20, SET_IN_FILE },
@@ -332,7 +340,7 @@
 #endif
 
 static char def_inv_order[MAXOCLASSES] = {
-	GOLD_CLASS, AMULET_CLASS, WEAPON_CLASS, ARMOR_CLASS, FOOD_CLASS,
+	COIN_CLASS, AMULET_CLASS, WEAPON_CLASS, ARMOR_CLASS, FOOD_CLASS,
 	SCROLL_CLASS, SPBOOK_CLASS, POTION_CLASS, RING_CLASS, WAND_CLASS,
 	TOOL_CLASS, GEM_CLASS, ROCK_CLASS, BALL_CLASS, CHAIN_CLASS, 0,
 };
@@ -478,7 +486,11 @@
 	flags.end_own = FALSE;
 	flags.end_top = 3;
 	flags.end_around = 2;
+	iflags.runmode = RUN_LEAP;
 	iflags.msg_history = 20;
+#ifdef TTY_GRAPHICS
+	iflags.prevmsg_window = 's';
+#endif
 
 	/* Use negative indices to indicate not yet selected */
 	flags.initrole = -1;
@@ -516,7 +528,7 @@
 	 * config file/environment variable below.
 	 */
 	/* this detects the IBM-compatible console on most 386 boxes */
-	if (!strncmp(nh_getenv("TERM"), "AT", 2)) {
+	if ((opts = nh_getenv("TERM")) && !strncmp(opts, "AT", 2)) {
 		switch_graphics(IBM_GRAPHICS);
 # ifdef TEXTCOLOR
 		iflags.use_color = TRUE;
@@ -526,7 +538,8 @@
 #if defined(UNIX) || defined(VMS)
 # ifdef TTY_GRAPHICS
 	/* detect whether a "vt" terminal can handle alternate charsets */
-	if (!strncmpi(nh_getenv("TERM"), "vt", 2) && (AS && AE) &&
+	if ((opts = nh_getenv("TERM")) &&
+	    !strncmpi(opts, "vt", 2) && AS && AE &&
 	    index(AS, '\016') && index(AE, '\017')) {
 		switch_graphics(DEC_GRAPHICS);
 	}
@@ -744,7 +757,7 @@
     num = 0;
 #ifndef GOLDOBJ
     if (!index(op, GOLD_SYM))
-	buf[num++] = GOLD_CLASS;
+	buf[num++] = COIN_CLASS;
 #else
     /*  !!!! probably unnecessary with gold as normal inventory */
 #endif
@@ -820,7 +833,7 @@
 {
 	int i;
 	for (i = 0; i < WARNCOUNT; i++)
-	    warnsyms[i] = graph_chars[i];
+	    if (graph_chars[i]) warnsyms[i] = graph_chars[i];
 }
 
 STATIC_OVL int
@@ -1018,7 +1031,7 @@
 			    preferred_pet = 'n';
 			    break;
 			default:
-			    pline("Unrecognized pet type '%s'", op);
+			    pline("Unrecognized pet type '%s'.", op);
 			    break;
 		    }
 		} else if (negated) preferred_pet = 'n';
@@ -1049,6 +1062,25 @@
 		return;
 	}
 
+	fullname = "runmode";
+	if (match_optname(opts, fullname, 4, TRUE)) {
+		if (negated) {
+			iflags.runmode = RUN_TPORT;
+		} else if ((op = string_for_opt(opts, FALSE)) != 0) {
+		    if (!strncmpi(op, "teleport", strlen(op)))
+			iflags.runmode = RUN_TPORT;
+		    else if (!strncmpi(op, "run", strlen(op)))
+			iflags.runmode = RUN_LEAP;
+		    else if (!strncmpi(op, "walk", strlen(op)))
+			iflags.runmode = RUN_STEP;
+		    else if (!strncmpi(op, "crawl", strlen(op)))
+			iflags.runmode = RUN_CRAWL;
+		    else
+			badoption(opts);
+		}
+		return;
+	}
+
 	fullname = "msghistory";
 	if (match_optname(opts, fullname, 3, TRUE)) {
 		op = string_for_env_opt(fullname, opts, negated);
@@ -1058,6 +1090,41 @@
 		return;
 	}
 
+	fullname="msg_window";
+	/* msg_window:single, combo, full or reversed */
+	if (match_optname(opts, fullname, 4, TRUE)) {
+	/* allow option to be silently ignored by non-tty ports */
+#ifdef TTY_GRAPHICS
+		int tmp;
+		if (!(op = string_for_opt(opts, TRUE))) {
+		    tmp = negated ? 's' : 'f';
+		} else {
+			  if (negated) {
+			  	bad_negation(fullname, TRUE);
+			  	return;
+				  }
+		    tmp = tolower(*op);
+		}
+		switch (tmp) {
+			case 's':	/* single message history cycle (default if negated) */
+				iflags.prevmsg_window = 's';
+				break;
+			case 'c':	/* combination: two singles, then full page reversed */
+				iflags.prevmsg_window = 'c';
+				break;
+			case 'f':	/* full page (default if no opts) */
+				iflags.prevmsg_window = 'f';
+				break;
+			case 'r':	/* full page (reversed) */
+				iflags.prevmsg_window = 'r';
+				break;
+			default:
+				badoption(opts);
+		}
+#endif
+		return;
+	}
+
 	/* WINCAP
 	 * setting font options  */
 	fullname = "font";
@@ -1131,30 +1198,6 @@
 		return;
 	}
 #ifdef CHANGE_COLOR
-#ifdef MAC
-	fullname = "use_stone";
-	if (match_optname(opts, fullname, 6, TRUE)) {
-		op = string_for_env_opt(fullname, opts, negated);
-		if ((negated && !op) || (!negated && op)) {
-			iflags.use_stone = negated ? 0 : atoi(op);
-		} else if (negated) bad_negation(fullname, TRUE);
-		return;
-	}
-
-	fullname = "background";
-	if (match_optname(opts, fullname, 5,TRUE))
-	{
-		if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0)
-		{
-			if (!strncmpi (op, "white", 5))
-				change_background (1);
-			else if (!strncmpi (op, "black", 5))
-				change_background (0);
-		}
-		return;
-	}
-#endif	
-
 	if (match_optname(opts, "palette", 3, TRUE)
 # ifdef MAC
 	    || match_optname(opts, "hicolor", 3, TRUE)
@@ -1827,6 +1870,16 @@
 		return;
 	}
 	/* WINCAP
+	 * scroll_amount:nn */
+	fullname = "scroll_amount";
+	if (match_optname(opts, fullname, sizeof("scroll_amount")-1, TRUE)) {
+		op = string_for_opt(opts, negated);
+		if ((negated && !op) || (!negated && op)) {
+			iflags.wc_scroll_amount = negated ? 1 : atoi(op);
+		} else if (negated) bad_negation(fullname, TRUE);
+		return;
+	}
+	/* WINCAP
 	 * scroll_margin:nn */
 	fullname = "scroll_margin";
 	if (match_optname(opts, fullname, sizeof("scroll_margin")-1, TRUE)) {
@@ -2065,10 +2118,9 @@
 			    vision_recalc(2);		/* shut down vision */
 			    vision_full_recalc = 1;	/* delayed recalc */
 			}
-			else if ((boolopt[i].addr) == &iflags.use_inverse) {
-			    need_redraw = TRUE;
-			}
-			else if ((boolopt[i].addr) == &iflags.hilite_pet) {
+			else if ((boolopt[i].addr) == &iflags.use_inverse ||
+					(boolopt[i].addr) == &iflags.showrace ||
+					(boolopt[i].addr) == &iflags.hilite_pet) {
 			    need_redraw = TRUE;
 			}
 #ifdef TEXTCOLOR
@@ -2104,6 +2156,9 @@
 	"strained", "overtaxed", "overloaded"
 };
 
+static NEARDATA const char *runmodes[] = {
+	"teleport", "run", "walk", "crawl"
+};
 
 /*
  * Convert the given string of object classes to a string of default object
@@ -2133,7 +2188,7 @@
     char from_ch, to_ch;
 {
     if (n_menu_mapped >= MAX_MENU_MAPPED_CMDS)
-	pline("out of menu map space");
+	pline("out of menu map space.");
     else {
 	mapped_menu_cmds[n_menu_mapped] = from_ch;
 	mapped_menu_op[n_menu_mapped] = to_ch;
@@ -2160,7 +2215,7 @@
 }
 
 
-#if defined(MICRO) || defined(MAC)
+#if defined(MICRO) || defined(MAC) || defined(WIN32)
 # define OPTIONS_HEADING "OPTIONS"
 #else
 # define OPTIONS_HEADING "NETHACKOPTIONS"
@@ -2225,7 +2280,7 @@
 	start_menu(tmpwin);
 
 	any.a_void = 0;
-	add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
+ add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_BOLD,
 		 "Booleans (selecting will toggle value):", MENU_UNSELECTED);
 	any.a_int = 0;
 	/* first list any other non-modifiable booleans, then modifiable ones */
@@ -2257,7 +2312,7 @@
 	indexoffset = boolcount;
 	any.a_void = 0;
 	add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED);
-	add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
+ add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_BOLD,
 		 "Compounds (selecting will prompt for new value):",
 		 MENU_UNSELECTED);
 
@@ -2298,7 +2353,7 @@
 		}
 #ifdef PREFIXES_IN_USE
 	add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED);
-	add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
+ add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_BOLD,
 		 "Variable playground locations:", MENU_UNSELECTED);
 	for (i = 0; i < PREFIX_COUNT; i++)
 		doset_add_menu(tmpwin, fqn_prefix_names[i], 0);
@@ -2329,6 +2384,8 @@
 							setinitial, fromfile)) {
 			Sprintf(buf, "Set %s to what?", compopt[opt_indx].name);
 			getlin(buf, buf2);
+			if (buf2[0] == '\033')
+			    continue;
 			Sprintf(buf, "%s:%s", compopt[opt_indx].name, buf2);
 			/* pass the buck */
 			parseoptions(buf, setinitial, fromfile);
@@ -2358,7 +2415,8 @@
     char buf[BUFSZ];
     boolean retval = FALSE;
     
-    /* Special handling of menustyle, pickup_burden, and pickup_types, disclose options. */
+    /* Special handling of menustyle, pickup_burden, and pickup_types,
+       disclose, runmode, and msg_window options. */
     if (!strcmp("menustyle", optname)) {
 	const char *style_name;
 	menu_item *style_pick = (menu_item *)0;
@@ -2465,6 +2523,82 @@
 	    }
 	}
 	retval = TRUE;
+    } else if (!strcmp("runmode", optname)) {
+	const char *mode_name;
+	menu_item *mode_pick = (menu_item *)0;
+	tmpwin = create_nhwindow(NHW_MENU);
+	start_menu(tmpwin);
+	for (i = 0; i < SIZE(runmodes); i++) {
+		mode_name = runmodes[i];
+		any.a_int = i + 1;
+		add_menu(tmpwin, NO_GLYPH, &any, *mode_name, 0,
+			 ATR_NONE, mode_name, MENU_UNSELECTED);
+	}
+	end_menu(tmpwin, "Select run/travel display mode:");
+	if (select_menu(tmpwin, PICK_ONE, &mode_pick) > 0) {
+		iflags.runmode = mode_pick->item.a_int - 1;
+		free((genericptr_t)mode_pick);
+	}
+	destroy_nhwindow(tmpwin);
+	retval = TRUE;
+    } 
+#ifdef TTY_GRAPHICS
+      else if (!strcmp("msg_window", optname)) {
+	/* by Christian W. Cooper */
+	menu_item *window_pick = (menu_item *)0;
+	tmpwin = create_nhwindow(NHW_MENU);
+	start_menu(tmpwin);
+	any.a_char = 's';
+	add_menu(tmpwin, NO_GLYPH, &any, 's', 0,
+		ATR_NONE, "single", MENU_UNSELECTED);
+	any.a_char = 'c';
+	add_menu(tmpwin, NO_GLYPH, &any, 'c', 0,
+		ATR_NONE, "combination", MENU_UNSELECTED);
+	any.a_char = 'f';
+	add_menu(tmpwin, NO_GLYPH, &any, 'f', 0,
+		ATR_NONE, "full", MENU_UNSELECTED);
+	any.a_char = 'r';
+	add_menu(tmpwin, NO_GLYPH, &any, 'r', 0,
+		ATR_NONE, "reversed", MENU_UNSELECTED);
+	end_menu(tmpwin, "Select message history display type:");
+	if (select_menu(tmpwin, PICK_ONE, &window_pick) > 0) {
+		iflags.prevmsg_window = window_pick->item.a_char;
+		free((genericptr_t)window_pick);
+	}
+	destroy_nhwindow(tmpwin);
+        retval = TRUE;
+    }
+#endif
+     else if (!strcmp("align_message", optname) ||
+		!strcmp("align_status", optname)) {
+	menu_item *window_pick = (menu_item *)0;
+	char abuf[BUFSZ];
+	boolean msg = (*(optname+6) == 'm');
+
+	tmpwin = create_nhwindow(NHW_MENU);
+	start_menu(tmpwin);
+	any.a_int = ALIGN_TOP;
+	add_menu(tmpwin, NO_GLYPH, &any, 't', 0,
+		ATR_NONE, "top", MENU_UNSELECTED);
+	any.a_int = ALIGN_BOTTOM;
+	add_menu(tmpwin, NO_GLYPH, &any, 'b', 0,
+		ATR_NONE, "bottom", MENU_UNSELECTED);
+	any.a_int = ALIGN_LEFT;
+	add_menu(tmpwin, NO_GLYPH, &any, 'l', 0,
+		ATR_NONE, "left", MENU_UNSELECTED);
+	any.a_int = ALIGN_RIGHT;
+	add_menu(tmpwin, NO_GLYPH, &any, 'r', 0,
+		ATR_NONE, "right", MENU_UNSELECTED);
+	Sprintf(abuf, "Select %s window placement relative to the map:",
+		msg ? "message" : "status");
+	end_menu(tmpwin, abuf);
+	if (select_menu(tmpwin, PICK_ONE, &window_pick) > 0) {		
+		if (msg) iflags.wc_align_message = window_pick->item.a_int;
+		else iflags.wc_align_status = window_pick->item.a_int;
+		free((genericptr_t)window_pick);
+	}
+	destroy_nhwindow(tmpwin);
+        retval = TRUE;
     }
     return retval;
 }
@@ -2602,6 +2736,12 @@
 		Sprintf(buf, "%s", to_be_done);
 	else if (!strcmp(optname, "msghistory"))
 		Sprintf(buf, "%u", iflags.msg_history);
+#ifdef TTY_GRAPHICS
+	else if (!strcmp(optname, "msg_window"))
+		Sprintf(buf, "%s", (iflags.prevmsg_window=='s') ? "single" :
+					(iflags.prevmsg_window=='c') ? "combination" :
+					(iflags.prevmsg_window=='f') ? "full" : "reversed");
+#endif
 	else if (!strcmp(optname, "name"))
 		Sprintf(buf, "%s", plname);
 	else if (!strcmp(optname, "objects"))
@@ -2628,10 +2768,16 @@
 		Sprintf(buf, "%s", rolestring(flags.initrace, races, noun));
 	else if (!strcmp(optname, "role"))
 		Sprintf(buf, "%s", rolestring(flags.initrole, roles, name.m));
+	else if (!strcmp(optname, "runmode"))
+		Sprintf(buf, "%s", runmodes[iflags.runmode]);
 	else if (!strcmp(optname, "scores")) {
 		Sprintf(buf, "%d top/%d around%s", flags.end_top,
 				flags.end_around, flags.end_own ? "/own" : "");
 	}
+	else if (!strcmp(optname, "scroll_amount")) {
+		if (iflags.wc_scroll_amount) Sprintf(buf, "%d",iflags.wc_scroll_amount);
+		else Strcpy(buf, defopt);
+	}
 	else if (!strcmp(optname, "scroll_margin")) {
 		if (iflags.wc_scroll_margin) Sprintf(buf, "%d",iflags.wc_scroll_margin);
 		else Strcpy(buf, defopt);
@@ -3018,8 +3164,8 @@
 	{"color", WC_COLOR},
 	{"eight_bit_tty", WC_EIGHT_BIT_IN},
 	{"hilite_pet", WC_HILITE_PET},
-	{"large_font", WC_LARGE_FONT},	/* now obsolete */
 	{"popup_dialog", WC_POPUP_DIALOG},
+	{"player_selection", WC_PLAYER_SELECTION},
 	{"preload_tiles", WC_PRELOAD_TILES},
 	{"tiled_map", WC_TILED_MAP},
 	{"tile_file", WC_TILE_FILE},
@@ -3042,8 +3188,12 @@
 	{"font_status", WC_FONT_STATUS},
 	{"font_text", WC_FONT_TEXT},
 	{"map_mode", WC_MAP_MODE},
+	{"scroll_amount", WC_SCROLL_AMOUNT},
 	{"scroll_margin", WC_SCROLL_MARGIN},
+	{"splash_screen", WC_SPLASH_SCREEN},
 	{"vary_msgcount",WC_VARY_MSGCOUNT},
+	{"windowcolors", WC_WINDOWCOLORS},
+	{"mouse_support", WC_MOUSE_SUPPORT},
 	{(char *)0, 0L}
 };
 
@@ -3057,12 +3207,13 @@
  */
 void
 set_option_mod_status(optnam, status)
-char *optnam;
+const char *optnam;
 int status;
 {
 	int k;
 	if (status < SET_IN_FILE || status > SET_IN_GAME) {
-		impossible("set_option_mod_status: status out of range %d.", status);
+		impossible("set_option_mod_status: status out of range %d.",
+			   status);
 		return;
 	}
 	for (k = 0; boolopt[k].name; k++) {
@@ -3094,7 +3245,8 @@
 {
 	int k = 0;
 	if (status < SET_IN_FILE || status > SET_IN_GAME) {
-		impossible("set_option_mod_status: status out of range %d.", status);
+		impossible("set_option_mod_status: status out of range %d.",
+			   status);
 		return;
 	}
 	while (wc_options[k].wc_name) {
@@ -3177,8 +3329,8 @@
 	int j;
 	char buf[BUFSZ];
 	char *wn, *tfg, *tbg, *newop;
-	static char *wnames[] = {"menu", "message", "status", "text"};
-	static char *shortnames[] = {"mnu", "msg", "sts", "txt"};
+	static const char *wnames[] = { "menu", "message", "status", "text" };
+	static const char *shortnames[] = { "mnu", "msg", "sts", "txt" };
 	static char **fgp[] = {
 		&iflags.wc_foregrnd_menu,
 		&iflags.wc_foregrnd_message,
diff -Naurd ../nethack-3.4.0/src/pager.c ./src/pager.c
--- ../nethack-3.4.0/src/pager.c Wed Mar 20 23:43:13 2002
+++ ./src/pager.c Mon Feb 24 15:25:05 2003
@@ -65,7 +65,7 @@
 
     buf[0] = monbuf[0] = 0;
     glyph = glyph_at(x,y);
-    if (u.ux == x && u.uy == y && canseeself()) {
+    if (u.ux == x && u.uy == y && senseself()) {
 	char race[QBUFSZ];
 
 	/* if not polymorphed, show both the role and the race */
@@ -79,6 +79,11 @@
 		race,
 		mons[u.umonnum].mname,
 		plname);
+	/* file lookup can't distinguish between "gnomish wizard" monster
+	   and correspondingly named player character, always picking the
+	   former; force it to find the general "wizard" entry instead */
+	if (Role_if(PM_WIZARD) && Race_if(PM_GNOME) && !Upolyd)
+	    pm = &mons[PM_WIZARD];
 
 #ifdef STEED
 	if (u.usteed) {
@@ -89,6 +94,27 @@
 	    Strcat(buf, steedbuf);
 	}
 #endif
+	/* When you see yourself normally, no explanation is appended
+	   (even if you could also see yourself via other means).
+	   Sensing self while blind or swallowed is treated as if it
+	   were by normal vision (cf canseeself()). */
+	if ((Invisible || u.uundetected) && !Blind && !u.uswallow) {
+	    unsigned how = 0;
+
+	    if (Infravision)	 how |= 1;
+	    if (Unblind_telepat) how |= 2;
+	    if (Detect_monsters) how |= 4;
+
+	    if (how)
+		Sprintf(eos(buf), " [seen: %s%s%s%s%s]",
+			(how & 1) ? "infravision" : "",
+			/* add comma if telep and infrav */
+			((how & 3) > 2) ? ", " : "",
+			(how & 2) ? "telepathy" : "",
+			/* add comma if detect and (infrav or telep or both) */
+			((how & 7) > 4) ? ", " : "",
+			(how & 4) ? "monster detection" : "");
+	}
     } else if (u.uswallow) {
 	/* all locations when swallowed other than the hero are the monster */
 	Sprintf(buf, "interior of %s",
@@ -121,6 +147,18 @@
 	    if (mtmp->mleashed)
 		Strcat(buf, ", leashed to you");
 
+	    if (mtmp->mtrapped && cansee(mtmp->mx, mtmp->my)) {
+		struct trap *t = t_at(mtmp->mx, mtmp->my);
+		int tt = t ? t->ttyp : NO_TRAP;
+
+		/* newsym lets you know of the trap, so mention it here */
+		if (tt == BEAR_TRAP || tt == PIT ||
+		    tt == SPIKED_PIT ||tt == WEB) {
+		    Strcat(buf, ", trapped in ");
+		    Strcat(buf, defsyms[trap_to_defsym(tt)].explanation);
+		}
+	    }
+
 	    {
 		int ways_seen = 0, normal = 0, xraydist;
 		boolean useemon = (boolean) canseemon(mtmp);
@@ -200,7 +238,7 @@
 	if (!otmp || otmp->otyp != glyph_to_obj(glyph)) {
 	    if (glyph_to_obj(glyph) != STRANGE_OBJECT) {
 		otmp = mksobj(glyph_to_obj(glyph), FALSE, FALSE);
-		if (otmp->oclass == GOLD_CLASS)
+		if (otmp->oclass == COIN_CLASS)
 		    otmp->quan = 2L; /* to force pluralization */
 		else if (otmp->otyp == SLIME_MOLD)
 		    otmp->spe = current_fruit;	/* give the fruit a type */
@@ -431,7 +469,7 @@
     boolean from_screen;	/* question from the screen */
     boolean need_to_look;	/* need to get explan. from glyph */
     boolean hit_trap;		/* true if found trap explanation */
-    int skipped_venom = 0;	/* non-zero if we ignored "splash of venom" */
+    int skipped_venom;		/* non-zero if we ignored "splash of venom" */
     static const char *mon_interior = "the interior of a monster";
 
     if (quick) {
@@ -468,6 +506,7 @@
 	/* Reset some variables. */
 	need_to_look = FALSE;
 	pm = (struct permonst *)0;
+	skipped_venom = 0;
 	found = 0;
 	out_str[0] = '\0';
 
@@ -521,7 +560,8 @@
 
 	/* Check for monsters */
 	for (i = 0; i < MAXMCLASSES; i++) {
-	    if (sym == (from_screen ? monsyms[i] : def_monsyms[i])) {
+	    if (sym == (from_screen ? monsyms[i] : def_monsyms[i]) &&
+		monexplain[i]) {
 		need_to_look = TRUE;
 		if (!found) {
 		    Sprintf(out_str, "%c       %s", sym, an(monexplain[i]));
@@ -532,11 +572,14 @@
 		}
 	    }
 	}
-	/* handle '@' as a special case; firstmatch is guaranteed
-	   to already be set in that case */
-	if (!from_screen ? (sym == def_monsyms[S_HUMAN]) :
-		(cc.x == u.ux && cc.y == u.uy && sym == monsyms[S_HUMAN]))
-	     found += append_str(out_str, "you");	/* tack on "or you" */
+	/* handle '@' as a special case if it refers to you and you're
+	   playing a character which isn't normally displayed by that
+	   symbol; firstmatch is assumed to already be set for '@' */
+	if ((from_screen ?
+		(sym == monsyms[S_HUMAN] && cc.x == u.ux && cc.y == u.uy) :
+		(sym == def_monsyms[S_HUMAN] && !iflags.showrace)) &&
+	    !(Race_if(PM_HUMAN) || Race_if(PM_ELF)) && !Upolyd)
+	    found += append_str(out_str, "you");	/* tack on "or you" */
 
 	/*
 	 * Special case: if identifying from the screen, and we're swallowed,
@@ -629,6 +672,10 @@
 		} else {
 			found += append_str(out_str, def_warnsyms[i].explanation);
 		}
+		/* Kludge: warning trumps boulders on the display.
+		   Reveal the boulder too or player can get confused */
+		if (sobj_at(BOULDER, cc.x, cc.y))
+			Strcat(out_str, " co-located with a boulder");
 		break;	/* out of for loop*/
 	    }
 	}
@@ -646,8 +693,15 @@
 	}
 
 	/* handle optional boulder symbol as a special case */ 
-	if (iflags.bouldersym && sym == iflags.bouldersym)
+	if (iflags.bouldersym && sym == iflags.bouldersym) {
+	    if (!found) {
+		firstmatch = "boulder";
+		Sprintf(out_str, "%c       %s", sym, an(firstmatch));
+		found++;
+	    } else {
 		found += append_str(out_str, "boulder");
+	    }
+	}
 	
 	/*
 	 * If we are looking at the screen, follow multiple possibilities or
@@ -711,7 +765,7 @@
 	register struct trap *trap;
 	int x, y, tt;
 
-	if (!getdir((char *)0)) return 0;
+	if (!getdir("^")) return 0;
 	x = u.ux + u.dx;
 	y = u.uy + u.dy;
 	for (trap = ftrap; trap; trap = trap->ntrap)
@@ -737,12 +791,14 @@
 	return 0;
 }
 
-int
-dowhatdoes()
+char *
+dowhatdoes_core(q, cbuf)
+char q;
+char *cbuf;
 {
 	dlb *fp;
-	char bufr[BUFSZ+6];
-	register char *buf = &bufr[6], *ep, q, ctrl, meta;
+	char bufr[BUFSZ];
+	register char *buf = &bufr[6], *ep, ctrl, meta;
 
 	fp = dlb_fopen(CMDHELPFILE, "r");
 	if (!fp) {
@@ -750,16 +806,9 @@
 		return 0;
 	}
 
-#if defined(UNIX) || defined(VMS)
-	introff();
-#endif
-	q = yn_function("What command?", (char *)0, '\0');
-#if defined(UNIX) || defined(VMS)
-	intron();
-#endif
-	ctrl = ((q <= '\033') ? (q - 1 + 'A') : 0);
+  	ctrl = ((q <= '\033') ? (q - 1 + 'A') : 0);
 	meta = ((0x80 & q) ? (0x7f & q) : 0);
-	while(dlb_fgets(buf,BUFSZ,fp))
+	while(dlb_fgets(buf,BUFSZ-6,fp)) {
 	    if ((ctrl && *buf=='^' && *(buf+1)==ctrl) ||
 		(meta && *buf=='M' && *(buf+1)=='-' && *(buf+2)==meta) ||
 		*buf==q) {
@@ -778,12 +827,33 @@
 			buf[0] = q;
 			(void) strncpy(buf+1, "       ", 7);
 		}
-		pline("%s", buf);
 		(void) dlb_fclose(fp);
-		return 0;
+		Strcpy(cbuf, buf);
+		return cbuf;
 	    }
-	pline("I've never heard of such commands.");
+	}
 	(void) dlb_fclose(fp);
+	return (char *)0;
+}
+
+int
+dowhatdoes()
+{
+	char bufr[BUFSZ];
+	char q, *reslt;
+
+#if defined(UNIX) || defined(VMS)
+	introff();
+#endif
+	q = yn_function("What command?", (char *)0, '\0');
+#if defined(UNIX) || defined(VMS)
+	intron();
+#endif
+	reslt = dowhatdoes_core(q, bufr);
+	if (reslt)
+		pline("%s", reslt);
+	else
+		pline("I've never heard of such commands.");
 	return 0;
 }
 
diff -Naurd ../nethack-3.4.0/src/pickup.c ./src/pickup.c
--- ../nethack-3.4.0/src/pickup.c Wed Mar 20 23:43:13 2002
+++ ./src/pickup.c Mon Feb 24 15:25:05 2003
@@ -32,7 +32,7 @@
 STATIC_PTR int FDECL(ck_bag,(struct obj *));
 STATIC_PTR int FDECL(out_container,(struct obj *));
 STATIC_DCL int FDECL(menu_loot, (int, struct obj *, BOOLEAN_P));
-STATIC_DCL int FDECL(in_or_out_menu, (const char *,struct obj *));
+STATIC_DCL int FDECL(in_or_out_menu, (const char *,struct obj *, BOOLEAN_P, BOOLEAN_P));
 STATIC_DCL int FDECL(container_at, (int, int, BOOLEAN_P));
 STATIC_DCL boolean FDECL(able_to_loot, (int, int));
 STATIC_DCL boolean FDECL(mon_beside, (int, int));
@@ -87,32 +87,36 @@
 
 #ifndef GOLDOBJ
 int
-collect_obj_classes(ilets, otmp, here, incl_gold, filter)
+collect_obj_classes(ilets, otmp, here, incl_gold, filter, itemcount)
 char ilets[];
 register struct obj *otmp;
 boolean here, incl_gold;
 boolean FDECL((*filter),(OBJ_P));
+int *itemcount;
 #else
 int
-collect_obj_classes(ilets, otmp, here, filter)
+collect_obj_classes(ilets, otmp, here, filter, itemcount)
 char ilets[];
 register struct obj *otmp;
 boolean here;
 boolean FDECL((*filter),(OBJ_P));
+int *itemcount;
 #endif
 {
 	register int iletct = 0;
 	register char c;
 
+	*itemcount = 0;
 #ifndef GOLDOBJ
 	if (incl_gold)
-	    ilets[iletct++] = def_oc_syms[GOLD_CLASS];
+	    ilets[iletct++] = def_oc_syms[COIN_CLASS];
 #endif
 	ilets[iletct] = '\0'; /* terminate ilets so that index() will work */
 	while (otmp) {
 	    c = def_oc_syms[(int)otmp->oclass];
 	    if (!index(ilets, c) && (!filter || (*filter)(otmp)))
 		ilets[iletct++] = c,  ilets[iletct] = '\0';
+	    *itemcount += 1;
 	    otmp = here ? otmp->nexthere : otmp->nobj;
 	}
 
@@ -158,6 +162,7 @@
 	boolean not_everything;
 	char qbuf[QBUFSZ];
 	boolean m_seen;
+	int itemcount;
 
 	oclasses[oclassct = 0] = '\0';
 	*one_at_a_time = *everything = m_seen = FALSE;
@@ -165,12 +170,17 @@
 #ifndef GOLDOBJ
 				     incl_gold,
 #endif
-				     (boolean FDECL((*),(OBJ_P))) 0);
+				     (boolean FDECL((*),(OBJ_P))) 0, &itemcount);
 	if (iletct == 0) {
 		return FALSE;
 	} else if (iletct == 1) {
 		oclasses[0] = def_char_to_objclass(ilets[0]);
 		oclasses[1] = '\0';
+		if (itemcount && menu_on_demand) {
+			ilets[iletct++] = 'm';
+			*menu_on_demand = 0;
+			ilets[iletct] = '\0';
+		}
 	} else  {	/* more than one choice available */
 		const char *where = 0;
 		register char sym, oc_of_sym, *p;
@@ -312,20 +322,21 @@
 allow_category(obj)
 struct obj *obj;
 {
+    if (Role_if(PM_PRIEST)) obj->bknown = TRUE;
     if (((index(valid_menu_classes,'u') != (char *)0) && obj->unpaid) ||
 	(index(valid_menu_classes, obj->oclass) != (char *)0))
 	return TRUE;
     else if (((index(valid_menu_classes,'U') != (char *)0) &&
-	(obj->oclass != GOLD_CLASS && obj->bknown && !obj->blessed && !obj->cursed)))
+	(obj->oclass != COIN_CLASS && obj->bknown && !obj->blessed && !obj->cursed)))
 	return TRUE;
     else if (((index(valid_menu_classes,'B') != (char *)0) &&
-	(obj->oclass != GOLD_CLASS && obj->bknown && obj->blessed)))
+	(obj->oclass != COIN_CLASS && obj->bknown && obj->blessed)))
 	return TRUE;
     else if (((index(valid_menu_classes,'C') != (char *)0) &&
-	(obj->oclass != GOLD_CLASS && obj->bknown && obj->cursed)))
+	(obj->oclass != COIN_CLASS && obj->bknown && obj->cursed)))
 	return TRUE;
     else if (((index(valid_menu_classes,'X') != (char *)0) &&
-	(obj->oclass != GOLD_CLASS && !obj->bknown)))
+	(obj->oclass != COIN_CLASS && !obj->bknown)))
 	return TRUE;
     else
 	return FALSE;
@@ -437,9 +448,9 @@
 	    goto menu_pickup;
 	}
 
-	if (flags.menu_style != MENU_TRADITIONAL) {
-	    /* use menus exclusively */
+	if (flags.menu_style != MENU_TRADITIONAL || iflags.menu_requested) {
 
+	    /* use menus exclusively */
 	    if (count) {	/* looking for N of something */
 		char buf[QBUFSZ];
 		Sprintf(buf, "Pick %d of what?", count);
@@ -524,7 +535,7 @@
 		    continue;
 
 		if (!all_of_a_type) {
-		    char qbuf[QBUFSZ];
+		    char qbuf[BUFSZ];
 		    Sprintf(qbuf, "Pick up %s?", doname(obj));
 		    switch ((obj->quan < 2L) ? ynaq(qbuf) : ynNaq(qbuf)) {
 		    case 'q': goto end_query;	/* out 2 levels */
@@ -905,15 +916,15 @@
 }
 
 /* could we carry `obj'? if not, could we carry some of it/them? */
-STATIC_OVL
-long carry_count(obj, container, count, telekinesis, wt_before, wt_after)
+STATIC_OVL long
+carry_count(obj, container, count, telekinesis, wt_before, wt_after)
 struct obj *obj, *container;	/* object to pick up, bag it's coming out of */
 long count;
 boolean telekinesis;
 int *wt_before, *wt_after;
 {
     boolean adjust_wt = container && carried(container),
-	    is_gold = obj->oclass == GOLD_CLASS;
+	    is_gold = obj->oclass == COIN_CLASS;
     int wt, iw, ow, oow;
     long qq, savequan;
 #ifdef GOLDOBJ
@@ -1090,7 +1101,7 @@
     if (*cnt_p < 1L) {
 	result = -1;	/* nothing lifted */
 #ifndef GOLDOBJ
-    } else if (obj->oclass != GOLD_CLASS && inv_cnt() >= 52 &&
+    } else if (obj->oclass != COIN_CLASS && inv_cnt() >= 52 &&
 		!merge_choice(invent, obj)) {
 #else
     } else if (inv_cnt() >= 52 && !merge_choice(invent, obj)) {
@@ -1107,7 +1118,7 @@
 	    if (telekinesis) {
 		result = 0;	/* don't lift */
 	    } else {
-		char qbuf[QBUFSZ];
+		char qbuf[BUFSZ];
 		long savequan = obj->quan;
 
 		obj->quan = *cnt_p;
@@ -1121,6 +1132,7 @@
 		case 'n':  result =  0; break;
 		default:   break;	/* 'y' => result == 1 */
 		}
+		clear_nhwindow(WIN_MESSAGE);
 	    }
 	}
     }
@@ -1166,7 +1178,7 @@
 	} else if (obj->oartifact && !touch_artifact(obj,&youmonst)) {
 	    return 0;
 #ifndef GOLDOBJ
-	} else if (obj->oclass == GOLD_CLASS) {
+	} else if (obj->oclass == COIN_CLASS) {
 	    /* Special consideration for gold pieces... */
 	    long iw = (long)max_capacity() - GOLD_WT(u.ugold);
 	    long gold_capacity = GOLD_CAPACITY(iw, u.ugold);
@@ -1247,7 +1259,7 @@
 
 #ifdef GOLDOBJ
         /* Whats left of the special case for gold :-) */
-	if (obj->oclass == GOLD_CLASS) flags.botl = 1;
+	if (obj->oclass == COIN_CLASS) flags.botl = 1;
 #endif
 	if (obj->quan != count && obj->otyp != LOADSTONE)
 	    obj = splitobj(obj, count);
@@ -1275,10 +1287,7 @@
 struct obj *otmp;
 {
 	obj_extract_self(otmp);
-	if (otmp->no_charge) {
-	    /* this attribute only applies to objects outside invent */
-	    otmp->no_charge = 0;
-	} else if (otmp != uball && costly_spot(otmp->ox, otmp->oy)) {
+	if (otmp != uball && costly_spot(otmp->ox, otmp->oy)) {
 	    char saveushops[5], fakeshop[2];
 
 	    /* addtobill cares about your location rather than the object's;
@@ -1295,6 +1304,8 @@
 	    if (!index(u.ushops, *fakeshop))
 		remote_burglary(otmp->ox, otmp->oy);
 	}
+	if (otmp->no_charge)	/* only applies to objects outside invent */
+	    otmp->no_charge = 0;
 	if (Invisible) newsym(otmp->ox, otmp->oy);
 	return addinv(otmp);	/* might merge it with other objects */
 }
@@ -1368,8 +1379,7 @@
 	if (!can_reach_floor()) {
 #ifdef STEED
 		if (u.usteed && P_SKILL(P_RIDING) < P_BASIC)
-			You("aren't skilled enough to reach from %s.",
-				mon_nam(u.usteed));
+			rider_cant_reach(); /* not skilled enough to reach */
 		else
 #endif
 			You("cannot reach the %s.", surface(x, y));
@@ -1386,8 +1396,8 @@
 	return TRUE;
 }
 
-STATIC_OVL
-boolean mon_beside(x,y)
+STATIC_OVL boolean
+mon_beside(x,y)
 int x, y;
 {
 	int i,j,nx,ny;
@@ -1402,16 +1412,16 @@
 }
 
 int
-doloot()	/* loot a container on the floor. */
+doloot()	/* loot a container on the floor or loot saddle from mon. */
 {
     register struct obj *cobj, *nobj;
     register int c = -1;
     int timepassed = 0;
-    int x,y;
+    coord cc;
     boolean underfoot = TRUE;
     const char *dont_find_anything = "don't find anything";
     struct monst *mtmp;
-    char qbuf[QBUFSZ];
+    char qbuf[BUFSZ];
     int prev_inquiry = 0;
     boolean prev_loot = FALSE;
 
@@ -1423,13 +1433,15 @@
 	You("have no hands!");	/* not `body_part(HAND)' */
 	return 0;
     }
-    x = u.ux; y = u.uy;
+    cc.x = u.ux; cc.y = u.uy;
 
 lootcont:
 
-    if (container_at(x, y, FALSE)) {
-	if (!able_to_loot(x, y)) return 0;
-	for (cobj = level.objects[x][y]; cobj; cobj = nobj) {
+    if (container_at(cc.x, cc.y, FALSE)) {
+	boolean any = FALSE;
+
+	if (!able_to_loot(cc.x, cc.y)) return 0;
+	for (cobj = level.objects[cc.x][cc.y]; cobj; cobj = nobj) {
 	    nobj = cobj->nexthere;
 
 	    if (Is_container(cobj)) {
@@ -1437,6 +1449,7 @@
 		c = ynq(qbuf);
 		if (c == 'q') return (timepassed);
 		if (c == 'n') continue;
+		any = TRUE;
 
 		if (cobj->olocked) {
 		    pline("Hmmm, it seems to be locked.");
@@ -1459,6 +1472,7 @@
 		if (multi < 0) return 1;		/* chest trap */
 	    }
 	}
+	if (any) c = 'y';
     } else if (Confusion) {
 #ifndef GOLDOBJ
 	if (u.ugold){
@@ -1468,7 +1482,7 @@
 	struct obj *goldob;
 	/* Find a money object to mess with */
 	for (goldob = invent; goldob; goldob = goldob->nobj) {
-	    if (goldob->oclass == GOLD_CLASS) break;
+	    if (goldob->oclass == COIN_CLASS) break;
 	}
 	if (goldob){
 	    long contribution = rnd((int)min(LARGEST_INT, goldob->quan));
@@ -1516,32 +1530,28 @@
 		pline("Ok, now there is loot here.");
 	    }
 	}
-    } else if (IS_GRAVE(levl[x][y].typ)) {
+    } else if (IS_GRAVE(levl[cc.x][cc.y].typ)) {
 	You("need to dig up the grave to effectively loot it...");
     }
     /*
      * 3.3.1 introduced directional looting for some things.
      */
     if (c != 'y' && mon_beside(u.ux, u.uy)) {
-	if (!getdir("Loot in what direction?")) {
-	    pline(Never_mind);
-	    return(0);
-	}
-	x = u.ux + u.dx;
-	y = u.uy + u.dy;
-	if (x == u.ux && y == u.uy) {
+	if (!get_adjacent_loc("Loot in what direction?", "Invalid loot location",
+			u.ux, u.uy, &cc)) return 0;
+	if (cc.x == u.ux && cc.y == u.uy) {
 	    underfoot = TRUE;
-	    if (container_at(x, y, FALSE))
+	    if (container_at(cc.x, cc.y, FALSE))
 		goto lootcont;
 	} else
 	    underfoot = FALSE;
 	if (u.dz < 0) {
 	    You("%s to loot on the %s.", dont_find_anything,
-		ceiling(x, y));
+		ceiling(cc.x, cc.y));
 	    timepassed = 1;
 	    return timepassed;
 	}
-	mtmp = m_at(x, y);
+	mtmp = m_at(cc.x, cc.y);
 	if (mtmp) timepassed = loot_mon(mtmp, &prev_inquiry, &prev_loot);
 
 	/* Preserve pre-3.3.1 behaviour for containers.
@@ -1549,7 +1559,7 @@
 	 * from one square away to change that in the future.
 	 */
 	if (!underfoot) {
-	    if (container_at(x, y, FALSE)) {
+	    if (container_at(cc.x, cc.y, FALSE)) {
 		if (mtmp) {
 		    You_cant("loot anything %sthere with %s in the way.",
 			    prev_inquiry ? "else " : "", mon_nam(mtmp));
@@ -1609,7 +1619,7 @@
 		if ((unwornmask = otmp->owornmask) != 0L) {
 		    mtmp->misc_worn_check &= ~unwornmask;
 		    otmp->owornmask = 0L;
-		    update_mon_intrinsics(mtmp, otmp, FALSE);
+		    update_mon_intrinsics(mtmp, otmp, FALSE, FALSE);
 		}
 		otmp = hold_another_object(otmp, "You drop %s!", doname(otmp),
 					(const char *)0);
@@ -1665,8 +1675,8 @@
 in_container(obj)
 register struct obj *obj;
 {
-	boolean is_gold = (obj->oclass == GOLD_CLASS);
 	boolean floor_container = !carried(current_container);
+	boolean was_unpaid = FALSE;
 	char buf[BUFSZ];
 
 	if (!current_container) {
@@ -1751,9 +1761,16 @@
 		(void) snuff_lit(obj);
 
 	if (floor_container && costly_spot(u.ux, u.uy)) {
+	    if (current_container->no_charge && !obj->unpaid) {
+		/* don't sell when putting the item into your own container */
+		obj->no_charge = 1;
+	    } else {
+		/* sellobj() will take an unpaid item off the shop bill */
+		was_unpaid = obj->unpaid ? TRUE : FALSE;
 		sellobj_state(SELL_DELIBERATE);
 		sellobj(obj, u.ux, u.uy);
 		sellobj_state(SELL_NORMAL);
+	    }
 	}
 	if (Icebox && obj->otyp != OIL_LAMP && obj->otyp != BRASS_LANTERN
 			&& !Is_candle(obj)) {
@@ -1764,21 +1781,11 @@
 			(void) stop_timer(REVIVE_MON, (genericptr_t)obj);
 			/* mark a non-reviving corpse as such */
 			if (rot_alarm) obj->norevive = 1;
-  		}
-	}
-
-	else if (Is_mbag(current_container) && mbag_explodes(obj, 0)) {
-		You("are blasted by a magical explosion!");
-
-		/* the !floor_container case is taken care of */
-		if(*u.ushops && costly_spot(u.ux, u.uy) && floor_container) {
-		    register struct monst *shkp;
-
-		    if ((shkp = shop_keeper(*u.ushops)) != 0)
-			(void)stolen_value(current_container, u.ux, u.uy,
-					   (boolean)shkp->mpeaceful, FALSE);
 		}
+	} else if (Is_mbag(current_container) && mbag_explodes(obj, 0)) {
+		You("are blasted by a magical explosion!");
 		/* did not actually insert obj yet */
+		if (was_unpaid) addtobill(obj, FALSE, FALSE, TRUE);
 		obfree(obj, (struct obj *)0);
 		delete_contents(current_container);
 		if (!floor_container)
@@ -1799,7 +1806,11 @@
 	    (void) add_to_container(current_container, obj);
 	    current_container->owt = weight(current_container);
 	}
-	if (is_gold) bot(); /* update gold piece count immediately */
+	/* gold needs this, and freeinv() many lines above may cause
+	 * the encumbrance to disappear from the status, so just always
+	 * update status immediately.
+	 */
+	bot();
 
 	return(current_container ? 1 : -1);
 }
@@ -1817,7 +1828,7 @@
 register struct obj *obj;
 {
 	register struct obj *otmp;
-	boolean is_gold = (obj->oclass == GOLD_CLASS);
+	boolean is_gold = (obj->oclass == COIN_CLASS);
 	int res, loadlev;
 	long count;
 
@@ -1865,15 +1876,14 @@
 	}
 	/* simulated point of time */
 
-	if (is_pick(obj) && !obj->unpaid && *u.ushops && shop_keeper(*u.ushops))
-		verbalize("You sneaky cad! Get out of here with that pick!");
 	if(!obj->unpaid && !carried(current_container) &&
 	     costly_spot(current_container->ox, current_container->oy)) {
-
 		obj->ox = current_container->ox;
 		obj->oy = current_container->oy;
 		addtobill(obj, FALSE, FALSE, FALSE);
 	}
+	if (is_pick(obj) && !obj->unpaid && *u.ushops && shop_keeper(*u.ushops))
+		verbalize("You sneaky cad! Get out of here with that pick!");
 
 	otmp = addinv(obj);
 	loadlev = near_capacity();
@@ -1906,11 +1916,19 @@
 	struct monst *shkp;
 	boolean one_by_one, allflag, loot_out = FALSE, loot_in = FALSE;
 	char select[MAXOCLASSES+1];
-	char qbuf[QBUFSZ];
+	char qbuf[BUFSZ], emptymsg[BUFSZ], pbuf[QBUFSZ];
 	long loss = 0L;
 	int cnt = 0, used = 0, lcnt = 0,
 	    menu_on_request;
 
+	emptymsg[0] = '\0';
+	if (nohands(youmonst.data)) {
+		You("have no hands!");	/* not `body_part(HAND)' */
+		return 0;
+	} else if (!freehand()) {
+		You("have no free %s.", body_part(HAND));
+		return 0;
+	}
 	if (obj->olocked) {
 	    pline("%s to be locked.", Tobjnam(obj, "seem"));
 	    if (held) You("must put it down to unlock.");
@@ -1992,20 +2010,31 @@
 	    }
 	}
 
-	if (cnt && loss)
+	if (lcnt && loss)
 	    You("owe %ld %s for lost item%s.",
 		loss, currency(loss), lcnt > 1 ? "s" : "");
 
 	obj->owt = weight(obj);
 
-	if (!cnt) {
-	    pline("%s %s empty.", Yname2(obj), otense(obj, "are"));
-	} else {
+	if (!cnt) Sprintf(emptymsg, "%s %s empty.", Yname2(obj), otense(obj, "are"));
+	if (cnt || flags.menu_style == MENU_FULL) {
 	    Sprintf(qbuf, "Do you want to take %s out of %s?",
 		    something, yname(obj));
 	    if (flags.menu_style != MENU_TRADITIONAL) {
 		if (flags.menu_style == MENU_FULL) {
-		    int t = in_or_out_menu("Do what?", current_container);
+		    int t;
+		    char menuprompt[BUFSZ];
+		    boolean outokay = (cnt != 0);
+		    boolean inokay = (invent != 0);
+		    if (!outokay && !inokay) {
+			pline("%s", emptymsg);
+			pline("You don't have anything to put in.");
+			return used;
+		    }
+		    menuprompt[0] = '\0';
+		    if (!cnt) Sprintf(menuprompt, "%s ", emptymsg);
+		    Strcat(menuprompt, "Do what?");
+		    t = in_or_out_menu(menuprompt, current_container, outokay, inokay);
 		    if (t <= 0) return 0;
 		    loot_out = (t & 0x01) != 0;
 		    loot_in  = (t & 0x02) != 0;
@@ -2021,7 +2050,9 @@
 ask_again2:
 		menu_on_request = 0;
 		add_valid_menu_class(0);	/* reset */
-		switch (yn_function(qbuf, ":ynq", 'n')) {
+		Strcpy(pbuf, ":ynq");
+		if (cnt) Strcat(pbuf, "m");
+		switch (yn_function(qbuf, pbuf, 'n')) {
 		case ':':
 		    container_contents(current_container, FALSE, FALSE);
 		    goto ask_again2;
@@ -2046,11 +2077,17 @@
 		    /*FALLTHRU*/
 		case 'n':
 		    break;
+		case 'm':
+		    menu_on_request = -2; /* triggers ALL_CLASSES */
+		    used |= menu_loot(menu_on_request, current_container, FALSE) > 0;
+		    break;
 		case 'q':
 		default:
 		    return used;
 		}
 	    }
+	} else {
+	    pline("%s", emptymsg);		/* <whatever> is empty. */
 	}
 
 #ifndef GOLDOBJ
@@ -2062,9 +2099,26 @@
 	    You("don't have anything to put in.");
 	    return used;
 	}
-	if (flags.menu_style != MENU_FULL || !cnt) {
-	    loot_in = (yn_function("Do you wish to put something in?",
-				   ynqchars, 'n') == 'y');
+	if (flags.menu_style != MENU_FULL) {
+	    Sprintf(qbuf, "Do you wish to put %s in?", something);
+	    Strcpy(pbuf, ynqchars);
+	    if (flags.menu_style == MENU_TRADITIONAL && invent && inv_cnt() > 0)
+		Strcat(pbuf, "m");
+	    switch (yn_function(qbuf, pbuf, 'n')) {
+		case 'y':
+		    loot_in = TRUE;
+		    break;
+		case 'n':
+		    break;
+		case 'm':
+		    add_valid_menu_class(0);	  /* reset */
+		    menu_on_request = -2; /* triggers ALL_CLASSES */
+		    used |= menu_loot(menu_on_request, current_container, TRUE) > 0;
+		    break;
+		case 'q':
+		default:
+		    return used;
+	    }
 	}
 	/*
 	 * Gone: being nice about only selecting food if we know we are
@@ -2078,6 +2132,7 @@
 		 * and put it at the head of the inventory list.
 		 */
 		u_gold = mkgoldobj(u.ugold);	/* removes from u.ugold */
+		u_gold->in_use = TRUE;
 		u.ugold = u_gold->quan;		/* put the gold back */
 		assigninvlet(u_gold);		/* might end up as NOINVSYM */
 		u_gold->nobj = invent;
@@ -2108,10 +2163,11 @@
 	}
 
 #ifndef GOLDOBJ
-	if (u_gold && invent && invent->oclass == GOLD_CLASS) {
+	if (u_gold && invent && invent->oclass == COIN_CLASS) {
 	    /* didn't stash [all of] it */
 	    u_gold = invent;
 	    invent = u_gold->nobj;
+	    u_gold->in_use = FALSE;
 	    dealloc_obj(u_gold);
 	}
 #endif
@@ -2178,8 +2234,13 @@
 			/* special split case also handled by askchain() */
 		    }
 		    res = put_in ? in_container(otmp) : out_container(otmp);
-		    if (res < 0)
+		    if (res < 0) {
+			if (otmp != pick_list[i].item.a_obj) {
+			    /* split occurred, merge again */
+			    (void) merged(&pick_list[i].item.a_obj, &otmp);
+			}
 			break;
+		    }
 		}
 		free((genericptr_t)pick_list);
 	}
@@ -2188,28 +2249,39 @@
 }
 
 STATIC_OVL int
-in_or_out_menu(prompt, obj)
+in_or_out_menu(prompt, obj, outokay, inokay)
 const char *prompt;
 struct obj *obj;
+boolean outokay, inokay;
 {
     winid win;
     anything any;
     menu_item *pick_list;
     char buf[BUFSZ];
     int n;
+    const char *menuselector = iflags.lootabc ? "abc" : "oib";
 
     any.a_void = 0;
     win = create_nhwindow(NHW_MENU);
     start_menu(win);
-    any.a_int = 1;
-    Sprintf(buf,"Take %s out of %s", something, the(xname(obj)));
-    add_menu(win, NO_GLYPH, &any, 'o', 0, ATR_NONE, buf, MENU_UNSELECTED);
-    any.a_int = 2;
-    Sprintf(buf,"Put %s into %s", something, the(xname(obj)));
-    add_menu(win, NO_GLYPH, &any, 'i', 0, ATR_NONE, buf, MENU_UNSELECTED);
-    any.a_int = 3;
-    add_menu(win, NO_GLYPH, &any, 'b', 0, ATR_NONE,
-		"Both of the above", MENU_UNSELECTED);
+    if (outokay) {
+	any.a_int = 1;
+	Sprintf(buf,"Take %s out of %s", something, the(xname(obj)));
+	add_menu(win, NO_GLYPH, &any, *menuselector, 0, ATR_NONE,
+			buf, MENU_UNSELECTED);
+    }
+    menuselector++;
+    if (inokay) {
+	any.a_int = 2;
+	Sprintf(buf,"Put %s into %s", something, the(xname(obj)));
+	add_menu(win, NO_GLYPH, &any, *menuselector, 0, ATR_NONE, buf, MENU_UNSELECTED);
+    }
+    menuselector++;
+    if (outokay && inokay) {
+	any.a_int = 3;
+	add_menu(win, NO_GLYPH, &any, *menuselector, 0, ATR_NONE,
+			"Both of the above", MENU_UNSELECTED);
+    }
     end_menu(win, prompt);
     n = select_menu(win, PICK_ONE, &pick_list);
     destroy_nhwindow(win);
diff -Naurd ../nethack-3.4.0/src/pline.c ./src/pline.c
--- ../nethack-3.4.0/src/pline.c Wed Mar 20 23:43:13 2002
+++ ./src/pline.c Mon Feb 24 15:25:05 2003
@@ -248,6 +248,11 @@
 impossible VA_DECL(const char *, s)
 	VA_START(s);
 	VA_INIT(s, const char *);
+	{
+	    char pbuf[BUFSZ];
+	    Vsprintf(pbuf,s,VA_ARGS);
+	    paniclog("impossible", pbuf);
+	}
 	vpline(s,VA_ARGS);
 	pline("Program in disorder - perhaps you'd better #quit.");
 	VA_END();
diff -Naurd ../nethack-3.4.0/src/polyself.c ./src/polyself.c
--- ../nethack-3.4.0/src/polyself.c Wed Mar 20 23:43:13 2002
+++ ./src/polyself.c Mon Feb 24 15:25:05 2003
@@ -33,8 +33,8 @@
 const char *fmt, *arg;
 {
 	boolean sticky = sticks(youmonst.data) && u.ustuck && !u.uswallow,
-		was_mimicking_gold = (youmonst.m_ap_type == M_AP_OBJECT
-				      && youmonst.mappearance == GOLD_PIECE);
+		was_mimicking = (youmonst.m_ap_type == M_AP_OBJECT);
+
 	boolean was_blind = !!Blind;
 
 	if (Upolyd) {
@@ -52,7 +52,7 @@
 
 	if (sticky) uunstick();
 	find_ac();
-	if (was_mimicking_gold) {
+	if (was_mimicking) {
 	    if (multi < 0) unmul("");
 	} else {
 	    /*
@@ -83,6 +83,10 @@
 	    }
 	    done(GENOCIDED);
 	}
+
+	if (u.twoweap && !could_twoweap(youmonst.data))
+	    untwoweapon();
+
 	if (was_blind && !Blind) {	/* reverting from eyeless */
 	    Blinded = 1L;
 	    make_blinded(0L, TRUE);	/* remove blindness */
@@ -155,7 +159,7 @@
 	reset_rndmonst(NON_PM);	/* new monster generation criteria */
 
 	/* random experience points for the new experience level */
-	u.uexp = rndexp();
+	u.uexp = rndexp(FALSE);
 
 	/* u.uhpmax * u.ulevel / oldlvl: proportionate hit points to new level
 	 * -10 and +10: don't apply proportionate HP to 10 of a starting
@@ -302,7 +306,7 @@
 	/* The below polyok() fails either if everything is genocided, or if
 	 * we deliberately chose something illegal to force newman().
 	 */
-	if (!polyok(&mons[mntmp]) || !rn2(5))
+	if (!polyok(&mons[mntmp]) || !rn2(5) || your_race(&mons[mntmp]))
 		newman();
 	else if(!polymon(mntmp)) return;
 
@@ -352,10 +356,12 @@
 		flags.female = u.mfemale;
 	}
 
-	if (youmonst.m_ap_type == M_AP_OBJECT &&
-		youmonst.mappearance == GOLD_PIECE) {
-	    /* stop mimicking gold immediately */
+	if (youmonst.m_ap_type) {
+	    /* stop mimicking immediately */
 	    if (multi < 0) unmul("");
+	} else if (mons[mntmp].mlet != S_MIMIC) {
+	    /* as in polyman() */
+	    youmonst.m_ap_type = M_AP_NOTHING;
 	}
 	if (is_male(&mons[mntmp])) {
 		if(flags.female) dochange = TRUE;
@@ -583,7 +589,7 @@
 	}
 #endif
     } else if (sliparm(youmonst.data)) {
-	if ((otmp = uarm) != 0) {
+	if (((otmp = uarm) != 0) && (racial_exception(&youmonst, otmp) < 1)) {
 		if (donning(otmp)) cancel_don();
 		Your("armor falls around you!");
 		(void) Armor_gone();
@@ -606,6 +612,23 @@
 	}
 #endif
     }
+    if (has_horns(youmonst.data)) {
+	if ((otmp = uarmh) != 0) {
+	    if (is_flimsy(otmp) && !donning(otmp)) {
+		char hornbuf[BUFSZ], yourbuf[BUFSZ];
+
+		/* Future possiblities: This could damage/destroy helmet */
+		Sprintf(hornbuf, "horn%s", plur(num_horns(youmonst.data)));
+		Your("%s through %s %s.", vtense(hornbuf, "pierce"),
+		     shk_your(yourbuf, otmp), xname(otmp));
+	    } else {
+		if (donning(otmp)) cancel_don();
+		Your("helmet falls to the %s!", surface(u.ux, u.uy));
+		(void) Helmet_off();
+		dropx(otmp);
+	    }
+	}
+    }
     if (nohands(youmonst.data) || verysmall(youmonst.data)) {
 	if ((otmp = uarmg) != 0) {
 	    if (donning(otmp)) cancel_don();
@@ -668,6 +691,8 @@
 		    dropx(otmp2);
 	    }
 	    untwoweapon();
+	} else if (!could_twoweap(youmonst.data)) {
+	    untwoweapon();
 	}
     }
 }
@@ -705,6 +730,8 @@
 int
 dobreathe()
 {
+	struct attack *mattk;
+
 	if (Strangled) {
 	    You_cant("breathe.  Sorry.");
 	    return(0);
@@ -717,17 +744,13 @@
 	flags.botl = 1;
 
 	if (!getdir((char *)0)) return(0);
-	else {
-	    register struct attack *mattk;
-	    register int i;
 
-	    for(i = 0; i < NATTK; i++) {
-		mattk = &(youmonst.data->mattk[i]);
-		if(mattk->aatyp == AT_BREA) break;
-	    }
+	mattk = attacktype_fordmg(youmonst.data, AT_BREA, AD_ANY);
+	if (!mattk)
+	    impossible("bad breath attack?");	/* mouthwash needed... */
+	else
 	    buzz((int) (20 + mattk->adtyp-1), (int)mattk->damn,
 		u.ux, u.uy, u.dx, u.dy);
-	}
 	return(1);
 }
 
@@ -998,8 +1021,7 @@
 			/* as if gazing at a sleeping anything is fruitful... */
 			You("turn to stone...");
 			killer_format = KILLED_BY;
-			killer =
-			 "deliberately gazing at Medusa's hideous countenance";
+			killer = "deliberately meeting Medusa's gaze";
 			done(STONING);
 		    }
 		}
@@ -1109,6 +1131,10 @@
 		"rear claw", "foreclaw", "clawed", "head", "rear limb",
 		"light headed", "neck", "spine", "rear claw tip",
 		"fur", "blood", "lung", "nose", "stomach" },
+	*bird_parts[] = { "wing", "eye", "face", "wing", "wing tip",
+		"foot", "wing", "winged", "head", "leg",
+		"light headed", "neck", "spine", "toe",
+		"feathers", "blood", "lung", "bill", "stomach" },
 	*horse_parts[] = { "foreleg", "eye", "face", "forehoof", "hoof tip",
 		"rear hoof", "foreclaw", "hooved", "head", "rear leg",
 		"light headed", "neck", "backbone", "rear hoof tip",
@@ -1169,9 +1195,17 @@
 		(part == ARM || part == FINGER || part == FINGERTIP ||
 		    part == HAND || part == HANDED))
 	    return humanoid_parts[part];
+	if (mptr == &mons[PM_RAVEN])
+	    return bird_parts[part];
 	if (mptr->mlet == S_CENTAUR || mptr->mlet == S_UNICORN ||
 		(mptr == &mons[PM_ROTHE] && part != HAIR))
 	    return horse_parts[part];
+	if (mptr->mlet == S_LIGHT) {
+		if (part == HANDED) return "rayed";
+		else if (part == ARM || part == FINGER ||
+				part == FINGERTIP || part == HAND) return "ray";
+		else return "beam";
+	}
 	if (mptr->mlet == S_EEL && mptr != &mons[PM_JELLYFISH])
 	    return fish_parts[part];
 	if (slithy(mptr) || (mptr->mlet == S_DRAGON && part == HAIR))
@@ -1225,7 +1259,7 @@
 	if (u.umonnum != PM_FLESH_GOLEM && u.umonnum != PM_IRON_GOLEM)
 		return;
 	switch (damtype) {
-		case AD_ELEC: if (u.umonnum == PM_IRON_GOLEM)
+		case AD_ELEC: if (u.umonnum == PM_FLESH_GOLEM)
 				heal = dam / 6; /* Approx 1 per die */
 			break;
 		case AD_FIRE: if (u.umonnum == PM_IRON_GOLEM)
diff -Naurd ../nethack-3.4.0/src/potion.c ./src/potion.c
--- ../nethack-3.4.0/src/potion.c Wed Mar 20 23:43:14 2002
+++ ./src/potion.c Mon Feb 24 15:25:05 2003
@@ -152,11 +152,13 @@
 	long old = Vomiting;
 
 	if(!xtime && old)
-	    if(talk) You_feel("much less nauseous now.");
+	    if(talk) You_feel("much less nauseated now.");
 
 	set_itimeout(&Vomiting, xtime);
 }
 
+static const char vismsg[] = "vision seems to %s for a moment but is %s now.";
+static const char eyemsg[] = "%s momentarily %s.";
 
 void
 make_blinded(xtime, talk)
@@ -167,9 +169,6 @@
 	boolean u_could_see, can_see_now;
 	int eyecnt;
 	char buf[BUFSZ];
-	static const char
-		vismsg[] = "vision seems to %s for a moment but is %s now.",
-		eyemsg[] = "%s momentarily %s.";
 
 	/* we need to probe ahead in case the Eyes of the Overworld
 	   are or will be overriding blindness */
@@ -245,17 +244,13 @@
 boolean talk;
 long mask;	/* nonzero if resistance status should change by mask */
 {
+	long old = HHallucination;
 	boolean changed = 0;
-#ifdef LINT
-	const char *message = 0;
-#else
-	const char *message;
-#endif
+	const char *message, *verb;
 
-	if (!xtime)
-	    message = "Everything looks SO boring now.";
-	else
-	    message = "Oh wow!  Everything seems so cosmic!";
+	message = (!xtime) ? "Everything %s SO boring now." :
+			     "Oh wow!  Everything %s so cosmic!";
+	verb = (!Blind) ? "looks" : "feels";
 
 	if (mask) {
 	    if (HHallucination) changed = TRUE;
@@ -266,6 +261,22 @@
 	    if (!EHalluc_resistance && (!!HHallucination != !!xtime))
 		changed = TRUE;
 	    set_itimeout(&HHallucination, xtime);
+
+	    /* clearing temporary hallucination without toggling vision */
+	    if (!changed && !HHallucination && old && talk) {
+		if (!haseyes(youmonst.data)) {
+		    strange_feeling((struct obj *)0, (char *)0);
+		} else if (Blind) {
+		    char buf[BUFSZ];
+		    int eyecnt = eyecount(youmonst.data);
+
+		    Strcpy(buf, body_part(EYE));
+		    Your(eyemsg, (eyecnt == 1) ? buf : makeplural(buf),
+			 (eyecnt == 1) ? "itches" : "itch");
+		} else {	/* Grayswandir */
+		    Your(vismsg, "flatten", "normal");
+		}
+	    }
 	}
 
 	if (changed) {
@@ -277,8 +288,13 @@
 		see_objects();
 		see_traps();
 	    }
+
+	    /* for perm_inv and anything similar
+	    (eg. Qt windowport's equipped items display) */
+	    update_inventory();
+
 	    flags.botl = 1;
-	    if (!Blind && talk) pline(message);
+	    if (talk) pline(message, verb);
 	}
 }
 
@@ -303,8 +319,11 @@
 	nomovemsg = "You regain your composure.";
 }
 
+/* "Quaffing is like drinking, except you spill more."  -- Terry Pratchett
+ */
 int
-dodrink() {
+dodrink()
+{
 	register struct obj *otmp;
 	const char *potion_descr;
 
@@ -368,6 +387,7 @@
 {
 	int retval;
 
+	otmp->in_use = TRUE;
 	nothing = unkn = 0;
 	if((retval = peffects(otmp)) >= 0) return(retval);
 
@@ -539,10 +559,12 @@
 		if (otmp->cursed)
 		    pline("Yecch!  This tastes %s.",
 			  Hallucination ? "overripe" : "rotten");
-		else pline(Hallucination ?
-		"This tastes like 10%% real %s%s juice all-natural beverage." :
-				"This tastes like %s%s juice.",
-			  otmp->odiluted ? "reconstituted " : "", pl_fruit);
+		else
+		    pline(Hallucination ?
+		      "This tastes like 10%% real %s%s all-natural beverage." :
+				"This tastes like %s%s.",
+			  otmp->odiluted ? "reconstituted " : "",
+			  fruitname(TRUE));
 		if (otmp->otyp == POT_FRUIT_JUICE) {
 		    u.uhunger += (otmp->odiluted ? 5 : 10) * (2 + bcsign(otmp));
 		    newuhs(FALSE);
@@ -571,7 +593,7 @@
 		if (Free_action)
 		    You("stiffen momentarily.");
 		else {
-		    if (Levitation||Is_airlevel(&u.uz)||Is_waterlevel(&u.uz))
+		    if (Levitation || Is_airlevel(&u.uz)||Is_waterlevel(&u.uz))
 			You("are motionlessly suspended.");
 #ifdef STEED
 		    else if (u.usteed)
@@ -632,8 +654,8 @@
 	case POT_SICKNESS:
 		pline("Yecch!  This stuff tastes like poison.");
 		if (otmp->blessed) {
-		    pline("(But in fact it was mildly stale %s juice.)",
-			  pl_fruit);
+		    pline("(But in fact it was mildly stale %s.)",
+			  fruitname(TRUE));
 		    if (!Role_if(PM_HEALER)) {
 			if (otmp->corpsenm)
 			    losehp(1,
@@ -645,8 +667,8 @@
 		} else {
 		    if(Poison_resistance)
 			pline(
-		    "(But in fact it was biologically contaminated %s juice.)",
-			      pl_fruit);
+			  "(But in fact it was biologically contaminated %s.)",
+			      fruitname(TRUE));
 		    if (Role_if(PM_HEALER))
 			pline("Fortunately, you have been immunized.");
 		    else {
@@ -763,7 +785,7 @@
 			/* blessed potions place you at a random spot in the
 			 * middle of the new level instead of the low point
 			 */
-			u.uexp = rndexp();
+			u.uexp = rndexp(TRUE);
 		break;
 	case POT_HEALING:
 		You_feel("better.");
@@ -1428,6 +1450,7 @@
 		/* KMH -- Water into acid causes an explosion */
 		if (obj->otyp == POT_ACID) {
 			pline("It boils vigorously!");
+			You("are caught in the explosion!");
 			losehp(rnd(10), "elementary chemistry", KILLED_BY);
 			makeknown(obj->otyp);
 			update_inventory();
@@ -1480,7 +1503,7 @@
 			} else {
 			    if (!Blind) {
 				    boolean oq1 = obj->quan == 1L;
-				    pline_The("spellbook%s fade%s.",
+				    pline_The("spellbook%s %s.",
 					oq1 ? "" : "s", otense(obj, "fade"));
 			    }
 			    if(obj->unpaid && costly_spot(u.ux, u.uy)) {
@@ -1523,9 +1546,14 @@
 		tmp = (here == POOL) ? "pool" : "moat";
 		Sprintf(qbuf, "Dip it into the %s?", tmp);
 		if (yn(qbuf) == 'y') {
-		    if (Levitation)
+		    if (Levitation) {
 			floating_above(tmp);
-		    else {
+#ifdef STEED
+		    } else if (u.usteed && !is_swimmer(u.usteed->data) &&
+			    P_SKILL(P_RIDING) < P_BASIC) {
+			rider_cant_reach(); /* not skilled enough to reach */
+#endif
+		    } else {
 			(void) get_wet(obj);
 			if (obj->otyp == POT_ACID) useup(obj);
 		    }
@@ -1539,6 +1567,7 @@
 		pline("That is a potion bottle, not a Klein bottle!");
 		return 0;
 	}
+	potion->in_use = TRUE;		/* assume it will be used up */
 	if(potion->otyp == POT_WATER) {
 		boolean useeit = !Blind;
 		if (useeit) (void) Shk_Your(Your_buf, obj);
@@ -1548,7 +1577,7 @@
 				    pline("%s %s %s.",
 					  Your_buf,
 					  aobjnam(obj, "softly glow"),
-					  hcolor(amber));
+					  hcolor(NH_AMBER));
 				uncurse(obj);
 				obj->bknown=1;
 	poof:
@@ -1559,7 +1588,7 @@
 				return(1);
 			} else if(!obj->blessed) {
 				if (useeit) {
-				    tmp = hcolor(light_blue);
+				    tmp = hcolor(NH_LIGHT_BLUE);
 				    pline("%s %s with a%s %s aura.",
 					  Your_buf,
 					  aobjnam(obj, "softly glow"),
@@ -1581,7 +1610,7 @@
 				goto poof;
 			} else if(!obj->cursed) {
 				if (useeit) {
-				    tmp = hcolor(Black);
+				    tmp = hcolor(NH_BLACK);
 				    pline("%s %s with a%s %s aura.",
 					  Your_buf,
 					  aobjnam(obj, "glow"),
@@ -1624,11 +1653,13 @@
 			makeknown(POT_POLYMORPH);
 			useup(potion);
 			prinv((char *)0, obj, 0L);
+			return 1;
 		} else {
 			pline("Nothing seems to happen.");
-			useup(potion);
+			goto poof;
 		}
 	    }
+	    potion->in_use = FALSE;	/* didn't go poof */
 	    return(1);
 	} else if(obj->oclass == POTION_CLASS && obj->otyp != potion->otyp) {
 		/* Mixing potions is dangerous... */
@@ -1813,6 +1844,7 @@
 	    }
 	    if (obj->age > 1000L) {
 		pline("%s %s full.", Yname2(obj), otense(obj, "are"));
+		potion->in_use = FALSE;	/* didn't go poof */
 	    } else {
 		You("fill %s with oil.", yname(obj));
 		check_unpaid(potion);	/* Yendorian Fuel Tax */
@@ -1827,9 +1859,20 @@
 	    return 1;
 	}
 
+	potion->in_use = FALSE;		/* didn't go poof */
 	if ((obj->otyp == UNICORN_HORN || obj->otyp == AMETHYST) &&
 	    (mixture = mixtype(obj, potion)) != 0) {
+		char oldbuf[BUFSZ], newbuf[BUFSZ];
+		short old_otyp = potion->otyp;
+		boolean old_dknown = FALSE;
 		boolean more_than_one = potion->quan > 1;
+
+		oldbuf[0] = '\0';
+		if (potion->dknown) {
+		    old_dknown = TRUE;
+		    Sprintf(oldbuf, "%s ",
+			    hcolor(OBJ_DESCR(objects[potion->otyp])));
+		}
 		/* with multiple merged potions, split off one and
 		   just clear it */
 		if (potion->quan > 1L) {
@@ -1847,24 +1890,29 @@
 		else
 		    singlepotion->cursed = obj->cursed;  /* odiluted left as-is */
 		singlepotion->bknown = FALSE;
-		if (Blind)
-			singlepotion->dknown = FALSE;
-		else {
-			if (mixture == POT_WATER &&
-#ifdef DCC30_BUG
-			    (singlepotion->dknown = !Hallucination,
-			     singlepotion->dknown != 0))
-#else
-			    (singlepotion->dknown = !Hallucination) != 0)
-#endif
-				pline_The("potion%s clears.",
-					more_than_one ? " that you dipped into" : "");
-			else
-				pline_The("potion%s turns %s.",
-					more_than_one ? " that you dipped into" : "",
-					hcolor(OBJ_DESCR(objects[mixture])));
+		if (Blind) {
+		    singlepotion->dknown = FALSE;
+		} else {
+		    singlepotion->dknown = !Hallucination;
+		    if (mixture == POT_WATER && singlepotion->dknown)
+			Sprintf(newbuf, "clears");
+		    else
+			Sprintf(newbuf, "turns %s",
+				hcolor(OBJ_DESCR(objects[mixture])));
+		    pline_The("%spotion%s %s.", oldbuf,
+			      more_than_one ? " that you dipped into" : "",
+			      newbuf);
+		    if(!objects[old_otyp].oc_uname &&
+			!objects[old_otyp].oc_name_known && old_dknown) {
+			struct obj fakeobj;
+			fakeobj = zeroobj;
+			fakeobj.dknown = 1;
+			fakeobj.otyp = old_otyp;
+			fakeobj.oclass = POTION_CLASS;
+			docall(&fakeobj);
+		    }
 		}
-	    	obj_extract_self(singlepotion);
+		obj_extract_self(singlepotion);
 		singlepotion = hold_another_object(singlepotion,
 					"You juggle and drop %s!",
 					doname(singlepotion), (const char *)0);
diff -Naurd ../nethack-3.4.0/src/pray.c ./src/pray.c
--- ../nethack-3.4.0/src/pray.c Wed Mar 20 23:43:14 2002
+++ ./src/pray.c Mon Feb 24 15:25:05 2003
@@ -6,6 +6,7 @@
 #include "epri.h"
 
 STATIC_PTR int NDECL(prayer_done);
+STATIC_DCL struct obj *NDECL(worst_cursed_item);
 STATIC_DCL int NDECL(in_trouble);
 STATIC_DCL void FDECL(fix_worst_trouble,(int));
 STATIC_DCL void FDECL(angrygods,(ALIGNTYP_P));
@@ -23,6 +24,9 @@
 STATIC_DCL boolean FDECL(water_prayer,(BOOLEAN_P));
 STATIC_DCL boolean FDECL(blocked_boulder,(int,int));
 
+/* simplify a few tests */
+#define Cursed_obj(obj,typ) ((obj) && (obj)->otyp == (typ) && (obj)->cursed)
+
 /*
  * Logic behind deities and altars and such:
  * + prayers are made to your god if not on an altar, and to the altar's god
@@ -59,6 +63,13 @@
 #define FERVENT 9
 #define STRIDENT 4
 
+/*
+ * The actual trouble priority is determined by the order of the
+ * checks performed in in_trouble() rather than by these numeric
+ * values, so keep that code and these values synchronized in
+ * order to have the values be meaningful.
+ */
+
 #define TROUBLE_STONED 12
 #define TROUBLE_SLIMED 11
 #define TROUBLE_STRANGLED 10
@@ -69,18 +80,20 @@
 #define TROUBLE_LYCANTHROPE 5
 #define TROUBLE_COLLAPSING 4
 #define TROUBLE_STUCK_IN_WALL 3
-#define TROUBLE_CURSED_BLINDFOLD 2
-#define TROUBLE_CURSED_LEVITATION 1
+#define TROUBLE_CURSED_LEVITATION 2
+#define TROUBLE_CURSED_BLINDFOLD 1
 
 #define TROUBLE_PUNISHED (-1)
-#define TROUBLE_CURSED_ITEMS (-2)
-#define TROUBLE_BLIND (-3)
-#define TROUBLE_POISONED (-4)
-#define TROUBLE_WOUNDED_LEGS (-5)
-#define TROUBLE_HUNGRY (-6)
-#define TROUBLE_STUNNED (-7)
-#define TROUBLE_CONFUSED (-8)
-#define TROUBLE_HALLUCINATION (-9)
+#define TROUBLE_FUMBLING (-2)
+#define TROUBLE_CURSED_ITEMS (-3)
+#define TROUBLE_SADDLE (-4)
+#define TROUBLE_BLIND (-5)
+#define TROUBLE_POISONED (-6)
+#define TROUBLE_WOUNDED_LEGS (-7)
+#define TROUBLE_HUNGRY (-8)
+#define TROUBLE_STUNNED (-9)
+#define TROUBLE_CONFUSED (-10)
+#define TROUBLE_HALLUCINATION (-11)
 
 /* We could force rehumanize of polyselfed people, but we can't tell
    unintentional shape changes from the other kind. Oh well. */
@@ -102,7 +115,9 @@
 STATIC_OVL int
 in_trouble()
 {
+#ifdef STEED
 	register struct obj *otmp;
+#endif
 	int i, j, count=0;
 
 /* Borrowed from eat.c */
@@ -115,6 +130,9 @@
 #define FAINTED		5
 #define STARVED		6
 
+	/*
+	 * major troubles
+	 */
 	if(Stoned) return(TROUBLE_STONED);
 	if(Slimed) return(TROUBLE_SLIMED);
 	if(Strangled) return(TROUBLE_STRANGLED);
@@ -136,36 +154,28 @@
 	if (count == 8 && !Passes_walls)
 		return(TROUBLE_STUCK_IN_WALL);
 
-	if((uarmf && uarmf->otyp==LEVITATION_BOOTS && uarmf->cursed) ||
-		(uleft && uleft->otyp==RIN_LEVITATION && uleft->cursed) ||
-		(uright && uright->otyp==RIN_LEVITATION && uright->cursed))
+	if (Cursed_obj(uarmf, LEVITATION_BOOTS) ||
+		stuck_ring(uleft, RIN_LEVITATION) ||
+		stuck_ring(uright, RIN_LEVITATION))
 		return(TROUBLE_CURSED_LEVITATION);
 	if(Blindfolded && ublindf->cursed) return(TROUBLE_CURSED_BLINDFOLD);
 
+	/*
+	 * minor troubles
+	 */
 	if(Punished) return(TROUBLE_PUNISHED);
-	for(otmp=invent; otmp; otmp=otmp->nobj)
-		if((otmp->otyp==LOADSTONE || otmp->otyp==LUCKSTONE) &&
-			otmp->cursed)
-		    return(TROUBLE_CURSED_ITEMS);
-	if((uarmh && uarmh->cursed) ||	/* helmet */
-	   (uarms && uarms->cursed) ||	/* shield */
-	   (uarmg && uarmg->cursed) ||	/* gloves */
-	   (uarm && uarm->cursed) ||	/* armor */
-	   (uarmc && uarmc->cursed) ||	/* cloak */
-	   (uarmf && uarmf->cursed && uarmf->otyp != LEVITATION_BOOTS) ||
-					/* boots */
-	   (ublindf && ublindf->otyp == LENSES && ublindf->cursed) ||
-	   				/* lenses: blindfold is TROUBLE_CURSED_BLINDFOLD */
-#ifdef TOURIST
-	   (uarmu && uarmu->cursed) ||  /* shirt */
+	if (Cursed_obj(uarmg, GAUNTLETS_OF_FUMBLING) ||
+		Cursed_obj(uarmf, FUMBLE_BOOTS))
+	    return TROUBLE_FUMBLING;
+	if (worst_cursed_item()) return TROUBLE_CURSED_ITEMS;
+#ifdef STEED
+	if (u.usteed) {	/* can't voluntarily dismount from a cursed saddle */
+	    otmp = which_armor(u.usteed, W_SADDLE);
+	    if (Cursed_obj(otmp, SADDLE)) return TROUBLE_SADDLE;
+	}
 #endif
-	   (welded(uwep)) ||
-	   (uleft && uleft->cursed && uleft->otyp != RIN_LEVITATION) ||
-	   (uright && uright->cursed && uright->otyp != RIN_LEVITATION) ||
-	   (uamul && uamul->cursed))
-	    return(TROUBLE_CURSED_ITEMS);
 
-	if(Blinded > 1) return(TROUBLE_BLIND);
+	if (Blinded > 1 && haseyes(youmonst.data)) return(TROUBLE_BLIND);
 	for(i=0; i<A_MAX; i++)
 	    if(ABASE(i) < AMAX(i)) return(TROUBLE_POISONED);
 	if(Wounded_legs
@@ -177,20 +187,78 @@
 	if(HStun) return (TROUBLE_STUNNED);
 	if(HConfusion) return (TROUBLE_CONFUSED);
 	if(Hallucination) return(TROUBLE_HALLUCINATION);
-
 	return(0);
 }
 
-const char leftglow[] = "left ring softly glows";
-const char rightglow[] = "right ring softly glows";
+/* select an item for TROUBLE_CURSED_ITEMS */
+STATIC_OVL struct obj *
+worst_cursed_item()
+{
+    register struct obj *otmp;
+
+    /* if strained or worse, check for loadstone first */
+    if (near_capacity() >= HVY_ENCUMBER) {
+	for (otmp = invent; otmp; otmp = otmp->nobj)
+	    if (Cursed_obj(otmp, LOADSTONE)) return otmp;
+    }
+    /* weapon takes precedence if it is interfering
+       with taking off a ring or shield */
+    if (welded(uwep) &&					/* weapon */
+	    (uright || (bimanual(uwep) && (uleft || uarms)))) {
+	otmp = uwep;
+    /* gloves come next, due to rings */
+    } else if (uarmg && uarmg->cursed) {		/* gloves */
+	otmp = uarmg;
+    /* then shield due to two handed weapons and spells */
+    } else if (uarms && uarms->cursed) {		/* shield */
+	otmp = uarms;
+    /* then cloak due to body armor */
+    } else if (uarmc && uarmc->cursed) {		/* cloak */
+	otmp = uarmc;
+    } else if (uarm && uarm->cursed) {			/* suit */
+	otmp = uarm;
+    } else if (uarmh && uarmh->cursed) {		/* helmet */
+	otmp = uarmh;
+    } else if (uarmf && uarmf->cursed) {		/* boots */
+	otmp = uarmf;
+#ifdef TOURIST
+    } else if (uarmu && uarmu->cursed) {		/* shirt */
+	otmp = uarmu;
+#endif
+    } else if (uamul && uamul->cursed) {		/* amulet */
+	otmp = uamul;
+    } else if (uleft && uleft->cursed) {		/* left ring */
+	otmp = uleft;
+    } else if (uright && uright->cursed) {		/* right ring */
+	otmp = uright;
+    } else if (ublindf && ublindf->cursed) {		/* eyewear */
+	otmp = ublindf;	/* must be non-blinding lenses */
+    /* if weapon wasn't handled above, do it now */
+    } else if (welded(uwep)) {				/* weapon */
+	otmp = uwep;
+    /* active secondary weapon even though it isn't welded */
+    } else if (uswapwep && uswapwep->cursed && u.twoweap) {
+	otmp = uswapwep;
+    /* all worn items ought to be handled by now */
+    } else {
+	for (otmp = invent; otmp; otmp = otmp->nobj) {
+	    if (!otmp->cursed) continue;
+	    if (otmp->otyp == LOADSTONE || confers_luck(otmp))
+		break;
+	}
+    }
+    return otmp;
+}
 
 STATIC_OVL void
 fix_worst_trouble(trouble)
 register int trouble;
 {
 	int i;
-	struct obj *otmp;
+	struct obj *otmp = 0;
 	const char *what = (const char *)0;
+	static NEARDATA const char leftglow[] = "left ring softly glows",
+				   rightglow[] = "right ring softly glows";
 
 	switch (trouble) {
 	    case TROUBLE_STONED:
@@ -219,7 +287,7 @@
 		    /* teleport should always succeed, but if not,
 		     * just untrap them.
 		     */
-		    if(!safe_teleds())
+		    if(!safe_teleds(FALSE))
 			u.utrap = 0;
 		    break;
 	    case TROUBLE_STARVING:
@@ -256,19 +324,15 @@
 	    case TROUBLE_STUCK_IN_WALL:
 		    Your("surroundings change.");
 		    /* no control, but works on no-teleport levels */
-		    (void) safe_teleds();
+		    (void) safe_teleds(FALSE);
 		    break;
 	    case TROUBLE_CURSED_LEVITATION:
-		    if (uarmf && uarmf->otyp==LEVITATION_BOOTS
-						&& uarmf->cursed)
+		    if (Cursed_obj(uarmf, LEVITATION_BOOTS)) {
 			otmp = uarmf;
-		    else if (uleft && uleft->otyp==RIN_LEVITATION
-						&& uleft->cursed) {
-			otmp = uleft;
-			what = leftglow;
-		    } else {
-			otmp = uright;
-			what = rightglow;
+		    } else if ((otmp = stuck_ring(uleft,RIN_LEVITATION)) !=0) {
+			if (otmp == uleft) what = leftglow;
+		    } else if ((otmp = stuck_ring(uright,RIN_LEVITATION))!=0) {
+			if (otmp == uright) what = rightglow;
 		    }
 		    goto decurse;
 	    case TROUBLE_CURSED_BLINDFOLD:
@@ -277,67 +341,36 @@
 	    case TROUBLE_LYCANTHROPE:
 		    you_unwere(TRUE);
 		    break;
+	/*
+	 */
 	    case TROUBLE_PUNISHED:
 		    Your("chain disappears.");
 		    unpunish();
 		    break;
+	    case TROUBLE_FUMBLING:
+		    if (Cursed_obj(uarmg, GAUNTLETS_OF_FUMBLING))
+			otmp = uarmg;
+		    else if (Cursed_obj(uarmf, FUMBLE_BOOTS))
+			otmp = uarmf;
+		    goto decurse;
+		    /*NOTREACHED*/
+		    break;
 	    case TROUBLE_CURSED_ITEMS:
-		    /* weapon takes precedence if it interferes
-		       with taking off a ring or shield */
-		    if (welded(uwep) &&			/* weapon */
-			(uright || (bimanual(uwep) && (uleft || uarms))))
-			    otmp = uwep;
-		    /* gloves come next, due to rings */
-		    else if (uarmg && uarmg->cursed)	/* gloves */
-			    otmp = uarmg;
-		    /* then shield due to two handed weapons and spells */
-		    else if (uarms && uarms->cursed)	/* shield */
-			    otmp = uarms;
-		    /* then cloak due to body armor */
-		    else if (uarmc && uarmc->cursed)	/* cloak */
-			    otmp = uarmc;
-		    else if (uarm && uarm->cursed)	/* armor */
-			    otmp = uarm;
-		    else if (uarmh && uarmh->cursed)	/* helmet */
-			    otmp = uarmh;
-		    else if (uarmf && uarmf->cursed)	/* boots */
-			    otmp = uarmf;
-#ifdef TOURIST
-		    else if (uarmu && uarmu->cursed)	/* shirt */
-			    otmp = uarmu;
-#endif
-		    /* (perhaps amulet should take precedence over rings?) */
-		    else if (uleft && uleft->cursed) {
-			    otmp = uleft;
-			    what = leftglow;
-		    } else if (uright && uright->cursed) {
-			    otmp = uright;
-			    what = rightglow;
-		    } else if (uamul && uamul->cursed) /* amulet */
-			    otmp = uamul;
-		    else if (ublindf && ublindf->cursed) /* eyewear */
-			    otmp = ublindf;  /* must be non-blinding lenses */
-		    /* if weapon wasn't handled above, do it now */
-		    else if (welded(uwep))		/* weapon */
-			    otmp = uwep;
-		    else {
-			    for(otmp=invent; otmp; otmp=otmp->nobj)
-				if ((otmp->otyp==LOADSTONE ||
-				     otmp->otyp==LUCKSTONE) && otmp->cursed)
-					break;
-		    }
+		    otmp = worst_cursed_item();
+		    if (otmp == uright) what = rightglow;
+		    else if (otmp == uleft) what = leftglow;
 decurse:
 		    if (!otmp) {
 			impossible("fix_worst_trouble: nothing to uncurse.");
 			return;
 		    }
 		    uncurse(otmp);
-		    otmp->bknown = TRUE;
-		    if (!Blind)
-			    Your("%s %s.",
-				 what ? what :
-				 (const char *)aobjnam(otmp, "softly glow"),
-				 hcolor(amber));
+		    if (!Blind) {
+			Your("%s %s.", what ? what :
+				(const char *)aobjnam(otmp, "softly glow"),
+			     hcolor(NH_AMBER));
+			otmp->bknown = TRUE;
+		    }
 		    update_inventory();
 		    break;
 	    case TROUBLE_POISONED:
@@ -354,14 +387,17 @@
 		    (void) encumber_msg();
 		    break;
 	    case TROUBLE_BLIND:
-	    	    {
-	    	    	int num_eyes = eyecount(youmonst.data);
-			Your("%s feel%s better.",
-			     (num_eyes == 1) ? body_part(EYE) : makeplural(body_part(EYE)),
-			     (num_eyes == 1) ? "s" : "");
-			make_blinded(0L,FALSE);
-			break;
-		    }
+		{
+		    int num_eyes = eyecount(youmonst.data);
+		    const char *eye = body_part(EYE);
+
+		    Your("%s feel%s better.",
+			 (num_eyes == 1) ? eye : makeplural(eye),
+			 (num_eyes == 1) ? "s" : "");
+		    u.ucreamed = 0;
+		    make_blinded(0L,FALSE);
+		    break;
+		}
 	    case TROUBLE_WOUNDED_LEGS:
 		    heal_legs();
 		    break;
@@ -375,6 +411,19 @@
 		    pline ("Looks like you are back in Kansas.");
 		    make_hallucinated(0L,FALSE,0L);
 		    break;
+#ifdef STEED
+	    case TROUBLE_SADDLE:
+		    otmp = which_armor(u.usteed, W_SADDLE);
+		    uncurse(otmp);
+		    if (!Blind) {
+			pline("%s %s %s.",
+			      s_suffix(upstart(y_monnam(u.usteed))),
+			      aobjnam(otmp, "softly glow"),
+			      hcolor(NH_AMBER));
+			otmp->bknown = TRUE;
+		    }
+		    break;
+#endif
 	}
 }
 
@@ -445,7 +494,7 @@
 	    if (!Disint_resistance)
 		fry_by_god(resp_god);
 	    else {
-		You("bask in its %s glow for a minute...", Black);
+		You("bask in its %s glow for a minute...", NH_BLACK);
 		godvoice(resp_god, "I believe it not!");
 	    }
 	    if (Is_astralevel(&u.uz) || Is_sanctum(&u.uz)) {
@@ -517,7 +566,7 @@
 	    case 5:	gods_angry(resp_god);
 			if (!Blind && !Antimagic)
 			    pline("%s glow surrounds you.",
-				  An(hcolor(Black)));
+				  An(hcolor(NH_BLACK)));
 			rndcurse();
 			break;
 	    case 7:
@@ -664,7 +713,7 @@
       {
 	char swordbuf[BUFSZ];
 
-	Sprintf(swordbuf, "%s sword", hcolor(Black));
+	Sprintf(swordbuf, "%s sword", hcolor(NH_BLACK));
 	if (class_gift != STRANGE_OBJECT) {
 	    ;		/* already got bonus above */
 	} else if (in_hand) {
@@ -745,9 +794,9 @@
 	    /* if hero was in trouble, but got better, no special favor */
 	    if (p_trouble == 0) pat_on_head = 1;
 	} else {
-	    int action = rn1(on_altar() ? 3 + on_shrine() : 2, Luck+1);
+	    int action = rn1(Luck + (on_altar() ? 3 + on_shrine() : 2), 1);
 
-	    if (!on_altar()) action = max(action,2);
+	    if (!on_altar()) action = min(action, 3);
 	    if (u.ualign.record < STRIDENT)
 		action = (u.ualign.record > 0 || !rnl(2)) ? 1 : 0;
 
@@ -767,6 +816,9 @@
 	    }
 	}
 
+    /* note: can't get pat_on_head unless all troubles have just been
+       fixed or there were no troubles to begin with; hallucination
+       won't be in effect so special handling for it is superfluous */
     if(pat_on_head)
 	switch(rn2((Luck + 6)>>1)) {
 	case 0:	break;
@@ -785,7 +837,7 @@
 		    uwep->bknown = TRUE;
 		    if (!Blind)
 			Your("%s %s%s.", aobjnam(uwep, "softly glow"),
-			     hcolor(amber), repair_buf);
+			     hcolor(NH_AMBER), repair_buf);
 		    else You_feel("the power of %s over your %s.",
 			u_gname(), xname(uwep));
 		    *repair_buf = '\0';
@@ -795,7 +847,7 @@
 		    if (!Blind)
 			Your("%s with %s aura%s.",
 			     aobjnam(uwep, "softly glow"),
-			     an(hcolor(light_blue)), repair_buf);
+			     an(hcolor(NH_LIGHT_BLUE)), repair_buf);
 		    else You_feel("the blessing of %s over your %s.",
 			u_gname(), xname(uwep));
 		    *repair_buf = '\0';
@@ -816,8 +868,8 @@
 	    break;
 	case 3:
 	    /* takes 2 hints to get the music to enter the stronghold */
-	    if (flags.soundok && !u.uevent.uopened_dbridge) {
-		if(u.uevent.uheard_tune < 1) {
+	    if (!u.uevent.uopened_dbridge) {
+		if (u.uevent.uheard_tune < 1) {
 		    godvoice(g_align,(char *)0);
 		    verbalize("Hark, %s!",
 			  youmonst.data->mlet == S_HUMAN ? "mortal" : "creature");
@@ -826,7 +878,7 @@
 		    u.uevent.uheard_tune++;
 		    break;
 		} else if (u.uevent.uheard_tune < 2) {
-		    You_hear(Hallucination ? "a funeral march..." : "a divine music...");
+		    You_hear("a divine music...");
 		    pline("It sounds like:  \"%s\".", tune);
 		    u.uevent.uheard_tune++;
 		    break;
@@ -835,7 +887,7 @@
 	    /* Otherwise, falls into next case */
 	case 2:
 	    if (!Blind)
-		You("are surrounded by %s glow.", an(hcolor(golden)));
+		You("are surrounded by %s glow.", an(hcolor(NH_GOLDEN)));
 	    /* if any levels have been lost (and not yet regained),
 	       treat this effect like blessed full healing */
 	    if (u.ulevel < u.ulevelmax) {
@@ -860,13 +912,13 @@
 	    if (Blind)
 		You_feel("the power of %s.", u_gname());
 	    else You("are surrounded by %s aura.",
-		     an(hcolor(light_blue)));
+		     an(hcolor(NH_LIGHT_BLUE)));
 	    for(otmp=invent; otmp; otmp=otmp->nobj) {
 		if (otmp->cursed) {
 		    uncurse(otmp);
 		    if (!Blind) {
 			Your("%s %s.", aobjnam(otmp, "softly glow"),
-			     hcolor(amber));
+			     hcolor(NH_AMBER));
 			otmp->bknown = TRUE;
 			++any;
 		    }
@@ -973,7 +1025,7 @@
 	      ((other && changed > 1L) ? "Some of the" :
 					(other ? "One of the" : "The")),
 	      ((other || changed > 1L) ? "s" : ""), (changed > 1L ? "" : "s"),
-	      (bless_water ? hcolor(light_blue) : hcolor(Black)));
+	      (bless_water ? hcolor(NH_LIGHT_BLUE) : hcolor(NH_BLACK)));
     }
     return((boolean)(changed > 0L));
 }
@@ -1045,7 +1097,7 @@
     int pm;
     aligntyp altaralign = a_align(u.ux,u.uy);
 
-    if (!on_altar()) {
+    if (!on_altar() || u.uswallow) {
 	You("are not standing on an altar.");
 	return 0;
     }
@@ -1109,7 +1161,7 @@
 		if (altaralign == A_CHAOTIC && u.ualign.type != A_CHAOTIC) {
 		    pline(
 		     "The blood floods the altar, which vanishes in %s cloud!",
-			  an(hcolor(Black)));
+			  an(hcolor(NH_BLACK)));
 		    levl[u.ux][u.uy].typ = ROOM;
 		    levl[u.ux][u.uy].altarmask = 0;
 		    if(Invisible) newsym(u.ux, u.uy);
@@ -1311,8 +1363,8 @@
 		    if (!Blind)
 			pline_The("altar glows %s.",
 			      hcolor(
-			      u.ualign.type == A_LAWFUL ? White :
-			      u.ualign.type ? Black : (const char *)"gray"));
+			      u.ualign.type == A_LAWFUL ? NH_WHITE :
+			      u.ualign.type ? NH_BLACK : (const char *)"gray"));
 
 		    if (rnl(u.ulevel) > 6 && u.ualign.record > 0 &&
 		       rnd(u.ualign.record) > (3*ALIGNLIM)/4)
diff -Naurd ../nethack-3.4.0/src/priest.c ./src/priest.c
--- ../nethack-3.4.0/src/priest.c Wed Mar 20 23:43:14 2002
+++ ./src/priest.c Mon Feb 24 15:25:05 2003
@@ -49,10 +49,7 @@
 	else allowflags = ALLOW_SSM | ALLOW_SANCT;
 	if (passes_walls(mtmp->data)) allowflags |= (ALLOW_ROCK|ALLOW_WALL);
 	if (throws_rocks(mtmp->data)) allowflags |= ALLOW_ROCK;
-	if (tunnels(mtmp->data) &&
-		    (!needspick(mtmp->data) || m_carrying(mtmp, PICK_AXE) ||
-		     m_carrying(mtmp, DWARVISH_MATTOCK)))
-		allowflags |= ALLOW_DIG;
+	if (tunnels(mtmp->data)) allowflags |= ALLOW_DIG;
 	if (!nohands(mtmp->data) && !verysmall(mtmp->data)) {
 		allowflags |= OPENDOOR;
 		if (m_carrying(mtmp, SKELETON_KEY)) allowflags |= BUSTDOOR;
@@ -339,14 +336,22 @@
 		shrined = has_shrine(priest);
 		sanctum = (priest->data == &mons[PM_HIGH_PRIEST] &&
 			   (Is_sanctum(&u.uz) || In_endgame(&u.uz)));
-		can_speak = (priest->mcanmove && !priest->msleeping);
-		if (can_speak)
+		can_speak = (priest->mcanmove && !priest->msleeping &&
+			     flags.soundok);
+		if (can_speak) {
+		    unsigned save_priest = priest->ispriest;
+		    /* don't reveal the altar's owner upon temple entry in
+		       the endgame; for the Sanctum, the next message names
+		       Moloch so suppress the "of Moloch" for him here too */
+		    if (sanctum && !Hallucination) priest->ispriest = 0;
 		    pline("%s intones:",
-			  (!Blind ? Monnam(priest) : "A nearby voice"));
+			canseemon(priest) ? Monnam(priest) : "A nearby voice");
+		    priest->ispriest = save_priest;
+		}
 		msg2 = 0;
 		if(sanctum && Is_sanctum(&u.uz)) {
 		    if(priest->mpeaceful) {
-			msg1 = "Infidel, you entered Moloch's Sanctum!";
+			msg1 = "Infidel, you have entered Moloch's Sanctum!";
 			msg2 = "Be gone!";
 			priest->mpeaceful = 0;
 			set_malign(priest);
diff -Naurd ../nethack-3.4.0/src/quest.c ./src/quest.c
--- ../nethack-3.4.0/src/quest.c Wed Mar 20 23:43:14 2002
+++ ./src/quest.c Mon Feb 24 15:25:05 2003
@@ -16,7 +16,7 @@
 STATIC_DCL void NDECL(on_locate);
 STATIC_DCL void NDECL(on_goal);
 STATIC_DCL boolean NDECL(not_capable);
-STATIC_DCL boolean FDECL(is_pure, (BOOLEAN_P));
+STATIC_DCL int FDECL(is_pure, (BOOLEAN_P));
 STATIC_DCL void FDECL(expulsion, (BOOLEAN_P));
 STATIC_DCL void NDECL(chat_with_leader);
 STATIC_DCL void NDECL(chat_with_nemesis);
@@ -96,7 +96,7 @@
 ok_to_quest()
 {
 	return((boolean)((Qstat(got_quest) || Qstat(got_thanks)))
-			&& is_pure(FALSE));
+			&& (is_pure(FALSE) > 0));
 }
 
 STATIC_OVL boolean
@@ -105,10 +105,11 @@
 	return((boolean)(u.ulevel < MIN_QUEST_LEVEL));
 }
 
-STATIC_OVL boolean
+STATIC_OVL int
 is_pure(talk)
 boolean talk;
 {
+    int purity;
     aligntyp original_alignment = u.ualignbase[A_ORIGINAL];
 
 #ifdef WIZARD
@@ -126,9 +127,11 @@
 	}
     }
 #endif
-    return (boolean)(u.ualign.record >= MIN_QUEST_ALIGN &&
-		     u.ualign.type == original_alignment &&
-		     u.ualignbase[A_CURRENT] == original_alignment);
+    purity = (u.ualign.record >= MIN_QUEST_ALIGN &&
+	      u.ualign.type == original_alignment &&
+	      u.ualignbase[A_CURRENT] == original_alignment) ?  1 :
+	     (u.ualignbase[A_CURRENT] != original_alignment) ? -1 : 0;
+    return purity;
 }
 
 /*
@@ -245,7 +248,10 @@
 	    qt_pager(QT_BADLEVEL);
 	    exercise(A_WIS, TRUE);
 	    expulsion(FALSE);
-	  } else if(!is_pure(TRUE)) {
+	  } else if(is_pure(TRUE) < 0) {
+	    com_pager(QT_BANISHED);
+	    expulsion(TRUE);
+	  } else if(is_pure(TRUE) == 0) {
 	    qt_pager(QT_BADALIGN);
 	    if(Qstat(not_ready) == MAX_QUEST_TRIES) {
 	      qt_pager(QT_LASTLEADER);
diff -Naurd ../nethack-3.4.0/src/read.c ./src/read.c
--- ../nethack-3.4.0/src/read.c Wed Mar 20 23:43:15 2002
+++ ./src/read.c Mon Feb 24 15:25:05 2003
@@ -17,13 +17,6 @@
 
 #ifdef OVLB
 
-/* elven armor vibrates warningly when enchanted beyond a limit */
-#define is_elven_armor(optr)	((optr)->otyp == ELVEN_LEATHER_HELM\
-				|| (optr)->otyp == ELVEN_MITHRIL_COAT\
-				|| (optr)->otyp == ELVEN_CLOAK\
-				|| (optr)->otyp == ELVEN_SHIELD\
-				|| (optr)->otyp == ELVEN_BOOTS)
-
 boolean	known;
 
 static NEARDATA const char readable[] =
@@ -127,11 +120,7 @@
 	if (scroll->otyp == SCR_MAIL) confused = FALSE;
 #endif
 	if(scroll->oclass == SPBOOK_CLASS) {
-	    if(confused) {
-		You("cannot grasp the meaning of this tome.");
-		return(0);
-	    } else
-		return(study_book(scroll));
+	    return(study_book(scroll));
 	}
 	scroll->in_use = TRUE;	/* scroll, not spellbook, now being read */
 	if(scroll->otyp != SCR_BLANK_PAPER) {
@@ -274,7 +263,7 @@
 		    wand_explode(obj);
 		    return;
 		}
-		if (obj->spe >= lim) p_glow2(obj,blue);
+		if (obj->spe >= lim) p_glow2(obj, NH_BLUE);
 		else p_glow1(obj);
 	    }
 
@@ -345,7 +334,7 @@
 			else
 				obj->spe += n;
 		    }
-		    p_glow2(obj,blue);
+		    p_glow2(obj, NH_BLUE);
 		} else {
 		    n = rn1(5,10);		/* 5..15 */
 		    if (obj->spe + n <= 50)
@@ -357,7 +346,7 @@
 			else
 				obj->spe += n;
 		    }
-		    p_glow2(obj,White);
+		    p_glow2(obj, NH_WHITE);
 		}
 		break;
 	    case OIL_LAMP:
@@ -372,7 +361,7 @@
 		} else if (is_blessed) {
 		    obj->spe = 1;
 		    obj->age = 1500;
-		    p_glow2(obj,blue);
+		    p_glow2(obj, NH_BLUE);
 		} else {
 		    obj->spe = 1;
 		    obj->age += 750;
@@ -384,7 +373,7 @@
 		if (is_cursed) stripspe(obj);
 		else if (is_blessed) {
 		    obj->spe = 6;
-		    p_glow2(obj,blue);
+		    p_glow2(obj, NH_BLUE);
 		} else {
 		    if (obj->spe < 5) {
 			obj->spe++;
@@ -401,7 +390,7 @@
 			obj->spe += rn1(10, 6);
 		    else obj->spe += rn1(5, 6);
 		    if (obj->spe > 50) obj->spe = 50;
-		    p_glow2(obj,blue);
+		    p_glow2(obj, NH_BLUE);
 		} else {
 		    obj->spe += rnd(5);
 		    if (obj->spe > 50) obj->spe = 50;
@@ -418,7 +407,7 @@
 		} else if (is_blessed) {
 		    obj->spe += d(2,4);
 		    if (obj->spe > 20) obj->spe = 20;
-		    p_glow2(obj,blue);
+		    p_glow2(obj, NH_BLUE);
 		} else {
 		    obj->spe += rnd(4);
 		    if (obj->spe > 20) obj->spe = 20;
@@ -702,7 +691,7 @@
 			    Your("%s %s covered by a %s %s %s!",
 				xname(otmp), otense(otmp, "are"),
 				sobj->cursed ? "mottled" : "shimmering",
-				hcolor(sobj->cursed ? Black : golden),
+				 hcolor(sobj->cursed ? NH_BLACK : NH_GOLDEN),
 				sobj->cursed ? "glow" :
 				  (is_shield(otmp) ? "layer" : "shield"));
 			}
@@ -715,6 +704,7 @@
 			}
 			break;
 		}
+		/* elven armor vibrates warningly when enchanted beyond a limit */
 		special_armor = is_elven_armor(otmp) ||
 			(Role_if(PM_WIZARD) && otmp->otyp == CORNUTHAUM);
 		if (sobj->cursed)
@@ -736,7 +726,7 @@
 		     otense(otmp, Blind ? "vibrate" : "glow"),
 		     (!Blind && !same_color) ? " " : nul,
 		     (Blind || same_color) ? nul :
-			hcolor(sobj->cursed ? Black : silver),
+			hcolor(sobj->cursed ? NH_BLACK : NH_SILVER),
 		     otense(otmp, "evaporate"));
 			if(is_cloak(otmp)) (void) Cloak_off();
 			if(is_boots(otmp)) (void) Boots_off();
@@ -772,7 +762,7 @@
 		        s == 0 ? "violently " : nul,
 			otense(otmp, Blind ? "vibrate" : "glow"),
 			(!Blind && !same_color) ? " " : nul,
-			(Blind || same_color) ? nul : hcolor(sobj->cursed ? Black : silver),
+			(Blind || same_color) ? nul : hcolor(sobj->cursed ? NH_BLACK : NH_SILVER),
 			  (s*s>1) ? "while" : "moment");
 		otmp->cursed = sobj->cursed;
 		if (!otmp->blessed || sobj->cursed)
@@ -801,7 +791,7 @@
 				return(1);
 			}
 			otmp->oerodeproof = sobj->cursed;
-			p_glow2(otmp,purple);
+			p_glow2(otmp, NH_PURPLE);
 			break;
 		}
 		if(!sobj->cursed || !otmp || !otmp->cursed) {
@@ -829,11 +819,11 @@
 			Your("%s begin to %s%s.",
 			    makeplural(body_part(HAND)),
 			    Blind ? "tingle" : "glow ",
-			    Blind ? nul : hcolor(purple));
+			    Blind ? nul : hcolor(NH_PURPLE));
 			make_confused(HConfusion + rnd(100),FALSE);
 		    } else {
 			pline("A %s%s surrounds your %s.",
-			    Blind ? nul : hcolor(red),
+			    Blind ? nul : hcolor(NH_RED),
 			    Blind ? "faint buzz" : " glow",
 			    body_part(HEAD));
 			make_confused(0L,TRUE);
@@ -843,7 +833,7 @@
 			Your("%s%s %s%s.",
 			makeplural(body_part(HAND)),
 			Blind ? "" : " begin to glow",
-			Blind ? (const char *)"tingle" : hcolor(red),
+			Blind ? (const char *)"tingle" : hcolor(NH_RED),
 			u.umconf ? " even more" : "");
 			u.umconf++;
 		    } else {
@@ -855,7 +845,7 @@
 			    Your("%s glow a%s brilliant %s.",
 				makeplural(body_part(HAND)),
 				u.umconf ? "n even more" : "",
-				hcolor(red));
+				hcolor(NH_RED));
 			/* after a while, repeated uses become less effective */
 			if (u.umconf >= 40)
 			    u.umconf++;
@@ -915,15 +905,43 @@
 		if (sobj->cursed) {
 		    pline_The("scroll disintegrates.");
 		} else {
-		    for (obj = invent; obj; obj = obj->nobj)
-			if (sobj->blessed ||
-			     (obj->owornmask &&
-			       ((obj->owornmask & ~W_SWAPWEP) || u.twoweap)) ||
+		    for (obj = invent; obj; obj = obj->nobj) {
+			long wornmask;
+#ifdef GOLDOBJ
+			/* gold isn't subject to cursing and blessing */
+			if (obj->oclass == COIN_CLASS) continue;
+#endif
+			wornmask = (obj->owornmask & ~(W_BALL|W_ART|W_ARTI));
+			if (wornmask && !sobj->blessed) {
+			    /* handle a couple of special cases; we don't
+			       allow auxiliary weapon slots to be used to
+			       artificially increase number of worn items */
+			    if (obj == uswapwep) {
+				if (!u.twoweap) wornmask = 0L;
+			    } else if (obj == uquiver) {
+				if (obj->oclass == WEAPON_CLASS) {
+				    /* mergeable weapon test covers ammo,
+				       missiles, spears, daggers & knives */
+				    if (!objects[obj->otyp].oc_merge) 
+					wornmask = 0L;
+				} else if (obj->oclass == GEM_CLASS) {
+				    /* possibly ought to check whether
+				       alternate weapon is a sling... */
+				    if (!uslinging()) wornmask = 0L;
+				} else {
+				    /* weptools don't merge and aren't
+				       reasonable quivered weapons */
+				    wornmask = 0L;
+				}
+			    }
+			}
+			if (sobj->blessed || wornmask ||
 			     obj->otyp == LOADSTONE ||
 			     (obj->otyp == LEASH && obj->leashmon)) {
 			    if(confused) blessorcurse(obj, 2);
 			    else uncurse(obj);
 			}
+		    }
 		}
 		if(Punished && !confused) unpunish();
 		update_inventory();
@@ -952,7 +970,7 @@
 			    Your("%s covered by a %s %s %s!",
 				aobjnam(uwep, "are"),
 				sobj->cursed ? "mottled" : "shimmering",
-				hcolor(sobj->cursed ? purple : golden),
+				hcolor(sobj->cursed ? NH_PURPLE : NH_GOLDEN),
 				sobj->cursed ? "glow" : "shield");
 			}
 			if (uwep->oerodeproof && (uwep->oeroded || uwep->oeroded2)) {
@@ -1409,7 +1427,7 @@
 static void
 do_class_genocide()
 {
-	register int i, j, immunecnt, gonecnt, goodcnt, class;
+	int i, j, immunecnt, gonecnt, goodcnt, class, feel_dead = 0;
 	char buf[BUFSZ];
 	boolean gameover = FALSE;	/* true iff killed self */
 
@@ -1424,7 +1442,8 @@
 		    (void)mungspaces(buf);
 		} while (buf[0]=='\033' || !buf[0]);
 		/* choosing "none" preserves genocideless conduct */
-		if (!strcmpi(buf, "none")) return;
+		if (!strcmpi(buf, "none") ||
+		    !strcmpi(buf, "nothing")) return;
 
 		if (strlen(buf) == 1) {
 		    if (buf[0] == ILLOBJ_SYM)
@@ -1499,19 +1518,26 @@
 			    update_inventory();		/* eggs & tins */
 			    pline("Wiped out all %s.", nam);
 			    if (Upolyd && i == u.umonnum) {
-				if (Unchanging) done(GENOCIDED);
-				rehumanize();
+				u.mh = -1;
+				if (Unchanging) {
+				    if (!feel_dead++) You("die.");
+				    /* finish genociding this class of
+				       monsters before ultimately dying */
+				    gameover = TRUE;
+				} else
+				    rehumanize();
 			    }
-			    /* Self-genocide if it matches either your race or role */
-			    /* Assumption: male and female forms share the same letter */
+			    /* Self-genocide if it matches either your race
+			       or role.  Assumption:  male and female forms
+			       share same monster class. */
 			    if (i == urole.malenum || i == urace.malenum) {
 				u.uhp = -1;
-				killer_format = KILLED_BY_AN;
-				killer = "scroll of genocide";
-				if (Upolyd)
-				    You_feel("dead inside.");
-				else
+				if (Upolyd) {
+				    if (!feel_dead++) You_feel("dead inside.");
+				} else {
+				    if (!feel_dead++) You("die.");
 				    gameover = TRUE;
+				}
 			    }
 			} else if (mvitals[i].mvflags & G_GENOD) {
 			    if (!gameover)
@@ -1542,7 +1568,11 @@
 			}
 		    }
 		}
-		if (gameover) done(GENOCIDED);
+		if (gameover || u.uhp == -1) {
+		    killer_format = KILLED_BY_AN;
+		    killer = "scroll of genocide";
+		    if (gameover) done(GENOCIDED);
+		}
 		return;
 	}
 }
@@ -1579,7 +1609,7 @@
 			buf);
 		(void)mungspaces(buf);
 		/* choosing "none" preserves genocideless conduct */
-		if (!strcmpi(buf, "none")) {
+		if (!strcmpi(buf, "none") || !strcmpi(buf, "nothing")) {
 		    /* ... but no free pass if cursed */
 		    if (!(how & REALLY)) {
 			ptr = rndmonst();
@@ -1766,44 +1796,59 @@
 }
 
 #ifdef WIZARD
+/*
+ * Make a new monster with the type controlled by the user.
+ *
+ * Note:  when creating a monster by class letter, specifying the
+ * "strange object" (']') symbol produces a random monster rather
+ * than a mimic; this behavior quirk is useful so don't "fix" it...
+ */
 boolean
 create_particular()
 {
-	char buf[BUFSZ], monclass = MAXMCLASSES;
-	int which = PM_PLAYERMON, tries = 0, i;
-	struct permonst *whichpm = 0;
+	char buf[BUFSZ], *bufp, monclass = MAXMCLASSES;
+	int which, tries, i;
+	struct permonst *whichpm;
 	struct monst *mtmp;
 	boolean madeany = FALSE;
-	boolean maketame = FALSE;
+	boolean maketame, makepeaceful, makehostile;
 
+	tries = 0;
 	do {
+	    which = urole.malenum;	/* an arbitrary index into mons[] */
+	    maketame = makepeaceful = makehostile = FALSE;
 	    getlin("Create what kind of monster? [type the name or symbol]",
 		   buf);
-	    if (buf[0] == '\033') return FALSE;
-	    (void)mungspaces(buf);
-	    if (strlen(buf) == 1) {
-		monclass = def_char_to_monclass(buf[0]);
-		if (monclass == MAXMCLASSES)
-		    pline("I've never heard of such monsters.");
-		else break;
+	    bufp = mungspaces(buf);
+	    if (*bufp == '\033') return FALSE;
+	    /* allow the initial disposition to be specified */
+	    if (!strncmpi(bufp, "tame ", 5)) {
+		bufp += 5;
+		maketame = TRUE;
+	    } else if (!strncmpi(bufp, "peaceful ", 9)) {
+		bufp += 9;
+		makepeaceful = TRUE;
+	    } else if (!strncmpi(bufp, "hostile ", 8)) {
+		bufp += 8;
+		makehostile = TRUE;
+	    }
+	    /* decide whether a valid monster was chosen */
+	    if (strlen(bufp) == 1) {
+		monclass = def_char_to_monclass(*bufp);
+		if (monclass != MAXMCLASSES) break;	/* got one */
 	    } else {
-		if (!strncmpi(buf, "tame ", 5)) {
-		    which = name_to_mon(buf+5);
-		    maketame = TRUE;
-		} else {
-		    which = name_to_mon(buf);
-		    maketame = FALSE;
-		}
-		if (which < LOW_PM) pline("I've never heard of such monsters.");
-		else {
-		    whichpm = &mons[which];
-		    break;
-		}
+		which = name_to_mon(bufp);
+		if (which >= LOW_PM) break;		/* got one */
 	    }
+	    /* no good; try again... */
+	    pline("I've never heard of such monsters.");
 	} while (++tries < 5);
-	if (tries == 5) pline(thats_enough_tries);
-	else {
+
+	if (tries == 5) {
+	    pline(thats_enough_tries);
+	} else {
 	    (void) cant_create(&which, FALSE);
+	    whichpm = &mons[which];
 	    for (i = 0; i <= multi; i++) {
 		if (monclass != MAXMCLASSES)
 		    whichpm = mkclass(monclass, 0);
@@ -1813,8 +1858,14 @@
 			initedog(mtmp);
 			set_malign(mtmp);
 		    }
-		} else
+		} else {
 		    mtmp = makemon(whichpm, u.ux, u.uy, NO_MM_FLAGS);
+		    if ((makepeaceful || makehostile) && mtmp) {
+			mtmp->mtame = 0;	/* sanity precaution */
+			mtmp->mpeaceful = makepeaceful ? 1 : 0;
+			set_malign(mtmp);
+		    }
+		}
 		if (mtmp) madeany = TRUE;
 	    }
 	}
diff -Naurd ../nethack-3.4.0/src/region.c ./src/region.c
--- ../nethack-3.4.0/src/region.c Wed Mar 20 23:43:15 2002
+++ ./src/region.c Mon Feb 24 15:25:05 2003
@@ -43,6 +43,7 @@
 NhRegion *FDECL(create_force_field, (XCHAR_P,XCHAR_P,int,int));
 #endif
 
+static void FDECL(reset_region_mids, (NhRegion *));
 
 static callback_proc callbacks[] = {
 #define INSIDE_GAS_CLOUD 0
@@ -124,7 +125,8 @@
     reg->leave_f = NO_CALLBACK;
     reg->can_leave_f = NO_CALLBACK;
     reg->inside_f = NO_CALLBACK;
-    reg->player_inside = FALSE;
+    clear_hero_inside(reg);
+    clear_heros_fault(reg);
     reg->n_monst = 0;
     reg->max_monst = 0;
     reg->monsters = NULL;
@@ -245,7 +247,7 @@
     ret_reg->can_enter_f = reg->can_enter_f;
     ret_reg->leave_f = reg->leave_f;
     ret_reg->can_leave_f = reg->can_leave_f;
-    ret_reg->player_inside = reg->player_inside;
+    ret_reg->player_flags = reg->player_flags;	/* set/clear_hero_inside,&c*/
     ret_reg->n_monst = reg->n_monst;
     if (reg->n_monst > 0) {
 	ret_reg->monsters = (unsigned *)
@@ -310,7 +312,10 @@
 		newsym(i, j);
 	}
     /* Check for player now... */
-    reg->player_inside = inside_region(reg, u.ux, u.uy);
+    if (inside_region(reg, u.ux, u.uy)) 
+	set_hero_inside(reg);
+    else
+	clear_hero_inside(reg);
 }
 
 /*
@@ -387,7 +392,7 @@
 	    regions[i]->ttl--;
 	/* Check if player is inside region */
 	f_indx = regions[i]->inside_f;
-	if (f_indx != NO_CALLBACK && regions[i]->player_inside)
+	if (f_indx != NO_CALLBACK && hero_inside(regions[i]))
 	    (void) (*callbacks[f_indx])(regions[i], (genericptr_t) 0);
 	/* Check if any monster is inside region */
 	if (f_indx != NO_CALLBACK) {
@@ -420,12 +425,12 @@
     /* First check if we can do the move */
     for (i = 0; i < n_regions; i++) {
 	if (inside_region(regions[i], x, y)
-	    && !regions[i]->player_inside && !regions[i]->attach_2_u) {
+	    && !hero_inside(regions[i]) && !regions[i]->attach_2_u) {
 	    if ((f_indx = regions[i]->can_enter_f) != NO_CALLBACK)
 		if (!(*callbacks[f_indx])(regions[i], (genericptr_t) 0))
 		    return FALSE;
 	} else
-	    if (regions[i]->player_inside
+	    if (hero_inside(regions[i])
 		&& !inside_region(regions[i], x, y)
 		&& !regions[i]->attach_2_u) {
 	    if ((f_indx = regions[i]->can_leave_f) != NO_CALLBACK)
@@ -436,9 +441,9 @@
 
     /* Callbacks for the regions we do leave */
     for (i = 0; i < n_regions; i++)
-	if (regions[i]->player_inside &&
+	if (hero_inside(regions[i]) &&
 		!regions[i]->attach_2_u && !inside_region(regions[i], x, y)) {
-	    regions[i]->player_inside = FALSE;
+	    clear_hero_inside(regions[i]);
 	    if (regions[i]->leave_msg != NULL)
 		pline(regions[i]->leave_msg);
 	    if ((f_indx = regions[i]->leave_f) != NO_CALLBACK)
@@ -447,9 +452,9 @@
 
     /* Callbacks for the regions we do enter */
     for (i = 0; i < n_regions; i++)
-	if (!regions[i]->player_inside &&
+	if (!hero_inside(regions[i]) &&
 		!regions[i]->attach_2_u && inside_region(regions[i], x, y)) {
-	    regions[i]->player_inside = TRUE;
+	    set_hero_inside(regions[i]);
 	    if (regions[i]->enter_msg != NULL)
 		pline(regions[i]->enter_msg);
 	    if ((f_indx = regions[i]->enter_f) != NO_CALLBACK)
@@ -497,7 +502,7 @@
 
     /* Callbacks for the regions we do enter */
     for (i = 0; i < n_regions; i++)
-	if (!regions[i]->player_inside &&
+	if (!hero_inside(regions[i]) &&
 		!regions[i]->attach_2_u && inside_region(regions[i], x, y)) {
 	    add_mon_to_reg(regions[i], mon);
 	    if ((f_indx = regions[i]->enter_f) != NO_CALLBACK)
@@ -515,10 +520,10 @@
     register int i;
 
     for (i = 0; i < n_regions; i++)
-	if (!regions[i]->attach_2_u)
-	    regions[i]->player_inside = inside_region(regions[i], u.ux, u.uy);
+	if (!regions[i]->attach_2_u && inside_region(regions[i], u.ux, u.uy))
+	    set_hero_inside(regions[i]);
 	else
-	    regions[i]->player_inside = FALSE;
+	    clear_hero_inside(regions[i]);
 }
 
 /*
@@ -641,7 +646,7 @@
 	bwrite(fd, (genericptr_t) &regions[i]->can_leave_f, sizeof (short));
 	bwrite(fd, (genericptr_t) &regions[i]->leave_f, sizeof (short));
 	bwrite(fd, (genericptr_t) &regions[i]->inside_f, sizeof (short));
-	bwrite(fd, (genericptr_t) &regions[i]->player_inside, sizeof (boolean));
+	bwrite(fd, (genericptr_t) &regions[i]->player_flags, sizeof (boolean));
 	bwrite(fd, (genericptr_t) &regions[i]->n_monst, sizeof (short));
 	for (j = 0; j < regions[i]->n_monst; j++)
 	    bwrite(fd, (genericptr_t) &regions[i]->monsters[j],
@@ -657,8 +662,9 @@
 }
 
 void
-rest_regions(fd)
+rest_regions(fd, ghostly)
 int fd;
+boolean ghostly; /* If a bones file restore */
 {
     int i, j;
     unsigned n;
@@ -667,7 +673,8 @@
 
     clear_regions();		/* Just for security */
     mread(fd, (genericptr_t) &tmstamp, sizeof (tmstamp));
-    tmstamp = (moves - tmstamp);
+    if (ghostly) tmstamp = 0;
+    else tmstamp = (moves - tmstamp);
     mread(fd, (genericptr_t) &n_regions, sizeof (n_regions));
     max_regions = n_regions;
     if (n_regions > 0)
@@ -714,7 +721,11 @@
 	mread(fd, (genericptr_t) &regions[i]->can_leave_f, sizeof (short));
 	mread(fd, (genericptr_t) &regions[i]->leave_f, sizeof (short));
 	mread(fd, (genericptr_t) &regions[i]->inside_f, sizeof (short));
-	mread(fd, (genericptr_t) &regions[i]->player_inside, sizeof (boolean));
+	mread(fd, (genericptr_t) &regions[i]->player_flags, sizeof (boolean));
+	if (ghostly) {	/* settings pertained to old player */
+	    clear_hero_inside(regions[i]);
+	    clear_heros_fault(regions[i]);
+	}
 	mread(fd, (genericptr_t) &regions[i]->n_monst, sizeof (short));
 	if (regions[i]->n_monst > 0)
 	    regions[i]->monsters =
@@ -729,10 +740,33 @@
 	mread(fd, (genericptr_t) &regions[i]->glyph, sizeof (int));
 	mread(fd, (genericptr_t) &regions[i]->arg, sizeof (genericptr_t));
     }
-    /* remove expired regions, do not trigger the expire_f callback (yet!) */
+    /* remove expired regions, do not trigger the expire_f callback (yet!);
+       also update monster lists if this data is coming from a bones file */
     for (i = n_regions - 1; i >= 0; i--)
 	if (regions[i]->ttl == 0)
 	    remove_region(regions[i]);
+	else if (ghostly && regions[i]->n_monst > 0)
+	    reset_region_mids(regions[i]);
+}
+
+/* update monster IDs for region being loaded from bones; `ghostly' implied */
+static void
+reset_region_mids(reg)
+NhRegion *reg;
+{
+    int i = 0, n = reg->n_monst;
+    unsigned *mid_list = reg->monsters;
+
+    while (i < n)
+	if (!lookup_id_mapping(mid_list[i], &mid_list[i])) {
+	    /* shrink list to remove missing monster; order doesn't matter */
+	    mid_list[i] = mid_list[--n];
+	} else {
+	    /* move on to next monster */
+	    ++i;
+	}
+    reg->n_monst = n;
+    return;
 }
 
 #if 0
@@ -818,6 +852,8 @@
 	tmprect.hy--;
     }
     ff->ttl = ttl;
+    if (!in_mklev && !flags.mon_moving)
+	set_heros_fault(ff);		/* assume player has created it */
  /* ff->can_enter_f = enter_force_field; */
  /* ff->can_leave_f = enter_force_field; */
     add_region(ff);
@@ -898,7 +934,10 @@
 		return FALSE;
 	    mtmp->mhp -= rnd(dam) + 5;
 	    if (mtmp->mhp <= 0) {
-		killed(mtmp);
+		if (heros_fault(reg))
+		    killed(mtmp);
+		else
+		    monkilled(mtmp, "gas cloud", AD_DRST);
 		if (mtmp->mhp <= 0) {	/* not lifesaved */
 		    return TRUE;
 		}
@@ -932,6 +971,8 @@
 	tmprect.hy--;
     }
     cloud->ttl = rn1(3,4);
+    if (!in_mklev && !flags.mon_moving)
+	set_heros_fault(cloud);		/* assume player has created it */
     cloud->inside_f = INSIDE_GAS_CLOUD;
     cloud->expire_f = EXPIRE_GAS_CLOUD;
     cloud->arg = (genericptr_t) damage;
diff -Naurd ../nethack-3.4.0/src/restore.c ./src/restore.c
--- ../nethack-3.4.0/src/restore.c Wed Mar 20 23:43:15 2002
+++ ./src/restore.c Mon Feb 24 15:25:05 2003
@@ -6,7 +6,7 @@
 #include "lev.h"
 #include "tcap.h" /* for TERMLIB and ASCIIGRAPH */
 
-#ifdef MICRO
+#if defined(MICRO)
 extern int dotcnt;	/* shared with save */
 extern int dotrow;	/* shared with save */
 #endif
@@ -106,6 +106,17 @@
 
 	for (otmp = invent; otmp; otmp = otmp2) {
 	    otmp2 = otmp->nobj;
+#ifndef GOLDOBJ
+	    if (otmp->oclass == COIN_CLASS) {
+		/* in_use gold is created by some menu operations */
+		if (!otmp->in_use) {
+		    impossible("inven_inuse: !in_use gold in inventory");
+		}
+		extract_nobj(otmp, &invent);
+		otmp->in_use = FALSE;
+		dealloc_obj(otmp);
+	    } else
+#endif /* GOLDOBJ */
 	    if (otmp->in_use) {
 		if (!quietly) pline("Finishing off %s...", xname(otmp));
 		useup(otmp);
@@ -344,6 +355,8 @@
 register int fd;
 unsigned int *stuckid, *steedid;	/* STEED */
 {
+	/* discover is actually flags.explore */
+	boolean remember_discover = discover;
 	struct obj *otmp;
 	int uid;
 
@@ -360,6 +373,7 @@
 
 	mread(fd, (genericptr_t) &flags, sizeof(struct flag));
 	flags.bypasses = 0;	/* never use the saved value of bypasses */
+	if (remember_discover) discover = remember_discover;
 
 	role_init();	/* Reset the initial role, race, gender, and alignment */
 #ifdef AMII_GRAPHICS
@@ -470,10 +484,14 @@
 #endif
 {
 	register int nfd;
+	char whynot[BUFSZ];
 
-	nfd = create_levelfile(ltmp);
-
-	if (nfd < 0)	panic("Cannot open temp level %d!", ltmp);
+	nfd = create_levelfile(ltmp, whynot);
+	if (nfd < 0) {
+		/* BUG: should suppress any attempt to write a panic
+		   save file if file creation is now failing... */
+		panic("restlevelfile: %s", whynot);
+	}
 #ifdef MFLOPPY
 	if (!savelev(nfd, ltmp, COUNT_SAVE)) {
 
@@ -528,6 +546,10 @@
 	int rtmp;
 	struct obj *otmp;
 
+#ifdef STORE_PLNAME_IN_FILE
+	mread(fd, (genericptr_t) plname, PL_NSIZ);
+#endif
+
 	restoring = TRUE;
 	getlev(fd, 0, (xchar)0, FALSE);
 	if (!restgamestate(fd, &stuckid, &steedid)) {
@@ -607,6 +629,9 @@
 	(void) lseek(fd, (off_t)0, 0);
 #endif
 	(void) uptodate(fd, (char *)0);		/* skip version info */
+#ifdef STORE_PLNAME_IN_FILE
+	mread(fd, (genericptr_t) plname, PL_NSIZ);
+#endif
 	getlev(fd, 0, (xchar)0, FALSE);
 	(void) close(fd);
 
@@ -654,11 +679,13 @@
 }
 
 void
-trickery()
+trickery(reason)
+char *reason;
 {
 	pline("Strange, this map is not as I remember it.");
 	pline("Somebody is trying some trickery here...");
 	pline("This game is void.");
+	killer = reason;
 	done(TRICKED);
 }
 
@@ -698,16 +725,18 @@
 #else
 	mread(fd, (genericptr_t) &dlvl, sizeof(dlvl));
 #endif
-	if((pid && pid != hpid) || (lev && dlvl != lev)) {
+	if ((pid && pid != hpid) || (lev && dlvl != lev)) {
+	    char trickbuf[BUFSZ];
+
+	    if (pid && pid != hpid)
+		Sprintf(trickbuf, "PID (%d) doesn't match saved PID (%d)!",
+			hpid, pid);
+	    else
+		Sprintf(trickbuf, "This is level %d, not %d!", dlvl, lev);
 #ifdef WIZARD
-		if (wizard) {
-			if (pid && pid != hpid)
-				pline("PID (%d) doesn't match saved PID (%d)!", hpid, pid);
-			else if (lev && dlvl != lev)
-				pline("This is level %d, not %d!", dlvl, lev);
-		}
+	    if (wizard) pline(trickbuf);
 #endif
-		trickery();
+	    trickery(trickbuf);
 	}
 
 #ifdef RLECOMP
@@ -810,7 +839,7 @@
 	}
 	restdamage(fd, ghostly);
 
-	rest_regions(fd);
+	rest_regions(fd, ghostly);
 	if (ghostly) {
 	    /* Now get rid of all the temp fruits... */
 	    freefruitchn(oldfruit),  oldfruit = 0;
@@ -1005,6 +1034,7 @@
 register unsigned len;
 {
     /*register int readlen = 0;*/
+    if (fd < 0) error("Restore error; mread attempting to read file %d.", fd);
     mreadfd = fd;
     while (len--) {
 	if (inrunlength > 0) {
diff -Naurd ../nethack-3.4.0/src/rip.c ./src/rip.c
--- ../nethack-3.4.0/src/rip.c Wed Mar 20 23:43:16 2002
+++ ./src/rip.c Mon Feb 24 15:25:05 2003
@@ -6,7 +6,7 @@
 
 STATIC_DCL void FDECL(center, (int, char *));
 
-extern const char *killed_by_prefix[];
+extern const char * const killed_by_prefix[];	/* from topten.c */
 
 #if defined(TTY_GRAPHICS) || defined(X11_GRAPHICS) || defined(GEM_GRAPHICS) || defined(MSWIN_GRAPHICS)
 # define TEXT_TOMBSTONE
diff -Naurd ../nethack-3.4.0/src/role.c ./src/role.c
--- ../nethack-3.4.0/src/role.c Wed Mar 20 23:43:16 2002
+++ ./src/role.c Mon Feb 24 15:25:05 2003
@@ -1100,7 +1100,7 @@
 {
 	int k, gendercount = 0, aligncount = 0;
 	char buf[BUFSZ];
-	char *err_ret = " character's";
+	static char err_ret[] = " character's";
 	boolean donefirst = FALSE;
 
 	if (!suppliedbuf || buflen < 1) return err_ret;
diff -Naurd ../nethack-3.4.0/src/save.c ./src/save.c
--- ../nethack-3.4.0/src/save.c Wed Mar 20 23:43:16 2002
+++ ./src/save.c Mon Feb 24 15:25:05 2003
@@ -1,9 +1,10 @@
-/*	SCCS Id: @(#)save.c	3.4	2002/01/19	*/
+/*	SCCS Id: @(#)save.c	3.4	2002/08/22	*/
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /* NetHack may be freely redistributed.  See license for details. */
 
 #include "hack.h"
 #include "lev.h"
+#include "quest.h"
 
 #ifndef NO_SIGNAL
 #include <signal.h>
@@ -12,8 +13,6 @@
 #include <fcntl.h>
 #endif
 
-#include "quest.h"
-
 #ifdef MFLOPPY
 long bytes_counted;
 static int count_only;
@@ -66,6 +65,7 @@
 		program_state.done_hup = 0;
 #endif
 		if(dosave0()) {
+			program_state.something_worth_saving = 0;
 			u.uhp = -1;		/* universal game's over indicator */
 			/* make sure they see the Saving message */
 			display_nhwindow(WIN_MESSAGE, TRUE);
@@ -116,6 +116,7 @@
 	register int fd, ofd;
 	xchar ltmp;
 	d_level uz_save;
+	char whynot[BUFSZ];
 
 	if (!SAVEF[0])
 		return 0;
@@ -149,7 +150,6 @@
 	HUP mark_synch();	/* flush any buffered screen output */
 
 	fd = create_savefile();
-
 	if(fd < 0) {
 		HUP pline("Cannot open save file.");
 		(void) delete_savefile();	/* ab@unido */
@@ -203,6 +203,9 @@
 #endif /* MFLOPPY */
 
 	store_version(fd);
+#ifdef STORE_PLNAME_IN_FILE
+	bwrite(fd, (genericptr_t) plname, PL_NSIZ);
+#endif
 	ustuck_id = (u.ustuck ? u.ustuck->m_id : 0);
 #ifdef STEED
 	usteed_id = (u.usteed ? u.usteed->m_id : 0);
@@ -239,11 +242,12 @@
 		}
 		mark_synch();
 #endif
-		ofd = open_levelfile(ltmp);
+		ofd = open_levelfile(ltmp, whynot);
 		if (ofd < 0) {
-		    HUP pline("Cannot read level %d.", ltmp);
+		    HUP pline("%s", whynot);
 		    (void) close(fd);
 		    (void) delete_savefile();
+		    HUP killer = whynot;
 		    HUP done(TRICKED);
 		    return(0);
 		}
@@ -324,6 +328,7 @@
 {
 	int fd, hpid;
 	static boolean havestate = TRUE;
+	char whynot[BUFSZ];
 
 	/* When checkpointing is on, the full state needs to be written
 	 * on each checkpoint.  When checkpointing is off, only the pid
@@ -343,24 +348,30 @@
 		 * to any internal compression schemes since they must be
 		 * readable by an external utility
 		 */
-		fd = open_levelfile(0);
+		fd = open_levelfile(0, whynot);
 		if (fd < 0) {
-		    pline("Cannot open level 0.");
+		    pline("%s", whynot);
 		    pline("Probably someone removed it.");
+		    killer = whynot;
 		    done(TRICKED);
 		    return;
 		}
 
 		(void) read(fd, (genericptr_t) &hpid, sizeof(hpid));
 		if (hackpid != hpid) {
-		    pline("Level 0 pid bad!");
+		    Sprintf(whynot,
+			    "Level #0 pid (%d) doesn't match ours (%d)!",
+			    hpid, hackpid);
+		    pline("%s", whynot);
+		    killer = whynot;
 		    done(TRICKED);
 		}
 		(void) close(fd);
 
-		fd = create_levelfile(0);
+		fd = create_levelfile(0, whynot);
 		if (fd < 0) {
-		    pline("Cannot rewrite level 0.");
+		    pline("%s", whynot);
+		    killer = whynot;
 		    done(TRICKED);
 		    return;
 		}
@@ -371,6 +382,9 @@
 		    (void) write(fd, (genericptr_t) &currlev, sizeof(currlev));
 		    save_savefile_name(fd);
 		    store_version(fd);
+#ifdef STORE_PLNAME_IN_FILE
+		    bwrite(fd, (genericptr_t) plname, PL_NSIZ);
+#endif
 		    ustuck_id = (u.ustuck ? u.ustuck->m_id : 0);
 #ifdef STEED
 		    usteed_id = (u.usteed ? u.usteed->m_id : 0);
@@ -1021,7 +1035,7 @@
 	}
 # ifdef WIZARD
 	if (wizard) {
-		pline("Swapping in `%s'", from);
+		pline("Swapping in `%s'.", from);
 		wait_synch();
 	}
 # endif
diff -Naurd ../nethack-3.4.0/src/shk.c ./src/shk.c
--- ../nethack-3.4.0/src/shk.c Wed Mar 20 23:43:17 2002
+++ ./src/shk.c Mon Feb 24 15:25:05 2003
@@ -24,6 +24,7 @@
 #define IS_SHOP(x)	(rooms[x].rtype >= SHOPBASE)
 
 extern const struct shclass shtypes[];	/* defined in shknam.c */
+extern struct obj *thrownobj;		/* defined in dothrow.c */
 
 STATIC_VAR NEARDATA long int followmsg;	/* last time of follow message */
 
@@ -51,7 +52,7 @@
 STATIC_DCL void FDECL(shk_names_obj,
 		 (struct monst *,struct obj *,const char *,long,const char *));
 STATIC_DCL struct obj *FDECL(bp_to_obj, (struct bill_x *));
-STATIC_DCL boolean FDECL(inherits, (struct monst *, int, BOOLEAN_P));
+STATIC_DCL boolean FDECL(inherits, (struct monst *,int,int));
 STATIC_DCL void FDECL(set_repo_loc, (struct eshk *));
 STATIC_DCL boolean NDECL(angry_shk_exists);
 STATIC_DCL void FDECL(rile_shk, (struct monst *));
@@ -64,7 +65,7 @@
 STATIC_DCL void FDECL(bill_box_content, (struct obj *, BOOLEAN_P, BOOLEAN_P,
 				     struct monst *));
 #ifdef OVL1
-static void FDECL(rob_shop, (struct monst *));
+static boolean FDECL(rob_shop, (struct monst *));
 #endif
 
 #ifdef OVLB
@@ -88,7 +89,8 @@
     Returns the amount actually paid, so we can know
     if the monster kept the change.
  */
-long money2mon(mon, amount)
+long
+money2mon(mon, amount)
 struct monst *mon;
 long amount;
 {
@@ -103,8 +105,10 @@
 	return 0L;
     }
 
-    if (ygold->quan > amount) ygold = splitobj(ygold, amount);
-    else if (ygold->owornmask) remove_worn_item(ygold);		/* quiver */
+    if (ygold->quan > amount)
+	ygold = splitobj(ygold, amount);
+    else if (ygold->owornmask)
+	remove_worn_item(ygold, FALSE);		/* quiver */
     freeinv(ygold);
     add_to_minv(mon, ygold);
     flags.botl = 1;
@@ -282,6 +286,7 @@
 	clear_unpaid(invent);
 	clear_unpaid(fobj);
 	clear_unpaid(level.buriedobjlist);
+	if (thrownobj) thrownobj->unpaid = 0;
 	for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
 		clear_unpaid(mtmp->minvent);
 	for(mtmp = migrating_mons; mtmp; mtmp = mtmp->nmon)
@@ -423,13 +428,13 @@
 	    return;
 	}
 
-	rob_shop(shkp);
-
+	if (rob_shop(shkp)) {
 #ifdef KOPS
-	call_kops(shkp, (!newlev && levl[u.ux0][u.uy0].edge));
+	    call_kops(shkp, (!newlev && levl[u.ux0][u.uy0].edge));
 #else
-	(void) angry_guards(FALSE);
+	    (void) angry_guards(FALSE);
 #endif
+	}
 }
 
 /* robbery from outside the shop via telekinesis or grappling hook */
@@ -448,17 +453,19 @@
 	if (!eshkp->billct && !eshkp->debit)	/* bill is settled */
 	    return;
 
-	rob_shop(shkp);
-
+	if (rob_shop(shkp)) {
 #ifdef KOPS
-	/* [might want to set 2nd arg based on distance from shop doorway] */
-	call_kops(shkp, FALSE);
+	    /*[might want to set 2nd arg based on distance from shop doorway]*/
+	    call_kops(shkp, FALSE);
 #else
-	(void) angry_guards(FALSE);
+	    (void) angry_guards(FALSE);
 #endif
+	}
 }
 
-static void
+/* shop merchandize has been taken; pay for it with any credit available;  
+   return false if the debt is fully covered by credit, true otherwise */
+static boolean
 rob_shop(shkp)
 struct monst *shkp;
 {
@@ -476,7 +483,7 @@
 	    total -= eshkp->credit;
 	}
 	setpaid(shkp);
-	if (!total) return;
+	if (!total) return FALSE;
 
 	/* by this point, we know an actual robbery has taken place */
 	eshkp->robbed += total;
@@ -486,6 +493,7 @@
 	    adjalign(-sgn(u.ualign.type));
 
 	hot_pursuit(shkp);
+	return TRUE;
 }
 
 void
@@ -610,7 +618,8 @@
    making sure they're unpaid and the same type of object; we check the price
    quoted by the shopkeeper and also that they both belong to the same shk.
  */
-boolean same_price(obj1, obj2)
+boolean
+same_price(obj1, obj2)
 struct obj *obj1, *obj2;
 {
 	register struct monst *shkp1, *shkp2;
@@ -889,6 +898,7 @@
 #endif
 		pacify_guards();
 	}
+	after_shk_move(shkp);
 }
 
 STATIC_OVL boolean
@@ -989,10 +999,11 @@
 	if(!shkp->isshk) return;
 
 	rile_shk(shkp);
+	(void) strncpy(ESHK(shkp)->customer, plname, PL_NSIZ);
 	ESHK(shkp)->following = 1;
 }
 
-/* used when the shkp is teleported out of his shop,
+/* used when the shkp is teleported or falls (ox == 0) out of his shop,
  * or when the player is not on a costly_spot and he
  * damages something inside the shop.  these conditions
  * must be checked by the calling function.
@@ -1019,7 +1030,7 @@
 	   which makes this message look pretty silly, so temporarily restore
 	   her original location during the call to Monnam. */
 	sx = shkp->mx,  sy = shkp->my;
-	if (cansee(ox, oy) && !cansee(sx, sy))
+	if (isok(ox, oy) && cansee(ox, oy) && !cansee(sx, sy))
 		shkp->mx = ox,  shkp->my = oy;
 	pline("%s %s!", Monnam(shkp),
 	      !ANGRY(shkp) ? "gets angry" : "is furious");
@@ -1528,7 +1539,9 @@
 	}
 
 	pay(ltmp, shkp);
-	shk_names_obj(shkp, obj, "bought %s for %ld gold piece%s.%s", ltmp, "");
+	shk_names_obj(shkp, obj, consumed ?
+			"paid for %s at a cost of %ld gold piece%s.%s" :
+			"bought %s for %ld gold piece%s.%s", ltmp, "");
 	obj->quan = save_quan;		/* restore original count */
 	/* quan => amount just bought, save_quan => remaining unpaid count */
 	if (consumed) {
@@ -1556,12 +1569,17 @@
 /* routine called after dying (or quitting) */
 boolean
 paybill(croaked)
-boolean croaked;
+int croaked;	/* -1: escaped dungeon; 0: quit; 1: died */
 {
 	register struct monst *mtmp, *mtmp2, *resident= (struct monst *)0;
 	register boolean taken = FALSE;
 	register int numsk = 0;
 
+	/* if we escaped from the dungeon, shopkeepers can't reach us;
+	   shops don't occur on level 1, but this could happen if hero
+	   level teleports out of the dungeon and manages not to die */
+	if (croaked < 0) return FALSE;
+
 	/* this is where inventory will end up if any shk takes it */
 	repo_location.x = repo_location.y = 0;
 
@@ -1592,7 +1610,7 @@
 inherits(shkp, numsk, croaked)
 struct monst *shkp;
 int numsk;
-boolean croaked;
+int croaked;
 {
 	long loss = 0L;
 #ifdef GOLDOBJ
@@ -1660,7 +1678,7 @@
 		if (loss > umoney || !loss || roomno == eshkp->shoproom) {
 			eshkp->robbed -= umoney;
 			if (eshkp->robbed < 0L) eshkp->robbed = 0L;
-                        money2mon(shkp, umoney);
+                        if (umoney > 0) money2mon(shkp, umoney);
 #endif
 			flags.botl = 1;
 			pline("%s %s all your possessions.",
@@ -1726,7 +1744,8 @@
 }
 
 /* called at game exit, after inventory disclosure but before making bones */
-void finish_paybill()
+void
+finish_paybill()
 {
 	register struct obj *otmp;
 	int ox = repo_location.x,
@@ -1890,7 +1909,7 @@
 
 	/* the price of contained objects */
 	for (otmp = obj->cobj; otmp; otmp = otmp->nobj) {
-	    if (otmp->oclass == GOLD_CLASS) continue;
+	    if (otmp->oclass == COIN_CLASS) continue;
 	    /* the "top" container is evaluated by caller */
 	    if (usell) {
 		if (saleable(shkp, otmp) &&
@@ -1920,7 +1939,7 @@
 
 	/* accumulate contained gold */
 	for (otmp = obj->cobj; otmp; otmp = otmp->nobj)
-	    if (otmp->oclass == GOLD_CLASS)
+	    if (otmp->oclass == COIN_CLASS)
 		value += otmp->quan;
 	    else if (Has_contents(otmp))
 		value += contained_gold(otmp);
@@ -1938,7 +1957,7 @@
 
 	/* the "top" container is treated in the calling fn */
 	for (otmp = obj->cobj; otmp; otmp = otmp->nobj) {
-	    if (otmp->oclass == GOLD_CLASS) continue;
+	    if (otmp->oclass == COIN_CLASS) continue;
 
 	    if (!otmp->unpaid && !(sale && saleable(shkp, otmp)))
 		otmp->no_charge = 1;
@@ -1956,7 +1975,7 @@
 
 	/* the "top" container is treated in the calling fn */
 	for (otmp = obj->cobj; otmp; otmp = otmp->nobj) {
-	    if (otmp->oclass == GOLD_CLASS) continue;
+	    if (otmp->oclass == COIN_CLASS) continue;
 
 	    if (otmp->no_charge)
 		otmp->no_charge = 0;
@@ -2091,7 +2110,7 @@
 	register struct obj *otmp;
 
 	for (otmp = obj->cobj; otmp; otmp = otmp->nobj) {
-		if (otmp->oclass == GOLD_CLASS) continue;
+		if (otmp->oclass == COIN_CLASS) continue;
 
 		/* the "top" box is added in addtobill() */
 		if (!otmp->no_charge)
@@ -2164,7 +2183,7 @@
 		return;
 	}
 
-	if(obj->oclass == GOLD_CLASS) {
+	if(obj->oclass == COIN_CLASS) {
 		costly_gold(obj->ox, obj->oy, obj->quan);
 		return;
 	}
@@ -2338,7 +2357,7 @@
 
 	if (Has_contents(obj))
 	    for(otmp = obj->cobj; otmp; otmp = otmp->nobj) {
-		if(otmp->oclass == GOLD_CLASS) continue;
+		if(otmp->oclass == COIN_CLASS) continue;
 
 		if (Has_contents(otmp))
 		    subfrombill(otmp, shkp);
@@ -2370,7 +2389,7 @@
 	/* the price of contained objects, if any */
 	for(otmp = obj->cobj; otmp; otmp = otmp->nobj) {
 
-	    if(otmp->oclass == GOLD_CLASS) continue;
+	    if(otmp->oclass == COIN_CLASS) continue;
 
 	    if (!Has_contents(otmp)) {
 		if(ininv) {
@@ -2404,7 +2423,7 @@
 	if (!shkp || !inhishop(shkp))
 	    return (0L);
 
-	if(obj->oclass == GOLD_CLASS) {
+	if(obj->oclass == COIN_CLASS) {
 	    gvalue += obj->quan;
 	} else if (Has_contents(obj)) {
 	    register boolean ininv = !!count_unpaid(obj->cobj);
@@ -2425,7 +2444,8 @@
 	    ESHK(shkp)->debit += value;
 
 	    if(!silent) {
-		char *still = "";
+		const char *still = "";
+
 		if (credit_use) {
 		    if (ESHK(shkp)->credit) {
 			You("have %ld %s credit remaining.",
@@ -2437,11 +2457,12 @@
 		    }
 		    still = "still ";
 		}
-		if(obj->oclass == GOLD_CLASS)
-		    You("%sowe %s %ld %s!", still, mon_nam(shkp), value, currency(value));
-		else You("%sowe %s %ld %s for %s!", still,
-			mon_nam(shkp),
-			value, currency(value),
+		if(obj->oclass == COIN_CLASS)
+		    You("%sowe %s %ld %s!", still,
+			mon_nam(shkp), value, currency(value));
+		else
+		    You("%sowe %s %ld %s for %s!", still,
+			mon_nam(shkp), value, currency(value),
 			obj->quan > 1L ? "them" : "it");
 	    }
 	} else {
@@ -2449,8 +2470,6 @@
 
 	    if(!silent) {
 		if(cansee(shkp->mx, shkp->my)) {
-		    if(ESHK(shkp)->customer[0] == 0)
-			(void) strncpy(ESHK(shkp)->customer,plname,PL_NSIZ);
 		    Norep("%s booms: \"%s, you are a thief!\"",
 				Monnam(shkp), plname);
 		} else  Norep("You hear a scream, \"Thief!\"");
@@ -2492,7 +2511,7 @@
 	register struct eshk *eshkp;
 	long ltmp = 0L, cltmp = 0L, gltmp = 0L, offer;
 	boolean saleitem, cgold = FALSE, container = Has_contents(obj);
-	boolean isgold = (obj->oclass == GOLD_CLASS);
+	boolean isgold = (obj->oclass == COIN_CLASS);
 	boolean only_partially_your_contents = FALSE;
 
 	if(!(shkp = shop_keeper(*in_rooms(x, y, SHOPBASE))) ||
@@ -2616,7 +2635,7 @@
 	   || (obj->oclass == FOOD_CLASS && obj->oeaten)
 	   || (Is_candle(obj) &&
 		   obj->age < 20L * (long)objects[obj->otyp].oc_cost)) {
-		pline("%s seems not interested%s.", Monnam(shkp),
+		pline("%s seems uninterested%s.", Monnam(shkp),
 			cgold ? " in the rest" : "");
 		if (container)
 		    dropped_container(obj, shkp, FALSE);
@@ -3255,8 +3274,24 @@
 		}
 	}
 
-	return(move_special(shkp,inhishop(shkp),
-			    appr,uondoor,avoid,omx,omy,gx,gy));
+	z = move_special(shkp,inhishop(shkp),appr,uondoor,avoid,omx,omy,gx,gy);
+	if (z > 0) after_shk_move(shkp);
+
+	return z;
+}
+
+/* called after shopkeeper moves, in case the move causes re-entry into shop */
+void
+after_shk_move(shkp)
+struct monst *shkp;
+{
+	struct eshk *eshkp = ESHK(shkp);
+
+	if (eshkp->bill_p == (struct bill_x *) -1000 && inhishop(shkp)) {
+	    /* reset bill_p, need to re-calc player's occupancy too */
+	    eshkp->bill_p = &eshkp->bill[0];
+	    check_special_room(FALSE);
+	}
 }
 
 #endif /*OVL3*/
@@ -3276,14 +3311,17 @@
 register int fall;
 {
     register struct monst *shkp = shop_keeper(*u.ushops);
-    int lang = 0;
-    char *grabs = "grabs";
+    int lang;
+    const char *grabs = "grabs";
 
     if(!shkp) return;
 
     /* 0 == can't speak, 1 == makes animal noises, 2 == speaks */
-    if (!is_silent(shkp->data) && shkp->data->msound <= MS_ANIMAL)
-    	lang = 1;
+    lang = 0;
+    if (shkp->msleeping || !shkp->mcanmove || is_silent(shkp->data))
+	;	/* lang stays 0 */
+    else if (shkp->data->msound <= MS_ANIMAL)
+	lang = 1;
     else if (shkp->data->msound >= MS_HUMANOID)
 	lang = 2;
 
@@ -3347,6 +3385,8 @@
 		if ((obj->owornmask & ~(W_SWAPWEP|W_QUIVER)) != 0 ||
 			(obj == uswapwep && u.twoweap) ||
 			(obj->otyp == LEASH && obj->leashmon)) continue;
+		if (obj == current_wand) continue;
+		setnotworn(obj);
 		freeinv(obj);
 		subfrombill(obj, shkp);
 		(void) add_to_minv(shkp, obj);	/* may free obj */
@@ -3382,8 +3422,9 @@
 #endif	/* KOPS */
 
 void
-pay_for_damage(dmgstr)
+pay_for_damage(dmgstr, cant_mollify)
 const char *dmgstr;
+boolean cant_mollify;
 {
 	register struct monst *shkp = (struct monst *)0;
 	char shops_affected[5];
@@ -3493,11 +3534,11 @@
 	    (void) mnearto(shkp, x, y, TRUE);
 	}
 
-	if((um_dist(x, y, 1) && !uinshp) ||
+	if((um_dist(x, y, 1) && !uinshp) || cant_mollify ||
 #ifndef GOLDOBJ
-			(u.ugold + ESHK(shkp)->credit) < cost_of_damage
+	   (u.ugold + ESHK(shkp)->credit) < cost_of_damage
 #else
-			(money_cnt(invent) + ESHK(shkp)->credit) < cost_of_damage
+	   (money_cnt(invent) + ESHK(shkp)->credit) < cost_of_damage
 #endif
 				|| !rn2(50)) {
 		if(um_dist(x, y, 1) && !uinshp) {
@@ -3569,7 +3610,7 @@
 	return(struct obj *)0;
 
     for (otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere)
-	if (otmp->oclass != GOLD_CLASS)
+	if (otmp->oclass != COIN_CLASS)
 	    break;
     /* note: otmp might have ->no_charge set, but that's ok */
     return (otmp && costly_spot(x, y) && NOTANGRY(shkp)
@@ -3593,7 +3634,7 @@
     putstr(tmpwin, 0, "Fine goods for sale:");
     putstr(tmpwin, 0, "");
     for (otmp = first_obj; otmp; otmp = otmp->nexthere) {
-	if (otmp->oclass == GOLD_CLASS) continue;
+	if (otmp->oclass == COIN_CLASS) continue;
 	cost = (otmp->no_charge || otmp == uball || otmp == uchain) ? 0L :
 		get_cost(otmp, (struct monst *)0);
 	if (Has_contents(otmp))
diff -Naurd ../nethack-3.4.0/src/shknam.c ./src/shknam.c
--- ../nethack-3.4.0/src/shknam.c Wed Mar 20 23:43:17 2002
+++ ./src/shknam.c Mon Feb 24 15:25:05 2003
@@ -13,10 +13,10 @@
 #else
 
 STATIC_DCL void FDECL(mkshobj_at, (const struct shclass *,int,int));
-STATIC_DCL void FDECL(nameshk, (struct monst *,const char **));
+STATIC_DCL void FDECL(nameshk, (struct monst *,const char * const *));
 STATIC_DCL int  FDECL(shkinit, (const struct shclass *,struct mkroom *));
 
-static const char *shkliquors[] = {
+static const char * const shkliquors[] = {
     /* Ukraine */
     "Njezjin", "Tsjernigof", "Gomel", "Ossipewsk", "Gorlowka",
     /* N. Russia */
@@ -31,7 +31,7 @@
     0
 };
 
-static const char *shkbooks[] = {
+static const char * const shkbooks[] = {
     /* Eire */
     "Skibbereen", "Kanturk", "Rath Luirc", "Ennistymon", "Lahinch",
     "Kinnegad", "Lugnaquillia", "Enniscorthy", "Gweebarra",
@@ -42,7 +42,7 @@
     0
 };
 
-static const char *shkarmors[] = {
+static const char * const shkarmors[] = {
     /* Turquie */
     "Demirci", "Kalecik", "Boyabai", "Yildizeli", "Gaziantep",
     "Siirt", "Akhalataki", "Tirebolu", "Aksaray", "Ermenak",
@@ -53,11 +53,11 @@
     0
 };
 
-static const char *shkwands[] = {
+static const char * const shkwands[] = {
     /* Wales */
     "Yr Wyddgrug", "Trallwng", "Mallwyd", "Pontarfynach",
     "Rhaeader", "Llandrindod", "Llanfair-ym-muallt",
-    "Y-Fenni", "Measteg", "Rhydaman", "Beddgelert",
+    "Y-Fenni", "Maesteg", "Rhydaman", "Beddgelert",
     "Curig", "Llanrwst", "Llanerchymedd", "Caergybi",
     /* Scotland */
     "Nairn", "Turriff", "Inverurie", "Braemar", "Lochnagar",
@@ -67,7 +67,7 @@
     0
 };
 
-static const char *shkrings[] = {
+static const char * const shkrings[] = {
     /* Hollandse familienamen */
     "Feyfer", "Flugi", "Gheel", "Havic", "Haynin", "Hoboken",
     "Imbyze", "Juyn", "Kinsky", "Massis", "Matray", "Moy",
@@ -80,7 +80,7 @@
     0
 };
 
-static const char *shkfoods[] = {
+static const char * const shkfoods[] = {
     /* Indonesia */
     "Djasinga", "Tjibarusa", "Tjiwidej", "Pengalengan",
     "Bandjar", "Parbalingga", "Bojolali", "Sarangan",
@@ -92,7 +92,7 @@
     0
 };
 
-static const char *shkweapons[] = {
+static const char * const shkweapons[] = {
     /* Perigord */
     "Voulgezac", "Rouffiac", "Lerignac", "Touverac", "Guizengeard",
     "Melac", "Neuvicq", "Vanzac", "Picq", "Urignac", "Corignac",
@@ -103,7 +103,7 @@
     0
 };
 
-static const char *shktools[] = {
+static const char * const shktools[] = {
     /* Spmi */
     "Ymla", "Eed-morra", "Cubask", "Nieb", "Bnowr Falr", "Telloc Cyaj",
     "Sperc", "Noskcirdneh", "Yawolloh", "Hyeghu", "Niskal", "Trahnil",
@@ -134,7 +134,7 @@
     0
 };
 
-static const char *shklight[] = {
+static const char * const shklight[] = {
     /* Romania */
     "Zarnesti", "Slanic", "Nehoiasu", "Ludus", "Sighisoara", "Nisipitu",
     "Razboieni", "Bicaz", "Dorohoi", "Vaslui", "Fetesti", "Tirgu Neamt",
@@ -146,7 +146,7 @@
     0
 };
 
-static const char *shkgeneral[] = {
+static const char * const shkgeneral[] = {
     /* Suriname */
     "Hebiwerie", "Possogroenoe", "Asidonhopo", "Manlobbi",
     "Adjama", "Pakka Pakka", "Kabalebo", "Wonotobo",
@@ -271,7 +271,7 @@
 STATIC_OVL void
 nameshk(shk, nlp)
 struct monst *shk;
-const char *nlp[];
+const char * const *nlp;
 {
 	int i, trycnt, names_avail;
 	const char *shname = 0;
diff -Naurd ../nethack-3.4.0/src/sit.c ./src/sit.c
--- ../nethack-3.4.0/src/sit.c Wed Mar 20 23:43:17 2002
+++ ./src/sit.c Mon Feb 24 15:25:05 2003
@@ -17,10 +17,11 @@
 		flags.botl = 1;
 	}
 #else
-        struct obj *otmp;
+        struct obj *otmp, *nobj;
 	int lost_money = 0;
-	for (otmp = invent; otmp; otmp = otmp->nobj) {
-		if (otmp->oclass == GOLD_CLASS) {
+	for (otmp = invent; otmp; otmp = nobj) {
+		nobj = otmp->nobj;
+		if (otmp->oclass == COIN_CLASS) {
 			lost_money = 1;
 			delobj(otmp);
 		}
@@ -37,7 +38,7 @@
 int
 dosit()
 {
-	static const char *sit_message = "sit on the %s.";
+	static const char sit_message[] = "sit on the %s.";
 	register struct trap *trap;
 	register int typ = levl[u.ux][u.uy].typ;
 
@@ -270,8 +271,8 @@
 
 	    if (!rn2(3) && IS_THRONE(levl[u.ux][u.uy].typ)) {
 		/* may have teleported */
-		pline_The("throne vanishes in a puff of logic.");
 		levl[u.ux][u.uy].typ = ROOM;
+		pline_The("throne vanishes in a puff of logic.");
 		newsym(u.ux,u.uy);
 	    }
 
@@ -312,7 +313,7 @@
 	int	nobj = 0;
 	int	cnt, onum;
 	struct	obj	*otmp;
-	static const char *mal_aura = "feel a malignant aura surround %s.";
+	static const char mal_aura[] = "feel a malignant aura surround %s.";
 
 	if (uwep && (uwep->oartifact == ART_MAGICBANE) && rn2(20)) {
 	    You(mal_aura, "the magic-absorbing blade");
@@ -324,14 +325,27 @@
 	    You(mal_aura, "you");
 	}
 
-	for (otmp = invent; otmp; otmp = otmp->nobj)  nobj++;
-
+	for (otmp = invent; otmp; otmp = otmp->nobj) {
+#ifdef GOLDOBJ
+	    /* gold isn't subject to being cursed or blessed */
+	    if (otmp->oclass == COIN_CLASS) continue;
+#endif
+	    nobj++;
+	}
 	if (nobj) {
 	    for (cnt = rnd(6/((!!Antimagic) + (!!Half_spell_damage) + 1));
 		 cnt > 0; cnt--)  {
-		onum = rn2(nobj);
-		for(otmp = invent; onum != 0; onum--)
-		    otmp = otmp->nobj;
+		onum = rnd(nobj);
+		for (otmp = invent; otmp; otmp = otmp->nobj) {
+#ifdef GOLDOBJ
+		    /* as above */
+		    if (otmp->oclass == COIN_CLASS) continue;
+#endif
+		    if (--onum == 0) break;	/* found the target */
+		}
+		/* the !otmp case should never happen; picking an already
+		   cursed item happens--avoid "resists" message in that case */
+		if (!otmp || otmp->cursed) continue;	/* next target */
 
 		if(otmp->oartifact && spec_ability(otmp, SPFX_INTEL) &&
 		   rn2(10) < 8) {
@@ -346,6 +360,25 @@
 	    }
 	    update_inventory();
 	}
+
+#ifdef STEED
+	/* treat steed's saddle as extended part of hero's inventory */
+	if (u.usteed && !rn2(4) &&
+		(otmp = which_armor(u.usteed, W_SADDLE)) != 0 &&
+		!otmp->cursed) {	/* skip if already cursed */
+	    if (otmp->blessed)
+		unbless(otmp);
+	    else
+		curse(otmp);
+	    if (!Blind) {
+		pline("%s %s %s.",
+		      s_suffix(upstart(y_monnam(u.usteed))),
+		      aobjnam(otmp, "glow"),
+		      hcolor(otmp->cursed ? NH_BLACK : (const char *)"brown"));
+		otmp->bknown = TRUE;
+	    }
+	}
+#endif	/*STEED*/
 }
 
 void
diff -Naurd ../nethack-3.4.0/src/sounds.c ./src/sounds.c
--- ../nethack-3.4.0/src/sounds.c Wed Mar 20 23:43:17 2002
+++ ./src/sounds.c Mon Feb 24 15:25:05 2003
@@ -1,11 +1,13 @@
-/*	SCCS Id: @(#)sounds.c	3.4	2001/02/14	*/
+/*	SCCS Id: @(#)sounds.c	3.4	2002/05/06	*/
 /*	Copyright (c) 1989 Janet Walz, Mike Threepoint */
 /* NetHack may be freely redistributed.  See license for details. */
 
 #include "hack.h"
 #include "edog.h"
 #ifdef USER_SOUNDS
+# ifdef USER_SOUNDS_REGEX
 #include <regex.h>
+# endif
 #endif
 
 #ifdef OVLB
@@ -45,7 +47,7 @@
     hallu = Hallucination ? 1 : 0;
 
     if (level.flags.nfountains && !rn2(400)) {
-	static const char *fountain_msg[4] = {
+	static const char * const fountain_msg[4] = {
 		"bubbling water.",
 		"water falling on coins.",
 		"the splashing of a naiad.",
@@ -55,7 +57,7 @@
     }
 #ifdef SINK
     if (level.flags.nsinks && !rn2(300)) {
-	static const char *sink_msg[3] = {
+	static const char * const sink_msg[3] = {
 		"a slow drip.",
 		"a gurgling noise.",
 		"dishes being washed!",
@@ -64,7 +66,7 @@
     }
 #endif
     if (level.flags.has_court && !rn2(200)) {
-	static const char *throne_msg[4] = {
+	static const char * const throne_msg[4] = {
 		"the tones of courtly conversation.",
 		"a sceptre pounded in judgment.",
 		"Someone shouts \"Off with %s head!\"",
@@ -86,7 +88,7 @@
 	}
     }
     if (level.flags.has_swamp && !rn2(200)) {
-	static const char *swamp_msg[3] = {
+	static const char * const swamp_msg[3] = {
 		"hear mosquitoes!",
 		"smell marsh gas!",	/* so it's a smell...*/
 		"hear Donald Duck!",
@@ -181,7 +183,7 @@
 	}
     }
     if (level.flags.has_barracks && !rn2(200)) {
-	static const char *barracks_msg[4] = {
+	static const char * const barracks_msg[4] = {
 		"blades being honed.",
 		"loud snoring.",
 		"dice being thrown.",
@@ -205,7 +207,7 @@
 	}
     }
     if (level.flags.has_zoo && !rn2(200)) {
-	static const char *zoo_msg[3] = {
+	static const char * const zoo_msg[3] = {
 		"a sound reminiscent of an elephant stepping on a peanut.",
 		"a sound reminiscent of a seal barking.",
 		"Doctor Doolittle!",
@@ -227,7 +229,7 @@
 	}
 	if (tended_shop(sroom) &&
 		!index(u.ushops, ROOM_INDEX(sroom) + ROOMOFFSET)) {
-	    static const char *shop_msg[3] = {
+	    static const char * const shop_msg[3] = {
 		    "someone cursing shoplifters.",
 		    "the chime of a cash register.",
 		    "Neiman and Marcus arguing!",
@@ -243,7 +245,7 @@
 		break;
 	/* and don't produce silly effects when she's clearly visible */
 	if (mtmp && (hallu || !canseemon(mtmp))) {
-	    static const char *ora_msg[5] = {
+	    static const char * const ora_msg[5] = {
 		    "a strange wind.",		/* Jupiter at Dodona */
 		    "convulsive ravings.",	/* Apollo at Delphi */
 		    "snoring snakes.",		/* AEsculapius at Epidaurus */
@@ -259,7 +261,7 @@
 #endif /* OVL0 */
 #ifdef OVLB
 
-static const char *h_sounds[] = {
+static const char * const h_sounds[] = {
     "beep", "boing", "sing", "belche", "creak", "cough", "rattle",
     "ululate", "pop", "jingle", "sniffle", "tinkle", "eep"
 };
@@ -495,7 +497,7 @@
 		    		verbl_msg = "I only drink... potions.";
     	        } else {
 			int vampindex;
-	    		static const char *vampmsg[] = {
+	    		static const char * const vampmsg[] = {
 			       /* These first two (0 and 1) are specially handled below */
 	    			"I vant to suck your %s!",
 	    			"I vill come after %s without regret!",
@@ -623,7 +625,7 @@
 	    break;
 	case MS_LAUGH:
 	    {
-		static const char *laugh_msg[4] = {
+		static const char * const laugh_msg[4] = {
 		    "giggles.", "chuckles.", "snickers.", "laughs.",
 		};
 		pline_msg = laugh_msg[rn2(4)];
@@ -739,7 +741,7 @@
 		verbalize("Just the facts, %s.",
 		      flags.female ? "Ma'am" : "Sir");
 	    else {
-		static const char *arrest_msg[3] = {
+		static const char * const arrest_msg[3] = {
 		    "Anything you say can be used against you.",
 		    "You're under arrest!",
 		    "Stop in the name of the Law!",
@@ -787,11 +789,11 @@
 	    break;
 	case MS_SOLDIER:
 	    {
-		static const char *soldier_foe_msg[3] = {
+		static const char * const soldier_foe_msg[3] = {
 		    "Resistance is useless!",
 		    "You're dog meat!",
 		    "Surrender!",
-		},		  *soldier_pax_msg[3] = {
+		},		  * const soldier_pax_msg[3] = {
 		    "What lousy pay we're getting here!",
 		    "The food's not fit for Orcs!",
 		    "My feet hurt, I've been on them all day!",
@@ -860,7 +862,10 @@
 	return(1);
     }
 
-    (void) getdir("Talk to whom? (in what direction)");
+    if (!getdir("Talk to whom? (in what direction)")) {
+	/* decided not to chat */
+	return(0);
+    }
 
 #ifdef STEED
     if (u.usteed && u.dz > 0)
@@ -902,6 +907,9 @@
 	return(0);
     }
 
+    /* if this monster is waiting for something, prod it into action */
+    mtmp->mstrategy &= ~STRAT_WAITMASK;
+
     if (mtmp->mtame && mtmp->meating) {
 	if (!canspotmon(mtmp))
 	    map_invisible(mtmp->mx, mtmp->my);
@@ -917,7 +925,11 @@
 extern void FDECL(play_usersound, (const char*, int));
 
 typedef struct audio_mapping_rec {
+#ifdef USER_SOUNDS_REGEX
 	struct re_pattern_buffer regex;
+#else
+	char *pattern;
+#endif
 	char *filename;
 	int volume;
 	struct audio_mapping_rec *next;
@@ -950,17 +962,25 @@
 
 	    if (can_read_file(filespec)) {
 		new_map = (audio_mapping *)alloc(sizeof(audio_mapping));
+#ifdef USER_SOUNDS_REGEX
 		new_map->regex.translate = 0;
 		new_map->regex.fastmap = 0;
 		new_map->regex.buffer = 0;
 		new_map->regex.allocated = 0;
 		new_map->regex.regs_allocated = REGS_FIXED;
+#else
+		new_map->pattern = (char *)alloc(strlen(text) + 1);
+		Strcpy(new_map->pattern, text);
+#endif
 		new_map->filename = strdup(filespec);
 		new_map->volume = volume;
 		new_map->next = soundmap;
 
+#ifdef USER_SOUNDS_REGEX
 		err = re_compile_pattern(text, strlen(text), &new_map->regex);
-
+#else
+		err = 0;
+#endif
 		if (err) {
 		    raw_print(err);
 		    free(new_map->filename);
@@ -989,7 +1009,11 @@
 	audio_mapping* cursor = soundmap;
 
 	while (cursor) {
+#ifdef USER_SOUNDS_REGEX
 	    if (re_search(&cursor->regex, msg, strlen(msg), 0, 9999, 0) >= 0) {
+#else
+	    if (pmatch(cursor->pattern, msg)) {
+#endif
 		play_usersound(cursor->filename, cursor->volume);
 	    }
 	    cursor = cursor->next;
diff -Naurd ../nethack-3.4.0/src/sp_lev.c ./src/sp_lev.c
--- ../nethack-3.4.0/src/sp_lev.c Wed Mar 20 23:43:18 2002
+++ ./src/sp_lev.c Mon Feb 24 15:25:05 2003
@@ -945,7 +945,7 @@
 		panic("create_object:  unexpected object class '%c'",c);
 
 	    /* KMH -- Create piles of gold properly */
-	    if (oclass == GOLD_CLASS)
+	    if (oclass == COIN_CLASS)
 		otmp = mkgold(0L, x, y);
 	    else
 		otmp = mkobj_at(oclass, x, y, !named);
@@ -1953,13 +1953,13 @@
 		} else
 		    r->monsters = 0;
 
-		/* read the objects */
+		/* read the objects, in same order as mazes */
 		Fread((genericptr_t) &r->nobject, 1, sizeof(r->nobject), fd);
 		if ((n = r->nobject) != 0) {
 		    r->objects = NewTab(object, n);
-		    while (n--) {
-			r->objects[(int)n] = New(object);
-			load_one_object(fd, r->objects[(int)n]);
+		    for (j = 0; j < n; ++j) {
+			r->objects[j] = New(object);
+			load_one_object(fd, r->objects[j]);
 		    }
 		} else
 		    r->objects = 0;
diff -Naurd ../nethack-3.4.0/src/spell.c ./src/spell.c
--- ../nethack-3.4.0/src/spell.c Wed Mar 20 23:43:18 2002
+++ ./src/spell.c Mon Feb 24 15:25:05 2003
@@ -21,7 +21,8 @@
 	((char)((spell < 26) ? ('a' + spell) : ('A' + spell - 26)))
 
 STATIC_DCL int FDECL(spell_let_to_idx, (CHAR_P));
-STATIC_DCL void FDECL(cursed_book, (int));
+STATIC_DCL boolean FDECL(cursed_book, (struct obj *bp));
+STATIC_DCL boolean FDECL(confused_book, (struct obj *));
 STATIC_DCL void FDECL(deadbook, (struct obj *));
 STATIC_PTR int NDECL(learn);
 STATIC_DCL boolean FDECL(getspell, (int *));
@@ -29,6 +30,7 @@
 STATIC_DCL int FDECL(percent_success, (int));
 STATIC_DCL int NDECL(throwspell);
 STATIC_DCL void NDECL(cast_protection);
+STATIC_DCL void FDECL(spell_backfire, (int));
 STATIC_DCL const char *FDECL(spelltypemnemonic, (int));
 STATIC_DCL int FDECL(isqrt, (int));
 
@@ -102,10 +104,13 @@
     return -1;
 }
 
-STATIC_OVL void
-cursed_book(lev)
-	register int	lev;
+/* TRUE: book should be destroyed by caller */
+STATIC_OVL boolean
+cursed_book(bp)
+	struct obj *bp;
 {
+	int lev = objects[bp->otyp].oc_level;
+
 	switch(rn2(lev)) {
 	case 0:
 		You_feel("a wrenching sensation.");
@@ -145,9 +150,12 @@
 			     Blind ? "feel" : "look");
 		    break;
 		}
+		/* temp disable in_use; death should not destroy the book */
+		bp->in_use = FALSE;
 		losestr(Poison_resistance ? rn1(2,1) : rn1(4,3));
 		losehp(rnd(Poison_resistance ? 6 : 10),
 		       "contact-poisoned spellbook", KILLED_BY_AN);
+		bp->in_use = TRUE;
 		break;
 	case 6:
 		if(Antimagic) {
@@ -156,14 +164,39 @@
 		} else {
 		    pline("As you read the book, it %s in your %s!",
 			  explodes, body_part(FACE));
-		    losehp (2*rnd(10)+5, "exploding rune", KILLED_BY_AN);
+		    losehp(2*rnd(10)+5, "exploding rune", KILLED_BY_AN);
 		}
-		break;
+		return TRUE;
 	default:
 		rndcurse();
 		break;
 	}
-	return;
+	return FALSE;
+}
+
+/* study while confused: returns TRUE if the book is destroyed */
+STATIC_OVL boolean
+confused_book(spellbook)
+struct obj *spellbook;
+{
+	boolean gone = FALSE;
+
+	if (!rn2(3) && spellbook->otyp != SPE_BOOK_OF_THE_DEAD) {
+	    spellbook->in_use = TRUE;	/* in case called from learn */
+	    pline(
+	"Being confused you have difficulties in controlling your actions.");
+	    display_nhwindow(WIN_MESSAGE, FALSE);
+	    You("accidentally tear the spellbook to pieces.");
+	    if (!objects[spellbook->otyp].oc_name_known &&
+		!objects[spellbook->otyp].oc_uname)
+		docall(spellbook);
+	    useup(spellbook);
+	    gone = TRUE;
+	} else {
+	    You("find yourself reading the %s line over and over again.",
+		spellbook == book ? "next" : "first");
+	}
+	return gone;
 }
 
 /* special effects for The Book of the Dead */
@@ -212,8 +245,15 @@
 	    pline_The("invocation fails!");
 	    pline("At least one of your artifacts is cursed...");
 	} else if(arti1_primed && arti2_primed) {
+	    unsigned soon = (unsigned) d(2,6);	/* time til next intervene() */
+
+	    /* successful invocation */
 	    mkinvokearea();
 	    u.uevent.invoked = 1;
+	    /* in case you haven't killed the Wizard yet, behave as if
+	       you just did */
+	    u.uevent.udemigod = 1;	/* wizdead() */
+	    if (!u.udg_cnt || u.udg_cnt > soon) u.udg_cnt = soon;
 	} else {	/* at least one artifact not prepared properly */
 	    You("have a feeling that %s is amiss...", something);
 	    goto raise_dead;
@@ -282,9 +322,16 @@
 
 	/* JDS: lenses give 50% faster reading; 33% smaller read time */
 	if (delay && ublindf && ublindf->otyp == LENSES && rn2(2)) delay++;
+	if (Confusion) {		/* became confused while learning */
+	    (void) confused_book(book);
+	    book = 0;			/* no longer studying */
+	    nomul(delay);		/* remaining delay is uninterrupted */
+	    delay = 0;
+	    return(0);
+	}
 	if (delay) {	/* not if (delay++), so at end delay == 0 */
-		delay++;
-		return(1); /* still busy */
+	    delay++;
+	    return(1); /* still busy */
 	}
 	exercise(A_WIS, TRUE);		/* you're studying. */
 	booktype = book->otyp;
@@ -328,7 +375,11 @@
 	if (i == MAXSPELL) impossible("Too many spells memorized!");
 
 	if (book->cursed) {	/* maybe a demon cursed it */
-		cursed_book(objects[booktype].oc_level);
+	    if (cursed_book(book)) {
+		useup(book);
+		book = 0;
+		return 0;
+	    }
 	}
 	if (costly) check_unpaid(book);
 	book = 0;
@@ -343,7 +394,7 @@
 	register boolean confused = (Confusion != 0);
 	boolean too_hard = FALSE;
 
-	if (delay && spellbook == book &&
+	if (delay && !confused && spellbook == book &&
 		    /* handle the sequence: start reading, get interrupted,
 		       have book become erased somehow, resume reading it */
 		    booktype != SPE_BLANK_PAPER) {
@@ -391,7 +442,8 @@
 			    - 2*objects[booktype].oc_level
 			    + ((ublindf && ublindf->otyp == LENSES) ? 2 : 0);
 			/* only wizards know if a spell is too difficult */
-			if (Role_if(PM_WIZARD) && read_ability < 20) {
+			if (Role_if(PM_WIZARD) && read_ability < 20 &&
+			    !confused) {
 			    char qbuf[QBUFSZ];
 			    Sprintf(qbuf,
 		      "This spellbook is %sdifficult to comprehend. Continue?",
@@ -409,11 +461,12 @@
 		}
 
 		if (too_hard) {
-		    cursed_book(objects[booktype].oc_level);
+		    boolean gone = cursed_book(spellbook);
+
 		    nomul(delay);			/* study time */
 		    delay = 0;
-		    if(!rn2(3)) {
-			pline_The("spellbook crumbles to dust!");
+		    if(gone || !rn2(3)) {
+			if (!gone) pline_The("spellbook crumbles to dust!");
 			if (!objects[spellbook->otyp].oc_name_known &&
 				!objects[spellbook->otyp].oc_uname)
 			    docall(spellbook);
@@ -422,24 +475,12 @@
 			spellbook->in_use = FALSE;
 		    return(1);
 		} else if (confused) {
-			if (!rn2(3) &&
-				spellbook->otyp != SPE_BOOK_OF_THE_DEAD) {
-			    pline(
-	  "Being confused you have difficulties in controlling your actions.");
-			    display_nhwindow(WIN_MESSAGE, FALSE);
-			    You("accidentally tear the spellbook to pieces.");
-			    if (!objects[spellbook->otyp].oc_name_known &&
-				   !objects[spellbook->otyp].oc_uname)
-				docall(spellbook);
-			    useup(spellbook);
-			} else {
-			    You(
-		  "find yourself reading the first line over and over again.");
-			    spellbook->in_use = FALSE;
-			}
-			nomul(delay);
-			delay = 0;
-			return(1);
+		    if (!confused_book(spellbook)) {
+			spellbook->in_use = FALSE;
+		    }
+		    nomul(delay);
+		    delay = 0;
+		    return(1);
 		}
 		spellbook->in_use = FALSE;
 
@@ -617,7 +658,7 @@
 
 	if (gain > 0) {
 	    if (!Blind) {
-		const char *hgolden = hcolor(golden);
+		const char *hgolden = hcolor(NH_GOLDEN);
 
 		if (u.uspellprot)
 		    pline_The("%s haze around you becomes more dense.",
@@ -639,6 +680,35 @@
 	}
 }
 
+/* attempting to cast a forgotten spell will cause disorientation */
+STATIC_OVL void
+spell_backfire(spell)
+int spell;
+{
+    long duration = (long)((spellev(spell) + 1) * 3);	 /* 6..24 */
+
+    /* prior to 3.4.1, the only effect was confusion; it still predominates */
+    switch (rn2(10)) {
+    case 0:
+    case 1:
+    case 2:
+    case 3: make_confused(duration, FALSE);			/* 40% */
+	    break;
+    case 4:
+    case 5:
+    case 6: make_confused(2L * duration / 3L, FALSE);		/* 30% */
+	    make_stunned(duration / 3L, FALSE);
+	    break;
+    case 7:
+    case 8: make_stunned(2L * duration / 3L, FALSE);		/* 20% */
+	    make_confused(duration / 3L, FALSE);
+	    break;
+    case 9: make_stunned(duration, FALSE);			/* 10% */
+	    break;
+    }
+    return;
+}
+
 int
 spelleffects(spell, atme)
 int spell;
@@ -657,7 +727,7 @@
 	if (spellknow(spell) <= 0) {
 	    Your("knowledge of this spell is twisted.");
 	    pline("It invokes nightmarish images in your mind...");
-	    make_confused((long)spellev(spell) * 3, FALSE);
+	    spell_backfire(spell);
 	    return(0);
 	} else if (spellknow(spell) <= 100) {
 	    You("strain to recall the spell.");
@@ -807,7 +877,10 @@
 	case SPE_STONE_TO_FLESH:
 		if (!(objects[pseudo->otyp].oc_dir == NODIR)) {
 			if (atme) u.dx = u.dy = u.dz = 0;
-			else (void) getdir((char *)0);
+			else if (!getdir((char *)0)) {
+			    /* getdir cancelled, re-use previous direction */
+			    pline_The("magical energy is released!");
+			}
 			if(!u.dx && !u.dy && !u.dz) {
 			    if ((damage = zapyourself(pseudo, TRUE)) != 0) {
 				char buf[BUFSZ];
@@ -884,8 +957,7 @@
 	}
 
 	/* gain skill for successful cast */
-	if (role_skill != P_ISRESTRICTED && role_skill < P_EXPERT)
-	    use_skill(skill, spellev(spell));
+	use_skill(skill, spellev(spell));
 
 	obfree(pseudo, (struct obj *)0);	/* now, get rid of it */
 	return(1);
@@ -1001,7 +1073,7 @@
 		Sprintf(buf, "%-20s     Level  %-12s Fail", "    Name", "Category");
 	else
 		Sprintf(buf, "Name\tLevel\tCategory\tFail");
-	add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED);
+	add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_BOLD, buf, MENU_UNSELECTED);
 	for (i = 0; i < MAXSPELL && spellid(i) != NO_SPELL; i++) {
 		Sprintf(buf, iflags.menu_tab_sep ?
 			"%s\t%-d%s\t%s\t%-d%%" : "%-20s  %2d%s   %-12s %3d%%",
diff -Naurd ../nethack-3.4.0/src/steal.c ./src/steal.c
--- ../nethack-3.4.0/src/steal.c Wed Mar 20 23:43:18 2002
+++ ./src/steal.c Mon Feb 24 15:25:05 2003
@@ -51,6 +51,7 @@
 		    Monnam(mtmp), makeplural(body_part(FOOT)));
 	    if(!u.ugold || !rn2(5)) {
 		if (!tele_restrict(mtmp)) rloc(mtmp);
+		/* do not set mtmp->mavenge here; gold on the floor is fair game */
 		monflee(mtmp, 0, FALSE, FALSE);
 	    }
 	} else if(u.ugold) {
@@ -58,6 +59,7 @@
 	    Your("purse feels lighter.");
 	    mtmp->mgold += tmp;
 	if (!tele_restrict(mtmp)) rloc(mtmp);
+	    mtmp->mavenge = 1;
 	    monflee(mtmp, 0, FALSE, FALSE);
 	    flags.botl = 1;
 	}
@@ -157,6 +159,8 @@
 			freeinv(otmp);
 			pline("%s steals %s!", Monnam(mtmp), doname(otmp));
 			(void) mpickobj(mtmp,otmp);	/* may free otmp */
+			/* Implies seduction, "you gladly hand over ..."
+			   so we don't set mavenge bit here. */
 			monflee(mtmp, 0, FALSE, FALSE);
 			if (!tele_restrict(mtmp)) rloc(mtmp);
 		        break;
@@ -172,8 +176,9 @@
 /* An object you're wearing has been taken off by a monster (theft or
    seduction).  Also used if a worn item gets transformed (stone to flesh). */
 void
-remove_worn_item(obj)
+remove_worn_item(obj, unchain_ball)
 struct obj *obj;
+boolean unchain_ball;	/* whether to unpunish or just unwield */
 {
 	if (donning(obj))
 	    cancel_don();
@@ -198,19 +203,21 @@
 	    Ring_gone(obj);
 	} else if (obj->owornmask & W_TOOL) {
 	    Blindf_off(obj);
-	} else if (obj->owornmask & (W_BALL|W_CHAIN)) {
-	    unpunish();
 	} else if (obj->owornmask & (W_WEP|W_SWAPWEP|W_QUIVER)) {
 	    if (obj == uwep)
 		uwepgone();
-	    else if (obj == uswapwep)
+	    if (obj == uswapwep)
 		uswapwepgone();
-	    else if (obj == uquiver)
+	    if (obj == uquiver)
 		uqwepgone();
 	}
 
-	/* catchall */
-	if (obj->owornmask) setnotworn(obj);
+	if (obj->owornmask & (W_BALL|W_CHAIN)) {
+	    if (unchain_ball) unpunish();
+	} else if (obj->owornmask) {
+	    /* catchall */
+	    setnotworn(obj);
+	}
 }
 
 /* Returns 1 when something was stolen (or at least, when N should flee now)
@@ -306,7 +313,7 @@
 		ostuck = (otmp->cursed && otmp->owornmask);
 
 	    if (ostuck || !can_carry(mtmp, otmp)) {
-		static const char *how[] = { "steal","snatch","grab","take" };
+		static const char * const how[] = { "steal","snatch","grab","take" };
  cant_take:
 		pline("%s tries to %s your %s but gives up.",
 		      Monnam(mtmp), how[rn2(SIZE(how))],
@@ -333,23 +340,24 @@
 		case AMULET_CLASS:
 		case RING_CLASS:
 		case FOOD_CLASS: /* meat ring */
-		    remove_worn_item(otmp);
+		    remove_worn_item(otmp, TRUE);
 		    break;
 		case ARMOR_CLASS:
 		    armordelay = objects[otmp->otyp].oc_delay;
 		    /* Stop putting on armor which has been stolen. */
 		    if (donning(otmp)) {
-			remove_worn_item(otmp);
+			remove_worn_item(otmp, TRUE);
 			break;
 		    } else if (monkey_business) {
 			/* animals usually don't have enough patience
 			   to take off items which require extra time */
 			if (armordelay >= 1 && rn2(10)) goto cant_take;
-			remove_worn_item(otmp);
+			remove_worn_item(otmp, TRUE);
 			break;
 		    } else {
 			int curssv = otmp->cursed;
 			int slowly;
+			boolean seen = canspotmon(mtmp);
 
 			otmp->cursed = 0;
 			/* can't charm you without first waking you */
@@ -357,20 +365,20 @@
 			slowly = (armordelay >= 1 || multi < 0);
 			if(flags.female)
 			    pline("%s charms you.  You gladly %s your %s.",
-				  Blind ? "She" : Monnam(mtmp),
+				  !seen ? "She" : Monnam(mtmp),
 				  curssv ? "let her take" :
 				  slowly ? "start removing" : "hand over",
 				  equipname(otmp));
 			else
 			    pline("%s seduces you and %s off your %s.",
-				  Blind ? "It" : Adjmonnam(mtmp, "beautiful"),
+				  !seen ? "She" : Adjmonnam(mtmp, "beautiful"),
 				  curssv ? "helps you to take" :
 				  slowly ? "you start taking" : "you take",
 				  equipname(otmp));
 			named++;
 			/* the following is to set multi for later on */
 			nomul(-armordelay);
-			remove_worn_item(otmp);
+			remove_worn_item(otmp, TRUE);
 			otmp->cursed = curssv;
 			if(multi < 0){
 				/*
@@ -391,10 +399,14 @@
 		}
 	}
 	else if (otmp->owornmask)
-	    remove_worn_item(otmp);
+	    remove_worn_item(otmp, TRUE);
 
 	/* do this before removing it from inventory */
 	if (objnambuf) Strcpy(objnambuf, yname(otmp));
+	/* set mavenge bit so knights won't suffer an
+	 * alignment penalty during retaliation;
+	 */
+	mtmp->mavenge = 1;
 
 	freeinv(otmp);
 	pline("%s stole %s.", named ? "She" : Monnam(mtmp), doname(otmp));
@@ -420,7 +432,7 @@
     int freed_otmp;
 
 #ifndef GOLDOBJ
-    if (otmp->oclass == GOLD_CLASS) {
+    if (otmp->oclass == COIN_CLASS) {
 	mtmp->mgold += otmp->quan;
 	obfree(otmp, (struct obj *)0);
 	freed_otmp = 1;
@@ -487,7 +499,7 @@
 
     if (otmp) { /* we have something to snatch */
 	if (otmp->owornmask)
-	    remove_worn_item(otmp);
+	    remove_worn_item(otmp, TRUE);
 	freeinv(otmp);
 	/* mpickobj wont merge otmp because none of the above things
 	   to steal are mergable */
@@ -543,6 +555,11 @@
 			    costly_spot(mtmp->mx, mtmp->my))
 				otmp->no_charge = 1;
 #endif
+			if (otmp->owornmask)
+			    update_mon_intrinsics(mtmp, otmp, FALSE, TRUE);
+		     /* obj_no_longer_held(otmp); -- done by place_object */
+			if (otmp->owornmask & W_WEP)
+			    setmnotwielded(mtmp, otmp);
 			otmp->owornmask = 0L;
 		}
 		if (is_pet && cansee(omx, omy) && flags.verbose)
diff -Naurd ../nethack-3.4.0/src/steed.c ./src/steed.c
--- ../nethack-3.4.0/src/steed.c Wed Mar 20 23:43:18 2002
+++ ./src/steed.c Mon Feb 24 15:25:05 2003
@@ -14,6 +14,13 @@
 
 STATIC_DCL boolean FDECL(landing_spot, (coord *, int));
 
+/* caller has decided that hero can't reach something while mounted */
+void
+rider_cant_reach()
+{
+     You("aren't skilled enough to reach from %s.", y_monnam(u.usteed));
+}
+
 /*** Putting the saddle on ***/
 
 /* Can this monster wear a saddle? */
@@ -132,6 +139,7 @@
 	/* Make the attempt */
 	if (rn2(100) < chance) {
 	    You("put the saddle on %s.", mon_nam(mtmp));
+	    if (otmp->owornmask) remove_worn_item(otmp, FALSE);
 	    freeinv(otmp);
 	    /* mpickobj may free otmp it if merges, but we have already
 	       checked for a saddle above, so no merger should happen */
@@ -139,7 +147,7 @@
 	    mtmp->misc_worn_check |= W_SADDLE;
 	    otmp->owornmask = W_SADDLE;
 	    otmp->leashmon = mtmp->m_id;
-	    update_mon_intrinsics(mtmp, otmp, TRUE);
+	    update_mon_intrinsics(mtmp, otmp, TRUE, FALSE);
 	} else
 	    pline("%s resists!", Monnam(mtmp));
 	return 1;
@@ -188,11 +196,9 @@
 	char buf[BUFSZ];
 	struct permonst *ptr;
 
-
 	/* Sanity checks */
 	if (u.usteed) {
-	    if (!force)
-	    	You("are already riding %s.", mon_nam(u.usteed));
+	    You("are already riding %s.", mon_nam(u.usteed));
 	    return (FALSE);
 	}
 
@@ -220,11 +226,10 @@
 #endif
 	    return (FALSE);
 	}
-	
+
 	if (Upolyd && (!humanoid(youmonst.data) || verysmall(youmonst.data) ||
-			bigmonst(youmonst.data))) {
-	    if (!force)
-	    	You("won't fit on a saddle.");
+			bigmonst(youmonst.data) || slithy(youmonst.data))) {
+	    You("won't fit on a saddle.");
 	    return (FALSE);
 	}
 	if(!force && (near_capacity() > SLT_ENCUMBER)) {
@@ -233,22 +238,19 @@
 	}
 
 	/* Can the player reach and see the monster? */
-    if (u.uswallow || u.ustuck || u.utrap || Punished) {
-        if (!force) {
-		if (Punished)
-			You("are unable to swing your %s over.",
-				body_part(LEG)); 
-		else
-        		You("are stuck here for now.");
-	}
-        return (FALSE);
-    }
 	if (!mtmp || (!force && ((Blind && !Blind_telepat) ||
 		mtmp->mundetected ||
 		mtmp->m_ap_type == M_AP_FURNITURE ||
 		mtmp->m_ap_type == M_AP_OBJECT))) {
-	    if (!force)
-	    	pline("I see nobody there.");
+	    pline("I see nobody there.");
+	    return (FALSE);
+	}
+	if (u.uswallow || u.ustuck || u.utrap || Punished ||
+	    !test_move(u.ux, u.uy, mtmp->mx-u.ux, mtmp->my-u.uy, TEST_MOVE)) {
+	    if (Punished || !(u.uswallow || u.ustuck || u.utrap))
+		You("are unable to swing your %s over.", body_part(LEG)); 
+	    else
+		You("are stuck here for now.");
 	    return (FALSE);
 	}
 
@@ -263,14 +265,22 @@
 	    char kbuf[BUFSZ];
 
 	    You("touch %s.", mon_nam(mtmp));
- 	    Sprintf(kbuf, "attempting to ride %s", an(mtmp->data->mname));
+	    Sprintf(kbuf, "attempting to ride %s", an(mtmp->data->mname));
 	    instapetrify(kbuf);
 	}
 	if (!mtmp->mtame || mtmp->isminion) {
-	    if (!force)
-	    	pline("I think %s would mind.", mon_nam(mtmp));
+	    pline("I think %s would mind.", mon_nam(mtmp));
 	    return (FALSE);
 	}
+	if (mtmp->mtrapped) {
+	    struct trap *t = t_at(mtmp->mx, mtmp->my);
+
+	    You_cant("mount %s while %s's trapped in %s.",
+		     mon_nam(mtmp), mhe(mtmp),
+		     an(defsyms[trap_to_defsym(t->ttyp)].explanation));
+	    return (FALSE);
+	}
+
 	if (!force && !Role_if(PM_KNIGHT) && !(--mtmp->mtame)) {
 	    /* no longer tame */
 	    newsym(mtmp->mx, mtmp->my);
@@ -284,8 +294,7 @@
 	    return (FALSE);
 	}
 	if (!can_saddle(mtmp) || !can_ride(mtmp)) {
-	    if (!force)
-	    	You_cant("ride such a creature.");
+	    You_cant("ride such a creature.");
 	    return (0);
 	}
 
@@ -310,15 +319,11 @@
 	    }
 	    You("slip while trying to get on %s.", mon_nam(mtmp));
 
-	    /* Unfortunately we don't have a version of the monster-naming
-	     * function that works well with "a" and "the" but ignores
-	     * hallucination.  Fortunately, we know the monster must be saddled
-	     * at this point, and that it can't have type_is_pname(), so we
-	     * don't need to worry about the special cases such a function
-	     * would have to consider.
-	     */
-	    Sprintf(buf, "slipped while mounting a saddled %s",
-		    m_monnam(mtmp));
+	    Sprintf(buf, "slipped while mounting %s",
+		    /* "a saddled mumak" or "a saddled pony called Dobbin" */
+		    x_monnam(mtmp, ARTICLE_A, (char *)0,
+			SUPPRESS_IT|SUPPRESS_INVISIBLE|SUPPRESS_HALLUCINATION,
+			     TRUE));
 	    losehp(rn1(5,10), buf, NO_KILLER_PREFIX);
 	    return (FALSE);
 	}
@@ -330,9 +335,11 @@
 	    	pline("%s magically floats up!", Monnam(mtmp));
 	    You("mount %s.", mon_nam(mtmp));
 	}
+	/* setuwep handles polearms differently when you're mounted */
+	if (uwep && is_pole(uwep)) unweapon = FALSE;
 	u.usteed = mtmp;
 	remove_monster(mtmp->mx, mtmp->my);
-	teleds(mtmp->mx, mtmp->my);
+	teleds(mtmp->mx, mtmp->my, TRUE);
 	return (TRUE);
 }
 
@@ -486,7 +493,8 @@
 	    case DISMOUNT_BYCHOICE:
 	    default:
 		if (otmp && otmp->cursed) {
-		    You("can't.  The saddle seems to be cursed.");
+		    You("can't.  The saddle %s cursed.",
+			otmp->bknown ? "is" : "seems to be");
 		    otmp->bknown = TRUE;
 		    return;
 		}
@@ -568,7 +576,7 @@
 		     * teleds() clears u.utrap
 		     */
 		    in_steed_dismounting = TRUE;
-		    teleds(cc.x, cc.y);
+		    teleds(cc.x, cc.y, TRUE);
 		    in_steed_dismounting = FALSE;
 
 		    /* Put your steed in your trap */
@@ -588,14 +596,17 @@
 	}
 
 	/* Return the player to the floor */
-	in_steed_dismounting = TRUE;
-	(void) float_down(0L, W_SADDLE);
-	in_steed_dismounting = FALSE;
-	flags.botl = 1;
 	if (reason != DISMOUNT_ENGULFED) {
-		(void)encumber_msg();
-		vision_full_recalc = 1;
-	}
+	    in_steed_dismounting = TRUE;
+	    (void) float_down(0L, W_SADDLE);
+	    in_steed_dismounting = FALSE;
+	    flags.botl = 1;
+	    (void)encumber_msg();
+	    vision_full_recalc = 1;
+	} else
+	    flags.botl = 1;
+	/* polearms behave differently when not mounted */
+	if (uwep && is_pole(uwep)) unweapon = TRUE;
 	return;
 }
 
diff -Naurd ../nethack-3.4.0/src/teleport.c ./src/teleport.c
--- ../nethack-3.4.0/src/teleport.c Wed Mar 20 23:43:18 2002
+++ ./src/teleport.c Mon Feb 24 15:25:05 2003
@@ -18,11 +18,13 @@
  * call it to generate new monster positions with fake monster structures.
  */
 boolean
-goodpos(x, y, mtmp)
+goodpos(x, y, mtmp, gpflags)
 int x,y;
 struct monst *mtmp;
+unsigned gpflags;
 {
 	struct permonst *mdat = NULL;
+	boolean ignorewater = ((gpflags & MM_IGNOREWATER) != 0);
 
 	if (!isok(x, y)) return FALSE;
 
@@ -42,17 +44,27 @@
 	if (mtmp) {
 	    struct monst *mtmp2 = m_at(x,y);
 
-	    if (mtmp2 && mtmp2 != mtmp)
+	    /* Be careful with long worms.  A monster may be placed back in
+	     * its own location.  Normally, if m_at() returns the same monster
+	     * that we're trying to place, the monster is being placed in its
+	     * own location.  However, that is not correct for worm segments,
+	     * because all the segments of the worm return the same m_at().
+	     * Actually we overdo the check a little bit--a worm can't be placed
+	     * in its own location, period.  If we just checked for mtmp->mx
+	     * != x || mtmp->my != y, we'd miss the case where we're called
+	     * to place the worm segment and the worm's head is at x,y.
+	     */
+	    if (mtmp2 && (mtmp2 != mtmp || mtmp->wormno))
 		return FALSE;
 
 	    mdat = mtmp->data;
-	    if (is_pool(x,y)) {
+	    if (is_pool(x,y) && !ignorewater) {
 		if (mtmp == &youmonst)
 			return !!(HLevitation || Flying || Wwalking ||
 					Swimming || Amphibious);
 		else	return (is_flyer(mdat) || is_swimmer(mdat) ||
 							is_clinger(mdat));
-	    } else if (mdat->mlet == S_EEL && rn2(13)) {
+	    } else if (mdat->mlet == S_EEL && rn2(13) && !ignorewater) {
 		return FALSE;
 	    } else if (is_lava(x,y)) {
 		if (mtmp == &youmonst)
@@ -62,7 +74,10 @@
 	    }
 	    if (passes_walls(mdat) && may_passwall(x,y)) return TRUE;
 	}
-	if (!ACCESSIBLE(levl[x][y].typ)) return FALSE;
+	if (!ACCESSIBLE(levl[x][y].typ)) {
+		if (!(is_pool(x,y) && ignorewater)) return FALSE;
+	}
+
 	if (closed_door(x, y) && (!mdat || !amorphous(mdat)))
 		return FALSE;
 	if (sobj_at(BOULDER, x, y) && (!mdat || !throws_rocks(mdat)))
@@ -84,6 +99,16 @@
 register xchar xx, yy;
 struct permonst *mdat;
 {
+	return enexto_core(cc, xx, yy, mdat, 0);
+}
+
+boolean
+enexto_core(cc, xx, yy, mdat, entflags)
+coord *cc;
+register xchar xx, yy;
+struct permonst *mdat;
+unsigned entflags;
+{
 #define MAX_GOOD 15
     coord good[MAX_GOOD], *good_ptr;
     int x, y, range, i;
@@ -111,28 +136,28 @@
 	ymax = min(ROWNO-1, yy+range);
 
 	for (x = xmin; x <= xmax; x++)
-	    if (goodpos(x, ymin, &fakemon)) {
+	    if (goodpos(x, ymin, &fakemon, entflags)) {
 		good_ptr->x = x;
 		good_ptr->y = ymin ;
 		/* beware of accessing beyond segment boundaries.. */
 		if (good_ptr++ == &good[MAX_GOOD-1]) goto full;
 	    }
 	for (x = xmin; x <= xmax; x++)
-	    if (goodpos(x, ymax, &fakemon)) {
+	    if (goodpos(x, ymax, &fakemon, entflags)) {
 		good_ptr->x = x;
 		good_ptr->y = ymax ;
 		/* beware of accessing beyond segment boundaries.. */
 		if (good_ptr++ == &good[MAX_GOOD-1]) goto full;
 	    }
 	for (y = ymin+1; y < ymax; y++)
-	    if (goodpos(xmin, y, &fakemon)) {
+	    if (goodpos(xmin, y, &fakemon, entflags)) {
 		good_ptr->x = xmin;
 		good_ptr-> y = y ;
 		/* beware of accessing beyond segment boundaries.. */
 		if (good_ptr++ == &good[MAX_GOOD-1]) goto full;
 	    }
 	for (y = ymin+1; y < ymax; y++)
-	    if (goodpos(xmax, y, &fakemon)) {
+	    if (goodpos(xmax, y, &fakemon, entflags)) {
 		good_ptr->x = xmax;
 		good_ptr->y = y ;
 		/* beware of accessing beyond segment boundaries.. */
@@ -195,40 +220,58 @@
 boolean trapok;
 {
 	if (!trapok && t_at(x, y)) return FALSE;
-	if (!goodpos(x, y, &youmonst)) return FALSE;
+	if (!goodpos(x, y, &youmonst, 0)) return FALSE;
 	if (!tele_jump_ok(u.ux, u.uy, x, y)) return FALSE;
+	if (!in_out_region(x, y)) return FALSE;
 	return TRUE;
 }
 
 void
-teleds(nux, nuy)
+teleds(nux, nuy, allow_drag)
 register int nux,nuy;
+boolean allow_drag;
 {
-	boolean dont_teleport_ball = FALSE;
+	boolean ball_active = (Punished && uball->where != OBJ_FREE),
+		ball_still_in_range = FALSE;
 
-	if (Punished) {
-	    /* If they're teleporting to a position where the ball doesn't need
-	     * to be moved, don't place the ball.  Especially useful when this
-	     * function is being called for crawling out of water instead of
-	     * real teleportation.
-	     */
+	/* If they have to move the ball, then drag if allow_drag is true;
+	 * otherwise they are teleporting, so unplacebc().  
+	 * If they don't have to move the ball, then always "drag" whether or
+	 * not allow_drag is true, because we are calling that function, not
+	 * to drag, but to move the chain.  *However* there are some dumb
+	 * special cases:
+	 *    0				 0
+	 *   _X  move east       ----->  X_
+	 *    @				  @
+	 * These are permissible if teleporting, but not if dragging.  As a
+	 * result, drag_ball() needs to know about allow_drag and might end
+	 * up dragging the ball anyway.  Also, drag_ball() might find that
+	 * dragging the ball is completely impossible (ball in range but there's
+	 * rock in the way), in which case it teleports the ball on its own.
+	 */
+	if (ball_active) {
 	    if (!carried(uball) && distmin(nux, nuy, uball->ox, uball->oy) <= 2)
-		dont_teleport_ball = TRUE;
-	    else
-		unplacebc();
+		ball_still_in_range = TRUE; /* don't have to move the ball */
+	    else {
+		/* have to move the ball */
+		if (!allow_drag || distmin(u.ux, u.uy, nux, nuy) > 1) {
+		    /* we should not have dist > 1 and allow_drag at the same
+		     * time, but just in case, we must then revert to teleport.
+		     */
+		    allow_drag = FALSE;
+		    unplacebc();
+		}
+	    }
 	}
 	u.utrap = 0;
 	u.ustuck = 0;
 	u.ux0 = u.ux;
 	u.uy0 = u.uy;
-	u.ux = nux;
-	u.uy = nuy;
-	fill_pit(u.ux0, u.uy0); /* do this now so that cansee() is correct */
 
 	if (hides_under(youmonst.data))
 		u.uundetected = OBJ_AT(nux, nuy);
 	else if (youmonst.data->mlet == S_EEL)
-		u.uundetected = is_pool(u.ux, u.uy);
+		u.uundetected = is_pool(nux, nuy);
 	else {
 		u.uundetected = 0;
 		/* mimics stop being unnoticed */
@@ -238,21 +281,32 @@
 
 	if (u.uswallow) {
 		u.uswldtim = u.uswallow = 0;
+		if (Punished && !ball_active) {
+		    /* ensure ball placement, like unstuck */
+		    ball_active = TRUE;
+		    allow_drag = FALSE;
+		}
 		docrt();
 	}
-	if (Punished) {
-	    if (dont_teleport_ball) {
+	if (ball_active) {
+	    if (ball_still_in_range || allow_drag) {
 		int bc_control;
 		xchar ballx, bally, chainx, chainy;
 		boolean cause_delay;
 
-		/* this should only drag the chain (and never give a near-
-		   capacity message) since we already checked ball distance */
-		(void) drag_ball(u.ux, u.uy, &bc_control, &ballx, &bally,
-					&chainx, &chainy, &cause_delay);
-		move_bc(0, bc_control, ballx, bally, chainx, chainy);
-	    } else
-		 placebc();
+		if (drag_ball(nux, nuy, &bc_control, &ballx, &bally,
+				    &chainx, &chainy, &cause_delay, allow_drag))
+		    move_bc(0, bc_control, ballx, bally, chainx, chainy);
+	    }
+	}
+	/* must set u.ux, u.uy after drag_ball(), which may need to know
+	   the old position if allow_drag is true... */
+	u.ux = nux;
+	u.uy = nuy;
+	fill_pit(u.ux0, u.uy0);
+	if (ball_active) {
+	    if (!ball_still_in_range && !allow_drag)
+		placebc();
 	}
 	initrack(); /* teleports mess up tracking monsters without this */
 	update_player_regions();
@@ -279,7 +333,8 @@
 }
 
 boolean
-safe_teleds()
+safe_teleds(allow_drag)
+boolean allow_drag;
 {
 	register int nux, nuy, tcnt = 0;
 
@@ -289,7 +344,7 @@
 	} while (!teleok(nux, nuy, (boolean)(tcnt > 200)) && ++tcnt <= 400);
 
 	if (tcnt <= 400) {
-		teleds(nux, nuy);
+		teleds(nux, nuy, allow_drag);
 		return TRUE;
 	} else
 		return FALSE;
@@ -302,7 +357,7 @@
 	coord c;
 
 	if (croom && somexy(croom, &c) && teleok(c.x,c.y,FALSE)) {
-		teleds(c.x,c.y);
+		teleds(c.x,c.y,FALSE);
 		return;
 	}
 	tele();
@@ -363,7 +418,7 @@
 	    You_feel("disoriented for a moment.");
 	    return;
 	}
-	if (Teleport_control
+	if ((Teleport_control && !Stunned)
 #ifdef WIZARD
 			    || wizard
 #endif
@@ -387,14 +442,14 @@
 		    /* possible extensions: introduce a small error if
 		       magic power is low; allow transfer to solid rock */
 		    if (teleok(cc.x, cc.y, FALSE)) {
-			teleds(cc.x, cc.y);
+			teleds(cc.x, cc.y, FALSE);
 			return;
 		    }
 		    pline("Sorry...");
 		}
 	}
 
-	(void) safe_teleds();
+	(void) safe_teleds(FALSE);
 }
 
 int
@@ -521,7 +576,7 @@
 	    You_feel("very disoriented for a moment.");
 	    return;
 	}
-	if (Teleport_control
+	if ((Teleport_control && !Stunned)
 #ifdef WIZARD
 	   || wizard
 #endif
@@ -533,10 +588,18 @@
 	    do {
 		if (++trycnt == 2) Strcat(qbuf, " [type a number]");
 		getlin(qbuf, buf);
-		if (!strcmp(buf,"\033"))	/* cancelled */
+		if (!strcmp(buf,"\033")) {	/* cancelled */
+		    if (Confusion && rnl(5)) {
+			pline("Oops...");
+			goto random_levtport;
+		    }
 		    return;
-		else if (!strcmp(buf,"*"))
+		} else if (!strcmp(buf,"*")) {
 		    goto random_levtport;
+		} else if (Confusion && rnl(5)) {
+		    pline("Oops...");
+		    goto random_levtport;
+		}
 		if ((newlev = lev_by_name(buf)) == 0) newlev = atoi(buf);
 	    } while (!newlev && !digit(buf[0]) &&
 		     (buf[0] != '-' || !digit(buf[1])) &&
@@ -605,6 +668,14 @@
 	killer = 0;		/* still alive, so far... */
 
 	if (newlev < 0) {
+		if (*u.ushops0) {
+		    /* take unpaid inventory items off of shop bills */
+		    in_mklev = TRUE;	/* suppress map update */
+		    u_left_shop(u.ushops0, TRUE);
+		    /* you're now effectively out of the shop */
+		    *u.ushops0 = *u.ushops = '\0';
+		    in_mklev = FALSE;
+		}
 		if (newlev <= -10) {
 			You("arrive in heaven.");
 			verbalize("Thou art early, but we'll admit thee.");
@@ -627,8 +698,8 @@
 		    pline("Unfortunately, you don't know how to fly.");
 		    You("plummet a few thousand feet to your death.");
 		    Sprintf(buf,
-				"teleported out of the dungeon and fell to %s death",
-				uhis());
+			  "teleported out of the dungeon and fell to %s death",
+			    uhis());
 		    killer = buf;
 		    killer_format = NO_KILLER_PREFIX;
 		}
@@ -770,7 +841,7 @@
 {
 	register int xx, yy;
 
-	if (!goodpos(x, y, mtmp)) return FALSE;
+	if (!goodpos(x, y, mtmp, 0)) return FALSE;
 	/*
 	 * Check for restricted areas present in some special levels.
 	 *
@@ -882,7 +953,7 @@
 	    /* if the wiz teleports away to heal, try the up staircase,
 	       to block the player's escaping before he's healed
 	       (deliberately use `goodpos' rather than `rloc_pos_ok' here) */
-	    if (goodpos(x, y, mtmp))
+	    if (goodpos(x, y, mtmp, 0))
 		goto found_xy;
 	}
 
@@ -891,14 +962,14 @@
 	    x = rn1(COLNO-3,2);
 	    y = rn2(ROWNO);
 	    if ((trycount < 500) ? rloc_pos_ok(x, y, mtmp)
-				 : goodpos(x, y, mtmp))
+				 : goodpos(x, y, mtmp, 0))
 		goto found_xy;
 	} while (++trycount < 1000);
 
 	/* last ditch attempt to find a good place */
 	for (x = 2; x < COLNO - 1; x++)
 	    for (y = 0; y < ROWNO; y++)
-		if (goodpos(x, y, mtmp))
+		if (goodpos(x, y, mtmp, 0))
 		    goto found_xy;
 
 	/* level either full of monsters or somehow faulty */
@@ -917,7 +988,7 @@
 	coord c;
 
 	if (croom && somexy(croom, &c) &&
-				goodpos(c.x, c.y, mtmp)) {
+				goodpos(c.x, c.y, mtmp, 0)) {
 		rloc_to(mtmp, c.x, c.y);
 		return;
 	}
@@ -1058,7 +1129,7 @@
 	    tx = rn1(COLNO-3,2);
 	    ty = rn2(ROWNO);
 	    if (!--try_limit) break;
-	} while (!goodpos(tx, ty, (struct monst *)0) ||
+	} while (!goodpos(tx, ty, (struct monst *)0, 0) ||
 		/* bug: this lacks provision for handling the Wizard's tower */
 		 (restricted_fall &&
 		  (!within_bounded_area(tx, ty, dndest.lx, dndest.ly,
diff -Naurd ../nethack-3.4.0/src/timeout.c ./src/timeout.c
--- ../nethack-3.4.0/src/timeout.c Wed Mar 20 23:43:19 2002
+++ ./src/timeout.c Mon Feb 24 15:25:05 2003
@@ -17,7 +17,7 @@
 #ifdef OVLB
 
 /* He is being petrified - dialogue by inmet!tower */
-static NEARDATA const char *stoned_texts[] = {
+static NEARDATA const char * const stoned_texts[] = {
 	"You are slowing down.",		/* 5 */
 	"Your limbs are stiffening.",		/* 4 */
 	"Your limbs have turned to stone.",	/* 3 */
@@ -40,8 +40,8 @@
 }
 
 /* He is getting sicker and sicker prior to vomiting */
-static NEARDATA const char *vomiting_texts[] = {
-	"are feeling mildly nauseous.",		/* 14 */
+static NEARDATA const char * const vomiting_texts[] = {
+	"are feeling mildly nauseated.",	/* 14 */
 	"feel slightly confused.",		/* 11 */
 	"can't seem to think straight.",	/* 8 */
 	"feel incredibly sick.",		/* 5 */
@@ -72,7 +72,7 @@
 	exercise(A_CON, FALSE);
 }
 
-static NEARDATA const char *choke_texts[] = {
+static NEARDATA const char * const choke_texts[] = {
 	"You find it hard to breathe.",
 	"You're gasping for air.",
 	"You can no longer breathe.",
@@ -80,7 +80,7 @@
 	"You suffocate."
 };
 
-static NEARDATA const char *choke_texts2[] = {
+static NEARDATA const char * const choke_texts2[] = {
 	"Your %s is becoming constricted.",
 	"Your blood is having trouble reaching your brain.",
 	"The pressure on your %s increases.",
@@ -100,7 +100,7 @@
 		const char *str = choke_texts[SIZE(choke_texts)-i];
 
 		if (index(str, '%'))
-		    pline(str, hcolor(blue));
+		    pline(str, hcolor(NH_BLUE));
 		else
 		    pline(str);
 	    }
@@ -108,7 +108,7 @@
 	exercise(A_STR, FALSE);
 }
 
-static NEARDATA const char *slime_texts[] = {
+static NEARDATA const char * const slime_texts[] = {
 	"You are turning a little %s.",           /* 5 */
 	"Your limbs are getting oozy.",              /* 4 */
 	"Your skin begins to peel away.",            /* 3 */
@@ -128,7 +128,7 @@
 	    if (index(str, '%')) {
 		if (i == 4L) {	/* "you are turning green" */
 		    if (!Blind)	/* [what if you're already green?] */
-			pline(str, hcolor(green));
+			pline(str, hcolor(NH_GREEN));
 		} else
 		    pline(str, an(Hallucination ? rndmonnam() : "green slime"));
 	    } else
@@ -202,7 +202,7 @@
 		u.uspellprot--;
 		find_ac();
 		if (!Blind)
-		    Norep("The %s haze around you %s.", hcolor(golden),
+		    Norep("The %s haze around you %s.", hcolor(NH_GOLDEN),
 			  u.uspellprot ? "becomes less dense" : "disappears");
 	    }
 	}
@@ -287,10 +287,11 @@
 			break;
 		case INVIS:
 			newsym(u.ux,u.uy);
-			if (!Invis && !BInvis &&
-			    !See_invisible && !Blind) {
-				You("are no longer invisible.");
-				stop_occupation();
+			if (!Invis && !BInvis && !Blind) {
+			    You(!See_invisible ?
+				    "are no longer invisible." :
+				    "can no longer see through yourself.");
+			    stop_occupation();
 			}
 			break;
 		case SEE_INVIS:
@@ -367,6 +368,13 @@
 {
 	stop_occupation();
 	nomul(how_long);
+	/* generally don't notice sounds while sleeping */
+	if (wakeup_msg && multi == how_long) {
+	    /* caller can follow with a direct call to Hear_again() if
+	       there's a need to override this when wakeup_msg is true */
+	    flags.soundok = 0;
+	    afternmv = Hear_again;	/* this won't give any messages */
+	}
 	/* early wakeup from combat won't be possible until next monster turn */
 	u.usleep = monstermoves;
 	nomovemsg = wakeup_msg ? "You wake up." : You_can_move_again;
@@ -621,6 +629,8 @@
 	if (u.usteed) on_foot = FALSE;
 #endif
 
+	if (otmp && on_foot && !u.uinwater && is_pool(u.ux, u.uy)) otmp = 0;
+
 	if (otmp && on_foot) {		/* trip over something in particular */
 	    /*
 		If there is only one item, it will have just been named
@@ -1307,7 +1317,7 @@
 } ttable;
 
 /* table of timeout functions */
-static ttable timeout_funcs[NUM_TIME_FUNCS] = {
+static const ttable timeout_funcs[NUM_TIME_FUNCS] = {
     TTAB(rot_organic,	(timeout_proc)0,	"rot_organic"),
     TTAB(rot_corpse,	(timeout_proc)0,	"rot_corpse"),
     TTAB(revive_mon,	(timeout_proc)0,	"revive_mon"),
diff -Naurd ../nethack-3.4.0/src/topten.c ./src/topten.c
--- ../nethack-3.4.0/src/topten.c Wed Mar 20 23:43:19 2002
+++ ./src/topten.c Mon Feb 24 15:25:05 2003
@@ -76,9 +76,9 @@
 #endif
 
 /* must fit with end.c; used in rip.c */
-NEARDATA const char *killed_by_prefix[] = {
+NEARDATA const char * const killed_by_prefix[] = {
 	"killed by ", "choked on ", "poisoned by ", "", "drowned in ",
-	"", "dissolved in ", "crushed to death by ", "petrified by ",
+	"burned by ", "dissolved in ", "crushed to death by ", "petrified by ",
 	"turned to slime by ", "killed by ", "", "", "", "", ""
 };
 
@@ -128,13 +128,13 @@
 struct toptenentry *tt;
 {
 #ifdef NO_SCAN_BRACK /* Version_ Pts DgnLevs_ Hp___ Died__Born id */
-	static const char *fmt = "%d %d %d %ld %d %d %d %d %d %d %ld %ld %d%*c";
-	static const char *fmt32 = "%c%c %s %s%*c";
-	static const char *fmt33 = "%s %s %s %s %s %s%*c";
+	static const char fmt[] = "%d %d %d %ld %d %d %d %d %d %d %ld %ld %d%*c";
+	static const char fmt32[] = "%c%c %s %s%*c";
+	static const char fmt33[] = "%s %s %s %s %s %s%*c";
 #else
-	static const char *fmt = "%d.%d.%d %ld %d %d %d %d %d %d %ld %ld %d ";
-	static const char *fmt32 = "%c%c %[^,],%[^\n]%*c";
-	static const char *fmt33 = "%s %s %s %s %[^,],%[^\n]%*c";
+	static const char fmt[] = "%d.%d.%d %ld %d %d %d %d %d %d %ld %ld %d ";
+	static const char fmt32[] = "%c%c %[^,],%[^\n]%*c";
+	static const char fmt33[] = "%s %s %s %s %[^,],%[^\n]%*c";
 #endif
 
 #ifdef UPDATE_RECORD_IN_PLACE
@@ -340,7 +340,7 @@
 
 #ifdef LOGFILE		/* used for debugging (who dies of what, where) */
 	if (lock_file(LOGFILE, SCOREPREFIX, 10)) {
-	    if(!(lfile = fopen_datafile(LOGFILE, "a", TRUE))) {
+	    if(!(lfile = fopen_datafile(LOGFILE, "a", SCOREPREFIX))) {
 		HUP raw_print("Cannot open log file!");
 	    } else {
 		writeentry(lfile, t0);
@@ -366,9 +366,9 @@
 		goto destroywin;
 
 #ifdef UPDATE_RECORD_IN_PLACE
-	rfile = fopen_datafile(RECORD, "r+", TRUE);
+	rfile = fopen_datafile(RECORD, "r+", SCOREPREFIX);
 #else
-	rfile = fopen_datafile(RECORD, "r", TRUE);
+	rfile = fopen_datafile(RECORD, "r", SCOREPREFIX);
 #endif
 
 	if (!rfile) {
@@ -445,7 +445,7 @@
 				     t0->fpos : final_fpos), SEEK_SET);
 #else
 		(void) fclose(rfile);
-		if(!(rfile = fopen_datafile(RECORD, "w", TRUE))){
+		if(!(rfile = fopen_datafile(RECORD, "w", SCOREPREFIX))){
 			HUP raw_print("Cannot write record file");
 			unlock_file(RECORD);
 			free_ttlist(tt_head);
@@ -629,8 +629,9 @@
 		}
 		Sprintf(eos(linebuf), fmt, arg);
 	    } else {
-		Sprintf(eos(linebuf), " in %s on level %d",
-			dungeons[t1->deathdnum].dname, t1->deathlev);
+		Sprintf(eos(linebuf), " in %s", dungeons[t1->deathdnum].dname);
+		if (t1->deathdnum != knox_level.dnum)
+		    Sprintf(eos(linebuf), " on level %d", t1->deathlev);
 		if (t1->deathlev != t1->maxlvl)
 		    Sprintf(eos(linebuf), " [max %d]", t1->maxlvl);
 	    }
@@ -762,7 +763,7 @@
 		return;
 	}
 
-	rfile = fopen_datafile(RECORD, "r", TRUE);
+	rfile = fopen_datafile(RECORD, "r", SCOREPREFIX);
 	if (!rfile) {
 		raw_print("Cannot open record file!");
 		return;
@@ -787,14 +788,6 @@
 	if (!argv[1][2]){	/* plain "-s" */
 		argc--;
 		argv++;
-#if 0 /* uses obsolete pl_classes[] */
-	} else if (!argv[1][3] && index(pl_classes, argv[1][2])) {
-		/* may get this case instead of next accidentally,
-		 * but neither is listed in the documentation, so
-		 * anything useful that happens is a bonus anyway */
-		argv[1]++;
-		argv[1][0] = '-';
-#endif
 	} else	argv[1] += 2;
 
 	if (argc > 1 && !strcmp(argv[1], "-v")) {
@@ -856,6 +849,12 @@
 	    else {
 		if (playerct > 1) Strcat(pbuf, "any of ");
 		for (i = 0; i < playerct; i++) {
+		    /* stop printing players if there are too many to fit */
+		    if (strlen(pbuf) + strlen(players[i]) + 2 >= BUFSZ) {
+			if (strlen(pbuf) < BUFSZ-4) Strcat(pbuf, "...");
+			else Strcpy(pbuf+strlen(pbuf)-4, "...");
+			break;
+		    }
 		    Strcat(pbuf, players[i]);
 		    if (i < playerct-1) {
 			if (players[i][0] == '-' &&
@@ -922,7 +921,7 @@
 
 	if (!otmp) return((struct obj *) 0);
 
-	rfile = fopen_datafile(RECORD, "r", TRUE);
+	rfile = fopen_datafile(RECORD, "r", SCOREPREFIX);
 	if (!rfile) {
 		impossible("Cannot open record file!");
 		return (struct obj *)0;
diff -Naurd ../nethack-3.4.0/src/trap.c ./src/trap.c
--- ../nethack-3.4.0/src/trap.c Wed Mar 20 23:43:19 2002
+++ ./src/trap.c Mon Feb 24 15:25:05 2003
@@ -1,10 +1,10 @@
-/*	SCCS Id: @(#)trap.c	3.4	2001/09/06	*/
+/*	SCCS Id: @(#)trap.c	3.4	2003/02/10	*/
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /* NetHack may be freely redistributed.  See license for details. */
 
 #include "hack.h"
 
-extern const char *destroy_strings[];
+extern const char * const destroy_strings[];	/* from zap.c */
 
 STATIC_DCL void FDECL(dofiretrap, (struct obj *));
 STATIC_DCL void NDECL(domagictrap);
@@ -20,7 +20,7 @@
 STATIC_DCL int FDECL(disarm_shooting_trap, (struct trap *, int));
 STATIC_DCL int FDECL(try_lift, (struct monst *, struct trap *, int, BOOLEAN_P));
 STATIC_DCL int FDECL(help_monster_out, (struct monst *, struct trap *));
-STATIC_DCL boolean FDECL(thitm, (int, struct monst *, struct obj *, int));
+STATIC_DCL boolean FDECL(thitm, (int,struct monst *,struct obj *,int,BOOLEAN_P));
 STATIC_DCL int FDECL(mkroll_launch,
 			(struct trap *,XCHAR_P,XCHAR_P,SHORT_P,long));
 STATIC_DCL boolean FDECL(isclearpath,(coord *, int, SCHAR_P, SCHAR_P));
@@ -34,14 +34,17 @@
 STATIC_VAR const char *the_your[2];
 STATIC_VAR const char tower_of_flame[];
 STATIC_VAR const char *A_gush_of_water_hits;
+STATIC_VAR const char * const blindgas[6];
 
 #else
 
-STATIC_VAR const char *a_your[2] = { "a", "your" };
-STATIC_VAR const char *A_Your[2] = { "A", "Your" };
-STATIC_VAR const char *the_your[2] = { "the", "your" };
+STATIC_VAR const char * const a_your[2] = { "a", "your" };
+STATIC_VAR const char * const A_Your[2] = { "A", "Your" };
+STATIC_VAR const char * const the_your[2] = { "the", "your" };
 STATIC_VAR const char tower_of_flame[] = "tower of flame";
-STATIC_VAR const char *A_gush_of_water_hits = "A gush of water hits";
+STATIC_VAR const char * const A_gush_of_water_hits = "A gush of water hits";
+STATIC_VAR const char * const blindgas[6] = 
+	{"humid", "odorless", "pungent", "chilling", "acrid", "biting"};
 
 #endif /* OVLB */
 
@@ -117,8 +120,8 @@
 boolean print;
 struct monst *victim;
 {
-	static NEARDATA const char *action[] = { "smoulder", "rust", "rot", "corrode" };
-	static NEARDATA const char *msg[] =  { "burnt", "rusted", "rotten", "corroded" };
+	static NEARDATA const char * const action[] = { "smoulder", "rust", "rot", "corrode" };
+	static NEARDATA const char * const msg[] =  { "burnt", "rusted", "rotten", "corroded" };
 	boolean vulnerable = FALSE;
 	boolean grprot = FALSE;
 	boolean is_primary = TRUE;
@@ -280,9 +283,11 @@
 	    case TRAPDOOR:
 		lev = &levl[x][y];
 		if (*in_rooms(x, y, SHOPBASE) &&
-			((typ == HOLE || typ == TRAPDOOR) || IS_DOOR(lev->typ)))
+			((typ == HOLE || typ == TRAPDOOR) ||
+			 IS_DOOR(lev->typ) || IS_WALL(lev->typ)))
 		    add_damage(x, y,		/* schedule repair */
-			(IS_DOOR(lev->typ) && !flags.mon_moving) ? 200L : 0L);
+			       ((IS_DOOR(lev->typ) || IS_WALL(lev->typ))
+				&& !flags.mon_moving) ? 200L : 0L);
 		lev->doormask = 0;	/* subsumes altarmask, icedpool... */
 		if (IS_ROOM(lev->typ)) /* && !IS_AIR(lev->typ) */
 		    lev->typ = ROOM;
@@ -331,6 +336,7 @@
 
 	if(td) {
 	    struct trap *t=t_at(u.ux,u.uy);
+	    seetrap(t);
 	    if (!In_sokoban(&u.uz)) {
 		if (t->ttyp == TRAPDOOR)
 			pline("A trap door opens up under you!");
@@ -403,6 +409,7 @@
 	struct monst *mon = 0;
 	struct obj *item;
 	coord cc;
+	boolean historic = (Role_if(PM_ARCHEOLOGIST) && !flags.mon_moving && statue->spe);
 
 	if (statue->oxlth && statue->oattached == OATTACHED_MONST) {
 	    cc.x = x,  cc.y = y;
@@ -442,12 +449,19 @@
 	/* mimic statue becomes seen mimic; other hiders won't be hidden */
 	if (mon->m_ap_type) seemimic(mon);
 	else mon->mundetected = FALSE;
-	if ((x == u.ux && y == u.uy) || cause == ANIMATE_SPELL)
-	    pline_The("statue comes to life!");
-	else if (cause == ANIMATE_SHATTER)
-	    pline("Instead of shattering, the statue suddenly comes alive!");
+	if ((x == u.ux && y == u.uy) || cause == ANIMATE_SPELL) {
+	    pline_The("statue %s!",
+		canspotmon(mon) ? "comes to life" : "disappears");
+		if (historic) {
+		    You_feel("guilty that the historic statue is now gone.");
+		    adjalign(-1);
+		}
+	} else if (cause == ANIMATE_SHATTER)
+	    pline("Instead of shattering, the statue suddenly %s!",
+		canspotmon(mon) ? "comes to life" : "disappears");
 	else /* cause == ANIMATE_NORMAL */
-	    You("find %s posing as a statue.", a_monnam(mon));
+	    You("find %s posing as a statue.",
+		canspotmon(mon) ? a_monnam(mon) : something);
 	/* avoid hiding under nothing */
 	if (x == u.ux && y == u.uy &&
 		Upolyd && hides_under(youmonst.data) && !OBJ_AT(x, y))
@@ -538,6 +552,10 @@
 	    }
 	}
 
+#ifdef STEED
+	if (u.usteed) u.usteed->mtrapseen |= (1 << (ttype-1));
+#endif
+
 	switch(ttype) {
 	    case ARROW_TRAP:
 		seetrap(trap);
@@ -671,9 +689,7 @@
 		    break;
 		}
 		pline("A cloud of gas puts you to sleep!");
-		flags.soundok = 0;
 		fall_asleep(-rnd(25), TRUE);
-		afternmv = Hear_again;
 #ifdef STEED
 		(void) steedintrap(trap, (struct obj *)0);
 #endif
@@ -760,17 +776,17 @@
 		    break;
 		}
 		if (!In_sokoban(&u.uz)) {
-		   char verbbuf[BUFSZ];
+		    char verbbuf[BUFSZ];
 #ifdef STEED
-		   if (u.usteed)
+		    if (u.usteed)
 		   	Sprintf(verbbuf,"lead %s",
 				x_monnam(u.usteed,
 					 u.usteed->mnamelth ? ARTICLE_NONE : ARTICLE_THE,
 				 	 "poor", SUPPRESS_SADDLE, FALSE));
-		   else
+		    else
 #endif
 		    Strcpy(verbbuf,"fall");
-		   You("%s into %s pit!", verbbuf, a_your[trap->madeby_u]);
+		    You("%s into %s pit!", verbbuf, a_your[trap->madeby_u]);
 		}
 		/* wumpus reference */
 		if (Role_if(PM_RANGER) && !trap->madeby_u && !trap->once &&
@@ -781,13 +797,14 @@
 			u.umonnum == PM_PIT_FIEND)
 		    pline("How pitiful.  Isn't that the pits?");
 		if (ttype == SPIKED_PIT) {
-		    char *predicament = "on a set of sharp iron spikes";
+		    const char *predicament = "on a set of sharp iron spikes";
 #ifdef STEED
 		    if (u.usteed) {
 			pline("%s lands %s!",
 				upstart(x_monnam(u.usteed,
 					 u.usteed->mnamelth ? ARTICLE_NONE : ARTICLE_THE,
-				 	 "poor", SUPPRESS_SADDLE, FALSE)), predicament);
+					 "poor", SUPPRESS_SADDLE, FALSE)),
+			      predicament);
 		    } else
 #endif
 		    You("land %s!", predicament);
@@ -820,8 +837,8 @@
 		break;
 	    case HOLE:
 	    case TRAPDOOR:
-		seetrap(trap);
 		if (!Can_fall_thru(&u.uz)) {
+		    seetrap(trap);	/* normally done in fall_through */
 		    impossible("dotrap: %ss cannot exist on this level.",
 			       defsyms[trap_to_defsym(ttype)].explanation);
 		    break;		/* don't activate it after all */
@@ -863,27 +880,54 @@
 		    break;
 		}
 		if (webmsgok) {
-		   char verbbuf[BUFSZ];
-		   verbbuf[0] = '\0';
+		    char verbbuf[BUFSZ];
+		    verbbuf[0] = '\0';
 #ifdef STEED
-		   if (u.usteed)
+		    if (u.usteed)
 		   	Sprintf(verbbuf,"lead %s",
 				x_monnam(u.usteed,
 					 u.usteed->mnamelth ? ARTICLE_NONE : ARTICLE_THE,
 				 	 "poor", SUPPRESS_SADDLE, FALSE));
-		   else
+		    else
 #endif
 			
 		    Sprintf(verbbuf, "%s", Levitation ? (const char *)"float" :
 		      		locomotion(youmonst.data, "stumble"));
-		   You("%s into %s spider web!", verbbuf, a_your[trap->madeby_u]);
+		    You("%s into %s spider web!",
+			verbbuf, a_your[trap->madeby_u]);
 		}
 		u.utraptype = TT_WEB;
 
-		/* Time stuck in the web depends on your strength. */
+		/* Time stuck in the web depends on your/steed strength. */
 		{
 		    register int str = ACURR(A_STR);
 
+#ifdef STEED
+		    /* If mounted, the steed gets trapped.  Use mintrap
+		     * to do all the work.  If mtrapped is set as a result,
+		     * unset it and set utrap instead.  In the case of a
+		     * strongmonst and mintrap said it's trapped, use a
+		     * short but non-zero trap time.  Otherwise, monsters
+		     * have no specific strength, so use player strength.
+		     * This gets skipped for webmsgok, which implies that
+		     * the steed isn't a factor.
+		     */
+		    if (u.usteed && webmsgok) {
+			/* mtmp location might not be up to date */
+			u.usteed->mx = u.ux;
+			u.usteed->my = u.uy;
+
+			/* mintrap currently does not return 2(died) for webs */
+			if (mintrap(u.usteed)) {
+			    u.usteed->mtrapped = 0;
+			    if (strongmonst(u.usteed->data)) str = 17;
+			} else {
+			    break;
+			}
+
+			webmsgok = FALSE; /* mintrap printed the messages */
+		    }
+#endif
 		    if (str <= 3) u.utrap = rn1(6,6);
 		    else if (str < 6) u.utrap = rn1(6,4);
 		    else if (str < 9) u.utrap = rn1(4,4);
@@ -894,7 +938,7 @@
 		    else {
 			u.utrap = 0;
 			if (webmsgok)
-				You("tear through %s web!", a_your[trap->madeby_u]);
+			    You("tear through %s web!", a_your[trap->madeby_u]);
 			deltrap(trap);
 			newsym(u.ux,u.uy);	/* get rid of trap symbol */
 		    }
@@ -1000,17 +1044,19 @@
 		fill_pit(u.ux, u.uy);
 		break;
 
-	    case ROLLING_BOULDER_TRAP:
+	    case ROLLING_BOULDER_TRAP: {
+		int style = ROLL | (trap->tseen ? LAUNCH_KNOWN : 0);
+
 		seetrap(trap);
 		pline("Click! You trigger a rolling boulder trap!");
 		if(!launch_obj(BOULDER, trap->launch.x, trap->launch.y,
-		      trap->launch2.x,trap->launch2.y, ROLL)) {
+		      trap->launch2.x, trap->launch2.y, style)) {
 		    deltrap(trap);
 		    newsym(u.ux,u.uy);	/* get rid of trap symbol */
 		    pline("Fortunately for you, no boulder was released.");
 		}
 		break;
-
+	    }
 	    case MAGIC_PORTAL:
 		seetrap(trap);
 		domagicportal(trap);
@@ -1048,7 +1094,7 @@
 				impossible("steed hit by non-existant arrow?");
 				return 0;
 			}
-			if(thitm(8, mtmp, otmp, 0)) trapkilled = TRUE;
+			if (thitm(8, mtmp, otmp, 0, FALSE)) trapkilled = TRUE;
 			steedhit = TRUE;
 			break;
 		case DART_TRAP:
@@ -1056,7 +1102,7 @@
 				impossible("steed hit by non-existant dart?");
 				return 0;
 			}
-			if(thitm(7, mtmp, otmp, 0)) trapkilled = TRUE;
+			if (thitm(7, mtmp, otmp, 0, FALSE)) trapkilled = TRUE;
 			steedhit = TRUE;
 			break;
 		case SLP_GAS_TRAP:
@@ -1072,7 +1118,7 @@
 			steedhit = TRUE;
 			break;
 		case LANDMINE:
-			if (thitm(0, mtmp, (struct obj *)0, rnd(16)))
+			if (thitm(0, mtmp, (struct obj *)0, rnd(16), FALSE))
 			    trapkilled = TRUE;
 			steedhit = TRUE;
 			break;
@@ -1080,14 +1126,15 @@
 		case SPIKED_PIT:
 			if (mtmp->mhp <= 0 ||
 				thitm(0, mtmp, (struct obj *)0,
-				      rnd((tt == PIT) ? 6 : 10)))
+				      rnd((tt == PIT) ? 6 : 10), FALSE))
 			    trapkilled = TRUE;
 			steedhit = TRUE;
 			break;
 		case POLY_TRAP: 
 		    if (!resists_magm(mtmp)) {
 			if (!resist(mtmp, WAND_CLASS, 0, NOTELL)) {
-			(void) newcham(mtmp, (struct permonst *)0, FALSE);
+			(void) newcham(mtmp, (struct permonst *)0,
+				       FALSE, FALSE);
 			if (!can_saddle(mtmp) || !can_ride(mtmp)) {
 				dismount_steed(DISMOUNT_POLY);
 			} else {
@@ -1118,7 +1165,7 @@
 blow_up_landmine(trap)
 struct trap *trap;
 {
-	scatter(trap->tx, trap->ty, 4,
+	(void)scatter(trap->tx, trap->ty, 4,
 		MAY_DESTROY | MAY_HIT | MAY_FRACTURE | VIS_EFFECTS,
 		(struct obj *)0);
 	del_engr_at(trap->tx, trap->ty);
@@ -1194,6 +1241,11 @@
 	dx = sgn(x2 - x1);
 	dy = sgn(y2 - y1);
 	switch (style) {
+	    case ROLL|LAUNCH_KNOWN:
+			/* use otrapped as a flag to ohitmon */
+			singleobj->otrapped = 1;
+			style &= ~LAUNCH_KNOWN;
+			/* fall through */
 	    case ROLL:
 			delaycnt = 2;
 			/* fall through */
@@ -1223,6 +1275,7 @@
 			    if (rn2(3)) {
 				pline("%s snatches the boulder.",
 					Monnam(mtmp));
+				singleobj->otrapped = 0;
 				(void) mpickobj(mtmp, singleobj);
 				used_up = TRUE;
 				break;
@@ -1242,7 +1295,7 @@
 		}
 		if (style == ROLL) {
 		    if (down_gate(bhitpos.x, bhitpos.y) != -1) {
-		       if (ship_object(singleobj, bhitpos.x, bhitpos.y, FALSE)){
+		        if(ship_object(singleobj, bhitpos.x, bhitpos.y, FALSE)){
 				used_up = TRUE;
 				break;
 			}
@@ -1258,8 +1311,9 @@
 				deltrap(t);
 				del_engr_at(bhitpos.x,bhitpos.y);
 				place_object(singleobj, bhitpos.x, bhitpos.y);
+				singleobj->otrapped = 0;
 				fracture_rock(singleobj);
-				scatter(bhitpos.x,bhitpos.y, 4,
+				(void)scatter(bhitpos.x,bhitpos.y, 4,
 					MAY_DESTROY|MAY_HIT|MAY_FRACTURE|VIS_EFFECTS,
 					(struct obj *)0);
 				if (cansee(bhitpos.x,bhitpos.y))
@@ -1273,6 +1327,7 @@
 			    	pline("Suddenly the rolling boulder disappears!");
 			    else
 			    	You_hear("a rumbling stop abruptly.");
+			    singleobj->otrapped = 0;
 			    if (t->ttyp == TELEP_TRAP)
 				rloco(singleobj);
 			    else {
@@ -1290,8 +1345,19 @@
 		    	    seetrap(t);
 			    used_up = TRUE;
 			    break;
+			case PIT:
+			case SPIKED_PIT:
+			case HOLE:
+			case TRAPDOOR:
+			    /* the boulder won't be used up if there is a
+			       monster in the trap; stop rolling anyway */
+			    x2 = bhitpos.x,  y2 = bhitpos.y;  /* stops here */
+			    if (flooreffects(singleobj, x2, y2, "fall"))
+				used_up = TRUE;
+			    dist = -1;	/* stop rolling immediately */
+			    break;
 			}
-			if (used_up) break;
+			if (used_up || dist == -1) break;
 		    }
 		    if (flooreffects(singleobj, bhitpos.x, bhitpos.y, "fall")) {
 			used_up = TRUE;
@@ -1299,11 +1365,19 @@
 		    }
 		    if (otyp == BOULDER &&
 		       (otmp2 = sobj_at(BOULDER, bhitpos.x, bhitpos.y)) != 0) {
-			char *bmsg =
-				" as one boulder sets another in motion";
-		    	You_hear("a loud crash%s!",
+			const char *bmsg =
+				     " as one boulder sets another in motion";
+
+			if (!isok(bhitpos.x + dx, bhitpos.y + dy) || !dist ||
+			    IS_ROCK(levl[bhitpos.x + dx][bhitpos.y + dy].typ))
+			    bmsg = " as one boulder hits another";
+
+			You_hear("a loud crash%s!",
 				cansee(bhitpos.x, bhitpos.y) ? bmsg : "");
 			obj_extract_self(otmp2);
+			/* pass off the otrapped flag to the next boulder */
+			otmp2->otrapped = singleobj->otrapped;
+			singleobj->otrapped = 0;
 			place_object(singleobj, bhitpos.x, bhitpos.y);
 			singleobj = otmp2;
 			otmp2 = (struct obj *)0;
@@ -1316,15 +1390,27 @@
 			levl[bhitpos.x][bhitpos.y].doormask = D_BROKEN;
 			if (dist) unblock_point(bhitpos.x, bhitpos.y);
 		}
+
+		/* if about to hit iron bars, do so now */
+		if (dist > 0 && isok(bhitpos.x + dx,bhitpos.y + dy) &&
+			levl[bhitpos.x + dx][bhitpos.y + dy].typ == IRONBARS) {
+		    x2 = bhitpos.x,  y2 = bhitpos.y;	/* object stops here */
+		    if (hits_bars(&singleobj, x2, y2, !rn2(20), 0)) {
+			if (!singleobj) used_up = TRUE;
+			break;
+		    }
+		}
 	}
 	tmp_at(DISP_END, 0);
 	if (!used_up) {
+		singleobj->otrapped = 0;
 		place_object(singleobj, x2,y2);
 		newsym(x2,y2);
 		return 1;
 	} else
 		return 2;
 }
+
 #endif /* OVL3 */
 #ifdef OVLB
 
@@ -1484,6 +1570,10 @@
 				   In_sokoban(&u.uz) && !trap->madeby_u);
 	    const char *fallverb;
 
+#ifdef STEED
+	    /* true when called from dotrap, inescapable is not an option */
+	    if (mtmp == u.usteed) inescapable = TRUE;
+#endif
 	    if (!inescapable &&
 		    ((mtmp->mtrapseen & (1 << (tt-1))) != 0 ||
 			(tt == HOLE && !mindless(mtmp->data)))) {
@@ -1500,6 +1590,10 @@
 	    /* bug?  `in_sight' ought to be split to distinguish between
 	       trap_in_sight and can_see_victim to handle invisible monsters */
 	    in_sight = canseemon(mtmp);
+#ifdef STEED
+	    /* assume hero can tell what's going on for the steed */
+	    if (mtmp == u.usteed) in_sight = TRUE;
+#endif
 	    switch (tt) {
 		case ARROW_TRAP:
 			otmp = mksobj(ARROW, TRUE, FALSE);
@@ -1507,7 +1601,7 @@
 			otmp->owt = weight(otmp);
 			otmp->opoisoned = 0;
 			if (in_sight) seetrap(trap);
-			if(thitm(8, mtmp, otmp, 0)) trapkilled = TRUE;
+			if (thitm(8, mtmp, otmp, 0, FALSE)) trapkilled = TRUE;
 			break;
 		case DART_TRAP:
 			otmp = mksobj(DART, TRUE, FALSE);
@@ -1515,14 +1609,14 @@
 			otmp->owt = weight(otmp);
 			if (!rn2(6)) otmp->opoisoned = 1;
 			if (in_sight) seetrap(trap);
-			if(thitm(7, mtmp, otmp, 0)) trapkilled = TRUE;
+			if (thitm(7, mtmp, otmp, 0, FALSE)) trapkilled = TRUE;
 			break;
 		case ROCKTRAP:
 			otmp = mksobj(ROCK, TRUE, FALSE);
 			otmp->quan = 1L;
 			otmp->owt = weight(otmp);
 			if (in_sight) seetrap(trap);
-			if (thitm(0, mtmp, otmp, d(2, 6)))
+			if (thitm(0, mtmp, otmp, d(2, 6), FALSE))
 			    trapkilled = TRUE;
 			break;
 
@@ -1655,9 +1749,22 @@
 				pline("%s is uninjured.", Monnam(mtmp));
 			    }
 			} else {
-			    int num = d(2,4);
+			    int num = d(2,4), alt;
+			    boolean immolate = FALSE;
 
-			    if (thitm(0, mtmp, (struct obj *)0, num))
+			    /* paper burns very fast, assume straw is tightly
+			     * packed and burns a bit slower */
+			    switch (monsndx(mtmp->data)) {
+			    case PM_PAPER_GOLEM:   immolate = TRUE;
+						   alt = mtmp->mhpmax; break;
+			    case PM_STRAW_GOLEM:   alt = mtmp->mhpmax / 2; break;
+			    case PM_WOOD_GOLEM:    alt = mtmp->mhpmax / 4; break;
+			    case PM_LEATHER_GOLEM: alt = mtmp->mhpmax / 8; break;
+			    default: alt = 0; break;
+			    }
+			    if (alt > num) num = alt;
+
+			    if (thitm(0, mtmp, (struct obj *)0, num, immolate))
 				trapkilled = TRUE;
 			    else
 				/* we know mhp is at least `num' below mhpmax,
@@ -1699,7 +1806,7 @@
 			mselftouch(mtmp, "Falling, ", FALSE);
 			if (mtmp->mhp <= 0 ||
 				thitm(0, mtmp, (struct obj *)0,
-				      rnd((tt == PIT) ? 6 : 10)))
+				      rnd((tt == PIT) ? 6 : 10), FALSE))
 			    trapkilled = TRUE;
 			break;
 		case HOLE:
@@ -1843,7 +1950,7 @@
 			if (!in_sight)
 				pline("Kaablamm!  You hear an explosion in the distance!");
 			blow_up_landmine(trap);
-			if(thitm(0, mtmp, (struct obj *)0, rnd(16)))
+			if (thitm(0, mtmp, (struct obj *)0, rnd(16), FALSE))
 				trapkilled = TRUE;
 			else {
 				/* monsters recursively fall into new pit */
@@ -1862,7 +1969,8 @@
 		    if (resists_magm(mtmp)) {
 			shieldeff(mtmp->mx, mtmp->my);
 		    } else if (!resist(mtmp, WAND_CLASS, 0, NOTELL)) {
-			(void) newcham(mtmp, (struct permonst *)0, FALSE);
+			(void) newcham(mtmp, (struct permonst *)0,
+				       FALSE, FALSE);
 			if (in_sight) seetrap(trap);
 		    }
 		    break;
@@ -1920,12 +2028,17 @@
 boolean byplayer;
 {
 	if (resists_ston(mon)) return;
-	if (cansee(mon->mx, mon->my))
-		pline("%s turns to stone.", Monnam(mon));
 	if (poly_when_stoned(mon->data)) {
 		mon_to_stone(mon);
 		return;
 	}
+
+	/* give a "<mon> is slowing down" message and also remove
+	   intrinsic speed (comparable to similar effect on the hero) */
+	mon_adjust_speed(mon, -3, (struct obj *)0);
+
+	if (cansee(mon->mx, mon->my))
+		pline("%s turns to stone.", Monnam(mon));
 	if (byplayer) {
 		stoned = TRUE;
 		xkilled(mon,0);
@@ -2047,6 +2160,11 @@
 	HLevitation &= ~hmask;
 	ELevitation &= ~emask;
 	if(Levitation) return(0); /* maybe another ring/potion/boots */
+	if(u.uswallow) {
+	    You("float down, but you are still %s.",
+		is_animal(u.ustuck->data) ? "swallowed" : "engulfed");
+	    return(1);
+	}
 
 	if (Punished && !carried(uball) &&
 	    (is_pool(uball->ox, uball->oy) ||
@@ -2152,7 +2270,7 @@
 struct obj *box;	/* null for floor trap */
 {
 	boolean see_it = !Blind;
-	int num;
+	int num, alt;
 
 /* Bug: for box case, the equivalent of burn_floor_paper() ought
  * to be done upon its contents.
@@ -2171,6 +2289,18 @@
 	if (Fire_resistance) {
 	    shieldeff(u.ux, u.uy);
 	    num = rn2(2);
+	} else if (Upolyd) {
+	    num = d(2,4);
+	    switch (u.umonnum) {
+	    case PM_PAPER_GOLEM:   alt = u.mhmax; break;
+	    case PM_STRAW_GOLEM:   alt = u.mhmax / 2; break;
+	    case PM_WOOD_GOLEM:    alt = u.mhmax / 4; break;
+	    case PM_LEATHER_GOLEM: alt = u.mhmax / 8; break;
+	    default: alt = 0; break;
+	    }
+	    if (alt > num) num = alt;
+	    if (u.mhmax > mons[u.umonnum].mlevel)
+		u.mhmax -= rn2(min(u.mhmax,num + 1)), flags.botl = 1;
 	} else {
 	    num = d(2,4);
 	    if (u.uhpmax > u.ulevel)
@@ -2392,9 +2522,12 @@
 register struct obj *obj;
 register boolean force, here;
 {
+	struct obj *otmp;
+
 	/* Scrolls, spellbooks, potions, weapons and
 	   pieces of armor may get affected by the water */
-	for (; obj; obj = (here ? obj->nexthere : obj->nobj)) {
+	for (; obj; obj = otmp) {
+		otmp = here ? obj->nexthere : obj->nobj;
 
 		(void) snuff_lit(obj);
 
@@ -2426,7 +2559,12 @@
 				pline("Steam rises from %s.", the(xname(obj)));
 			else obj->otyp = SPE_BLANK_PAPER;
 		} else if (obj->oclass == POTION_CLASS) {
-			if (obj->odiluted) {
+			if (obj->otyp == POT_ACID) {
+				/* damage player/monster? */
+				pline("A potion explodes!");
+				delobj(obj);
+				continue;
+			} else if (obj->odiluted) {
 				obj->otyp = POT_WATER;
 				obj->blessed = obj->cursed = 0;
 				obj->odiluted = 0;
@@ -2456,64 +2594,64 @@
 {
 	int invc = inv_cnt();
 
-
 	while (near_capacity() > (Punished ? UNENCUMBERED : SLT_ENCUMBER)) {
-		register struct obj *obj, *otmp = (struct obj *)0;
-		register int i;
+	    register struct obj *obj, *otmp = (struct obj *)0;
+	    register int i;
 
-		/* Pick a random object */
-		if (invc > 0) {
-			i = rn2(invc);
+	    /* Pick a random object */
+	    if (invc > 0) {
+		i = rn2(invc);
 		for (obj = invent; obj; obj = obj->nobj) {
-			/*
-			 * Undroppables are: body armor, boots, gloves,
-			 * amulets, and rings because of the time and effort
-			 * in removing them + loadstone and other cursed stuff
-			 * for obvious reasons.
-			 */
-			if (!((obj->otyp == LOADSTONE && obj->cursed) ||
-			      obj == uamul || obj == uleft || obj == uright ||
-			      obj == ublindf || obj == uarm || obj == uarmc ||
-			      obj == uarmg || obj == uarmf ||
+		    /*
+		     * Undroppables are: body armor, boots, gloves,
+		     * amulets, and rings because of the time and effort
+		     * in removing them + loadstone and other cursed stuff
+		     * for obvious reasons.
+		     */
+		    if (!((obj->otyp == LOADSTONE && obj->cursed) ||
+			  obj == uamul || obj == uleft || obj == uright ||
+			  obj == ublindf || obj == uarm || obj == uarmc ||
+			  obj == uarmg || obj == uarmf ||
 #ifdef TOURIST
-			      obj == uarmu ||
+			  obj == uarmu ||
 #endif
-			      (obj->cursed && (obj == uarmh || obj == uarms)) ||
-			      welded(obj)))
-				otmp = obj;
-			/* reached the mark and found some stuff to drop? */
-			if (--i < 0 && otmp) break;
+			  (obj->cursed && (obj == uarmh || obj == uarms)) ||
+			  welded(obj)))
+			otmp = obj;
+		    /* reached the mark and found some stuff to drop? */
+		    if (--i < 0 && otmp) break;
 
-			/* else continue */
-		}
+		    /* else continue */
 		}
+	    }
 #ifndef GOLDOBJ
-		if (!otmp) {
-			/* Nothing available left to drop; try gold */
-			if (u.ugold) {
-				pline("In desperation, you drop your purse.");
-				/* Hack: gold is not in the inventory, so make a gold object
-				 * and put it at the head of the inventory list.
-				 */
-				obj = mkgoldobj(u.ugold);    /* removes from u.ugold */
-				u.ugold = obj->quan;         /* put the gold back */
-				assigninvlet(obj);           /* might end up as NOINVSYM */
-				obj->nobj = invent;
-				invent = obj;
-				*lostsome = TRUE;
-				dropx(obj);
-				continue;                    /* Try again */
-			}
-			/* We can't even drop gold! */
-			return (FALSE);
+	    if (!otmp) {
+		/* Nothing available left to drop; try gold */
+		if (u.ugold) {
+		    pline("In desperation, you drop your purse.");
+		    /* Hack: gold is not in the inventory, so make a gold object
+		     * and put it at the head of the inventory list.
+		     */
+		    obj = mkgoldobj(u.ugold);    /* removes from u.ugold */
+		    obj->in_use = TRUE;
+		    u.ugold = obj->quan;         /* put the gold back */
+		    assigninvlet(obj);           /* might end up as NOINVSYM */
+		    obj->nobj = invent;
+		    invent = obj;
+		    *lostsome = TRUE;
+		    dropx(obj);
+		    continue;                    /* Try again */
 		}
+		/* We can't even drop gold! */
+		return (FALSE);
+	    }
 #else
-		if (!otmp) return (FALSE); /* nothing to drop! */	
+	    if (!otmp) return (FALSE); /* nothing to drop! */	
 #endif
-		if (otmp->owornmask && otmp != uball) remove_worn_item(otmp);
-		*lostsome = TRUE;
-		dropx(otmp);
-		invc--;
+	    if (otmp->owornmask) remove_worn_item(otmp, FALSE);
+	    *lostsome = TRUE;
+	    dropx(otmp);
+	    invc--;
 	}
 	return(TRUE);
 }
@@ -2584,8 +2722,8 @@
 		vision_full_recalc = 1;
 		return(FALSE);
 	}
-	if((Teleportation || can_teleport(youmonst.data)) &&
-	   (Teleport_control || rn2(3) < Luck+2)) {
+	if ((Teleportation || can_teleport(youmonst.data)) &&
+		    !u.usleep && (Teleport_control || rn2(3) < Luck+2)) {
 		You("attempt a teleport spell.");	/* utcsri!carroll */
 		(void) dotele();
 		if(!is_pool(u.ux,u.uy))
@@ -2599,11 +2737,17 @@
 	}
 #endif
 	crawl_ok = FALSE;
+	/* if sleeping, wake up now so that we don't crawl out of water
+	   while still asleep; we can't do that the same way that waking
+	   due to combat is handled; note unmul() clears u.usleep */
+	if (u.usleep) unmul("Suddenly you wake up!");
+	/* can't crawl if unable to move (crawl_ok flag stays false) */
+	if (multi < 0 || (Upolyd && !youmonst.data->mmove)) goto crawl;
 	/* look around for a place to crawl to */
 	for (i = 0; i < 100; i++) {
 		x = rn1(3,u.ux - 1);
 		y = rn1(3,u.uy - 1);
-		if (goodpos(x, y, &youmonst)) {
+		if (goodpos(x, y, &youmonst, 0)) {
 			crawl_ok = TRUE;
 			goto crawl;
 		}
@@ -2611,11 +2755,11 @@
 	/* one more scan */
 	for (x = u.ux - 1; x <= u.ux + 1; x++)
 		for (y = u.uy - 1; y <= u.uy + 1; y++)
-			if (goodpos(x, y, &youmonst)) {
+			if (goodpos(x, y, &youmonst, 0)) {
 				crawl_ok = TRUE;
 				goto crawl;
 			}
-crawl:;
+ crawl:
 	if (crawl_ok) {
 		boolean lost = FALSE;
 		/* time to do some strip-tease... */
@@ -2627,7 +2771,7 @@
 			You("dump some of your gear to lose weight...");
 		if (succ) {
 			pline("Pheew!  That was close.");
-			teleds(x,y);
+			teleds(x,y,TRUE);
 			return(TRUE);
 		}
 		/* still too much weight */
@@ -2640,13 +2784,15 @@
 	    "pool of water" : "moat";
 	done(DROWNING);
 	/* oops, we're still alive.  better get out of the water. */
-	while (!safe_teleds()) {
+	while (!safe_teleds(TRUE)) {
 		pline("You're still drowning.");
 		done(DROWNING);
 	}
-	u.uinwater = 0;
-	You("find yourself back %s.", Is_waterlevel(&u.uz) ?
+	if (u.uinwater) {
+	    u.uinwater = 0;
+	    You("find yourself back %s.", Is_waterlevel(&u.uz) ?
 		"in an air bubble" : "on land");
+	}
 	return(TRUE);
 }
 
@@ -2743,7 +2889,8 @@
 	boolean unused;
 
 	/* we know there's no monster in the way, and we're not trapped */
-	if (!Punished || drag_ball(x, y, &bc, &bx, &by, &cx, &cy, &unused)) {
+	if (!Punished || drag_ball(x, y, &bc, &bx, &by, &cx, &cy, &unused,
+		TRUE)) {
 	    u.ux0 = u.ux,  u.uy0 = u.uy;
 	    u.ux = x,  u.uy = y;
 	    u.umoved = TRUE;
@@ -2751,7 +2898,7 @@
 	    vision_recalc(1);
 	    check_leash(u.ux0, u.uy0);
 	    if (Punished) move_bc(0, bc, bx, by, cx, cy);
-	    spoteffects(TRUE);	/* dotrap() */
+	    spoteffects(FALSE);	/* dotrap() */
 	    exercise(A_WIS, FALSE);
 	}
 }
@@ -2820,6 +2967,12 @@
 				if (ttmp2) {
 				    pline_The("webbing sticks to you. You're caught too!");
 				    dotrap(ttmp2, NOWEBMSG);
+#ifdef STEED
+				    if (u.usteed && u.utrap) {
+					/* you, not steed, are trapped */
+					dismount_steed(DISMOUNT_FELL);
+				    }
+#endif
 				}
 			    } else
 				pline("%s remains entangled.", Monnam(mtmp));
@@ -2847,6 +3000,7 @@
 {
 	if (!ttmp->madeby_u) {
 	    if (rnl(10) < 8 && !mtmp->mpeaceful &&
+		    !mtmp->msleeping && !mtmp->mfrozen &&
 		    !mindless(mtmp->data) &&
 		    mtmp->data->mlet != S_HUMAN) {
 		mtmp->mpeaceful = 1;
@@ -3086,17 +3240,54 @@
 	struct trap *ttmp;
 	struct monst *mtmp;
 	boolean trap_skipped = FALSE;
+	boolean box_here = FALSE;
+	boolean deal_with_floor_trap = FALSE;
+	char the_trap[BUFSZ], qbuf[QBUFSZ];
+	int containercnt = 0;
 
 	if(!getdir((char *)0)) return(0);
 	x = u.ux + u.dx;
 	y = u.uy + u.dy;
 
+	for(otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere) {
+		if(Is_box(otmp) && !u.dx && !u.dy) {
+			box_here = TRUE;
+			containercnt++;
+			if (containercnt > 1) break;
+		}
+	}
+
 	if ((ttmp = t_at(x,y)) && ttmp->tseen) {
-		if (u.utrap) {
-			You("cannot deal with traps while trapped!");
-			return 1;
+		deal_with_floor_trap = TRUE;
+		Strcpy(the_trap, the(defsyms[trap_to_defsym(ttmp->ttyp)].explanation));
+		if (box_here) {
+			if (ttmp->ttyp == PIT || ttmp->ttyp == SPIKED_PIT) {
+			    You_cant("do much about %s%s.",
+					the_trap, u.utrap ?
+					" that you're stuck in" :
+					" while standing on the edge of it");
+			    trap_skipped = TRUE;
+			    deal_with_floor_trap = FALSE;
+			} else {
+			    Sprintf(qbuf, "There %s and %s here. %s %s?",
+				(containercnt == 1) ? "is a container" : "are containers",
+				an(defsyms[trap_to_defsym(ttmp->ttyp)].explanation),
+				ttmp->ttyp == WEB ? "Remove" : "Disarm", the_trap);
+			    switch (ynq(qbuf)) {
+				case 'q': return(0);
+				case 'n': trap_skipped = TRUE;
+					  deal_with_floor_trap = FALSE;
+					  break;
+			    }
+			}
 		}
-		switch(ttmp->ttyp) {
+		if (deal_with_floor_trap) {
+		    if (u.utrap) {
+			You("cannot deal with %s while trapped%s!", the_trap,
+				(x == u.ux && y == u.uy) ? " in it" : "");
+			return 1;
+		    }
+		    switch(ttmp->ttyp) {
 			case BEAR_TRAP:
 			case WEB:
 				return disarm_holdingtrap(ttmp);
@@ -3122,15 +3313,15 @@
 			default:
 				You("cannot disable %s trap.", (u.dx || u.dy) ? "that" : "this");
 				return 0;
-		} /* end switch */
+		    }
+		}
 	} /* end if */
 
 	if(!u.dx && !u.dy) {
 	    for(otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere)
 		if(Is_box(otmp)) {
-		    There("is %s here.", doname(otmp));
-
-		    switch (ynq("Check for traps?")) {
+		    Sprintf(qbuf, "There is %s here. Check it for traps?", doname(otmp));
+		    switch (ynq(qbuf)) {
 			case 'q': return(0);
 			case 'n': continue;
 		    }
@@ -3298,6 +3489,18 @@
 			      loss += stolen_value(obj, ox, oy,
 						(boolean)shkp->mpeaceful, TRUE);
 			  delete_contents(obj);
+			  /* we're about to delete all things at this location,
+			   * which could include the ball & chain.
+			   * If we attempt to call unpunish() in the
+			   * for-loop below we can end up with otmp2
+			   * being invalid once the chain is gone.
+			   * Deal with ball & chain right now instead.
+			   */
+			  if (Punished && !carried(uball) &&
+				((uchain->ox == u.ux && uchain->oy == u.uy) ||
+				 (uball->ox == u.ux && uball->oy == u.uy)))
+				unpunish();
+
 			  for(otmp = level.objects[u.ux][u.uy];
 							otmp; otmp = otmp2) {
 			      otmp2 = otmp->nexthere;
@@ -3376,8 +3579,8 @@
 		case 1:
 		case 0:
 			pline("A cloud of %s gas billows from %s.",
-						hcolor((char *)0),
-						the(xname(obj)));
+				Blind ? blindgas[rn2(SIZE(blindgas))] :
+				hcolor((char *)0), the(xname(obj)));
 			if(!Stunned) {
 			    if (Hallucination)
 				pline("What a groovy feeling!");
@@ -3433,7 +3636,8 @@
 	dealloc_trap(trap);
 }
 
-boolean delfloortrap(ttmp)
+boolean
+delfloortrap(ttmp)
 register struct trap *ttmp;
 {
 	/* Destroy a trap that emanates from the floor. */
@@ -3485,14 +3689,15 @@
 /* Monster is hit by trap. */
 /* Note: doesn't work if both obj and d_override are null */
 STATIC_OVL boolean
-thitm(tlev, mon, obj, d_override)
-register int tlev;
-register struct monst *mon;
-register struct obj *obj;
+thitm(tlev, mon, obj, d_override, nocorpse)
+int tlev;
+struct monst *mon;
+struct obj *obj;
 int d_override;
+boolean nocorpse;
 {
-	register int strike;
-	register boolean trapkilled = FALSE;
+	int strike;
+	boolean trapkilled = FALSE;
 
 	if (d_override) strike = 1;
 	else if (obj) strike = (find_mac(mon) + tlev + obj->spe <= rnd(20));
@@ -3518,7 +3723,7 @@
 			int xx = mon->mx;
 			int yy = mon->my;
 
-			monkilled(mon, "", AD_PHYS);
+			monkilled(mon, "", nocorpse ? -AD_RBRE : AD_PHYS);
 			if (mon->mhp <= 0) {
 				newsym(xx, yy);
 				trapkilled = TRUE;
@@ -3542,7 +3747,7 @@
 		!strncmp(nomovemsg,"You are consci", 14))));
 }
 
-static char lava_killer[] = "molten lava";
+static const char lava_killer[] = "molten lava";
 
 boolean
 lava_effects()
@@ -3603,7 +3808,7 @@
 	killer = lava_killer;
 	You("burn to a crisp...");
 	done(BURNING);
-	while (!safe_teleds()) {
+	while (!safe_teleds(TRUE)) {
 		pline("You're still burning.");
 		done(BURNING);
 	}
diff -Naurd ../nethack-3.4.0/src/u_init.c ./src/u_init.c
--- ../nethack-3.4.0/src/u_init.c Wed Mar 20 23:43:20 2002
+++ ./src/u_init.c Mon Feb 24 15:25:05 2003
@@ -215,7 +215,7 @@
 };
 #ifdef GOLDOBJ
 static struct trobj Money[] = {
-	{ GOLD_PIECE, 0 , GOLD_CLASS, 1, 0 },
+	{ GOLD_PIECE, 0 , COIN_CLASS, 1, 0 },
 	{ 0, 0, 0, 0, 0 }
 };
 #endif
@@ -251,7 +251,7 @@
     { NON_PM,	STRANGE_OBJECT,		STRANGE_OBJECT	      }
 };
 
-static struct def_skill Skill_A[] = {
+static const struct def_skill Skill_A[] = {
     { P_DAGGER, P_BASIC },		{ P_KNIFE,  P_BASIC },
     { P_PICK_AXE, P_EXPERT },		{ P_SHORT_SWORD, P_BASIC },
     { P_SCIMITAR, P_SKILLED },		{ P_SABER, P_EXPERT },
@@ -269,7 +269,7 @@
     { P_NONE, 0 }
 };
 
-static struct def_skill Skill_B[] = {
+static const struct def_skill Skill_B[] = {
     { P_DAGGER, P_BASIC },		{ P_AXE, P_EXPERT },
     { P_PICK_AXE, P_EXPERT },		{ P_SHORT_SWORD, P_BASIC },
     { P_BROAD_SWORD, P_SKILLED },	{ P_LONG_SWORD, P_SKILLED },
@@ -288,7 +288,7 @@
     { P_NONE, 0 }
 };
 
-static struct def_skill Skill_C[] = {
+static const struct def_skill Skill_C[] = {
     { P_DAGGER, P_BASIC },		{ P_KNIFE,  P_SKILLED },
     { P_AXE, P_SKILLED },		{ P_PICK_AXE, P_BASIC },
     { P_CLUB, P_EXPERT },		{ P_MACE, P_EXPERT },
@@ -303,7 +303,7 @@
     { P_NONE, 0 }
 };
 
-static struct def_skill Skill_H[] = {
+static const struct def_skill Skill_H[] = {
     { P_DAGGER, P_SKILLED },		{ P_KNIFE, P_EXPERT },
     { P_SHORT_SWORD, P_SKILLED },	{ P_SCIMITAR, P_BASIC },
     { P_SABER, P_BASIC },		{ P_CLUB, P_SKILLED },
@@ -317,7 +317,7 @@
     { P_NONE, 0 }
 };
 
-static struct def_skill Skill_K[] = {
+static const struct def_skill Skill_K[] = {
     { P_DAGGER, P_BASIC },		{ P_KNIFE, P_BASIC },
     { P_AXE, P_SKILLED },		{ P_PICK_AXE, P_BASIC },
     { P_SHORT_SWORD, P_SKILLED },	{ P_BROAD_SWORD, P_SKILLED },
@@ -339,7 +339,7 @@
     { P_NONE, 0 }
 };
 
-static struct def_skill Skill_Mon[] = {
+static const struct def_skill Skill_Mon[] = {
     { P_QUARTERSTAFF, P_BASIC },    { P_SPEAR, P_BASIC },
     { P_JAVELIN, P_BASIC },		    { P_CROSSBOW, P_BASIC },
     { P_SHURIKEN, P_BASIC },
@@ -351,7 +351,7 @@
     { P_NONE, 0 }
 };
 
-static struct def_skill Skill_P[] = {
+static const struct def_skill Skill_P[] = {
     { P_CLUB, P_EXPERT },		{ P_MACE, P_EXPERT },
     { P_MORNING_STAR, P_EXPERT },	{ P_FLAIL, P_EXPERT },
     { P_HAMMER, P_EXPERT },		{ P_QUARTERSTAFF, P_EXPERT },
@@ -367,7 +367,7 @@
     { P_NONE, 0 }
 };
 
-static struct def_skill Skill_R[] = {
+static const struct def_skill Skill_R[] = {
     { P_DAGGER, P_EXPERT },		{ P_KNIFE,  P_EXPERT },
     { P_SHORT_SWORD, P_EXPERT },	{ P_BROAD_SWORD, P_SKILLED },
     { P_LONG_SWORD, P_SKILLED },	{ P_TWO_HANDED_SWORD, P_BASIC },
@@ -387,7 +387,7 @@
     { P_NONE, 0 }
 };
 
-static struct def_skill Skill_Ran[] = {
+static const struct def_skill Skill_Ran[] = {
     { P_DAGGER, P_EXPERT },		 { P_KNIFE,  P_SKILLED },
     { P_AXE, P_SKILLED },	 { P_PICK_AXE, P_BASIC },
     { P_SHORT_SWORD, P_BASIC },	 { P_MORNING_STAR, P_BASIC },
@@ -408,7 +408,7 @@
     { P_NONE, 0 }
 };
 
-static struct def_skill Skill_S[] = {
+static const struct def_skill Skill_S[] = {
     { P_DAGGER, P_BASIC },		{ P_KNIFE,  P_SKILLED },
     { P_SHORT_SWORD, P_EXPERT },	{ P_BROAD_SWORD, P_SKILLED },
     { P_LONG_SWORD, P_EXPERT },		{ P_TWO_HANDED_SWORD, P_EXPERT },
@@ -427,7 +427,7 @@
 };
 
 #ifdef TOURIST
-static struct def_skill Skill_T[] = {
+static const struct def_skill Skill_T[] = {
     { P_DAGGER, P_EXPERT },		{ P_KNIFE,  P_SKILLED },
     { P_AXE, P_BASIC },			{ P_PICK_AXE, P_BASIC },
     { P_SHORT_SWORD, P_EXPERT },	{ P_BROAD_SWORD, P_BASIC },
@@ -453,7 +453,7 @@
 };
 #endif /* TOURIST */
 
-static struct def_skill Skill_V[] = {
+static const struct def_skill Skill_V[] = {
     { P_DAGGER, P_EXPERT },		{ P_AXE, P_EXPERT },
     { P_PICK_AXE, P_SKILLED },		{ P_SHORT_SWORD, P_SKILLED },
     { P_BROAD_SWORD, P_SKILLED },	{ P_LONG_SWORD, P_EXPERT },
@@ -472,7 +472,7 @@
     { P_NONE, 0 }
 };
 
-static struct def_skill Skill_W[] = {
+static const struct def_skill Skill_W[] = {
     { P_DAGGER, P_EXPERT },		{ P_KNIFE,  P_SKILLED },
     { P_AXE, P_SKILLED },		{ P_SHORT_SWORD, P_BASIC },
     { P_CLUB, P_SKILLED },		{ P_MACE, P_BASIC },
@@ -850,7 +850,7 @@
 restricted_spell_discipline(otyp)
 int otyp;
 {
-    struct def_skill *skills;
+    const struct def_skill *skills;
     int this_skill = spell_skilltype(otyp);
 
     switch (Role_switch) {
@@ -980,7 +980,7 @@
 		}
 
 #ifdef GOLDOBJ
-		if (trop->trclass == GOLD_CLASS) {
+		if (trop->trclass == COIN_CLASS) {
 			/* no "blessed" or "identified" money */
 			obj->quan = u.umoney0;
 		} else {
diff -Naurd ../nethack-3.4.0/src/uhitm.c ./src/uhitm.c
--- ../nethack-3.4.0/src/uhitm.c Wed Mar 20 23:43:20 2002
+++ ./src/uhitm.c Mon Feb 24 15:25:05 2003
@@ -8,6 +8,10 @@
 STATIC_DCL void FDECL(steal_it, (struct monst *, struct attack *));
 STATIC_DCL boolean FDECL(hitum, (struct monst *,int,struct attack *));
 STATIC_DCL boolean FDECL(hmon_hitmon, (struct monst *,struct obj *,int));
+#ifdef STEED
+STATIC_DCL int FDECL(joust, (struct monst *,struct obj *));
+#endif
+STATIC_DCL void NDECL(demonpet);
 STATIC_DCL boolean FDECL(m_slips_free, (struct monst *mtmp,struct attack *mattk));
 STATIC_DCL int FDECL(explum, (struct monst *,struct attack *));
 STATIC_DCL void FDECL(start_engulf, (struct monst *));
@@ -15,6 +19,7 @@
 STATIC_DCL int FDECL(gulpum, (struct monst *,struct attack *));
 STATIC_DCL boolean FDECL(hmonas, (struct monst *,int));
 STATIC_DCL void FDECL(nohandglow, (struct monst *));
+STATIC_DCL boolean FDECL(shade_aware, (struct obj *));
 
 extern boolean notonhead;	/* for long worms */
 /* The below might become a parameter instead if we use it a lot */
@@ -205,6 +210,22 @@
 	return(FALSE);
 }
 
+/*
+ * It is unchivalrous for a knight to attack the defenseless or from behind.
+ */
+void
+check_caitiff(mtmp)
+struct monst *mtmp;
+{
+	if (Role_if(PM_KNIGHT) && u.ualign.type == A_LAWFUL &&
+	    (!mtmp->mcanmove || mtmp->msleeping ||
+	     (mtmp->mflee && !mtmp->mavenge)) &&
+	    u.ualign.record > -10) {
+	    You("caitiff!");
+	    adjalign(-1);
+	}
+}
+
 schar
 find_roll_to_hit(mtmp)
 register struct monst *mtmp;
@@ -215,14 +236,7 @@
 	tmp = 1 + Luck + abon() + find_mac(mtmp) + u.uhitinc +
 		maybe_polyd(youmonst.data->mlevel, u.ulevel);
 
-/*	it is unchivalrous to attack the defenseless or from behind */
-	if (Role_if(PM_KNIGHT) && u.ualign.type == A_LAWFUL &&
-	    (!mtmp->mcanmove || mtmp->msleeping ||
-	    (mtmp->mflee && !mtmp->mavenge)) &&
-	    u.ualign.record > -10) {
-	    You("caitiff!");
-	    adjalign(-1);
-	}
+	check_caitiff(mtmp);
 
 /*	attacking peaceful creatures is bad for the samurai's giri */
 	if (Role_if(PM_SAMURAI) && mtmp->mpeaceful &&
@@ -254,8 +268,9 @@
 	    if (uarm) {
 		Your("armor is rather cumbersome...");
 		tmp -= urole.spelarmr;
-	    } else if (!uwep)
+	    } else if (!uwep && !uarms) {
 		tmp += (u.ulevel / 3) + 2;
+	    }
 	}
 
 /*	with a lot of luggage, your agility diminishes */
@@ -410,17 +425,20 @@
 	if(!*mhit) {
 	    missum(mon, uattk);
 	} else {
-	    int oldhp = mon->mhp;
+	    int oldhp = mon->mhp,
+		x = u.ux + u.dx, y = u.uy + u.dy;
 
-		/* KMH, conduct */
-		if (uwep && (uwep->oclass == WEAPON_CLASS || is_weptool(uwep)))
-		    u.uconduct.weaphit++;
+	    /* KMH, conduct */
+	    if (uwep && (uwep->oclass == WEAPON_CLASS || is_weptool(uwep)))
+		u.uconduct.weaphit++;
 
-	    /* we hit the monster; be careful: it might die! */
-	    notonhead = (mon->mx != u.ux+u.dx || mon->my != u.uy+u.dy);
+	    /* we hit the monster; be careful: it might die or
+	       be knocked into a different location */
+	    notonhead = (mon->mx != x || mon->my != y);
 	    malive = hmon(mon, uwep, 0);
-	    /*	This assumes that Stormbringer was uwep not uswapwep */ 
-	    if (malive && u.twoweap && !override_confirmation)
+	    /* this assumes that Stormbringer was uwep not uswapwep */ 
+	    if (malive && u.twoweap && !override_confirmation &&
+		    m_at(x, y) == mon)
 		malive = hmon(mon, uswapwep, 0);
 	    if (malive) {
 		/* monster still alive */
@@ -444,7 +462,7 @@
 			--u.uconduct.weaphit;
 		}
 		if (mon->wormno && *mhit)
-			cutworm(mon, u.ux+u.dx, u.uy+u.dy, uwep);
+		    cutworm(mon, x, y, uwep);
 	    }
 	}
 	return(malive);
@@ -499,18 +517,21 @@
 	 * associated with the damage don't come out until _after_ outputting
 	 * a hit message.
 	 */
-	boolean hittxt = FALSE, destroyed = FALSE;
+	boolean hittxt = FALSE, destroyed = FALSE, already_killed = FALSE;
 	boolean get_dmg_bonus = TRUE;
 	boolean ispoisoned = FALSE, needpoismsg = FALSE, poiskilled = FALSE;
 	boolean silvermsg = FALSE;
+	boolean valid_weapon_attack = FALSE;
+	boolean unarmed = !uwep && !uarm && !uarms;
 #ifdef STEED
-	boolean jousting = FALSE;
+	int jousting = 0;
 #endif
-	boolean valid_weapon_attack = FALSE;
 	int wtype;
 	struct obj *monwep;
 	char yourbuf[BUFSZ];
+	char unconventional[BUFSZ];	/* substituted for word "attack" in msg */
 
+	unconventional[0] = '\0';
 	wakeup(mon);
 	if(!obj) {	/* attack with bare hands */
 	    if (mdat == &mons[PM_SHADE])
@@ -558,6 +579,20 @@
 			tmp = 0;
 		    else
 			tmp = rnd(2);
+		    if (!thrown && obj == uwep && obj->otyp == BOOMERANG &&
+			    rnl(4) == 4-1) {
+			boolean more_than_1 = (obj->quan > 1L);
+
+			pline("As you hit %s, %s%s %s breaks into splinters.",
+			      mon_nam(mon), more_than_1 ? "one of " : "",
+			      shk_your(yourbuf, obj), xname(obj));
+			if (!more_than_1) uwepgone();	/* set unweapon */
+			useup(obj);
+			if (!more_than_1) obj = (struct obj *) 0;
+			hittxt = TRUE;
+			if (mdat != &mons[PM_SHADE])
+			    tmp++;
+		    }
 		} else {
 		    tmp = dmgval(obj, mon);
 		    /* a minimal hit doesn't exercise proficiency */
@@ -610,20 +645,14 @@
 				&& hates_silver(mdat))
 			silvermsg = TRUE;
 #ifdef STEED
-		    if (u.usteed && !thrown &&
-				weapon_type(obj) == P_LANCE && mon != u.ustuck)
-			jousting = TRUE;
+		    if (u.usteed && !thrown && tmp > 0 &&
+			    weapon_type(obj) == P_LANCE && mon != u.ustuck) {
+			jousting = joust(mon, obj);
+			/* exercise skill even for minimal damage hits */
+			if (jousting) valid_weapon_attack = TRUE;
+		    }
 #endif
-		    if(!thrown && obj == uwep && obj->otyp == BOOMERANG &&
-		       !rnl(3)) {
-			pline("As you hit %s, %s breaks into splinters.",
-			      mon_nam(mon), the(xname(obj)));
-			useup(obj);
-			obj = (struct obj *) 0;
-			hittxt = TRUE;
-			if (mdat != &mons[PM_SHADE])
-			    tmp++;
-		    } else if(thrown && (is_ammo(obj) || is_missile(obj))) {
+		    if (thrown && (is_ammo(obj) || is_missile(obj))) {
 			if (ammo_and_launcher(obj, uwep)) {
 			    /* Elves and Samurai do extra damage using
 			     * their bows&arrows; they're highly trained.
@@ -653,14 +682,15 @@
 		mdat = mon->data;
 		tmp = (mdat == &mons[PM_SHADE]) ? 0 : 1;
 	    } else {
-		boolean shade_aware = FALSE;
-
-		switch(obj->otyp) {
+		if (mdat == &mons[PM_SHADE] && !shade_aware(obj)) {
+		    tmp = 0;
+		    Strcpy(unconventional, cxname(obj));
+		} else {
+		    switch(obj->otyp) {
 		    case BOULDER:		/* 1d20 */
 		    case HEAVY_IRON_BALL:	/* 1d25 */
 		    case IRON_CHAIN:		/* 1d4+1 */
 			tmp = dmgval(obj, mon);
-			shade_aware = TRUE;	/* dmgval handles it */
 			break;
 		    case MIRROR:
 			if (breaktest(obj)) {
@@ -669,6 +699,8 @@
 			    change_luck(-2);
 			    useup(obj);
 			    obj = (struct obj *) 0;
+			    unarmed = FALSE;	/* avoid obj==0 confusion */
+			    get_dmg_bonus = FALSE;
 			    hittxt = TRUE;
 			}
 			tmp = 1;
@@ -676,9 +708,11 @@
 #ifdef TOURIST
 		    case EXPENSIVE_CAMERA:
 			You("succeed in destroying %s camera.  Congratulations!",
-			    shk_your(yourbuf, obj));
+			        shk_your(yourbuf, obj));
 			useup(obj);
 			return(TRUE);
+			/*NOTREACHED*/
+			break;
 #endif
 		    case CORPSE:		/* fixed by polder@cs.vu.nl */
 			if (touch_petrifies(&mons[obj->corpsenm])) {
@@ -722,7 +756,7 @@
 
 			if (touch_petrifies(&mons[obj->corpsenm])) {
 			    /*learn_egg_type(obj->corpsenm);*/
-			    You("hit %s with %s %s egg%s.  Splat!",
+			    pline("Splat! You hit %s with %s %s egg%s!",
 				mon_nam(mon),
 				obj->known ? "the" : cnt > 1L ? "some" : "a",
 				obj->known ? mons[obj->corpsenm].mname : "petrifying",
@@ -825,11 +859,8 @@
 			if(tmp < 1) tmp = 1;
 			else tmp = rnd(tmp);
 			if(tmp > 6) tmp = 6;
+		    }
 		}
-
-		if (!shade_aware && mdat == &mons[PM_SHADE] && obj &&
-				objects[obj->otyp].oc_material != SILVER)
-		    tmp = 0;
 	    }
 	}
 
@@ -883,7 +914,9 @@
 	    tmp = 0;
 	    if (mdat == &mons[PM_SHADE]) {
 		if (!hittxt) {
-		    Your("attack passes harmlessly through %s.",
+		    const char *what = unconventional[0] ? unconventional : "attack";
+		    Your("%s %s harmlessly through %s.",
+		    	what, vtense(what, "pass"),
 			mon_nam(mon));
 		    hittxt = TRUE;
 		}
@@ -894,27 +927,48 @@
 
 #ifdef STEED
 	if (jousting) {
+	    tmp += d(2, (obj == uwep) ? 10 : 2);	/* [was in dmgval()] */
 	    You("joust %s%s",
 			 mon_nam(mon), canseemon(mon) ? exclam(tmp) : ".");
-	    mhurtle(mon, u.dx, u.dy, 1);
+	    if (jousting < 0) {
+		Your("%s shatters on impact!", xname(obj));
+		/* (must be either primary or secondary weapon to get here) */
+		u.twoweap = FALSE;	/* untwoweapon() is too verbose here */
+		if (obj == uwep) uwepgone();		/* set unweapon */
+		/* minor side-effect: broken lance won't split puddings */
+		useup(obj);
+		obj = 0;
+	    }
+	    /* avoid migrating a dead monster */
+	    if (mon->mhp > tmp) {
+		mhurtle(mon, u.dx, u.dy, 1);
+		if (DEADMONSTER(mon)) already_killed = TRUE;
+	    }
 	    hittxt = TRUE;
 	} else
 #endif
 
 	/* VERY small chance of stunning opponent if unarmed. */
-	if (tmp > 1 && !thrown && !obj && !uwep && !uarm && !uarms && !Upolyd) {
+	if (unarmed && tmp > 1 && !thrown && !obj && !Upolyd) {
 	    if (rnd(100) < P_SKILL(P_BARE_HANDED_COMBAT) &&
 			!bigmonst(mdat) && !thick_skinned(mdat)) {
 		if (canspotmon(mon))
 		    pline("%s %s from your powerful strike!", Monnam(mon),
 			  makeplural(stagger(mon->data, "stagger")));
-		mhurtle(mon, u.dx, u.dy, 1);
+		/* avoid migrating a dead monster */
+		if (mon->mhp > tmp) {
+		    mhurtle(mon, u.dx, u.dy, 1);
+		    if (DEADMONSTER(mon)) already_killed = TRUE;
+		}
 		hittxt = TRUE;
 	    }
 	}
 
-	mon->mhp -= tmp;
-	if(mon->mhp < 1)
+	if (!already_killed) mon->mhp -= tmp;
+	/* adjustments might have made tmp become less than what
+	   a level draining artifact has already done to max HP */
+	if (mon->mhp > mon->mhpmax) mon->mhp = mon->mhpmax;
+	if (mon->mhp < 1)
 		destroyed = TRUE;
 	if (mon->mtame && (!mon->mflee || mon->mfleetim) && tmp > 0) {
 		abuse_dog(mon);
@@ -964,13 +1018,14 @@
 		pline_The("poison doesn't seem to affect %s.", mon_nam(mon));
 	if (poiskilled) {
 		pline_The("poison was deadly...");
-		xkilled(mon, 0);
+		if (!already_killed) xkilled(mon, 0);
 		return FALSE;
 	} else if (destroyed) {
-		killed(mon);	/* takes care of most messages */
+		if (!already_killed)
+		    killed(mon);	/* takes care of most messages */
 	} else if(u.umconf && !thrown) {
 		nohandglow(mon);
-		if(!mon->mconf && !resist(mon, '+', 0, NOTELL)) {
+		if (!mon->mconf && !resist(mon, SPBOOK_CLASS, 0, NOTELL)) {
 			mon->mconf = 1;
 			if (!mon->mstun && mon->mcanmove && !mon->msleeping &&
 				canseemon(mon))
@@ -981,6 +1036,27 @@
 	return((boolean)(destroyed ? FALSE : TRUE));
 }
 
+STATIC_OVL boolean
+shade_aware(obj)
+struct obj *obj;
+{
+	if (!obj) return FALSE;
+	/*
+	 * The things in this list either
+	 * 1) affect shades.
+	 *  OR
+	 * 2) are dealt with properly by other routines
+	 *    when it comes to shades.
+	 */
+	if (obj->otyp == BOULDER || obj->otyp == HEAVY_IRON_BALL
+	    || obj->otyp == IRON_CHAIN		/* dmgval handles those first three */
+	    || obj->otyp == MIRROR		/* silver in the reflective surface */
+	    || obj->otyp == CLOVE_OF_GARLIC	/* causes shades to flee */
+	    || objects[obj->otyp].oc_material == SILVER)
+		return TRUE;
+	return FALSE;
+}
+
 /* check whether slippery clothing protects from hug or wrap attack */
 /* [currently assumes that you are the attacker] */
 STATIC_OVL boolean
@@ -1025,7 +1101,34 @@
 	return FALSE;
 }
 
-STATIC_DCL void NDECL(demonpet);
+/* used when hitting a monster with a lance while mounted */
+STATIC_OVL int	/* 1: joust hit; 0: ordinary hit; -1: joust but break lance */
+joust(mon, obj)
+struct monst *mon;	/* target */
+struct obj *obj;	/* weapon */
+{
+    int skill_rating, joust_dieroll;
+
+    if (Fumbling || Stunned) return 0;
+    /* sanity check; lance must be wielded in order to joust */
+    if (obj != uwep && (obj != uswapwep || !u.twoweap)) return 0;
+
+    /* if using two weapons, use worse of lance and two-weapon skills */
+    skill_rating = P_SKILL(weapon_type(obj));	/* lance skill */
+    if (u.twoweap && P_SKILL(P_TWO_WEAPON_COMBAT) < skill_rating)
+	skill_rating = P_SKILL(P_TWO_WEAPON_COMBAT);
+    if (skill_rating == P_ISRESTRICTED) skill_rating = P_UNSKILLED; /* 0=>1 */
+
+    /* odds to joust are expert:80%, skilled:60%, basic:40%, unskilled:20% */
+    if ((joust_dieroll = rn2(5)) < skill_rating) {
+	if (joust_dieroll == 0 && rnl(50) == (50-1) &&
+		!unsolid(mon->data) && !obj_resists(obj, 0, 100))
+	    return -1;	/* hit that breaks lance */
+	return 1;	/* successful joust */
+    }
+    return 0;	/* no joust bonus; revert to ordinary attack */
+}
+
 /*
  * Send in a demon pet for the hero.  Exercise wisdom.
  *
@@ -1098,22 +1201,26 @@
 	}
 
 	while ((otmp = mdef->minvent) != 0) {
+	    if (!Upolyd) break;		/* no longer have ability to steal */
 	    /* take the object away from the monster */
 	    obj_extract_self(otmp);
 	    if ((unwornmask = otmp->owornmask) != 0L) {
 		mdef->misc_worn_check &= ~unwornmask;
-		if (otmp->owornmask & W_WEP)
+		if (otmp->owornmask & W_WEP) {
 		    setmnotwielded(mdef,otmp);
+		    MON_NOWEP(mdef);
+		}
 		otmp->owornmask = 0L;
-		update_mon_intrinsics(mdef, otmp, FALSE);
+		update_mon_intrinsics(mdef, otmp, FALSE, FALSE);
 
 		if (otmp == stealoid)	/* special message for final item */
 		    pline("%s finishes taking off %s suit.",
 			  Monnam(mdef), mhis(mdef));
 	    }
 	    /* give the object to the character */
-	    otmp = hold_another_object(otmp, "You steal %s.",
+	    otmp = hold_another_object(otmp, "You snatched but dropped %s.",
 				       doname(otmp), "You steal: ");
+	    if (otmp->where != OBJ_INVENT) continue;
 	    if (otmp->otyp == CORPSE &&
 		    touch_petrifies(&mons[otmp->corpsenm]) && !uarmg) {
 		char kbuf[BUFSZ];
@@ -1124,7 +1231,7 @@
 	    }
 	    /* more take-away handling, after theft message */
 	    if (unwornmask & W_WEP) {		/* stole wielded weapon */
-		possibly_unwield(mdef);
+		possibly_unwield(mdef, FALSE);
 	    } else if (unwornmask & W_ARMG) {	/* stole worn gloves */
 		mselftouch(mdef, (const char *)0, TRUE);
 		if (mdef->mhp <= 0)	/* it's now a statue */
@@ -1142,6 +1249,12 @@
 {
 	register struct permonst *pd = mdef->data;
 	register int	tmp = d((int)mattk->damn, (int)mattk->damd);
+	int armpro;
+	boolean negated;
+
+	armpro = magic_negation(mdef);
+	/* since hero can't be cancelled, only defender's armor applies */
+	negated = !((rn2(3) >= armpro) || !rn2(50));
 
 	if (is_demon(youmonst.data) && !rn2(13) && !uwep
 		&& u.umonnum != PM_SUCCUBUS && u.umonnum != PM_INCUBUS
@@ -1155,11 +1268,17 @@
 		    pline("%s %s for a moment.", Monnam(mdef),
 			  makeplural(stagger(mdef->data, "stagger")));
 		mdef->mstun = 1;
-		/* fall through to next case */
-	    case AD_WERE:	    /* no effect on monsters */
-	    case AD_HEAL:
+		goto physical;
 	    case AD_LEGS:
+	     /* if (u.ucancelled) { */
+	     /*    tmp = 0;	    */
+	     /*    break;	    */
+	     /* }		    */
+		goto physical;
+	    case AD_WERE:	    /* no special effect on monsters */
+	    case AD_HEAL:	    /* likewise */
 	    case AD_PHYS:
+ physical:
 		if(mattk->aatyp == AT_WEAP) {
 		    if(uwep) tmp = 0;
 		} else if(mattk->aatyp == AT_KICK) {
@@ -1174,16 +1293,21 @@
 		}
 		break;
 	    case AD_FIRE:
+		if (negated) {
+		    tmp = 0;
+		    break;
+		}
 		if (!Blind)
 		    pline("%s is %s!", Monnam(mdef),
-			  mdef->data == &mons[PM_WATER_ELEMENTAL] ? "boiling" :
-			  mattk->aatyp == AT_HUGS ?
-				"being roasted" : "on fire");
+			  on_fire(mdef->data, mattk));
 		if (pd == &mons[PM_STRAW_GOLEM] ||
 		    pd == &mons[PM_PAPER_GOLEM]) {
 		    if (!Blind)
-		    	pline("%s burns completely!", Monnam(mdef));
-		    xkilled(mdef,0);
+			pline("%s burns completely!", Monnam(mdef));
+		    xkilled(mdef,2);
+		    tmp = 0;
+		    break;
+		    /* Don't return yet; keep hp<1 and tmp=0 for pet msg */
 		}
 		tmp += destroy_mitem(mdef, SCROLL_CLASS, AD_FIRE);
 		tmp += destroy_mitem(mdef, SPBOOK_CLASS, AD_FIRE);
@@ -1198,6 +1322,10 @@
 		tmp += destroy_mitem(mdef, POTION_CLASS, AD_FIRE);
 		break;
 	    case AD_COLD:
+		if (negated) {
+		    tmp = 0;
+		    break;
+		}
 		if (!Blind) pline("%s is covered in frost!", Monnam(mdef));
 		if (resists_cold(mdef)) {
 		    shieldeff(mdef->mx, mdef->my);
@@ -1209,6 +1337,10 @@
 		tmp += destroy_mitem(mdef, POTION_CLASS, AD_COLD);
 		break;
 	    case AD_ELEC:
+		if (negated) {
+		    tmp = 0;
+		    break;
+		}
 		if (!Blind) pline("%s is zapped!", Monnam(mdef));
 		tmp += destroy_mitem(mdef, WAND_CLASS, AD_ELEC);
 		if (resists_elec(mdef)) {
@@ -1265,8 +1397,8 @@
 		tmp = 0;
 		break;
 	    case AD_TLPT:
-		if(tmp <= 0) tmp = 1;
-		if(tmp < mdef->mhp) {
+		if (tmp <= 0) tmp = 1;
+		if (!negated && tmp < mdef->mhp) {
 		    char nambuf[BUFSZ];
 		    boolean u_saw_mon = canseemon(mdef);
 		    /* record the name before losing sight of monster */
@@ -1303,7 +1435,7 @@
 		tmp = 0;
 		break;
 	    case AD_DRLI:
-		if (rn2(2) && !resists_drli(mdef)) {
+		if (!negated && !rn2(3) && !resists_drli(mdef)) {
 			int xtmp = d(2,6);
 			pline("%s suddenly seems weaker!", Monnam(mdef));
 			mdef->mhpmax -= xtmp;
@@ -1312,8 +1444,8 @@
 				xkilled(mdef,0);
 			} else
 				mdef->m_lev--;
+			tmp = 0;
 		}
-		tmp = 0;
 		break;
 	    case AD_RUST:
 		if (pd == &mons[PM_IRON_GOLEM]) {
@@ -1339,7 +1471,7 @@
 	    case AD_DRST:
 	    case AD_DRDX:
 	    case AD_DRCO:
-		if (!rn2(8)) {
+		if (!negated && !rn2(8)) {
 		    Your("%s was poisoned!", mpoisons_subj(&youmonst, mattk));
 		    if (resists_poison(mdef))
 			pline_The("poison doesn't seem to affect %s.",
@@ -1398,7 +1530,7 @@
 		exercise(A_WIS, TRUE);
 		break;
 	    case AD_STCK:
-		if (!sticks(mdef->data))
+		if (!negated && !sticks(mdef->data))
 		    u.ustuck = mdef; /* it's now stuck to you */
 		break;
 	    case AD_WRAP:
@@ -1413,7 +1545,8 @@
 			}
 		    } else if(u.ustuck == mdef) {
 			/* Monsters don't wear amulets of magical breathing */
-			if (is_pool(u.ux,u.uy) && !is_swimmer(mdef->data)) {
+			if (is_pool(u.ux,u.uy) && !is_swimmer(mdef->data) &&
+			    !amphibious(mdef->data)) {
 			    You("drown %s...", mon_nam(mdef));
 			    tmp = mdef->mhp;
 			} else if(mattk->aatyp == AT_HUGS)
@@ -1428,36 +1561,56 @@
 		} else tmp = 0;
 		break;
 	    case AD_PLYS:
-		if (mdef->mcanmove && !rn2(3) && tmp < mdef->mhp) {
+		if (!negated && mdef->mcanmove && !rn2(3) && tmp < mdef->mhp) {
 		    if (!Blind) pline("%s is frozen by you!", Monnam(mdef));
 		    mdef->mcanmove = 0;
 		    mdef->mfrozen = rnd(10);
 		}
 		break;
 	    case AD_SLEE:
-		if (!mdef->msleeping && sleep_monst(mdef, rnd(10), -1)) {
+		if (!negated && !mdef->msleeping &&
+			    sleep_monst(mdef, rnd(10), -1)) {
 		    if (!Blind)
 			pline("%s is put to sleep by you!", Monnam(mdef));
 		    slept_monst(mdef);
 		}
 		break;
 	    case AD_SLIM:
-	    	if (!rn2(4) && mdef->data != &mons[PM_FIRE_VORTEX] &&
-	    			mdef->data != &mons[PM_FIRE_ELEMENTAL] &&
-	    			mdef->data != &mons[PM_SALAMANDER] &&
-	    			mdef->data != &mons[PM_GREEN_SLIME]) {
-	    	    You("turn %s into slime.", mon_nam(mdef));
-	    	    (void) newcham(mdef, &mons[PM_GREEN_SLIME], FALSE);
-	    	    tmp = 0;
-	    	}
-	    	break;
+		if (negated) break;	/* physical damage only */
+		if (!rn2(4) && mdef->data != &mons[PM_FIRE_VORTEX] &&
+				mdef->data != &mons[PM_FIRE_ELEMENTAL] &&
+				mdef->data != &mons[PM_SALAMANDER] &&
+				mdef->data != &mons[PM_GREEN_SLIME]) {
+		    You("turn %s into slime.", mon_nam(mdef));
+		    (void) newcham(mdef, &mons[PM_GREEN_SLIME], FALSE, FALSE);
+		    tmp = 0;
+		}
+		break;
 	    case AD_ENCH:	/* KMH -- remove enchantment (disenchanter) */
-			/* There's no msomearmor() function, so just do damage */
-			break;
+		/* there's no msomearmor() function, so just do damage */
+	     /* if (negated) break; */
+		break;
+	    case AD_SLOW:
+		if (!negated && mdef->mspeed != MSLOW) {
+		    unsigned int oldspeed = mdef->mspeed;
+
+		    mon_adjust_speed(mdef, -1, (struct obj *)0);
+		    if (mdef->mspeed != oldspeed && canseemon(mdef))
+			pline("%s slows down.", Monnam(mdef));
+		}
+		break;
+	    case AD_CONF:
+		if (!mdef->mconf) {
+		    if (canseemon(mdef))
+			pline("%s looks confused.", Monnam(mdef));
+		    mdef->mconf = 1;
+		}
+		break;
 	    default:	tmp = 0;
-			break;
+		break;
 	}
 
+	mdef->mstrategy &= ~STRAT_WAITFORU; /* in case player is very fast */
 	if((mdef->mhp -= tmp) < 1) {
 	    if (mdef->mtame && !cansee(mdef->mx,mdef->my)) {
 		You_feel("embarrassed for a moment.");
@@ -1573,8 +1726,7 @@
 	    for (otmp = mdef->minvent; otmp; otmp = otmp->nobj)
 		(void) snuff_lit(otmp);
 
-	    if((!touch_petrifies(mdef->data) || Stone_resistance) &&
-		    (Unchanging || mdef->data != &mons[PM_GREEN_SLIME])) {
+	    if(!touch_petrifies(mdef->data) || Stone_resistance) {
 #ifdef LINT	/* static char msgbuf[BUFSZ]; */
 		char msgbuf[BUFSZ];
 #else
@@ -1636,6 +1788,14 @@
 				nomul(-tmp);
 				nomovemsg = msgbuf;
 			    } else pline("%s", msgbuf);
+			    if (mdef->data == &mons[PM_GREEN_SLIME]) {
+				Sprintf(msgbuf, "%s isn't sitting well with you.",
+					The(mdef->data->mname));
+				if (!Unchanging) {
+					Slimed = 5L;
+					flags.botl = 1;
+				}
+			    } else
 			    exercise(A_CON, TRUE);
 			}
 			end_engulf();
@@ -1910,8 +2070,10 @@
 			impossible("strange attack of yours (%d)",
 				 mattk->aatyp);
 	    }
-	    if (dhit == -1)
+	    if (dhit == -1) {
+		u.mh = -1;	/* dead in the current form */
 		rehumanize();
+	    }
 	    if (sum[i] == 2)
 		return((boolean)passive(mon, 1, 0, mattk->aatyp));
 							/* defender dead */
@@ -1976,21 +2138,26 @@
 	    exercise(A_STR, FALSE);
 	    break;
 	  case AD_STON:
-	    if(mhit) {
-	      /* mhit does not mean you physically hit; it just means the
-	         attack was successful */
-	      if ((aatyp == AT_KICK && !uarmf) ||
-		    ((aatyp == AT_WEAP || aatyp == AT_CLAW || aatyp == AT_MAGC
-				|| aatyp == AT_TUCH) && !uwep && !uarmg) ||
-		    aatyp == AT_BITE || aatyp == AT_STNG || aatyp == AT_BUTT ||
-		    aatyp == AT_TENT || aatyp == AT_HUGS || aatyp == AT_ENGL) {
-		if (!Stone_resistance &&
-		    !(poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))) {
+	    if (mhit) {		/* successful attack */
+		long protector = attk_protection((int)aatyp);
+
+		/* hero using monsters' AT_MAGC attack is hitting hand to
+		   hand rather than casting a spell */
+		if (aatyp == AT_MAGC) protector = W_ARMG;
+
+		if (protector == 0L ||		/* no protection */
+			(protector == W_ARMG && !uarmg && !uwep) ||
+			(protector == W_ARMF && !uarmf) ||
+			(protector == W_ARMH && !uarmh) ||
+			(protector == (W_ARMC|W_ARMG) && (!uarmc || !uarmg))) {
+		    if (!Stone_resistance &&
+			    !(poly_when_stoned(youmonst.data) &&
+				polymon(PM_STONE_GOLEM))) {
 			You("turn to stone...");
 			done_in_by(mon);
 			return 2;
+		    }
 		}
-	      }
 	    }
 	    break;
 	  case AD_RUST:
@@ -2239,13 +2406,13 @@
 		if (Blind)
 			Your("%s stop tingling.", hands);
 		else
-			Your("%s stop glowing %s.", hands, hcolor(red));
+			Your("%s stop glowing %s.", hands, hcolor(NH_RED));
 	} else {
 		if (Blind)
 			pline_The("tingling in your %s lessens.", hands);
 		else
 			Your("%s no longer glow so brightly %s.", hands,
-				hcolor(red));
+				hcolor(NH_RED));
 	}
 	u.umconf--;
 }
diff -Naurd ../nethack-3.4.0/src/vault.c ./src/vault.c
--- ../nethack-3.4.0/src/vault.c Wed Mar 20 23:43:20 2002
+++ ./src/vault.c Mon Feb 24 15:25:05 2003
@@ -133,7 +133,7 @@
     int dummy;		/* hack to avoid schain botch */
 #endif
     struct monst *guard;
-    int vaultroom = (int)vault_occupied(u.urooms);
+    int trycount, vaultroom = (int)vault_occupied(u.urooms);
 
     if(!vaultroom) {
 	u.uinvault = 0;
@@ -234,31 +234,38 @@
 	EGD(guard)->vroom = vaultroom;
 	EGD(guard)->warncnt = 0;
 
-	if(!cansee(guard->mx, guard->my)) {
-		mongone(guard);
-		return;
-	}
-
 	reset_faint();			/* if fainted - wake up */
-	pline("Suddenly one of the Vault's %s enters!",
-	      makeplural(g_monnam(guard)));
+	if (canspotmon(guard))
+	    pline("Suddenly one of the Vault's %s enters!",
+		  makeplural(g_monnam(guard)));
+	else
+	    pline("Someone else has entered the Vault.");
 	newsym(guard->mx,guard->my);
-	if ((youmonst.m_ap_type == M_AP_OBJECT &&
-		youmonst.mappearance == GOLD_PIECE) || u.uundetected) {
-	    /* You're mimicking a pile of gold or you're hidden. */
+	if (youmonst.m_ap_type == M_AP_OBJECT || u.uundetected) {
+	    if (youmonst.m_ap_type == M_AP_OBJECT &&
+			youmonst.mappearance != GOLD_PIECE)
+	    	verbalize("Hey! Who left that %s in here?", mimic_obj_name(&youmonst));
+	    /* You're mimicking some object or you're hidden. */
 	    pline("Puzzled, %s turns around and leaves.", mhe(guard));
 	    mongone(guard);
 	    return;
 	}
-	if (Strangled || is_silent(youmonst.data)) {
+	if (Strangled || is_silent(youmonst.data) || multi < 0) {
+	    /* [we ought to record whether this this message has already
+	       been given in order to vary it upon repeat visits, but
+	       discarding the monster and its egd data renders that hard] */
 	    verbalize("I'll be back when you're ready to speak to me!");
 	    mongone(guard);
 	    return;
 	}
+
 	stop_occupation();		/* if occupied, stop it *now* */
+	if (multi > 0) { nomul(0); unmul((char *)0); }
+	trycount = 5;
 	do {
-		getlin("\"Hello stranger, who are you?\" -",buf);
-	} while (!letter(buf[0]));
+	    getlin("\"Hello stranger, who are you?\" -", buf);
+	    (void) mungspaces(buf);
+	} while (!letter(buf[0]) && --trycount > 0);
 
 	if (u.ualign.type == A_LAWFUL &&
 	    /* ignore trailing text, in case player includes character's rank */
@@ -362,20 +369,24 @@
 wallify_vault(grd)
 struct monst *grd;
 {
-	int x, y;
+	int x, y, typ;
 	int vlt = EGD(grd)->vroom;
 	char tmp_viz;
-	xchar lowx = rooms[vlt].lx, hix = rooms[vlt].hx;
-	xchar lowy = rooms[vlt].ly, hiy = rooms[vlt].hy;
-	register struct obj *gold;
-	register boolean fixed = FALSE;
-	register boolean movedgold = FALSE;
+	xchar lox = rooms[vlt].lx - 1, hix = rooms[vlt].hx + 1,
+	      loy = rooms[vlt].ly - 1, hiy = rooms[vlt].hy + 1;
+	struct monst *mon;
+	struct obj *gold;
+	struct trap *trap;
+	boolean fixed = FALSE;
+	boolean movedgold = FALSE;
 
-	for(x = lowx-1; x <= hix+1; x++)
-	    for(y = lowy-1; y <= hiy+1; y += (hiy-lowy+2)) {
-		if(!IS_WALL(levl[x][y].typ) && !in_fcorridor(grd, x, y)) {
-		    if(MON_AT(x, y) && grd->mx != x && grd->my != y) {
-			struct monst *mon = m_at(x,y);
+	for (x = lox; x <= hix; x++)
+	    for (y = loy; y <= hiy; y++) {
+		/* if not on the room boundary, skip ahead */
+		if (x != lox && x != hix && y != loy && y != hiy) continue;
+
+		if (!IS_WALL(levl[x][y].typ) && !in_fcorridor(grd, x, y)) {
+		    if ((mon = m_at(x, y)) != 0 && mon != grd) {
 			if (mon->mtame) yelp(mon);
 			rloc(mon);
 		    }
@@ -383,16 +394,17 @@
 			move_gold(gold, EGD(grd)->vroom);
 			movedgold = TRUE;
 		    }
-		    if(x == lowx-1 && y == lowy-1)
-			levl[x][y].typ = TLCORNER;
-		    else if(x == hix+1 && y == lowy-1)
-			levl[x][y].typ = TRCORNER;
-		    else if(x == lowx-1 && y == hiy+1)
-			levl[x][y].typ = BLCORNER;
-		    else if(x == hix+1 && y == hiy+1)
-			levl[x][y].typ = BRCORNER;
-		    else levl[x][y].typ = HWALL;
-
+		    if ((trap = t_at(x, y)) != 0)
+			deltrap(trap);
+		    if (x == lox)
+			typ = (y == loy) ? TLCORNER :
+			      (y == hiy) ? BLCORNER : VWALL;
+		    else if (x == hix)
+			typ = (y == loy) ? TRCORNER :
+			      (y == hiy) ? BRCORNER : VWALL;
+		    else  /* not left or right side, must be top or bottom */
+			typ = HWALL;
+		    levl[x][y].typ = typ;
 		    levl[x][y].doormask = 0;
 		    /*
 		     * hack: player knows walls are restored because of the
@@ -406,28 +418,6 @@
 		    fixed = TRUE;
 		}
 	    }
-	for(x = lowx-1; x <= hix+1; x += (hix-lowx+2))
-	    for(y = lowy; y <= hiy; y++) {
-		if(!IS_WALL(levl[x][y].typ) && !in_fcorridor(grd, x, y)) {
-		    if(MON_AT(x, y) && grd->mx != x && grd->my != y) {
-			struct monst *mon = m_at(x,y);
-			if (mon->mtame) yelp(mon);
-			rloc(mon);
-		    }
-		    if ((gold = g_at(x, y)) != 0) {
-			move_gold(gold, EGD(grd)->vroom);
-			movedgold = TRUE;
-		    }
-		    levl[x][y].typ = VWALL;
-		    levl[x][y].doormask = 0;
-		    tmp_viz = viz_array[y][x];
-		    viz_array[y][x] = IN_SIGHT|COULD_SEE;
-		    newsym(x,y);
-		    viz_array[y][x] = tmp_viz;
-		    block_point(x,y);
-		    fixed = TRUE;
-		}
-	    }
 
 	if(movedgold || fixed) {
 	    if(in_fcorridor(grd, grd->mx, grd->my) || cansee(grd->mx, grd->my))
@@ -464,6 +454,8 @@
         long umoney = money_cnt(invent);
 	register boolean u_carry_gold = ((umoney + hidden_gold()) > 0L);
 #endif
+	boolean see_guard;
+
 	if(!on_level(&(egrd->gdlevel), &u.uz)) return(-1);
 	nx = ny = m = n = 0;
 	if(!u_in_vault && !grd_in_vault)
@@ -720,6 +712,7 @@
 cleanup:
 		x = grd->mx; y = grd->my;
 
+		see_guard = canspotmon(grd);
 		wallify_vault(grd);
 		remove_monster(grd->mx, grd->my);
 		newsym(grd->mx,grd->my);
@@ -729,7 +722,7 @@
 		restfakecorr(grd);
 		if(!semi_dead && (in_fcorridor(grd, u.ux, u.uy) ||
 				     cansee(x, y))) {
-		    if (!disappear_msg_seen)
+		    if (!disappear_msg_seen && see_guard)
 			pline("Suddenly, the %s disappears.", g_monnam(grd));
 		    return(1);
 		}
@@ -795,7 +788,7 @@
 #else
         for (coins = invent; coins; coins = nextcoins) {
             nextcoins = coins->nobj;
-	    if (objects[coins->otyp].oc_class == GOLD_CLASS) {
+	    if (objects[coins->otyp].oc_class == COIN_CLASS) {
 	        freeinv(coins);
                 place_object(coins, gx, gy);
 		stackobj(coins);
diff -Naurd ../nethack-3.4.0/src/version.c ./src/version.c
--- ../nethack-3.4.0/src/version.c Wed Mar 20 23:43:20 2002
+++ ./src/version.c Mon Feb 24 15:25:05 2003
@@ -14,12 +14,21 @@
 #include "patchlevel.h"
 #endif
 
+/* #define BETA_INFO "" */
+
 /* fill and return the given buffer with the nethack version string */
 char *
 getversionstring(buf)
 char *buf;
 {
-	return strcpy(buf, VERSION_ID);
+	 Strcpy(buf, VERSION_ID);
+#if defined(BETA) && defined(BETA_INFO)
+	 Sprintf(eos(buf), " %s", BETA_INFO);
+#endif
+#if defined(RUNTIME_PORT_ID)
+	 append_port_id(buf);
+#endif
+	return buf;
 }
 
 int
@@ -27,7 +36,7 @@
 {
 	char buf[BUFSZ];
 
-	pline(getversionstring(buf));
+	pline("%s", getversionstring(buf));
 	return 0;
 }
 
@@ -64,7 +73,13 @@
 	    if (complain)
 		pline("Version mismatch for file \"%s\".", filename);
 	    return FALSE;
-	} else if (version_data->feature_set != VERSION_FEATURES ||
+	} else if (
+#ifndef IGNORED_FEATURES
+		   version_data->feature_set != VERSION_FEATURES ||
+#else
+		   (version_data->feature_set & ~IGNORED_FEATURES) !=
+			  (VERSION_FEATURES & ~IGNORED_FEATURES) ||
+#endif
 		   version_data->entity_count != VERSION_SANITY1 ||
 		   version_data->struct_sizes != VERSION_SANITY2) {
 	    if (complain)
@@ -106,7 +121,7 @@
 store_version(fd)
 int fd;
 {
-	static struct version_info version_data = {
+	const static struct version_info version_data = {
 			VERSION_NUMBER, VERSION_FEATURES,
 			VERSION_SANITY1, VERSION_SANITY2
 	};
diff -Naurd ../nethack-3.4.0/src/weapon.c ./src/weapon.c
--- ../nethack-3.4.0/src/weapon.c Wed Mar 20 23:43:21 2002
+++ ./src/weapon.c Mon Feb 24 15:25:05 2003
@@ -56,7 +56,7 @@
 };
 
 /* note: entry [0] isn't used */
-STATIC_VAR NEARDATA const char *odd_skill_names[] = {
+STATIC_VAR NEARDATA const char * const odd_skill_names[] = {
     "no skill",
     "bare hands",		/* use barehands_or_martial[] instead */
     "two weapon combat",
@@ -74,12 +74,12 @@
     "matter spells",
 };
 /* indexed vis `is_martial() */
-STATIC_VAR NEARDATA const char *barehands_or_martial[] = {
+STATIC_VAR NEARDATA const char * const barehands_or_martial[] = {
     "bare handed combat", "martial arts"
 };
 
-STATIC_OVL
-void give_may_advance_msg(skill)
+STATIC_OVL void
+give_may_advance_msg(skill)
 int skill;
 {
 	You_feel("more confident in your %sskills.",
@@ -286,13 +286,6 @@
 		otmp->oclass == BALL_CLASS || otmp->oclass == CHAIN_CLASS) {
 	    int bonus = 0;
 
-#ifdef STEED
-		/* KMH -- Lances are especially made for riding */
-		if (otmp == uwep && u.usteed &&
-				objects[otmp->otyp].oc_skill == P_LANCE)
-			bonus += d(2,10);
-#endif
-
 	    if (otmp->blessed && (is_undead(ptr) || is_demon(ptr)))
 		bonus += rnd(4);
 	    if (is_axe(otmp) && is_wooden(ptr))
@@ -472,7 +465,7 @@
 }
 
 /* Weapons in order of preference */
-static NEARDATA short hwep[] = {
+static const NEARDATA short hwep[] = {
 	  CORPSE,  /* cockatrice corpse */
 	  TSURUGI, RUNESWORD, DWARVISH_MATTOCK, TWO_HANDED_SWORD, BATTLE_AXE,
 	  KATANA, UNICORN_HORN, CRYSKNIFE, TRIDENT, LONG_SWORD,
@@ -527,18 +520,18 @@
 }
 
 /* Called after polymorphing a monster, robbing it, etc....  Monsters
- * otherwise never unwield stuff on their own.  Shouldn't print messages.
+ * otherwise never unwield stuff on their own.  Might print message.
  */
 void
-possibly_unwield(mon)
-register struct monst *mon;
+possibly_unwield(mon, polyspot)
+struct monst *mon;
+boolean polyspot;
 {
-	register struct obj *obj;
-	struct obj *mw_tmp;
+	struct obj *obj, *mw_tmp;
 
 	if (!(mw_tmp = MON_WEP(mon)))
 		return;
-	for(obj=mon->minvent; obj; obj=obj->nobj)
+	for (obj = mon->minvent; obj; obj = obj->nobj)
 		if (obj == mw_tmp) break;
 	if (!obj) { /* The weapon was stolen or destroyed */
 		MON_NOWEP(mon);
@@ -550,13 +543,16 @@
 		MON_NOWEP(mon);
 		mon->weapon_check = NO_WEAPON_WANTED;
 		obj_extract_self(obj);
-		/* flooreffects unnecessary, can't wield boulders */
-		place_object(obj, mon->mx, mon->my);
-		stackobj(obj);
 		if (cansee(mon->mx, mon->my)) {
-			pline("%s drops %s.", Monnam(mon),
-				distant_name(obj, doname));
-			newsym(mon->mx, mon->my);
+		    pline("%s drops %s.", Monnam(mon),
+			  distant_name(obj, doname));
+		    newsym(mon->mx, mon->my);
+		}
+		/* might be dropping object into water or lava */
+		if (!flooreffects(obj, mon->mx, mon->my, "drop")) {
+		    if (polyspot) bypass_obj(obj);
+		    place_object(obj, mon->mx, mon->my);
+		    stackobj(obj);
 		}
 		return;
 	}
@@ -575,6 +571,7 @@
 	 */
 	if (!(mw_tmp->cursed && mon->weapon_check == NO_WEAPON_WANTED))
 	    mon->weapon_check = NEED_WEAPON;
+	return;
 }
 
 /* Let a monster try to wield a weapon, based on mon->weapon_check.
@@ -599,7 +596,23 @@
 		case NEED_PICK_AXE:
 			obj = m_carrying(mon, PICK_AXE);
 			/* KMH -- allow other picks */
-			if (!obj) obj = m_carrying(mon, DWARVISH_MATTOCK);
+			if (!obj && !which_armor(mon, W_ARMS))
+			    obj = m_carrying(mon, DWARVISH_MATTOCK);
+			break;
+		case NEED_AXE:
+			/* currently, only 2 types of axe */
+			obj = m_carrying(mon, BATTLE_AXE);
+			if (!obj || which_armor(mon, W_ARMS))
+			    obj = m_carrying(mon, AXE);
+			break;
+		case NEED_PICK_OR_AXE:
+			/* prefer pick for fewer switches on most levels */
+			obj = m_carrying(mon, DWARVISH_MATTOCK);
+			if (!obj) obj = m_carrying(mon, BATTLE_AXE);
+			if (!obj || which_armor(mon, W_ARMS)) {
+			    obj = m_carrying(mon, PICK_AXE);
+			    if (!obj) obj = m_carrying(mon, AXE);
+			}
 			break;
 		default: impossible("weapon_check %d for %s?",
 				mon->weapon_check, mon_nam(mon));
@@ -819,7 +832,7 @@
 	P_NAME(skill));
 }
 
-static struct skill_range {
+const static struct skill_range {
 	short first, last;
 	const char *name;
 } skill_ranges[] = {
@@ -871,7 +884,7 @@
 	    /* start with a legend if any entries will be annotated
 	       with "*" or "#" below */
 	    if (eventually_advance > 0 || maxxed_cnt > 0) {
-		any.a_int = 0;
+		any.a_void = 0;
 		if (eventually_advance > 0) {
 		    Sprintf(buf,
 			    "(Skill%s flagged by \"*\" may be enhanced %s.)",
@@ -1221,7 +1234,7 @@
  */
 void
 skill_init(class_skill)
-struct def_skill *class_skill;
+const struct def_skill *class_skill;
 {
 	struct obj *obj;
 	int skmax, skill;
diff -Naurd ../nethack-3.4.0/src/were.c ./src/were.c
--- ../nethack-3.4.0/src/were.c Wed Mar 20 23:43:21 2002
+++ ./src/were.c Mon Feb 24 15:25:05 2003
@@ -83,7 +83,7 @@
 	mon->mhp += (mon->mhpmax - mon->mhp) / 4;
 	newsym(mon->mx,mon->my);
 	mon_break_armor(mon, FALSE);
-	possibly_unwield(mon);
+	possibly_unwield(mon, FALSE);
 }
 
 boolean
diff -Naurd ../nethack-3.4.0/src/wield.c ./src/wield.c
--- ../nethack-3.4.0/src/wield.c Wed Mar 20 23:43:21 2002
+++ ./src/wield.c Mon Feb 24 15:25:05 2003
@@ -52,14 +52,6 @@
 
 STATIC_DCL int FDECL(ready_weapon, (struct obj *));
 
-/* elven weapons vibrate warningly when enchanted beyond a limit */
-#define is_elven_weapon(optr)	((optr)->otyp == ELVEN_ARROW\
-				|| (optr)->otyp == ELVEN_SPEAR\
-				|| (optr)->otyp == ELVEN_DAGGER\
-				|| (optr)->otyp == ELVEN_SHORT_SWORD\
-				|| (optr)->otyp == ELVEN_BROADSWORD\
-				|| (optr)->otyp == ELVEN_BOW)
-
 /* used by will_weld() */
 /* probably should be renamed */
 #define erodeable_wep(optr)	((optr)->oclass == WEAPON_CLASS \
@@ -260,6 +252,8 @@
 		return (0);
 	} else if (welded(uwep)) {
 		weldmsg(uwep);
+		/* previously interrupted armor removal mustn't be resumed */
+		reset_remarm();
 		return (0);
 	}
 
@@ -337,18 +331,20 @@
 dowieldquiver()
 {
 	register struct obj *newquiver;
-
+	const char *quivee_types = (uslinging() ||
+		  (uswapwep && objects[uswapwep->otyp].oc_skill == P_SLING)) ?
+				  bullets : ready_objs;
 
 	/* Since the quiver isn't in your hands, don't check cantwield(), */
 	/* will_weld(), touch_petrifies(), etc. */
 	multi = 0;
 
 	/* Because 'Q' used to be quit... */
-	if (!flags.suppress_alert || flags.suppress_alert < FEATURE_NOTICE_VER(3,3,0))
+	if (flags.suppress_alert < FEATURE_NOTICE_VER(3,3,0))
 		pline("Note: Please use #quit if you wish to exit the game.");
 
 	/* Prompt for a new quiver */
-	if (!(newquiver = getobj(uslinging() ? bullets : ready_objs, "ready")))
+	if (!(newquiver = getobj(quivee_types, "ready")))
 		/* Cancelled */
 		return (0);
 
@@ -401,15 +397,88 @@
 	return (0);
 }
 
+/* used for #rub and for applying pick-axe, whip, grappling hook, or polearm */
+/* (moved from apply.c) */
+boolean
+wield_tool(obj, verb)
+struct obj *obj;
+const char *verb;	/* "rub",&c */
+{
+    const char *what;
+    boolean more_than_1;
+
+    if (obj == uwep) return TRUE;   /* nothing to do if already wielding it */
+
+    if (!verb) verb = "wield";
+    what = xname(obj);
+    more_than_1 = (obj->quan > 1L ||
+		   strstri(what, "pair of ") != 0 ||
+		   strstri(what, "s of ") != 0);
+
+    if (obj->owornmask & (W_ARMOR|W_RING|W_AMUL|W_TOOL)) {
+	char yourbuf[BUFSZ];
+
+	You_cant("%s %s %s while wearing %s.",
+		 verb, shk_your(yourbuf, obj), what,
+		 more_than_1 ? "them" : "it");
+	return FALSE;
+    }
+    if (welded(uwep)) {
+	if (flags.verbose) {
+	    const char *hand = body_part(HAND);
+
+	    if (bimanual(uwep)) hand = makeplural(hand);
+	    if (strstri(what, "pair of ") != 0) more_than_1 = FALSE;
+	    pline(
+	     "Since your weapon is welded to your %s, you cannot %s %s %s.",
+		  hand, verb, more_than_1 ? "those" : "that", xname(obj));
+	} else {
+	    You_cant("do that.");
+	}
+	return FALSE;
+    }
+    if (cantwield(youmonst.data)) {
+	You_cant("hold %s strongly enough.", more_than_1 ? "them" : "it");
+	return FALSE;
+    }
+    /* check shield */
+    if (uarms && bimanual(obj)) {
+	You("cannot %s a two-handed %s while wearing a shield.",
+	    verb, (obj->oclass == WEAPON_CLASS) ? "weapon" : "tool");
+	return FALSE;
+    }
+    if (uquiver == obj) setuqwep((struct obj *)0);
+    if (uswapwep == obj) {
+	(void) doswapweapon();
+	/* doswapweapon might fail */
+	if (uswapwep == obj) return FALSE;
+    } else {
+	You("now wield %s.", doname(obj));
+	setuwep(obj);
+    }
+    if (uwep != obj) return FALSE;	/* rewielded old object after dying */
+    /* applying weapon or tool that gets wielded ends two-weapon combat */
+    if (u.twoweap)
+	untwoweapon();
+    if (obj->oclass != WEAPON_CLASS)
+	unweapon = TRUE;
+    return TRUE;
+}
+
 int
 can_twoweapon()
 {
 	struct obj *otmp;
 
 #define NOT_WEAPON(obj) (!is_weptool(obj) && obj->oclass != WEAPON_CLASS)
-	if (!could_twoweap(youmonst.data))
-		You_cant("use two weapons in your current form.");
-	else if (!uwep || !uswapwep)
+	if (!could_twoweap(youmonst.data)) {
+		if (Upolyd)
+		    You_cant("use two weapons in your current form.");
+		else
+		    pline("%s aren't able to use two weapons at once.",
+			  makeplural((flags.female && urole.name.f) ?
+				     urole.name.f : urole.name.m));
+	} else if (!uwep || !uswapwep)
 		Your("%s%s%s empty.", uwep ? "left " : uswapwep ? "right " : "",
 			body_part(HAND), (!uwep && !uswapwep) ? "s are" : " is");
 	else if (NOT_WEAPON(uwep) || NOT_WEAPON(uswapwep)) {
@@ -433,20 +502,26 @@
 		Sprintf(kbuf, "%s corpse", an(mons[uswapwep->corpsenm].mname));
 		instapetrify(kbuf);
 	} else if (Glib || uswapwep->cursed) {
-		char str[BUFSZ];
-		struct obj *obj = uswapwep;
-
-		/* Avoid trashing makeplural's static buffer */
-		Strcpy(str, makeplural(body_part(HAND)));
-		Your("%s from your %s!",  aobjnam(obj, "slip"), str);
 		if (!Glib)
-			obj->bknown = TRUE;
-		dropx(obj);
+			uswapwep->bknown = TRUE;
+		drop_uswapwep();
 	} else
 		return (TRUE);
 	return (FALSE);
 }
 
+void
+drop_uswapwep()
+{
+	char str[BUFSZ];
+	struct obj *obj = uswapwep;
+
+	/* Avoid trashing makeplural's static buffer */
+	Strcpy(str, makeplural(body_part(HAND)));
+	Your("%s from your %s!",  aobjnam(obj, "slip"), str);
+	dropx(obj);
+}
+
 int
 dotwoweapon()
 {
@@ -613,8 +688,9 @@
 register struct obj *otmp;
 register int amount;
 {
-	register const char *color = hcolor((amount < 0) ? Black : blue);
-	register const char *xtime;
+	const char *color = hcolor((amount < 0) ? NH_BLACK : NH_BLUE);
+	const char *xtime;
+	int otyp = STRANGE_OBJECT;
 
 	if(!uwep || (uwep->oclass != WEAPON_CLASS && !is_weptool(uwep))) {
 		char buf[BUFSZ];
@@ -626,11 +702,14 @@
 		return(0);
 	}
 
+	if (otmp && otmp->oclass == SCROLL_CLASS) otyp = otmp->otyp;
+
 	if(uwep->otyp == WORM_TOOTH && amount >= 0) {
 		uwep->otyp = CRYSKNIFE;
 		uwep->oerodeproof = 0;
 		Your("weapon seems sharper now.");
 		uwep->cursed = 0;
+		if (otyp != STRANGE_OBJECT) makeknown(otyp);
 		return(1);
 	}
 
@@ -638,6 +717,7 @@
 		uwep->otyp = WORM_TOOTH;
 		uwep->oerodeproof = 0;
 		Your("weapon seems duller now.");
+		if (otyp != STRANGE_OBJECT && otmp->bknown) makeknown(otyp);
 		return(1);
 	}
 
@@ -656,9 +736,7 @@
 	    else
 		Your("%s.", aobjnam(uwep, "evaporate"));
 
-	    while(uwep)		/* let all of them disappear */
-				/* note: uwep->quan = 1 is nogood if unpaid */
-		useup(uwep);
+	    useupall(uwep);	/* let all of them disappear */
 	    return(1);
 	}
 	if (!Blind) {
@@ -666,6 +744,9 @@
 	    Your("%s %s for a %s.",
 		 aobjnam(uwep, amount == 0 ? "violently glow" : "glow"),
 		 color, xtime);
+	    if (otyp != STRANGE_OBJECT && uwep->known &&
+		    (amount > 0 || (amount < 0 && otmp->bknown)))
+		makeknown(otyp);
 	}
 	uwep->spe += amount;
 	if(amount > 0) uwep->cursed = 0;
@@ -682,6 +763,7 @@
 	}
 
 	/* an elven magic clue, cookie@keebler */
+	/* elven weapons vibrate warningly when enchanted beyond a limit */
 	if ((uwep->spe > 5)
 		&& (is_elven_weapon(uwep) || uwep->oartifact || !rn2(7)))
 	    Your("%s unexpectedly.",
diff -Naurd ../nethack-3.4.0/src/wizard.c ./src/wizard.c
--- ../nethack-3.4.0/src/wizard.c Wed Mar 20 23:43:22 2002
+++ ./src/wizard.c Mon Feb 24 15:25:05 2003
@@ -9,6 +9,9 @@
 
 #include "hack.h"
 #include "qtext.h"
+#include "epri.h"
+
+extern const int monstr[];
 
 #ifdef OVLB
 
@@ -305,6 +308,7 @@
 	    case STRAT_HEAL:	/* hide and recover */
 		/* if wounded, hole up on or near the stairs (to block them) */
 		/* unless, of course, there are no stairs (e.g. endlevel) */
+		mtmp->mavenge = 1; /* covetous monsters attack while fleeing */
 		if (In_W_tower(mtmp->mx, mtmp->my, &u.uz) ||
 			(mtmp->iswiz && !xupstair && !mon_has_amulet(mtmp))) {
 		    if (!rn2(3 + mtmp->mhp/10)) rloc(mtmp);
@@ -321,7 +325,7 @@
 		/* fall through :-) */
 
 	    case STRAT_NONE:	/* harrass */
-	        if(!rn2(5)) mnexto(mtmp);
+		if (!rn2(!mtmp->mflee ? 5 : 33)) mnexto(mtmp);
 		return(0);
 
 	    default:		/* kill, maim, pillage! */
@@ -361,7 +365,7 @@
 			return(0);
 		    }
 	        } else { /* a monster has it - 'port beside it. */
-		    (void) mnearto(mtmp, tx, ty, TRUE);
+		    (void) mnearto(mtmp, tx, ty, FALSE);
 		    return(0);
 		}
 	    }
@@ -425,7 +429,7 @@
     int count=0;
 
     if(!rn2(10) && Inhell) {
-	msummon(&mons[PM_WIZARD_OF_YENDOR]);
+	msummon((struct monst *) 0);	/* summons like WoY */
 	count++;
     } else {
 	tmp = (u.ulevel > 3) ? u.ulevel/3 : 1; /* just in case -- rph */
@@ -434,10 +438,20 @@
 	bypos.y = u.uy;
 	for(i = rnd(tmp); i > 0; --i)
 	    for(j=0; j<20; j++) {
+		int makeindex;
+
+		/* Don't create more spellcasters of the monsters' level or
+		 * higher--avoids chain summoners filling up the level.
+		 */
+		do {
+		    makeindex = pick_nasty();
+		} while(mcast && attacktype(&mons[makeindex], AT_MAGC) &&
+			monstr[makeindex] >= monstr[mcast->mnum]);
+		/* do this after picking the monster to place */
 		if (mcast &&
-			!enexto(&bypos, mcast->mux, mcast->muy, mcast->data))
+		    !enexto(&bypos, mcast->mux, mcast->muy, &mons[makeindex]))
 		    continue;
-		if ((mtmp = makemon(&mons[pick_nasty()],
+		if ((mtmp = makemon(&mons[makeindex],
 				    bypos.x, bypos.y, NO_MM_FLAGS)) != 0) {
 		    mtmp->msleeping = mtmp->mpeaceful = mtmp->mtame = 0;
 		    set_malign(mtmp);
@@ -516,7 +530,7 @@
 			break;
 	    case 2:	if (!Blind)
 			    You("notice a %s glow surrounding you.",
-				  hcolor(Black));
+				  hcolor(NH_BLACK));
 			rndcurse();
 			break;
 	    case 3:	aggravate();
@@ -538,7 +552,7 @@
 	}
 }
 
-const char *random_insult[] = {
+const char * const random_insult[] = {
 	"antic",
 	"blackguard",
 	"caitiff",
@@ -569,7 +583,7 @@
 	"wretch",
 };
 
-const char *random_malediction[] = {
+const char * const random_malediction[] = {
 	"Hell shall soon claim thy remains,",
 	"I chortle at thee, thou pathetic",
 	"Prepare to die, thou",
@@ -608,7 +622,7 @@
 		    verbalize("%s %s!",
 			  random_malediction[rn2(SIZE(random_malediction))],
 			  random_insult[rn2(SIZE(random_insult))]);
-	} else if(is_lminion(mtmp->data)) {
+	} else if(is_lminion(mtmp)) {
 		com_pager(rn2(QTN_ANGELIC - 1 + (Hallucination ? 1 : 0)) +
 			      QT_ANGELIC);
 	} else {
diff -Naurd ../nethack-3.4.0/src/worm.c ./src/worm.c
--- ../nethack-3.4.0/src/worm.c Wed Mar 20 23:43:22 2002
+++ ./src/worm.c Mon Feb 24 15:25:05 2003
@@ -613,7 +613,7 @@
 
 	do {
 	    random_dir(ox, oy, &nx, &ny);
-	} while (!goodpos(nx, ny, worm) && (tryct++ < 50));
+	} while (!goodpos(nx, ny, worm, 0) && (tryct++ < 50));
 
 	if (tryct < 50)  {
 	    place_worm_seg(worm, nx, ny);
diff -Naurd ../nethack-3.4.0/src/worn.c ./src/worn.c
--- ../nethack-3.4.0/src/worn.c Wed Mar 20 23:43:22 2002
+++ ./src/worn.c Mon Feb 24 15:25:05 2003
@@ -1,11 +1,11 @@
-/*	SCCS Id: @(#)worn.c	3.4	2002/02/07	*/
+/*	SCCS Id: @(#)worn.c	3.4	2003/01/08	*/
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /* NetHack may be freely redistributed.  See license for details. */
 
 #include "hack.h"
 
 STATIC_DCL void FDECL(m_lose_armor, (struct monst *,struct obj *));
-STATIC_DCL void FDECL(m_dowear_type, (struct monst *,long,BOOLEAN_P));
+STATIC_DCL void FDECL(m_dowear_type, (struct monst *,long, BOOLEAN_P, BOOLEAN_P));
 STATIC_DCL int FDECL(extra_pref, (struct monst *, struct obj *));
 
 const struct worn {
@@ -147,7 +147,7 @@
 struct obj *obj;	/* item to make known if effect can be seen */
 {
     struct obj *otmp;
-    boolean give_msg = !in_mklev;
+    boolean give_msg = !in_mklev, petrify = FALSE;
     unsigned int oldspeed = mon->mspeed;
 
     switch (adjust) {
@@ -169,6 +169,11 @@
 	mon->permspeed = MSLOW;
 	give_msg = FALSE;	/* (not currently used) */
 	break;
+     case -3:			/* petrification */
+	/* take away intrinsic speed but don't reduce normal speed */
+	if (mon->permspeed == MFAST) mon->permspeed = 0;
+	petrify = TRUE;
+	break;
     }
 
     for (otmp = mon->minvent; otmp; otmp = otmp->nobj)
@@ -179,12 +184,16 @@
     else
 	mon->mspeed = mon->permspeed;
 
-    if (give_msg && mon->mspeed != oldspeed && canseemon(mon)) {
+    if (give_msg && (mon->mspeed != oldspeed || petrify) && canseemon(mon)) {
 	/* fast to slow (skipping intermediate state) or vice versa */
 	const char *howmuch = (mon->mspeed + oldspeed == MFAST + MSLOW) ?
 				"much " : "";
 
-	if (adjust > 0 || mon->mspeed == MFAST)
+	if (petrify) {
+	    /* mimic the player's petrification countdown; "slowing down"
+	       even if fast movement rate retained via worn speed boots */
+	    if (flags.verbose) pline("%s is slowing down.", Monnam(mon));
+	} else if (adjust > 0 || mon->mspeed == MFAST)
 	    pline("%s is suddenly moving %sfaster.", Monnam(mon), howmuch);
 	else
 	    pline("%s seems to be moving %sslower.", Monnam(mon), howmuch);
@@ -199,10 +208,10 @@
 
 /* armor put on or taken off; might be magical variety */
 void
-update_mon_intrinsics(mon, obj, on)
+update_mon_intrinsics(mon, obj, on, silently)
 struct monst *mon;
 struct obj *obj;
-boolean on;
+boolean on, silently;
 {
     int unseen;
     uchar mask;
@@ -218,8 +227,13 @@
 	    mon->minvis = !mon->invis_blkd;
 	    break;
 	 case FAST:
+	  {
+	    boolean save_in_mklev = in_mklev;
+	    if (silently) in_mklev = TRUE;
 	    mon_adjust_speed(mon, 0, obj);
+	    in_mklev = save_in_mklev;
 	    break;
+	  }
 	/* properties handled elsewhere */
 	 case ANTIMAGIC:
 	 case REFLECTING:
@@ -253,8 +267,13 @@
 	    mon->minvis = mon->perminvis;
 	    break;
 	 case FAST:
+	  {
+	    boolean save_in_mklev = in_mklev;
+	    if (silently) in_mklev = TRUE;
 	    mon_adjust_speed(mon, 0, obj);
+	    in_mklev = save_in_mklev;
 	    break;
+	  }
 	 case FIRE_RES:
 	 case COLD_RES:
 	 case SLEEP_RES:
@@ -301,7 +320,7 @@
 #endif
 
     /* if couldn't see it but now can, or vice versa, update display */
-    if (unseen ^ !canseemon(mon))
+    if (!silently && (unseen ^ !canseemon(mon)))
 	newsym(mon->mx, mon->my);
 }
 
@@ -341,47 +360,58 @@
 register struct monst *mon;
 boolean creation;
 {
+#define RACE_EXCEPTION TRUE
 	/* Note the restrictions here are the same as in dowear in do_wear.c
 	 * except for the additional restriction on intelligence.  (Players
 	 * are always intelligent, even if polymorphed).
 	 */
 	if (verysmall(mon->data) || nohands(mon->data) || is_animal(mon->data))
 		return;
-	/* give mummies a chance to wear their wrappings */
-	if (mindless(mon->data) && (mon->data->mlet != S_MUMMY || !creation))
+	/* give mummies a chance to wear their wrappings
+	 * and let skeletons wear their initial armor */
+	if (mindless(mon->data) && (!creation ||
+	    (mon->data->mlet != S_MUMMY && mon->data != &mons[PM_SKELETON])))
 		return;
 
-	m_dowear_type(mon, W_AMUL, creation);
+	m_dowear_type(mon, W_AMUL, creation, FALSE);
 #ifdef TOURIST
 	/* can't put on shirt if already wearing suit */
 	if (!cantweararm(mon->data) || (mon->misc_worn_check & W_ARM))
-	    m_dowear_type(mon, W_ARMU, creation);
+	    m_dowear_type(mon, W_ARMU, creation, FALSE);
 #endif
 	/* treating small as a special case allows
 	   hobbits, gnomes, and kobolds to wear cloaks */
 	if (!cantweararm(mon->data) || mon->data->msize == MZ_SMALL)
-	    m_dowear_type(mon, W_ARMC, creation);
-	m_dowear_type(mon, W_ARMH, creation);
+	    m_dowear_type(mon, W_ARMC, creation, FALSE);
+	m_dowear_type(mon, W_ARMH, creation, FALSE);
 	if (!MON_WEP(mon) || !bimanual(MON_WEP(mon)))
-	    m_dowear_type(mon, W_ARMS, creation);
-	m_dowear_type(mon, W_ARMG, creation);
+	    m_dowear_type(mon, W_ARMS, creation, FALSE);
+	m_dowear_type(mon, W_ARMG, creation, FALSE);
 	if (!slithy(mon->data) && mon->data->mlet != S_CENTAUR)
-	    m_dowear_type(mon, W_ARMF, creation);
+	    m_dowear_type(mon, W_ARMF, creation, FALSE);
 	if (!cantweararm(mon->data))
-	    m_dowear_type(mon, W_ARM, creation);
+	    m_dowear_type(mon, W_ARM, creation, FALSE);
+	else
+	    m_dowear_type(mon, W_ARM, creation, RACE_EXCEPTION);
 }
 
 STATIC_OVL void
-m_dowear_type(mon, flag, creation)
+m_dowear_type(mon, flag, creation, racialexception)
 struct monst *mon;
 long flag;
 boolean creation;
+boolean racialexception;
 {
 	struct obj *old, *best, *obj;
 	int m_delay = 0;
+	int unseen = !canseemon(mon);
+	char nambuf[BUFSZ];
 
 	if (mon->mfrozen) return; /* probably putting previous item on */
 
+	/* Get a copy of monster's name before altering its visibility */
+	Strcpy(nambuf, See_invisible ? Monnam(mon) : mon_nam(mon));
+
 	old = which_armor(mon, flag);
 	if (old && old->cursed) return;
 	if (old && flag == W_AMUL) return; /* no such thing as better amulets */
@@ -406,6 +436,8 @@
 		    break;
 		case W_ARMH:
 		    if (!is_helmet(obj)) continue;
+		    /* (flimsy exception matches polyself handling) */
+		    if (has_horns(mon->data) && !is_flimsy(obj)) continue;
 		    break;
 		case W_ARMS:
 		    if (!is_shield(obj)) continue;
@@ -418,6 +450,7 @@
 		    break;
 		case W_ARM:
 		    if (!is_suit(obj)) continue;
+		    if (racialexception && (racial_exception(mon, obj) < 1)) continue;
 		    break;
 	    }
 	    if (obj->owornmask) continue;
@@ -465,11 +498,19 @@
 	    if (mon->mfrozen) mon->mcanmove = 0;
 	}
 	if (old)
-	    update_mon_intrinsics(mon, old, FALSE);
+	    update_mon_intrinsics(mon, old, FALSE, creation);
 	mon->misc_worn_check |= flag;
 	best->owornmask |= flag;
-	update_mon_intrinsics(mon, best, TRUE);
+	update_mon_intrinsics(mon, best, TRUE, creation);
+	/* if couldn't see it but now can, or vice versa, */
+	if (!creation && (unseen ^ !canseemon(mon))) {
+		if (mon->minvis && !See_invisible) {
+			pline("Suddenly you cannot see %s.", nambuf);
+			makeknown(best->otyp);
+		} /* else if (!mon->minvis) pline("%s suddenly appears!", Amonnam(mon)); */
+	}
 }
+#undef RACE_EXCEPTION
 
 struct obj *
 which_armor(mon, flag)
@@ -490,8 +531,9 @@
 struct obj *obj;
 {
 	mon->misc_worn_check &= ~obj->owornmask;
+	if (obj->owornmask)
+	    update_mon_intrinsics(mon, obj, FALSE, FALSE);
 	obj->owornmask = 0L;
-	update_mon_intrinsics(mon, obj, FALSE);
 
 	obj_extract_self(obj);
 	place_object(obj, mon->mx, mon->my);
@@ -499,35 +541,44 @@
 	newsym(mon->mx, mon->my);
 }
 
+/* all objects with their bypass bit set should now be reset to normal */
 void
 clear_bypasses()
 {
 	struct obj *otmp, *nobj;
+	struct monst *mtmp;
 
 	for (otmp = fobj; otmp; otmp = nobj) {
 	    nobj = otmp->nobj;
 	    if (otmp->bypass) {
 		otmp->bypass = 0;
+		/* bypass will have inhibited any stacking, but since it's
+		   used for polymorph handling, the objects here probably
+		   have been transformed and won't be stacked in the usual
+		   manner afterwards; so don't bother with this */
 #if 0
-		/*  setting otmp->bypass changes mergability.
-		 *  If monster can ever drop anything that
-                 *  can and should merge, this code block
-		 *  should be enabled.
-		 */
-		{
-		    struct obj *obj;
+		if (objects[otmp->otyp].oc_merge) {
 		    xchar ox, oy;
+
 		    (void) get_obj_location(otmp, &ox, &oy, 0);
-		    obj_extract_self(otmp);
-		    obj = merge_choice(fobj, otmp);
-		    /* If it can't merge, then place it */
-		    if (!obj || (obj && !merged(&obj, &otmp)))
-		        place_object(otmp, ox, oy);
+		    stack_object(otmp);
 		    newsym(ox, oy);
 		}
-#endif
+#endif	/*0*/
 	    }
 	}
+	/* invent and mydogs chains shouldn't matter here */
+	for (otmp = migrating_objs; otmp; otmp = otmp->nobj)
+	    otmp->bypass = 0;
+	for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
+	    if (DEADMONSTER(mtmp)) continue;
+	    for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj)
+		otmp->bypass = 0;
+	}
+	for (mtmp = migrating_mons; mtmp; mtmp = mtmp->nmon) {
+	    for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj)
+		otmp->bypass = 0;
+	}
 	flags.bypasses = FALSE;
 }
 
@@ -547,6 +598,7 @@
 	register struct obj *otmp;
 	struct permonst *mdat = mon->data;
 	boolean vis = cansee(mon->mx, mon->my);
+	boolean handless_or_tiny = (nohands(mdat) || verysmall(mdat));
 	const char *pronoun = mhim(mon),
 			*ppronoun = mhis(mon);
 
@@ -626,12 +678,12 @@
 	    }
 #endif
 	}
-	if (nohands(mdat) || verysmall(mdat)) {
+	if (handless_or_tiny) {
+	    /* [caller needs to handle weapon checks] */
 	    if ((otmp = which_armor(mon, W_ARMG)) != 0) {
 		if (vis)
 		    pline("%s drops %s gloves%s!", Monnam(mon), ppronoun,
 					MON_WEP(mon) ? " and weapon" : "");
-		possibly_unwield(mon);
 		if (polyspot) bypass_obj(otmp);
 		m_lose_armor(mon, otmp);
 	    }
@@ -644,7 +696,11 @@
 		if (polyspot) bypass_obj(otmp);
 		m_lose_armor(mon, otmp);
 	    }
-	    if ((otmp = which_armor(mon, W_ARMH)) != 0) {
+	}
+	if (handless_or_tiny || has_horns(mdat)) {
+	    if ((otmp = which_armor(mon, W_ARMH)) != 0 &&
+		    /* flimsy test for horns matches polyself handling */
+		    (handless_or_tiny || !is_flimsy(otmp))) {
 		if (vis)
 		    pline("%s helmet falls to the %s!",
 			  s_suffix(Monnam(mon)), surface(mon->mx, mon->my));
@@ -654,8 +710,7 @@
 		m_lose_armor(mon, otmp);
 	    }
 	}
-	if (nohands(mdat) || verysmall(mdat) || slithy(mdat) ||
-	    mdat->mlet == S_CENTAUR) {
+	if (handless_or_tiny || slithy(mdat) || mdat->mlet == S_CENTAUR) {
 	    if ((otmp = which_armor(mon, W_ARMF)) != 0) {
 		if (vis) {
 		    if (is_whirly(mon->data))
@@ -711,4 +766,29 @@
     }
     return 0;
 }
+
+/*
+ * Exceptions to things based on race. Correctly checks polymorphed player race.
+ * Returns:
+ *	 0 No exception, normal rules apply.
+ * 	 1 If the race/object combination is acceptable.
+ *	-1 If the race/object combination is unacceptable.
+ */
+int
+racial_exception(mon, obj)
+struct monst *mon;
+struct obj *obj;
+{
+    const struct permonst *ptr = raceptr(mon);
+
+    /* Acceptable Exceptions: */
+    /* Allow hobbits to wear elven armor - LoTR */
+    if (ptr == &mons[PM_HOBBIT] && is_elven_armor(obj))
+	return 1;
+    /* Unacceptable Exceptions: */
+    /* Checks for object that certain races should never use go here */
+    /*	return -1; */
+
+    return 0;
+}
 /*worn.c*/
diff -Naurd ../nethack-3.4.0/src/write.c ./src/write.c
--- ../nethack-3.4.0/src/write.c Wed Mar 20 23:43:22 2002
+++ ./src/write.c Mon Feb 24 15:25:05 2003
@@ -84,9 +84,9 @@
 	    You("need hands to be able to write!");
 	    return 0;
 	} else if (Glib) {
-	    dropx(pen);
 	    pline("%s from your %s.",
 		  Tobjnam(pen, "slip"), makeplural(body_part(FINGER)));
+	    dropx(pen);
 	    return 1;
 	}
 
diff -Naurd ../nethack-3.4.0/src/zap.c ./src/zap.c
--- ../nethack-3.4.0/src/zap.c Wed Mar 20 23:43:22 2002
+++ ./src/zap.c Mon Feb 24 15:25:05 2003
@@ -28,7 +28,6 @@
 STATIC_DCL int FDECL(zhitm, (struct monst *,int,int,struct obj **));
 STATIC_DCL void FDECL(zhitu, (int,int,const char *,XCHAR_P,XCHAR_P));
 STATIC_DCL void FDECL(revive_egg, (struct obj *));
-STATIC_DCL boolean FDECL(hits_bars, (struct obj *));
 #ifdef STEED
 STATIC_DCL boolean FDECL(zap_steed, (struct obj *));
 #endif
@@ -59,11 +58,11 @@
 
 #ifndef OVLB
 STATIC_VAR const char are_blinded_by_the_flash[];
-extern const char *flash_types[];
+extern const char * const flash_types[];
 #else
 STATIC_VAR const char are_blinded_by_the_flash[] = "are blinded by the flash!";
 
-const char *flash_types[] = {		/* also used in buzzmu(mcastu.c) */
+const char * const flash_types[] = {	/* also used in buzzmu(mcastu.c) */
 	"magic missile",	/* Wands must be 0-9 */
 	"bolt of fire",
 	"bolt of cold",
@@ -110,9 +109,9 @@
 	boolean dbldam = Role_if(PM_KNIGHT) && u.uhave.questart;
 	int dmg, otyp = otmp->otyp;
 	const char *zap_type_text = "spell";
-#ifdef STEED
 	struct obj *obj;
-#endif
+	boolean disguised_mimic = (mtmp->data->mlet == S_MIMIC &&
+				   mtmp->m_ap_type != M_AP_NOTHING);
 
 	if (u.uswallow && mtmp == u.ustuck)
 	    reveal_invis = FALSE;
@@ -188,11 +187,14 @@
 			    pline("%s shudders!", Monnam(mtmp));
 			    makeknown(otyp);
 			}
+			/* dropped inventory shouldn't be hit by this zap */
+			for (obj = mtmp->minvent; obj; obj = obj->nobj)
+			    bypass_obj(obj);
 			/* flags.bypasses = TRUE; ## for make_corpse() */
 			/* no corpse after system shock */
 			xkilled(mtmp, 3);
 		    } else if (newcham(mtmp, (struct permonst *)0,
-				       (otyp != POT_POLYMORPH))) {
+				       (otyp != POT_POLYMORPH), FALSE)) {
 			if (!Hallucination && canspotmon(mtmp))
 			    makeknown(otyp);
 		    }
@@ -200,7 +202,7 @@
 		break;
 	case WAN_CANCELLATION:
 	case SPE_CANCELLATION:
-		cancel_monst(mtmp, otmp, TRUE, TRUE, FALSE);
+		(void) cancel_monst(mtmp, otmp, TRUE, TRUE, FALSE);
 		break;
 	case WAN_TELEPORTATION:
 	case SPE_TELEPORT_AWAY:
@@ -243,8 +245,8 @@
 #ifdef STEED
 		} else if (!!(obj = which_armor(mtmp, W_SADDLE))) {
 			mtmp->misc_worn_check &= ~obj->owornmask;
+			update_mon_intrinsics(mtmp, obj, FALSE, FALSE);
 			obj->owornmask = 0L;
-			update_mon_intrinsics(mtmp, obj, FALSE);
 			obj_extract_self(obj);
 			place_object(obj, mtmp->mx, mtmp->my);
 			/* call stackobj() if we ever drop anything that can merge */
@@ -264,9 +266,18 @@
 		    mtmp->mblinded = 0;
 		    mtmp->mcansee = 1;
 		}
-		if (canseemon(mtmp))
-		    pline("%s looks%s better.", Monnam(mtmp),
-			  otyp == SPE_EXTRA_HEALING ? " much" : "" );
+		if (canseemon(mtmp)) {
+		    if (disguised_mimic) {
+			if (mtmp->m_ap_type == M_AP_OBJECT &&
+			    mtmp->mappearance == STRANGE_OBJECT) {
+			    /* it can do better now */
+			    set_mimic_sym(mtmp);
+			    newsym(mtmp->mx, mtmp->my);
+			} else
+			    mimic_hit_msg(mtmp, otyp);
+		    } else pline("%s looks%s better.", Monnam(mtmp),
+				 otyp == SPE_EXTRA_HEALING ? " much" : "" );
+		}
 		if (mtmp->mtame || mtmp->mpeaceful) {
 		    adjalign(Role_if(PM_HEALER) ? 1 : sgn(u.ualign.type));
 		}
@@ -294,7 +305,7 @@
 		if (monsndx(mtmp->data) == PM_STONE_GOLEM) {
 		    char *name = Monnam(mtmp);
 		    /* turn into flesh golem */
-		    if (newcham(mtmp, &mons[PM_FLESH_GOLEM], FALSE)) {
+		    if (newcham(mtmp, &mons[PM_FLESH_GOLEM], FALSE, FALSE)) {
 			if (canseemon(mtmp))
 			    pline("%s turns to flesh!", name);
 		    } else {
@@ -640,7 +651,7 @@
 		    		    if (canseemon(ghost))
 		    		  	pline("%s is suddenly drawn into its former body!",
 						Monnam(ghost));
-				    mongone(ghost);
+				    mondead(ghost);
 				    recorporealization = TRUE;
 				    newsym(x2, y2);
 			    }
@@ -1191,6 +1202,8 @@
 	boolean can_merge = (id == STRANGE_OBJECT);
 	int obj_location = obj->where;
 
+	if (obj->otyp == BOULDER && In_sokoban(&u.uz))
+	    change_luck(-1);	/* Sokoban guilt */
 	if (id == STRANGE_OBJECT) { /* preserve symbol */
 	    int try_limit = 3;
 	    /* Try up to 3 times to make the magic-or-not status of
@@ -1343,7 +1356,7 @@
 	/* for now, take off worn items being polymorphed */
 	if (obj_location == OBJ_INVENT) {
 	    if (id == STRANGE_OBJECT)
-		remove_worn_item(obj);
+		remove_worn_item(obj, TRUE);
 	    else {
 		/* This is called only for stone to flesh.  It's a lot simpler
 		 * than it otherwise might be.  We don't need to check for
@@ -1351,7 +1364,7 @@
 		 * any) and only three worn masks are possible.
 		 */
 		otmp->owornmask = obj->owornmask;
-		remove_worn_item(obj);
+		remove_worn_item(obj, TRUE);
 		setworn(otmp, otmp->owornmask);
 		if (otmp->owornmask & LEFT_RING)
 		    uleft = otmp;
@@ -1427,6 +1440,7 @@
 struct obj *obj, *otmp;
 {
 	int res = 1;	/* affected object by default */
+	xchar refresh_x, refresh_y;
 
 	if (obj->bypass) {
 		/* The bypass bit is currently only used as follows:
@@ -1582,6 +1596,7 @@
 		res = 0;
 		break;
 	case SPE_STONE_TO_FLESH:
+		refresh_x = obj->ox; refresh_y = obj->oy;
 		if (objects[obj->otyp].oc_material != MINERAL &&
 			objects[obj->otyp].oc_material != GEMSTONE) {
 		    res = 0;
@@ -1592,15 +1607,15 @@
 		    case ROCK_CLASS:	/* boulders and statues */
 			if (obj->otyp == BOULDER) {
 			    obj = poly_obj(obj, HUGE_CHUNK_OF_MEAT);
-			    if (In_sokoban(&u.uz))
-				change_luck(-1);	/* Sokoban guilt */
 			    goto smell;
 			} else if (obj->otyp == STATUE) {
 			    xchar oox, ooy;
 
 			    (void) get_obj_location(obj, &oox, &ooy, 0);
+			    refresh_x = oox; refresh_y = ooy;
 			    if (!animate_statue(obj, oox, ooy,
 						ANIMATE_SPELL, (int *)0)) {
+				struct obj *item;
 makecorpse:			if (mons[obj->corpsenm].geno &
 							(G_NOCORPSE|G_UNIQ)) {
 				    res = 0;
@@ -1608,7 +1623,12 @@
 				}
 				/* Unlikely to get here since genociding
 				 * monsters also sets the G_NOCORPSE flag.
+				 * Drop the contents, poly_obj looses them.
 				 */
+				while ((item = obj->cobj) != 0) {
+				    obj_extract_self(item);
+				    place_object(item, oox, ooy);
+				}
 				obj = poly_obj(obj, CORPSE);
 				break;
 			    }
@@ -1627,6 +1647,7 @@
 			    break;
 			}
 			(void) get_obj_location(obj, &oox, &ooy, 0);
+			refresh_x = oox; refresh_y = ooy;
 			mon = makemon(&mons[obj->corpsenm],
 				      oox, ooy, NO_MM_FLAGS);
 			if (mon) {
@@ -1657,7 +1678,7 @@
 			res = 0;
 			break;
 		}
-		newsym(obj->ox,obj->oy);
+		newsym(refresh_x, refresh_y);
 		break;
 	default:
 		impossible("What an interesting effect (%d)", otmp->otyp);
@@ -1684,8 +1705,9 @@
 	   because that last call might end up operating on our `next_obj'
 	   (below), rather than on the current object, if it happens to
 	   encounter a statue which mustn't become animated. */
-	if (t && t->ttyp == STATUE_TRAP)
-	    (void) activate_statue_trap(t, tx, ty, TRUE);
+	if (t && t->ttyp == STATUE_TRAP &&
+	    activate_statue_trap(t, tx, ty, TRUE) && obj->otyp == WAN_STRIKING)
+	    makeknown(obj->otyp);
     }
 
     poly_zapped = -1;
@@ -1934,7 +1956,7 @@
 
 		case WAN_CANCELLATION:
 		case SPE_CANCELLATION:
-		    cancel_monst(&youmonst, obj, TRUE, FALSE, TRUE);
+		    (void) cancel_monst(&youmonst, obj, TRUE, FALSE, TRUE);
 		    break;
 
 		case SPE_DRAIN_LIFE:
@@ -2181,7 +2203,7 @@
  * effect is too strong.  currently non-hero monsters do not zap
  * themselves with cancellation.
  */
-void
+boolean
 cancel_monst(mdef, obj, youattack, allow_cancel_kill, self_cancel)
 register struct monst	*mdef;
 register struct obj	*obj;
@@ -2194,7 +2216,7 @@
 
 	if (youdefend ? (!youattack && Antimagic)
 		      : resist(mdef, obj->oclass, 0, NOTELL))
-		return;		/* resisted cancellation */
+		return FALSE;	/* resisted cancellation */
 
 	if (self_cancel) {	/* 1st cancel inventory */
 	    struct obj *otmp;
@@ -2213,7 +2235,11 @@
 	    if (Upolyd) {
 		if ((u.umonnum == PM_CLAY_GOLEM) && !Blind)
 		    pline(writing_vanishes, your);
-		rehumanize();
+
+		if (Unchanging)
+		    Your("amulet grows hot for a moment, then cools.");
+		else
+		    rehumanize();
 	    }
 	} else {
 	    mdef->mcan = TRUE;
@@ -2233,6 +2259,7 @@
 		}
 	    }
 	}
+	return TRUE;
 }
 
 /* you've zapped an immediate type wand up or down */
@@ -2549,25 +2576,6 @@
 #endif /*OVL0*/
 #ifdef OVL1
 
-/* return TRUE if obj_type can't pass through iron bars */
-static boolean
-hits_bars(obj)
-struct obj *obj;
-{
-    int obj_type = obj->otyp;
-    /*
-    There should be a _lot_ of things here..., but iron ball
-    started this change and boulders, chests, and boxes were added later...
-    Corpses and statues that are at least medium size are also screened.
-    */
-    if (obj_type == BOULDER || obj_type == HEAVY_IRON_BALL || obj_type == LARGE_BOX ||
-	obj_type == CHEST   || obj_type == ICE_BOX ||
-	((obj_type == CORPSE || obj_type == STATUE)
-	  && mons[obj->corpsenm].msize >= MZ_MEDIUM))
-	return TRUE;
-    return FALSE;
-}
-
 /*
  *  Called for the following distance effects:
  *	when a weapon is thrown (weapon == THROWN_WEAPON)
@@ -2594,9 +2602,9 @@
     FDECL((*fhito), (OBJ_P, OBJ_P));
 struct obj *obj;			/* object tossed/used */
 {
-	register struct monst *mtmp;
-	register uchar typ;
-	register boolean shopdoor = FALSE;
+	struct monst *mtmp;
+	uchar typ;
+	boolean shopdoor = FALSE, point_blank = TRUE;
 
 	if (weapon == KICKED_WEAPON) {
 	    /* object starts one square in front of player */
@@ -2635,8 +2643,11 @@
 	    typ = levl[bhitpos.x][bhitpos.y].typ;
 
 	    /* iron bars will block anything big enough */
-	    if ((weapon == THROWN_WEAPON || weapon == KICKED_WEAPON)
-	    		 && typ == IRONBARS && hits_bars(obj)) {
+	    if ((weapon == THROWN_WEAPON || weapon == KICKED_WEAPON) &&
+		    typ == IRONBARS &&
+		    hits_bars(&obj, x - ddx, y - ddy,
+			      point_blank ? 0 : !rn2(5), 1)) {
+		/* caveat: obj might now be null... */
 		bhitpos.x -= ddx;
 		bhitpos.y -= ddy;
 		break;
@@ -2713,13 +2724,11 @@
 		if(bhitpile(obj,fhito,bhitpos.x,bhitpos.y))
 		    range--;
 	    } else {
-boolean costly = shop_keeper(*in_rooms(bhitpos.x, bhitpos.y, SHOPBASE)) &&
-				costly_spot(bhitpos.x, bhitpos.y);
-
 		if(weapon == KICKED_WEAPON &&
-		      ((obj->oclass == GOLD_CLASS &&
+		      ((obj->oclass == COIN_CLASS &&
 			 OBJ_AT(bhitpos.x, bhitpos.y)) ||
-		    ship_object(obj, bhitpos.x, bhitpos.y, costly))) {
+			    ship_object(obj, bhitpos.x, bhitpos.y,
+					costly_spot(bhitpos.x, bhitpos.y)))) {
 			tmp_at(DISP_END, 0);
 			return (struct monst *)0;
 		}
@@ -2770,12 +2779,14 @@
 		    break;	/* physical objects fall onto sink */
 #endif
 	    }
+	    /* thrown/kicked missile has moved away from its starting spot */
+	    point_blank = FALSE;	/* affects passing through iron bars */
 	}
 
 	if (weapon != ZAPPED_WAND && weapon != INVIS_BEAM) tmp_at(DISP_END, 0);
 
 	if(shopdoor)
-	    pay_for_damage("destroy");
+	    pay_for_damage("destroy", FALSE);
 
 	return (struct monst *)0;
 }
@@ -3146,7 +3157,7 @@
 {
 	struct obj *obj, *obj2;
 	long i, scrquan, delquan;
-	const char *what;
+	char buf1[BUFSZ], buf2[BUFSZ];
 	int cnt = 0;
 
 	for (obj = level.objects[x][y]; obj; obj = obj2) {
@@ -3161,8 +3172,15 @@
 		    if (!rn2(3)) delquan++;
 		if (delquan) {
 		    /* save name before potential delobj() */
-		    what = !give_feedback ? 0 : (x == u.ux && y == u.uy) ?
-				xname(obj) : distant_name(obj, xname);
+		    if (give_feedback) {
+			obj->quan = 1;
+			Strcpy(buf1, (x == u.ux && y == u.uy) ?
+				xname(obj) : distant_name(obj, xname));
+			obj->quan = 2;
+		    	Strcpy(buf2, (x == u.ux && y == u.uy) ?
+				xname(obj) : distant_name(obj, xname));
+			obj->quan = scrquan;
+		    }
 		    /* useupf(), which charges, only if hero caused damage */
 		    if (u_caused) useupf(obj, delquan);
 		    else if (delquan < scrquan) obj->quan -= delquan;
@@ -3170,9 +3188,9 @@
 		    cnt += delquan;
 		    if (give_feedback) {
 			if (delquan > 1)
-			    pline("%ld %s burn.", delquan, what);
+			    pline("%ld %s burn.", delquan, buf2);
 			else
-			    pline("%s burns.", An(what));
+			    pline("%s burns.", An(buf1));
 		    }
 		}
 	    }
@@ -3424,10 +3442,12 @@
 		dy = -dy;
 	    } else {
 		if(isok(sx,lsy) && ZAP_POS(rmn = levl[sx][lsy].typ) &&
+		   !closed_door(sx,lsy) &&
 		   (IS_ROOM(rmn) || (isok(sx+dx,lsy) &&
 				     ZAP_POS(levl[sx+dx][lsy].typ))))
 		    bounce = 1;
 		if(isok(lsx,sy) && ZAP_POS(rmn = levl[lsx][sy].typ) &&
+		   !closed_door(lsx,sy) &&
 		   (IS_ROOM(rmn) || (isok(lsx,sy+dy) &&
 				     ZAP_POS(levl[lsx][sy+dy].typ))))
 		    if(!bounce || rn2(2))
@@ -3448,7 +3468,7 @@
     if (shopdamage)
 	pay_for_damage(abstype == ZT_FIRE ?  "burn away" :
 		       abstype == ZT_COLD ?  "shatter" :
-		       abstype == ZT_DEATH ? "disintegrate" : "destroy");
+		       abstype == ZT_DEATH ? "disintegrate" : "destroy", FALSE);
     bhitpos = save_bhitpos;
 }
 #endif /*OVLB*/
@@ -3708,12 +3728,14 @@
 	obj->onamelth = 0;		/* no names */
 	obj->oxlth = 0;			/* no extra data */
 	obj->oattached = OATTACHED_NOTHING;
-	obj_extract_self(obj);		/* move rocks back on top */
-	place_object(obj, obj->ox, obj->oy);
-	if(!does_block(obj->ox,obj->oy,&levl[obj->ox][obj->oy]))
-	    unblock_point(obj->ox,obj->oy);
-	if(cansee(obj->ox,obj->oy))
-	    newsym(obj->ox,obj->oy);
+	if (obj->where == OBJ_FLOOR) {
+		obj_extract_self(obj);		/* move rocks back on top */
+		place_object(obj, obj->ox, obj->oy);
+		if(!does_block(obj->ox,obj->oy,&levl[obj->ox][obj->oy]))
+	    		unblock_point(obj->ox,obj->oy);
+		if(cansee(obj->ox,obj->oy))
+		    newsym(obj->ox,obj->oy);
+	}
 }
 
 /* handle statue hit by striking/force bolt/pick-axe */
@@ -3742,7 +3764,7 @@
 	return TRUE;
 }
 
-const char *destroy_strings[] = {
+const char * const destroy_strings[] = {	/* also used in trap.c */
 	"freezes and shatters", "freeze and shatter", "shattered potion",
 	"boils and explodes", "boil and explode", "boiling potion",
 	"catches fire and burns", "catch fire and burn", "burning scroll",
@@ -3765,6 +3787,7 @@
 	    obj2 = obj->nobj;
 	    if(obj->oclass != osym) continue; /* test only objs of type osym */
 	    if(obj->oartifact) continue; /* don't destroy artifacts */
+	    if(obj->in_use && obj->quan == 1) continue; /* not available */
 	    xresist = skip = 0;
 #ifdef GCC_WARN
 	    dmg = dindx = 0;
@@ -3836,6 +3859,7 @@
 		    break;
 	    }
 	    if(!skip) {
+		if (obj->in_use) --quan; /* one will be used up elsewhere */
 		for(i = cnt = 0L; i < quan; i++)
 		    if(!rn2(3)) cnt++;
 
@@ -3987,11 +4011,12 @@
 	/* attack level */
 	switch (oclass) {
 	    case WAND_CLASS:	alev = 12;	 break;
-	    case TOOL_CLASS:	alev = 10;	 break;
+	    case TOOL_CLASS:	alev = 10;	 break;	/* instrument */
+	    case WEAPON_CLASS:	alev = 10;	 break;	/* artifact */
 	    case SCROLL_CLASS:	alev =  9;	 break;
 	    case POTION_CLASS:	alev =  6;	 break;
 	    case RING_CLASS:	alev =  5;	 break;
-	    default:		alev = u.ulevel; break;		/* spell */
+	    default:		alev = u.ulevel; break;	/* spell */
 	}
 	/* defense level */
 	dlev = (int)mtmp->m_lev;
@@ -4052,33 +4077,19 @@
 	u.uconduct.wishes++;
 
 	if (otmp != &zeroobj) {
-	    /* place_object looses these */
-	    boolean crysknife = (otmp->otyp == CRYSKNIFE);
-	    int oerode = otmp->oerodeproof;
-
-	    /* in case touching this object turns out to be fatal */
-	    place_object(otmp, u.ux, u.uy);
-
-	    if (otmp->oartifact && !touch_artifact(otmp,&youmonst)) {
-		obj_extract_self(otmp);	/* remove it from the floor */
-		dropy(otmp);		/* now put it back again :-) */
-	    } else {
-		obj_extract_self(otmp);
-		if (crysknife) {
-		    otmp->otyp = CRYSKNIFE;
-		    otmp->oerodeproof = oerode;
-		}
-		/* The(aobjnam()) is safe since otmp is unidentified -dlc */
-		(void) hold_another_object(otmp, u.uswallow ?
+	    /* The(aobjnam()) is safe since otmp is unidentified -dlc */
+	    (void) hold_another_object(otmp, u.uswallow ?
 				       "Oops!  %s out of your reach!" :
-				       Is_airlevel(&u.uz) || u.uinwater ?
+				       (Is_airlevel(&u.uz) ||
+					Is_waterlevel(&u.uz) ||
+					levl[u.ux][u.uy].typ < IRONBARS ||
+					levl[u.ux][u.uy].typ >= ICE) ?
 				       "Oops!  %s away from you!" :
 				       "Oops!  %s to the floor!",
 				       The(aobjnam(otmp,
 					     Is_airlevel(&u.uz) || u.uinwater ?
 						   "slip" : "drop")),
 				       (const char *)0);
-	    }
 	    u.ublesscnt += rn1(100,50);  /* the gods take notice */
 	}
 }

