<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">diff -Ndur nethack-3.4.3/include/extern.h nethack-patched/include/extern.h
--- nethack-3.4.3/include/extern.h	2006-12-04 21:58:58.000000000 +0000
+++ nethack-patched/include/extern.h	2007-02-10 22:25:14.000000000 +0000
@@ -54,6 +54,7 @@
 E void NDECL(init_artifacts);
 E void FDECL(save_artifacts, (int));
 E void FDECL(restore_artifacts, (int));
+E unsigned long FDECL(arti_prop_spfx, (int));
 E const char *FDECL(artiname, (int));
 E struct obj *FDECL(mk_artifact, (struct obj *,ALIGNTYP_P));
 E const char *FDECL(artifact_name, (const char *,short *));
@@ -1166,6 +1167,7 @@
 E boolean FDECL(hates_silver, (struct permonst *));
 E boolean FDECL(passes_bars, (struct permonst *));
 E boolean FDECL(can_track, (struct permonst *));
+E boolean FDECL(mon_prop, (struct monst *,int));
 E boolean FDECL(breakarm, (struct permonst *));
 E boolean FDECL(sliparm, (struct permonst *));
 E boolean FDECL(sticks, (struct permonst *));
@@ -1943,6 +1945,7 @@
 E void FDECL(rloc_to, (struct monst *,int,int));
 E boolean FDECL(rloc, (struct monst *, BOOLEAN_P));
 E boolean FDECL(tele_restrict, (struct monst *));
+E boolean FDECL(controls_teleport, (struct monst *));
 E void FDECL(mtele_trap, (struct monst *, struct trap *,int));
 E int FDECL(mlevel_tele_trap, (struct monst *, struct trap *,BOOLEAN_P,int));
 E void FDECL(rloco, (struct obj *));
@@ -2257,6 +2260,7 @@
 
 /* ### wield.c ### */
 
+E boolean FDECL(will_weld, (struct obj *));
 E void FDECL(setuwep, (struct obj *));
 E void FDECL(setuqwep, (struct obj *));
 E void FDECL(setuswapwep, (struct obj *));
@@ -2327,6 +2331,7 @@
 		(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 long FDECL(mfindringslot, (struct monst *, struct obj **));
 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 *));
diff -Ndur nethack-3.4.3/include/monattk.h nethack-patched/include/monattk.h
--- nethack-3.4.3/include/monattk.h	2006-12-04 21:59:00.000000000 +0000
+++ nethack-patched/include/monattk.h	2007-01-26 13:53:40.000000000 +0000
@@ -96,5 +96,6 @@
 #define MM_HIT		0x1	/* aggressor hit defender */
 #define MM_DEF_DIED	0x2	/* defender died */
 #define MM_AGR_DIED	0x4	/* aggressor died */
+#define MM_EXPELLED     0x8     /* defender was saved by slow digestion */
 
 #endif /* MONATTK_H */
diff -Ndur nethack-3.4.3/src/apply.c nethack-patched/src/apply.c
--- nethack-3.4.3/src/apply.c	2006-12-04 21:59:02.000000000 +0000
+++ nethack-patched/src/apply.c	2007-02-10 22:25:42.000000000 +0000
@@ -722,14 +722,14 @@
 		(void) mpickobj(mtmp,obj);
 		if (!tele_restrict(mtmp)) (void) rloc(mtmp, FALSE);
 	} else if (!is_unicorn(mtmp-&gt;data) &amp;&amp; !humanoid(mtmp-&gt;data) &amp;&amp;
-			(!mtmp-&gt;minvis || perceives(mtmp-&gt;data)) &amp;&amp; rn2(5)) {
+			(!mtmp-&gt;minvis || mon_prop(mtmp,SEE_INVIS)) &amp;&amp; rn2(5)) {
 		if (vis)
 		    pline("%s is frightened by its reflection.", Monnam(mtmp));
 		monflee(mtmp, d(2,4), FALSE, FALSE);
 	} else if (!Blind) {
 		if (mtmp-&gt;minvis &amp;&amp; !See_invisible)
 		    ;
-		else if ((mtmp-&gt;minvis &amp;&amp; !perceives(mtmp-&gt;data))
+		else if ((mtmp-&gt;minvis &amp;&amp; !mon_prop(mtmp,SEE_INVIS))
 			 || !haseyes(mtmp-&gt;data))
 		    pline("%s doesn't seem to notice its reflection.",
 			Monnam(mtmp));
@@ -2261,7 +2261,7 @@
 
 	    You("wrap your bullwhip around %s %s.",
 		s_suffix(mon_nam(mtmp)), onambuf);
-	    if (gotit &amp;&amp; otmp-&gt;cursed) {
+	    if (gotit &amp;&amp; will_weld(otmp)) {
 		pline("%s welded to %s %s%c",
 		      (otmp-&gt;quan == 1L) ? "It is" : "They are",
 		      mhis(mtmp), mon_hand,
diff -Ndur nethack-3.4.3/src/artifact.c nethack-patched/src/artifact.c
--- nethack-3.4.3/src/artifact.c	2006-12-04 21:59:02.000000000 +0000
+++ nethack-patched/src/artifact.c	2007-01-26 13:53:40.000000000 +0000
@@ -109,6 +109,26 @@
 	return(artilist[artinum].name);
 }
 
+/* Finds a matching SPFX for a prop - used in mondata.c */
+unsigned long
+arti_prop_spfx(prop)
+int prop;
+{
+	switch(prop) {
+	    case SEARCHING: return SPFX_SEEK;
+	    case WARNING: return SPFX_WARN;
+	    case TELEPAT: return SPFX_ESP;
+	    case HALLUC_RES: return SPFX_HALRES;
+	    case STEALTH: return SPFX_STLTH;
+	    case REGENERATION: return SPFX_REGEN;
+	    case TELEPORT_CONTROL: return SPFX_TCTRL;
+	    case ENERGY_REGENERATION: return SPFX_EREGEN;
+	    case HALF_SPDAM: return SPFX_HSPDAM;
+	    case HALF_PHDAM: return SPFX_HPHDAM;
+	    case REFLECTING: return SPFX_REFLECT;
+	} return 0L;
+}
+
 /*
    Make an artifact.  If a specific alignment is specified, then an object of
    the appropriate alignment is created from scratch, or 0 is returned if
@@ -248,7 +268,8 @@
 {
 	const struct artifact *arti = get_artifact(otmp);
 
-	return((boolean)(arti &amp;&amp; (arti-&gt;spfx &amp; abil)));
+	if (arti &amp;&amp; (arti-&gt;spfx &amp; abil)) return TRUE;
+	return(boolean)(arti &amp;&amp; (arti-&gt;cspfx &amp; abil));
 }
 
 /* used so that callers don't need to known about SPFX_ codes */
diff -Ndur nethack-3.4.3/src/dog.c nethack-patched/src/dog.c
--- nethack-3.4.3/src/dog.c	2006-12-04 21:59:02.000000000 +0000
+++ nethack-patched/src/dog.c	2007-01-26 13:53:40.000000000 +0000
@@ -470,7 +470,7 @@
 	}
 
 	/* recover lost hit points */
-	if (!regenerates(mtmp-&gt;data)) imv /= 20;
+	if (!mon_prop(mtmp,REGENERATION)) imv /= 20;
 	if (mtmp-&gt;mhp + imv &gt;= mtmp-&gt;mhpmax)
 	    mtmp-&gt;mhp = mtmp-&gt;mhpmax;
 	else mtmp-&gt;mhp += imv;
diff -Ndur nethack-3.4.3/src/dogmove.c nethack-patched/src/dogmove.c
--- nethack-3.4.3/src/dogmove.c	2006-12-04 21:59:02.000000000 +0000
+++ nethack-patched/src/dogmove.c	2007-01-26 13:53:40.000000000 +0000
@@ -616,7 +616,7 @@
 		    if ((int)mtmp2-&gt;m_lev &gt;= (int)mtmp-&gt;m_lev+2 ||
 			(mtmp2-&gt;data == &amp;mons[PM_FLOATING_EYE] &amp;&amp; rn2(10) &amp;&amp;
 			 mtmp-&gt;mcansee &amp;&amp; haseyes(mtmp-&gt;data) &amp;&amp; mtmp2-&gt;mcansee
-			 &amp;&amp; (perceives(mtmp-&gt;data) || !mtmp2-&gt;minvis)) ||
+			 &amp;&amp; (mon_prop(mtmp,SEE_INVIS) || !mtmp2-&gt;minvis)) ||
 			(mtmp2-&gt;data==&amp;mons[PM_GELATINOUS_CUBE] &amp;&amp; rn2(10)) ||
 			(max_passive_dmg(mtmp2, mtmp) &gt;= mtmp-&gt;mhp) ||
 			((mtmp-&gt;mhp*4 &lt; mtmp-&gt;mhpmax
diff -Ndur nethack-3.4.3/src/mcastu.c nethack-patched/src/mcastu.c
--- nethack-3.4.3/src/mcastu.c	2006-12-04 21:59:02.000000000 +0000
+++ nethack-patched/src/mcastu.c	2007-01-26 13:53:40.000000000 +0000
@@ -54,7 +54,7 @@
 
 	    if (undirected)
 		point_msg = "all around, then curses";
-	    else if ((Invis &amp;&amp; !perceives(mtmp-&gt;data) &amp;&amp;
+	    else if ((Invis &amp;&amp; !mon_prop(mtmp,SEE_INVIS) &amp;&amp;
 			(mtmp-&gt;mux != u.ux || mtmp-&gt;muy != u.uy)) ||
 		    (youmonst.m_ap_type == M_AP_OBJECT &amp;&amp;
 			youmonst.mappearance == STRANGE_OBJECT) ||
@@ -238,7 +238,7 @@
 	    pline("%s casts a spell%s!",
 		  canspotmon(mtmp) ? Monnam(mtmp) : "Something",
 		  is_undirected_spell(mattk-&gt;adtyp, spellnum) ? "" :
-		  (Invisible &amp;&amp; !perceives(mtmp-&gt;data) &amp;&amp; 
+		  (Invisible &amp;&amp; !mon_prop(mtmp,SEE_INVIS) &amp;&amp; 
 		   (mtmp-&gt;mux != u.ux || mtmp-&gt;muy != u.uy)) ?
 		  " at a spot near you" :
 		  (Displaced &amp;&amp; (mtmp-&gt;mux != u.ux || mtmp-&gt;muy != u.uy)) ?
@@ -368,7 +368,7 @@
 
 	    /* messages not quite right if plural monsters created but
 	       only a single monster is seen */
-	    if (Invisible &amp;&amp; !perceives(mtmp-&gt;data) &amp;&amp;
+	    if (Invisible &amp;&amp; !mon_prop(mtmp,SEE_INVIS) &amp;&amp;
 				    (mtmp-&gt;mux != u.ux || mtmp-&gt;muy != u.uy))
 		pline("%s around a spot near you!", mappear);
 	    else if (Displaced &amp;&amp; (mtmp-&gt;mux != u.ux || mtmp-&gt;muy != u.uy))
@@ -570,7 +570,7 @@
 	else if (let == S_SNAKE)
 	    pline("%s transforms a clump of sticks into snakes!",
 		Monnam(mtmp));
-	else if (Invisible &amp;&amp; !perceives(mtmp-&gt;data) &amp;&amp;
+	else if (Invisible &amp;&amp; !mon_prop(mtmp,SEE_INVIS) &amp;&amp;
 				(mtmp-&gt;mux != u.ux || mtmp-&gt;muy != u.uy))
 	    pline("%s summons insects around a spot near you!",
 		Monnam(mtmp));
diff -Ndur nethack-3.4.3/src/mhitm.c nethack-patched/src/mhitm.c
--- nethack-3.4.3/src/mhitm.c	2006-12-04 21:59:02.000000000 +0000
+++ nethack-patched/src/mhitm.c	2007-02-04 20:28:50.000000000 +0000
@@ -175,12 +175,14 @@
  *
  * This function returns a result bitfield:
  *
- *	    --------- aggressor died
- *	   /  ------- defender died
- *	  /  /  ----- defender was hit
- *	 /  /  /
- *	x  x  x
+ *           ----------- defender was "hurriedly expelled"
+ *	    /  --------- aggressor died
+ *	   /  /  ------- defender died
+ *	  /  /  /  ----- defender was hit
+ *	 /  /  /  /
+ *	x  x  x  x
  *
+ *      0x8     MM_EXPELLED
  *	0x4	MM_AGR_DIED
  *	0x2	MM_DEF_DIED
  *	0x1	MM_HIT
@@ -219,6 +221,13 @@
 	tmp += 4;
 	mdef-&gt;msleeping = 0;
     }
+    /* find rings of increase accuracy */
+    {
+	struct obj *o;
+	for (o = magr-&gt;minvent; o; o = o-&gt;nobj)
+	    if (o-&gt;owornmask &amp;&amp; o-&gt;otyp == RIN_INCREASE_ACCURACY)
+	        tmp += o-&gt;spe;
+    }
 
     /* undetect monsters become un-hidden if they are attacked */
     if (mdef-&gt;mundetected) {
@@ -448,7 +457,7 @@
 	}
 
 	if (magr-&gt;mcan || !magr-&gt;mcansee ||
-	    (magr-&gt;minvis &amp;&amp; !perceives(mdef-&gt;data)) ||
+	    (magr-&gt;minvis &amp;&amp; !mon_prop(mdef,SEE_INVIS)) ||
 	    !mdef-&gt;mcansee || mdef-&gt;msleeping) {
 	    if(vis) pline("but nothing happens.");
 	    return(MM_MISS);
@@ -465,7 +474,7 @@
 					"The gaze is reflected away by %s %s.");
 		    return (MM_MISS);
 		}
-		if (mdef-&gt;minvis &amp;&amp; !perceives(magr-&gt;data)) {
+		if (mdef-&gt;minvis &amp;&amp; !mon_prop(magr, SEE_INVIS)) {
 		    if (canseemon(magr)) {
 			pline("%s doesn't seem to notice that %s gaze was reflected.",
 			      Monnam(magr), mhis(magr));
@@ -540,8 +549,15 @@
 	    newsym(dx, dy);
 	}
 	else {					/* both alive, put them back */
-	    if (cansee(dx, dy))
+	    if (cansee(dx, dy)) {
+                if (status &amp; MM_EXPELLED) {
+                    strcpy(buf, Monnam(magr));
+		    pline("%s hurriedly regurgitates %s!", buf, mon_nam(mdef));
+                    pline("Obviously, it didn't like %s taste.", s_suffix(mon_nam(mdef)));
+                } else {
 		pline("%s is regurgitated!", Monnam(mdef));
+                }
+            }
 
 	    place_monster(magr, ax, ay);
 	    place_monster(mdef, dx, dy);
@@ -615,6 +631,13 @@
 		return MM_AGR_DIED;
 	    }
 	}
+	/* find rings of increase damage */
+	if (magr-&gt;minvent) {
+	    struct obj *o;
+	    for (o = magr-&gt;minvent; o; o = o-&gt;nobj)
+	        if (o-&gt;owornmask &amp;&amp; o-&gt;otyp == RIN_INCREASE_DAMAGE)
+	            tmp += o-&gt;spe;
+	}
 
 	/* cancellation factor is the same as when attacking the hero */
 	armpro = magic_negation(mdef);
@@ -622,6 +645,8 @@
 
 	switch(mattk-&gt;adtyp) {
 	    case AD_DGST:
+                if (mon_prop(mdef,SLOW_DIGESTION))
+                    return (MM_HIT | MM_EXPELLED);
 		/* eating a Rider or its corpse is fatal */
 		if (is_rider(mdef-&gt;data)) {
 		    if (vis)
@@ -922,7 +947,8 @@
 		tmp = 0;
 		break;
 	    case AD_HALU:
-		if (!magr-&gt;mcan &amp;&amp; haseyes(pd) &amp;&amp; mdef-&gt;mcansee) {
+		if (!magr-&gt;mcan &amp;&amp; haseyes(pd) &amp;&amp; mdef-&gt;mcansee
+			&amp;&amp; !mon_prop(mdef,HALLUC_RES)) {
 		    if (vis) pline("%s looks %sconfused.",
 				    Monnam(mdef), mdef-&gt;mconf ? "more " : "");
 		    mdef-&gt;mconf = 1;
@@ -1326,7 +1352,7 @@
 		if (mddat == &amp;mons[PM_FLOATING_EYE]) {
 		    if (!rn2(4)) tmp = 127;
 		    if (magr-&gt;mcansee &amp;&amp; haseyes(madat) &amp;&amp; mdef-&gt;mcansee &amp;&amp;
-			(perceives(madat) || !mdef-&gt;minvis)) {
+			(!mdef-&gt;minvis || mon_prop(magr, SEE_INVIS))) {
 			Sprintf(buf, "%s gaze is reflected by %%s %%s.",
 				s_suffix(mon_nam(mdef)));
 			if (mon_reflects(magr,
diff -Ndur nethack-3.4.3/src/mhitu.c nethack-patched/src/mhitu.c
--- nethack-3.4.3/src/mhitu.c	2006-12-04 21:59:02.000000000 +0000
+++ nethack-patched/src/mhitu.c	2007-01-28 22:42:52.000000000 +0000
@@ -163,7 +163,7 @@
 	compat = (mattk-&gt;adtyp == AD_SEDU || mattk-&gt;adtyp == AD_SSEX) &amp;&amp;
 		 could_seduce(mtmp, &amp;youmonst, (struct attack *)0);
 
-	if (!mtmp-&gt;mcansee || (Invis &amp;&amp; !perceives(mtmp-&gt;data))) {
+	if (!mtmp-&gt;mcansee || (Invis &amp;&amp; !mon_prop(mtmp,SEE_INVIS))) {
 	    const char *swings =
 		mattk-&gt;aatyp == AT_BITE ? "snaps" :
 		mattk-&gt;aatyp == AT_KICK ? "kicks" :
@@ -463,11 +463,20 @@
 	tmp = AC_VALUE(u.uac) + 10;		/* tmp ~= 0 - 20 */
 	tmp += mtmp-&gt;m_lev;
 	if(multi &lt; 0) tmp += 4;
-	if((Invis &amp;&amp; !perceives(mdat)) || !mtmp-&gt;mcansee)
+	if((Invis &amp;&amp; !mon_prop(mtmp,SEE_INVIS)) || !mtmp-&gt;mcansee)
 		tmp -= 2;
 	if(mtmp-&gt;mtrapped) tmp -= 2;
 	if(tmp &lt;= 0) tmp = 1;
 
+	/* find rings of increase accuracy */
+	{
+	    struct obj *o;
+	    for (o = mtmp-&gt;minvent; o; o = o-&gt;nobj)
+		if (o-&gt;owornmask &amp;&amp; o-&gt;otyp == RIN_INCREASE_ACCURACY)
+	            tmp += o-&gt;spe;
+	}
+
+
 	/* make eels visible the moment they hit/miss us */
 	if(mdat-&gt;mlet == S_EEL &amp;&amp; mtmp-&gt;minvis &amp;&amp; cansee(mtmp-&gt;mx,mtmp-&gt;my)) {
 		mtmp-&gt;minvis = 0;
@@ -906,6 +915,13 @@
 	dmg = d((int)mattk-&gt;damn, (int)mattk-&gt;damd);
 	if(is_undead(mdat) &amp;&amp; midnight())
 		dmg += d((int)mattk-&gt;damn, (int)mattk-&gt;damd); /* extra damage */
+	/* find rings of increase damage */
+	{
+	    struct obj *o;
+	    for (o = mtmp-&gt;minvent; o; o = o-&gt;nobj)
+	        if (o-&gt;owornmask &amp;&amp; o-&gt;otyp == RIN_INCREASE_DAMAGE)
+	            dmg += o-&gt;spe;
+	}
 
 /*	Next a cancellation factor	*/
 /*	Use uncancelled when the cancellation factor takes into account certain
@@ -1693,7 +1709,7 @@
 	}
 
 	if (mtmp != u.ustuck) return(0);
-	if (u.uswldtim &gt; 0) u.uswldtim -= 1;
+	if (u.uswldtim &gt; 0) u.uswldtim -= 1; /* what about slow digestion? */
 
 	switch(mattk-&gt;adtyp) {
 
@@ -2125,7 +2141,7 @@
 		defperc = (See_invisible != 0);
 		gendef = poly_gender();
 	} else {
-		defperc = perceives(mdef-&gt;data);
+		defperc = mon_prop(mdef,SEE_INVIS);
 		gendef = gender(mdef);
 	}
 
@@ -2160,7 +2176,9 @@
 register struct monst *mon;
 {
 	register struct obj *ring, *nring;
+        struct obj *oldring;
 	boolean fem = (mon-&gt;data == &amp;mons[PM_SUCCUBUS]); /* otherwise incubus */
+	long canputon = fem ? mfindringslot(mon, &amp;oldring) : TRUE;
 	char qbuf[QBUFSZ];
 
 	if (mon-&gt;mcan || mon-&gt;mspec_used) {
@@ -2179,68 +2197,82 @@
 	if (Blind) pline("It caresses you...");
 	else You_feel("very attracted to %s.", mon_nam(mon));
 
-	for(ring = invent; ring; ring = nring) {
-	    nring = ring-&gt;nobj;
-	    if (ring-&gt;otyp != RIN_ADORNMENT) continue;
-	    if (fem) {
-		if (rn2(20) &lt; ACURR(A_CHA)) {
-		    Sprintf(qbuf, "\"That %s looks pretty.  May I have it?\"",
-			safe_qbuf("",sizeof("\"That  looks pretty.  May I have it?\""),
-			xname(ring), simple_typename(ring-&gt;otyp), "ring"));
-		    makeknown(RIN_ADORNMENT);
-		    if (yn(qbuf) == 'n') continue;
-		} else pline("%s decides she'd like your %s, and takes it.",
-			Blind ? "She" : Monnam(mon), xname(ring));
-		makeknown(RIN_ADORNMENT);
-		if (ring==uleft || ring==uright) Ring_gone(ring);
-		if (ring==uwep) setuwep((struct obj *)0);
-		if (ring==uswapwep) setuswapwep((struct obj *)0);
-		if (ring==uquiver) setuqwep((struct obj *)0);
-		freeinv(ring);
-		(void) mpickobj(mon,ring);
-	    } else {
-		char buf[BUFSZ];
-
-		if (uleft &amp;&amp; uright &amp;&amp; uleft-&gt;otyp == RIN_ADORNMENT
-				&amp;&amp; uright-&gt;otyp==RIN_ADORNMENT)
-			break;
-		if (ring==uleft || ring==uright) continue;
-		if (rn2(20) &lt; ACURR(A_CHA)) {
-		    Sprintf(qbuf,"\"That %s looks pretty.  Would you wear it for me?\"",
-			safe_qbuf("",
-			    sizeof("\"That  looks pretty.  Would you wear it for me?\""),
+	/* Succubi only steal rings they actually want to put on. */
+	if (canputon) {
+	    for (ring = invent; ring; ring = nring) {
+		nring = ring-&gt;nobj;
+		if (ring-&gt;otyp != RIN_ADORNMENT || ring-&gt;spe &lt; 0) continue;
+		if (fem &amp;&amp; canputon) {
+		    if (oldring &amp;&amp; oldring-&gt;otyp == RIN_ADORNMENT &amp;&amp; ring-&gt;spe &lt; oldring-&gt;spe)
+			continue;
+		    if (rn2(20) &lt; ACURR(A_CHA)) {
+			Sprintf(qbuf, "\"That %s looks pretty.  May I have it?\"",
+			    safe_qbuf("",sizeof("\"That  looks pretty.  May I have it?\""),
 			    xname(ring), simple_typename(ring-&gt;otyp), "ring"));
+			makeknown(RIN_ADORNMENT);
+			if (yn(qbuf) == 'n') continue;
+		    } else pline("%s decides she'd like your %s, and takes it.",
+			    Blind ? "She" : Monnam(mon), xname(ring));
 		    makeknown(RIN_ADORNMENT);
-		    if (yn(qbuf) == 'n') continue;
+		    if (ring==uleft || ring==uright) Ring_gone(ring);
+		    if (ring==uwep) setuwep((struct obj *)0);
+		    if (ring==uswapwep) setuswapwep((struct obj *)0);
+		    if (ring==uquiver) setuqwep((struct obj *)0);
+		    freeinv(ring);
+		    (void) mpickobj(mon,ring);
+		    if (oldring) {
+			oldring-&gt;owornmask = 0L;
+			update_mon_intrinsics(mon, oldring, FALSE, FALSE);
+		    }
+		    mon-&gt;misc_worn_check |= canputon;
+		    ring-&gt;owornmask |= canputon;
+		    update_mon_intrinsics(mon, ring, TRUE, FALSE);
+		    canputon = mfindringslot(mon, &amp;oldring);
+		    if (!canputon) break;
 		} else {
-		    pline("%s decides you'd look prettier wearing your %s,",
-			Blind ? "He" : Monnam(mon), xname(ring));
-		    pline("and puts it on your finger.");
-		}
-		makeknown(RIN_ADORNMENT);
-		if (!uright) {
-		    pline("%s puts %s on your right %s.",
-			Blind ? "He" : Monnam(mon), the(xname(ring)), body_part(HAND));
-		    setworn(ring, RIGHT_RING);
-		} else if (!uleft) {
-		    pline("%s puts %s on your left %s.",
-			Blind ? "He" : Monnam(mon), the(xname(ring)), body_part(HAND));
-		    setworn(ring, LEFT_RING);
-		} else if (uright &amp;&amp; uright-&gt;otyp != RIN_ADORNMENT) {
-		    Strcpy(buf, xname(uright));
-		    pline("%s replaces your %s with your %s.",
-			Blind ? "He" : Monnam(mon), buf, xname(ring));
-		    Ring_gone(uright);
-		    setworn(ring, RIGHT_RING);
-		} else if (uleft &amp;&amp; uleft-&gt;otyp != RIN_ADORNMENT) {
-		    Strcpy(buf, xname(uleft));
-		    pline("%s replaces your %s with your %s.",
+		    char buf[BUFSZ];
+
+		    if (uleft &amp;&amp; uright &amp;&amp; uleft-&gt;otyp == RIN_ADORNMENT
+				    &amp;&amp; uright-&gt;otyp==RIN_ADORNMENT)
+			    break;
+		    if (ring==uleft || ring==uright) continue;
+		    if (rn2(20) &lt; ACURR(A_CHA)) {
+			Sprintf(qbuf,"\"That %s looks pretty.  Would you wear it for me?\"",
+			    safe_qbuf("",
+				sizeof("\"That  looks pretty.  Would you wear it for me?\""),
+				xname(ring), simple_typename(ring-&gt;otyp), "ring"));
+		 	makeknown(RIN_ADORNMENT);
+			if (yn(qbuf) == 'n') continue;
+		    } else {
+			pline("%s decides you'd look prettier wearing your %s,",
+			    Blind ? "He" : Monnam(mon), xname(ring));
+			pline("and puts it on your finger.");
+		    }
+		    makeknown(RIN_ADORNMENT);
+		    if (!uright) {
+			pline("%s puts %s on your right %s.",
+			    Blind ? "He" : Monnam(mon), the(xname(ring)), body_part(HAND));
+			setworn(ring, RIGHT_RING);
+		    } else if (!uleft) {
+			pline("%s puts %s on your left %s.",
+			    Blind ? "He" : Monnam(mon), the(xname(ring)), body_part(HAND));
+			setworn(ring, LEFT_RING);
+		    } else if (uright &amp;&amp; uright-&gt;otyp != RIN_ADORNMENT) {
+			Strcpy(buf, xname(uright));
+			pline("%s replaces your %s with your %s.",
 			Blind ? "He" : Monnam(mon), buf, xname(ring));
-		    Ring_gone(uleft);
-		    setworn(ring, LEFT_RING);
-		} else impossible("ring replacement");
-		Ring_on(ring);
-		prinv((char *)0, ring, 0L);
+			Ring_gone(uright);
+			setworn(ring, RIGHT_RING);
+		    } else if (uleft &amp;&amp; uleft-&gt;otyp != RIN_ADORNMENT) {
+			Strcpy(buf, xname(uleft));
+			pline("%s replaces your %s with your %s.",
+			    Blind ? "He" : Monnam(mon), buf, xname(ring));
+			Ring_gone(uleft);
+			setworn(ring, LEFT_RING);
+		    } else impossible("ring replacement");
+		    Ring_on(ring);
+		    prinv((char *)0, ring, 0L);
+		}
 	    }
 	}
 
@@ -2527,7 +2559,7 @@
 		if (u.umonnum == PM_FLOATING_EYE) {
 		    if (!rn2(4)) tmp = 127;
 		    if (mtmp-&gt;mcansee &amp;&amp; haseyes(mtmp-&gt;data) &amp;&amp; rn2(3) &amp;&amp;
-				(perceives(mtmp-&gt;data) || !Invis)) {
+				(mon_prop(mtmp,SEE_INVIS) || !Invis)) {
 			if (Blind)
 			    pline("As a blind %s, you cannot defend yourself.",
 							youmonst.data-&gt;mname);
diff -Ndur nethack-3.4.3/src/mon.c nethack-patched/src/mon.c
--- nethack-3.4.3/src/mon.c	2006-12-04 21:59:02.000000000 +0000
+++ nethack-patched/src/mon.c	2007-02-04 19:34:28.000000000 +0000
@@ -457,8 +457,23 @@
 	 */
 	if (!is_clinger(mtmp-&gt;data)
 	    &amp;&amp; !is_swimmer(mtmp-&gt;data) &amp;&amp; !amphibious(mtmp-&gt;data)) {
-	    if (cansee(mtmp-&gt;mx,mtmp-&gt;my)) {
-		    pline("%s drowns.", Monnam(mtmp));
+	    boolean canseem = cansee(mtmp-&gt;mx, mtmp-&gt;my);
+	    if (!level.flags.noteleport &amp;&amp;
+		mon_prop(mtmp, TELEPORT) &amp;&amp; !mtmp-&gt;msleeping &amp;&amp;
+		(rn2(2) || mon_prop(mtmp, TELEPORT_CONTROL))) {
+		/* The monster made its saving throw and teleported away! */
+		if (u.uswallow &amp;&amp; mtmp == u.ustuck) {
+		    You("are no longer inside %s!", mon_nam(mtmp));
+		}
+		else if (canseem)
+		    pline("%s suddenly vanishes!", Monnam(mtmp));
+		unstuck(mtmp);
+		(void) rloc(mtmp, FALSE);
+		water_damage(mtmp-&gt;minvent, FALSE, FALSE);
+		return 0;
+	    }
+	    if (canseem) {
+		pline("%s drowns.", Monnam(mtmp));
 	    }
 	    if (u.ustuck &amp;&amp; u.uswallow &amp;&amp; u.ustuck == mtmp) {
 	    /* This can happen after a purple worm plucks you off a
@@ -887,7 +902,7 @@
 		if (!can_carry(mtmp,otmp)) continue;
 		if (is_pool(mtmp-&gt;mx,mtmp-&gt;my)) continue;
 #ifdef INVISIBLE_OBJECTS
-		if (otmp-&gt;oinvis &amp;&amp; !perceives(mtmp-&gt;data)) continue;
+		if (otmp-&gt;oinvis &amp;&amp; !mon_prop(mtmp,SEE_INVIS)) continue;
 #endif
 		if (cansee(mtmp-&gt;mx,mtmp-&gt;my) &amp;&amp; flags.verbose)
 			pline("%s picks up %s.", Monnam(mtmp),
@@ -1080,7 +1095,7 @@
 	    if((is_pool(nx,ny) == wantpool || poolok) &amp;&amp;
 	       (lavaok || !is_lava(nx,ny))) {
 		int dispx, dispy;
-		boolean monseeu = (mon-&gt;mcansee &amp;&amp; (!Invis || perceives(mdat)));
+		boolean monseeu = (mon-&gt;mcansee &amp;&amp; (!Invis || mon_prop(mon,SEE_INVIS)));
 		boolean checkobj = OBJ_AT(nx,ny);
 
 		/* Displacement also displaces the Elbereth/scare monster,
diff -Ndur nethack-3.4.3/src/mondata.c nethack-patched/src/mondata.c
--- nethack-3.4.3/src/mondata.c	2006-12-04 21:59:02.000000000 +0000
+++ nethack-patched/src/mondata.c	2007-02-10 22:56:44.000000000 +0000
@@ -270,6 +270,51 @@
 		return((boolean)haseyes(ptr));
 }
 
+boolean
+mon_prop(mon,prop)
+register struct monst *mon;
+int prop;
+{
+    struct obj *o;
+    int adtyp = 0;
+    /* First, check if prop has a corresponding monflag */
+    switch(prop) {
+	case REGENERATION:
+	    if (regenerates(mon-&gt;data)) return TRUE;
+	    break;
+	case SEE_INVIS:
+	    if (perceives(mon-&gt;data)) return TRUE;
+	    break;
+	case TELEPORT:
+	    if (can_teleport(mon-&gt;data) &amp;&amp; !mon-&gt;mcan) return TRUE;
+	    break;
+	case TELEPORT_CONTROL:
+	    if (control_teleport(mon-&gt;data) || is_covetous(mon-&gt;data)) return TRUE;
+	    if (mon-&gt;m_lev &gt;= (attacktype(mon-&gt;data, AT_MAGC) ? 8 : 12)) return TRUE;
+	    break;
+	case TELEPAT:
+	    if (telepathic(mon-&gt;data)) return TRUE;
+	    break;
+	case HALLUC_RES:
+	    adtyp = AD_HALU;
+	    break;
+	case JUMPING:
+	    if (is_unicorn(mon-&gt;data)) return TRUE;
+	    break;
+	case ANTIMAGIC: /* just in case */
+	    return (resists_magm(mon));
+    }
+    /* Now check for extrinsics */
+    for (o = mon-&gt;minvent; o; o = o-&gt;nobj)
+	if ((o-&gt;owornmask &amp;&amp; objects[o-&gt;otyp].oc_oprop == prop) ||
+	    (o-&gt;oartifact &amp;&amp; ((adtyp &amp;&amp; protects(adtyp, o)) ||
+	    (arti_prop_spfx(prop) &amp;&amp; spec_ability(o,arti_prop_spfx(prop)))))) {
+		return TRUE;
+	}
+    return FALSE;
+
+}
+
 #endif /* OVL1 */
 #ifdef OVLB
 
diff -Ndur nethack-3.4.3/src/monmove.c nethack-patched/src/monmove.c
--- nethack-3.4.3/src/monmove.c	2006-12-04 21:59:02.000000000 +0000
+++ nethack-patched/src/monmove.c	2007-01-26 14:12:52.000000000 +0000
@@ -155,7 +155,7 @@
 boolean digest_meal;
 {
 	if (mon-&gt;mhp &lt; mon-&gt;mhpmax &amp;&amp;
-	    (moves % 20 == 0 || regenerates(mon-&gt;data))) mon-&gt;mhp++;
+	    (moves % 20 == 0 || mon_prop(mon,REGENERATION))) mon-&gt;mhp++;
 	if (mon-&gt;mspec_used) mon-&gt;mspec_used--;
 	if (digest_meal) {
 	    if (mon-&gt;meating) mon-&gt;meating--;
@@ -255,7 +255,7 @@
 	 * running into you by accident but possibly attacking the spot
 	 * where it guesses you are.
 	 */
-	if (!mtmp-&gt;mcansee || (Invis &amp;&amp; !perceives(mtmp-&gt;data))) {
+	if (!mtmp-&gt;mcansee || (Invis &amp;&amp; !mon_prop(mtmp,SEE_INVIS))) {
 		seescaryx = mtmp-&gt;mux;
 		seescaryy = mtmp-&gt;muy;
 	} else {
@@ -342,8 +342,8 @@
 	if (mtmp-&gt;mstun &amp;&amp; !rn2(10)) mtmp-&gt;mstun = 0;
 
 	/* some monsters teleport */
-	if (mtmp-&gt;mflee &amp;&amp; !rn2(40) &amp;&amp; can_teleport(mdat) &amp;&amp; !mtmp-&gt;iswiz &amp;&amp;
-	    !level.flags.noteleport) {
+	if (mtmp-&gt;mflee &amp;&amp; !rn2(40) &amp;&amp; mon_prop(mtmp,TELEPORT)
+	    &amp;&amp; !mtmp-&gt;iswiz &amp;&amp; !level.flags.noteleport) {
 		(void) rloc(mtmp, FALSE);
 		return(0);
 	}
@@ -434,7 +434,7 @@
 			if (m2-&gt;mpeaceful == mtmp-&gt;mpeaceful) continue;
 			if (mindless(m2-&gt;data)) continue;
 			if (m2 == mtmp) continue;
-			if ((telepathic(m2-&gt;data) &amp;&amp;
+			if ((mon_prop(m2,TELEPAT) &amp;&amp;
 			    (rn2(2) || m2-&gt;mblinded)) || !rn2(10)) {
 				if (cansee(m2-&gt;mx, m2-&gt;my))
 				    pline("It locks on to %s.", mon_nam(m2));
@@ -698,9 +698,9 @@
 #endif
 
 	/* teleport if that lies in our nature */
-	if(ptr == &amp;mons[PM_TENGU] &amp;&amp; !rn2(5) &amp;&amp; !mtmp-&gt;mcan &amp;&amp;
-	   !tele_restrict(mtmp)) {
-	    if(mtmp-&gt;mhp &lt; 7 || mtmp-&gt;mpeaceful || rn2(2))
+	if(mon_prop(mtmp,TELEPORT) &amp;&amp; !rn2(ptr == &amp;mons[PM_TENGU] ? 5 : 10) &amp;&amp;
+	        !tele_restrict(mtmp)) {
+	    if(!controls_teleport(mtmp) || rn2(2))
 		(void) rloc(mtmp, FALSE);
 	    else
 		mnexto(mtmp);
@@ -726,7 +726,7 @@
 				      (dist2(omx, omy, gx, gy) &lt;= 36));
 
 		if (!mtmp-&gt;mcansee ||
-		    (should_see &amp;&amp; Invis &amp;&amp; !perceives(ptr) &amp;&amp; rn2(11)) ||
+		    (should_see &amp;&amp; Invis &amp;&amp; !mon_prop(mtmp,SEE_INVIS) &amp;&amp; rn2(11)) ||
 		    (youmonst.m_ap_type == M_AP_OBJECT &amp;&amp; youmonst.mappearance == STRANGE_OBJECT) || u.uundetected ||
 		    (youmonst.m_ap_type == M_AP_OBJECT &amp;&amp; youmonst.mappearance == GOLD_PIECE &amp;&amp; !likes_gold(ptr)) ||
 		    (mtmp-&gt;mpeaceful &amp;&amp; !mtmp-&gt;isshk) ||  /* allow shks to follow */
@@ -1257,7 +1257,7 @@
 	   if you haven't moved away */
 	if (mx == u.ux &amp;&amp; my == u.uy) goto found_you;
 
-	notseen = (!mtmp-&gt;mcansee || (Invis &amp;&amp; !perceives(mtmp-&gt;data)));
+	notseen = (!mtmp-&gt;mcansee || (Invis &amp;&amp; !mon_prop(mtmp,SEE_INVIS)));
 	/* add cases as required.  eg. Displacement ... */
 	if (notseen || Underwater) {
 	    /* Xorns can smell valuable metal like gold, treat as seen */
diff -Ndur nethack-3.4.3/src/mplayer.c nethack-patched/src/mplayer.c
--- nethack-3.4.3/src/mplayer.c	2006-12-04 21:59:02.000000000 +0000
+++ nethack-patched/src/mplayer.c	2007-02-10 22:59:54.000000000 +0000
@@ -250,6 +250,28 @@
 		if (rn2(8))
 		    mk_mplayer_armor(mtmp, rnd_class(LOW_BOOTS, LEVITATION_BOOTS));
 		m_dowear(mtmp, TRUE);
+		/* done after wearing the dragon mail so the resists checks work */
+		if (rn2(8) || monsndx(ptr) == PM_WIZARD) {
+		    int i, ring, nposs = 0;
+		    static int poss[11];
+                    if (!resists_poison(mtmp)) poss[nposs++] = RIN_POISON_RESISTANCE;
+                    if (!resists_elec(mtmp)) poss[nposs++] = RIN_SHOCK_RESISTANCE;
+                    if (!resists_fire(mtmp)) poss[nposs++] = RIN_FIRE_RESISTANCE;
+                    if (!resists_cold(mtmp)) poss[nposs++] = RIN_COLD_RESISTANCE;
+                    if (!mtmp-&gt;minvis) poss[nposs++] = RIN_INVISIBILITY;
+                    if (!mon_prop(mtmp, SEE_INVIS)) poss[nposs++] = RIN_SEE_INVISIBLE;
+                    poss[nposs++] = RIN_REGENERATION;
+                    poss[nposs++] = RIN_TELEPORT_CONTROL;
+                    poss[nposs++] = RIN_INCREASE_ACCURACY;
+                    poss[nposs++] = RIN_INCREASE_DAMAGE;
+                    poss[nposs++] = RIN_PROTECTION;
+		    /* Wizards always get two different rings. */
+		    for (i=0; i &lt; 2 &amp;&amp; (monsndx(ptr) == PM_WIZARD || rn2(2)); ++i) {
+			ring = rn2(nposs);
+			mk_mplayer_armor(mtmp, poss[ring]);
+			poss[ring] = poss[--nposs];
+		    }
+		}
 
 		quan = rn2(3) ? rn2(3) : rn2(16);
 		while(quan--)
diff -Ndur nethack-3.4.3/src/muse.c nethack-patched/src/muse.c
--- nethack-3.4.3/src/muse.c	2006-12-04 21:59:02.000000000 +0000
+++ nethack-patched/src/muse.c	2007-01-30 19:07:12.000000000 +0000
@@ -626,7 +626,10 @@
 					Monnam(mtmp));
 			    return 2;
 			}
-			nlev = random_teleport_level();
+			if (!controls_teleport(mtmp))
+			    nlev = random_teleport_level();
+			else
+			    return 2;
 			if (nlev == depth(&amp;u.uz)) {
 			    if (vismon)
 				pline("%s shudders for a moment.",
@@ -1953,7 +1956,8 @@
 		mon-&gt;data == &amp;mons[PM_GHOST])	/* don't loot bones piles */
 	    return FALSE;
 
-	if (typ == WAN_MAKE_INVISIBLE || typ == POT_INVISIBILITY)
+	if (typ == WAN_MAKE_INVISIBLE || typ == POT_INVISIBILITY ||
+                                         typ == RIN_INVISIBILITY)
 	    return (boolean)(!mon-&gt;minvis &amp;&amp; !mon-&gt;invis_blkd &amp;&amp; !attacktype(mon-&gt;data, AT_GAZE));
 	if (typ == WAN_SPEED_MONSTER || typ == POT_SPEED)
 	    return (boolean)(mon-&gt;mspeed != MFAST);
@@ -2016,6 +2020,42 @@
 	    if (typ == EGG)
 		return (boolean)(touch_petrifies(&amp;mons[obj-&gt;corpsenm]));
 	    break;
+        case RING_CLASS:
+            /* Should match the list in m_dowear_type */
+            /* Uniques don't go for invisibility or teleportation;
+               it would probably be a waste of time. */
+            if (typ == RIN_PROTECTION ||
+		typ == RIN_INCREASE_DAMAGE ||
+		typ == RIN_INCREASE_ACCURACY)
+                return (obj-&gt;spe &gt; 0);
+	    if (typ == RIN_SEE_INVISIBLE)
+                return (!mon_prop(mon,SEE_INVIS));
+            if (typ == RIN_FIRE_RESISTANCE)
+                return (!resists_fire(mon));
+            if (typ == RIN_COLD_RESISTANCE)
+                return (!resists_cold(mon));
+            if (typ == RIN_SHOCK_RESISTANCE)
+                return (!resists_elec(mon));
+            if (typ == RIN_POISON_RESISTANCE)
+                return (!resists_poison(mon));
+            if (typ == RIN_SLOW_DIGESTION)
+                return (!mon_prop(mon,SLOW_DIGESTION));
+            if (typ == RIN_REGENERATION)
+                return (!mon_prop(mon,REGENERATION));
+            if (typ == RIN_TELEPORT_CONTROL)
+                return (!mon_prop(mon,TELEPORT_CONTROL));
+            /* Below this line are off-limits to uniques */
+            if (mon-&gt;data-&gt;geno &amp; G_UNIQ)
+                return (FALSE);
+            if (typ == RIN_INVISIBILITY)
+                return !(mon-&gt;minvis);
+            if (typ == RIN_TELEPORTATION)
+                return (!mon_prop(mon,TELEPORT));
+            if (typ == RIN_ADORNMENT)
+                return (mon-&gt;data == &amp;mons[PM_SUCCUBUS] &amp;&amp; obj-&gt;spe &gt; 0);
+	    if (typ == RIN_POLYMORPH) /* matches test for jumping on poly trap */
+		return (!mon-&gt;cham &amp;&amp; monstr[monsndx(mon-&gt;data)] &lt; 6);
+            break;
 	default:
 	    break;
 	}
diff -Ndur nethack-3.4.3/src/polyself.c nethack-patched/src/polyself.c
--- nethack-3.4.3/src/polyself.c	2006-12-04 21:59:04.000000000 +0000
+++ nethack-patched/src/polyself.c	2007-01-26 13:53:44.000000000 +0000
@@ -957,7 +957,7 @@
 	    if (DEADMONSTER(mtmp)) continue;
 	    if (canseemon(mtmp) &amp;&amp; couldsee(mtmp-&gt;mx, mtmp-&gt;my)) {
 		looked++;
-		if (Invis &amp;&amp; !perceives(mtmp-&gt;data))
+		if (Invis &amp;&amp; !mon_prop(mtmp,SEE_INVIS))
 		    pline("%s seems not to notice your gaze.", Monnam(mtmp));
 		else if (mtmp-&gt;minvis &amp;&amp; !See_invisible)
 		    You_cant("see where to gaze at %s.", Monnam(mtmp));
@@ -1092,7 +1092,7 @@
 		if(mtmp-&gt;mpeaceful)
 			continue;
 		u_sen = telepathic(mtmp-&gt;data) &amp;&amp; !mtmp-&gt;mcansee;
-		if (u_sen || (telepathic(mtmp-&gt;data) &amp;&amp; rn2(2)) || !rn2(10)) {
+		if (u_sen || (mon_prop(mtmp,TELEPAT) &amp;&amp; rn2(2)) || !rn2(10)) {
 			You("lock in on %s %s.", s_suffix(mon_nam(mtmp)),
 				u_sen ? "telepathy" :
 				telepathic(mtmp-&gt;data) ? "latent telepathy" :
diff -Ndur nethack-3.4.3/src/steal.c nethack-patched/src/steal.c
--- nethack-3.4.3/src/steal.c	2006-12-04 21:59:04.000000000 +0000
+++ nethack-patched/src/steal.c	2007-02-10 22:53:26.000000000 +0000
@@ -273,7 +273,7 @@
 	for(otmp = invent; otmp; otmp = otmp-&gt;nobj)
 	    if ((!uarm || otmp != uarmc) &amp;&amp; otmp != uskin
 #ifdef INVISIBLE_OBJECTS
-				&amp;&amp; (!otmp-&gt;oinvis || perceives(mtmp-&gt;data))
+				&amp;&amp; (!otmp-&gt;oinvis || mon_prop(mtmp,SEE_INVIS))
 #endif
 				)
 		tmp += ((otmp-&gt;owornmask &amp;
@@ -283,7 +283,7 @@
 	for(otmp = invent; otmp; otmp = otmp-&gt;nobj)
 	    if ((!uarm || otmp != uarmc) &amp;&amp; otmp != uskin
 #ifdef INVISIBLE_OBJECTS
-				&amp;&amp; (!otmp-&gt;oinvis || perceives(mtmp-&gt;data))
+				&amp;&amp; (!otmp-&gt;oinvis || mon_prop(mtmp,SEE_INVIS))
 #endif
 			)
 		if((tmp -= ((otmp-&gt;owornmask &amp;
@@ -314,6 +314,8 @@
 		ostuck = TRUE;	/* effectively worn; curse is implicit */
 	    else if (otmp == uquiver || (otmp == uswapwep &amp;&amp; !u.twoweap))
 		ostuck = FALSE;	/* not really worn; curse doesn't matter */
+	    else if (otmp-&gt;owornmask == W_WEP)
+		ostuck = will_weld(otmp);
 	    else
 		ostuck = (otmp-&gt;cursed &amp;&amp; otmp-&gt;owornmask);
 
@@ -506,11 +508,11 @@
 	if (otmp-&gt;owornmask)
 	    remove_worn_item(otmp, TRUE);
 	freeinv(otmp);
-	/* mpickobj wont merge otmp because none of the above things
-	   to steal are mergable */
+	/* mpickobj won't merge otmp because none of the above things
+	   to steal are mergeable */
 	(void) mpickobj(mtmp,otmp);	/* may merge and free otmp */
 	pline("%s stole %s!", Monnam(mtmp), doname(otmp));
-	if (can_teleport(mtmp-&gt;data) &amp;&amp; !tele_restrict(mtmp))
+	if (mon_prop(mtmp,TELEPORT) &amp;&amp; !tele_restrict(mtmp))
 	    (void) rloc(mtmp, FALSE);
     }
 }
diff -Ndur nethack-3.4.3/src/teleport.c nethack-patched/src/teleport.c
--- nethack-3.4.3/src/teleport.c	2006-12-04 21:59:04.000000000 +0000
+++ nethack-patched/src/teleport.c	2007-02-04 20:15:16.000000000 +0000
@@ -1057,6 +1057,17 @@
 	return FALSE;
 }
 
+/* Returns true if a monster wants to teleport to a specific location */
+boolean
+controls_teleport(mtmp)
+struct monst *mtmp;
+{
+	if (!mon_prop(mtmp, TELEPORT_CONTROL)) return FALSE; /* No choice */
+	if (mtmp-&gt;mtame) return TRUE; /* Teleport to player */
+	/* Fleeing or peaceful non-pets just want to go anywhere but here */
+	return !(mtmp-&gt;mhp &lt; 7 || mtmp-&gt;mflee || mtmp-&gt;mpeaceful);
+}
+
 void
 mtele_trap(mtmp, trap, in_sight)
 struct monst *mtmp;
@@ -1066,6 +1077,7 @@
 	char *monname;
 
 	if (tele_restrict(mtmp)) return;
+	if (resists_magm(mtmp)) return; /* same as player */
 	if (teleport_pet(mtmp, FALSE)) {
 	    /* save name with pre-movement visibility */
 	    monname = Monnam(mtmp);
@@ -1075,7 +1087,10 @@
 	     * the guard isn't going to come for it...
 	     */
 	    if (trap-&gt;once) mvault_tele(mtmp);
-	    else (void) rloc(mtmp, FALSE);
+	    else if (!controls_teleport(mtmp))
+		(void) rloc(mtmp, FALSE);
+	    else
+		mnexto(mtmp);
 
 	    if (in_sight) {
 		if (canseemon(mtmp))
@@ -1100,6 +1115,7 @@
 
 	if (mtmp == u.ustuck)	/* probably a vortex */
 	    return 0;		/* temporary? kludge */
+	if (resists_magm(mtmp)) return 0; /* same as player */
 	if (teleport_pet(mtmp, force_it)) {
 	    d_level tolevel;
 	    int migrate_typ = MIGR_RANDOM;
@@ -1137,7 +1153,10 @@
 				Monnam(mtmp));
 		    return 0;
 		}
-		nlev = random_teleport_level();
+	        if(!controls_teleport(mtmp))
+		    nlev = random_teleport_level();
+		else
+		    return 0;
 		if (nlev == depth(&amp;u.uz)) {
 		    if (in_sight)
 			pline("%s shudders for a moment.", Monnam(mtmp));
@@ -1280,7 +1299,7 @@
 		You("are no longer inside %s!", mon_nam(mtmp));
 	    unstuck(mtmp);
 	    (void) rloc(mtmp, FALSE);
-	} else if (is_rider(mtmp-&gt;data) &amp;&amp; rn2(13) &amp;&amp;
+	} else if (mon_prop(mtmp,TELEPORT_CONTROL) &amp;&amp; rn2(13) &amp;&amp;
 		   enexto(&amp;cc, u.ux, u.uy, mtmp-&gt;data))
 	    rloc_to(mtmp, cc.x, cc.y);
 	else
diff -Ndur nethack-3.4.3/src/uhitm.c nethack-patched/src/uhitm.c
--- nethack-3.4.3/src/uhitm.c	2006-12-04 21:59:04.000000000 +0000
+++ nethack-patched/src/uhitm.c	2007-01-26 18:18:20.000000000 +0000
@@ -1672,7 +1672,8 @@
 		}
 		break;
 	    case AD_HALU:
-		if (haseyes(mdef-&gt;data) &amp;&amp; mdef-&gt;mcansee) {
+		if (haseyes(mdef-&gt;data) &amp;&amp; mdef-&gt;mcansee
+			&amp;&amp; !mon_prop(mdef,HALLUC_RES)) {
 		    pline("%s is affected by your flash of light!",
 			  Monnam(mdef));
 		    mdef-&gt;mconf = 1;
@@ -1763,6 +1764,14 @@
 		start_engulf(mdef);
 		switch(mattk-&gt;adtyp) {
 		    case AD_DGST:
+                        /* slow digestion protects against engulfing */
+                        if (mon_prop(mdef,SLOW_DIGESTION)) {
+			    You("hurriedly regurgitate the sizzling in your %s.",
+				body_part(STOMACH));
+                            end_engulf();
+                            return (2);
+                        }
+
 			/* eating a Rider or its corpse is fatal */
 			if (is_rider(mdef-&gt;data)) {
 			 pline("Unfortunately, digesting any of it is fatal.");
diff -Ndur nethack-3.4.3/src/weapon.c nethack-patched/src/weapon.c
--- nethack-3.4.3/src/weapon.c	2006-12-04 21:59:04.000000000 +0000
+++ nethack-patched/src/weapon.c	2007-02-10 22:50:36.000000000 +0000
@@ -157,7 +157,7 @@
 
 #ifdef INVISIBLE_OBJECTS
 	/* Invisible weapons against monsters who can't see invisible */
-	if (otmp-&gt;oinvis &amp;&amp; !perceives(ptr)) tmp += 3;
+	if (otmp-&gt;oinvis &amp;&amp; !mon_prop(mon,SEE_INVIS)) tmp += 3;
 #endif
 
 	/* Check specially named weapon "to hit" bonuses */
@@ -630,7 +630,7 @@
 		 * can know it's cursed and needn't even bother trying.
 		 * Still....
 		 */
-		if (mw_tmp &amp;&amp; mw_tmp-&gt;cursed &amp;&amp; mw_tmp-&gt;otyp != CORPSE) {
+		if (mw_tmp &amp;&amp; will_weld(mw_tmp)) {
 		    if (canseemon(mon)) {
 			char welded_buf[BUFSZ];
 			const char *mon_hand = mbodypart(mon, HAND);
@@ -663,7 +663,7 @@
 		mon-&gt;weapon_check = NEED_WEAPON;
 		if (canseemon(mon)) {
 		    pline("%s wields %s!", Monnam(mon), doname(obj));
-		    if (obj-&gt;cursed &amp;&amp; obj-&gt;otyp != CORPSE) {
+		    if (will_weld(obj)) {
 			pline("%s %s to %s %s!",
 			    Tobjnam(obj, "weld"),
 			    is_plural(obj) ? "themselves" : "itself",
diff -Ndur nethack-3.4.3/src/wield.c nethack-patched/src/wield.c
--- nethack-3.4.3/src/wield.c	2006-12-04 21:59:04.000000000 +0000
+++ nethack-patched/src/wield.c	2007-02-10 23:00:12.000000000 +0000
@@ -60,9 +60,12 @@
 				|| (optr)-&gt;otyp == IRON_CHAIN)
 
 /* used by welded(), and also while wielding */
-#define will_weld(optr)		((optr)-&gt;cursed \
-				&amp;&amp; (erodeable_wep(optr) \
-				   || (optr)-&gt;otyp == TIN_OPENER))
+boolean
+will_weld(optr)
+register struct obj *optr;
+{
+    return (optr-&gt;cursed &amp;&amp; (erodeable_wep(optr) || optr-&gt;otyp == TIN_OPENER));
+}
 
 
 /*** Functions that place a given item in a slot ***/
diff -Ndur nethack-3.4.3/src/worn.c nethack-patched/src/worn.c
--- nethack-3.4.3/src/worn.c	2006-12-04 21:59:04.000000000 +0000
+++ nethack-patched/src/worn.c	2007-02-10 22:45:10.000000000 +0000
@@ -4,6 +4,8 @@
 
 #include "hack.h"
 
+extern const int monstr[];
+
 STATIC_DCL void FDECL(m_lose_armor, (struct monst *,struct obj *));
 STATIC_DCL void FDECL(m_dowear_type, (struct monst *,long, BOOLEAN_P, BOOLEAN_P));
 STATIC_DCL int FDECL(extra_pref, (struct monst *, struct obj *));
@@ -333,14 +335,16 @@
 	long mwflags = mon-&gt;misc_worn_check;
 
 	for (obj = mon-&gt;minvent; obj; obj = obj-&gt;nobj) {
-	    if (obj-&gt;owornmask &amp; mwflags)
+	    if (obj-&gt;owornmask &amp; mwflags &amp;&amp;
+		  obj-&gt;otyp != RIN_INCREASE_DAMAGE &amp;&amp;
+		  obj-&gt;otyp != RIN_INCREASE_ACCURACY)
 		base -= ARM_BONUS(obj);
 		/* since ARM_BONUS is positive, subtracting it increases AC */
 	}
 	return base;
 }
 
-/* weapons are handled separately; rings and eyewear aren't used by monsters */
+/* weapons are handled separately; eyewear isn't used by monsters */
 
 /* Wear the best object of each type that the monster has.  During creation,
  * the monster can put everything on at once; otherwise, wearing takes time.
@@ -360,6 +364,8 @@
 register struct monst *mon;
 boolean creation;
 {
+	struct obj *mw = MON_WEP(mon);
+	long flag;
 #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
@@ -384,8 +390,16 @@
 	if (!cantweararm(mon-&gt;data) || mon-&gt;data-&gt;msize == MZ_SMALL)
 	    m_dowear_type(mon, W_ARMC, creation, FALSE);
 	m_dowear_type(mon, W_ARMH, creation, FALSE);
-	if (!MON_WEP(mon) || !bimanual(MON_WEP(mon)))
+	if (!mw || !bimanual(mw))
 	    m_dowear_type(mon, W_ARMS, creation, FALSE);
+
+        /* Two rings per monster; ring takes up a "hand" slot */
+        if ((flag = mfindringslot(mon,(struct obj**)0)) != 0L)
+          m_dowear_type(mon, flag, creation, FALSE);
+        if ((flag = mfindringslot(mon,(struct obj**)0)) != 0L)
+        if (flag != 0L)
+          m_dowear_type(mon, flag, creation, FALSE);
+
 	m_dowear_type(mon, W_ARMG, creation, FALSE);
 	if (!slithy(mon-&gt;data) &amp;&amp; mon-&gt;data-&gt;mlet != S_CENTAUR)
 	    m_dowear_type(mon, W_ARMF, creation, FALSE);
@@ -395,6 +409,44 @@
 	    m_dowear_type(mon, W_ARM, creation, RACE_EXCEPTION);
 }
 
+/* Find an available ring slot, if possible.
+   Return the current object in that slot in *objp. */
+long
+mfindringslot(mon, objp)
+struct monst *mon;
+struct obj **objp;
+{
+    struct obj *oleft, *oright;
+    struct obj *mw = which_armor(mon, W_ARMG);
+    long flag; /* best available slot for the ring */
+
+    if (mw &amp;&amp; mw-&gt;cursed)  /* cursed gloves */
+        return 0L;
+    mw = MON_WEP(mon);
+    if (mw &amp;&amp; !will_weld(mw))  /* if it's not welded, we don't care */
+        mw = (struct obj *)0;
+    if (mw &amp;&amp; bimanual(mw))
+        return 0L;
+    oleft = which_armor(mon, W_RINGL);
+    oright = which_armor(mon, W_RINGR);
+    if (!oleft) {
+        flag = W_RINGL;
+    } else if (!mw &amp;&amp; (!oright || (oleft-&gt;cursed &amp;&amp; !oright-&gt;cursed))) {
+        flag = W_RINGR;
+    } else if (oright-&gt;cursed &amp;&amp; !oleft-&gt;cursed) {
+        flag = W_RINGL;
+    } else if (oright-&gt;cursed) { /* both rings cursed */
+	return 0L;
+    } else if (!mw &amp;&amp; (extra_pref(mon,oright) &gt;= extra_pref(mon,oleft))) {
+        flag = W_RINGR;
+    } else
+        flag = W_RINGL;
+
+    if (objp)
+        *objp = (flag == W_RINGL ? oleft : oright);
+    return flag;
+}
+
 STATIC_OVL void
 m_dowear_type(mon, flag, creation, racialexception)
 struct monst *mon;
@@ -452,6 +504,26 @@
 		    if (!is_suit(obj)) continue;
 		    if (racialexception &amp;&amp; (racial_exception(mon, obj) &lt; 1)) continue;
 		    break;
+                case W_RINGL:
+                case W_RINGR:
+                    /* Monsters can put on only the following rings. */
+                    if (obj-&gt;oclass != RING_CLASS ||
+			(obj-&gt;otyp != RIN_ADORNMENT &amp;&amp;
+			 obj-&gt;otyp != RIN_INVISIBILITY &amp;&amp;
+			 obj-&gt;otyp != RIN_FIRE_RESISTANCE &amp;&amp;
+			 obj-&gt;otyp != RIN_COLD_RESISTANCE &amp;&amp;
+			 obj-&gt;otyp != RIN_POISON_RESISTANCE &amp;&amp;
+			 obj-&gt;otyp != RIN_SHOCK_RESISTANCE &amp;&amp;
+			 obj-&gt;otyp != RIN_REGENERATION &amp;&amp;
+			 obj-&gt;otyp != RIN_TELEPORTATION &amp;&amp;
+			 obj-&gt;otyp != RIN_TELEPORT_CONTROL &amp;&amp;
+			 obj-&gt;otyp != RIN_POLYMORPH &amp;&amp;
+			 obj-&gt;otyp != RIN_SLOW_DIGESTION &amp;&amp;
+			 obj-&gt;otyp != RIN_INCREASE_DAMAGE &amp;&amp;
+			 obj-&gt;otyp != RIN_INCREASE_ACCURACY &amp;&amp;
+			 obj-&gt;otyp != RIN_PROTECTION))
+			continue;
+                    break;
 	    }
 	    if (obj-&gt;owornmask) continue;
 	    /* I'd like to define a VISIBLE_ARM_BONUS which doesn't assume the
@@ -752,19 +824,94 @@
 	return;
 }
 
-/* bias a monster's preferences towards armor that has special benefits. */
-/* currently only does speed boots, but might be expanded if monsters get to
-   use more armor abilities */
+/*
+ * Bias a monster's preferences towards armor that has special benefits.
+ * Currently does speed boots and various rings.
+ */
 static int
 extra_pref(mon, obj)
 struct monst *mon;
 struct obj *obj;
 {
-    if (obj) {
+	struct obj *old;
+	int rc = 1;
+	long i;
+
+	if (!obj) return 0;
+
 	if (obj-&gt;otyp == SPEED_BOOTS &amp;&amp; mon-&gt;permspeed != MFAST)
 	    return 20;
-    }
-    return 0;
+	if (obj-&gt;oclass != RING_CLASS)
+	    return 0;
+
+	/* Find out whether the monster already has some resistance. */
+	old = which_armor(mon, W_RINGL); 
+	if (old) update_mon_intrinsics(mon, old, FALSE, TRUE); 
+	old = which_armor(mon, W_RINGR); 
+	if (old) update_mon_intrinsics(mon, old, FALSE, TRUE); 
+	/* This list should match the list in m_dowear_type. */
+	switch (obj-&gt;otyp) {
+	case RIN_ADORNMENT:
+	    if (mon-&gt;data == &amp;mons[PM_SUCCUBUS] &amp;&amp; obj-&gt;spe &gt; 0)
+	        rc = 100 + obj-&gt;spe;
+	    break;
+	case RIN_FIRE_RESISTANCE:
+	    if (!resists_fire(mon))
+	        rc = dmgtype(youmonst.data, AD_FIRE)
+			|| (uwep &amp;&amp; uwep-&gt;oartifact == ART_FIRE_BRAND) ? 20 : 12;
+	    break;
+	case RIN_COLD_RESISTANCE:
+	    if (!resists_cold(mon))
+	        rc = dmgtype(youmonst.data, AD_COLD)
+			|| (uwep &amp;&amp; uwep-&gt;oartifact == ART_FROST_BRAND) ? 20 : 12;
+	    break;
+	case RIN_POISON_RESISTANCE:
+	    if (!resists_poison(mon))
+	        rc = dmgtype(youmonst.data,AD_DRST)
+		     || dmgtype(youmonst.data,AD_DRCO)
+		     || dmgtype(youmonst.data,AD_DRDX) ? 20 : 10;
+	    break;
+	case RIN_SHOCK_RESISTANCE:
+	    if (!resists_elec(mon))
+		rc = dmgtype(youmonst.data,AD_ELEC)
+			|| (uwep &amp;&amp; uwep-&gt;oartifact == ART_MJOLLNIR) ? 20 : 10;
+	    break;
+	case RIN_REGENERATION:
+	    rc = !mon_prop(mon,REGENERATION) ? 20 : 0;
+	    break;
+	case RIN_INVISIBILITY:
+	    if (mon-&gt;mtame || mon-&gt;mpeaceful)
+		rc = See_invisible ? 10 : 0;
+	    else rc = 30;
+	    break;
+	case RIN_INCREASE_DAMAGE:
+	case RIN_INCREASE_ACCURACY:
+	case RIN_PROTECTION:
+            if (obj-&gt;spe &gt; 0)
+                rc = 10 + 3*(obj-&gt;spe);
+            else rc = 0;
+            break;
+        case RIN_TELEPORTATION:
+	    if (!mon_prop(mon,TELEPORT))
+		rc = (obj-&gt;cursed) ? 5 : 15;
+	    break;
+	case RIN_TELEPORT_CONTROL:
+	    if (!mon_prop(mon,TELEPORT_CONTROL))
+		rc = mon_prop(mon,TELEPORT) ? 20 : 5;
+	    break;
+	case RIN_POLYMORPH:
+	    rc = (!mon-&gt;cham &amp;&amp; monstr[monsndx(mon-&gt;data)] &lt; 6) ? 15 : 0;
+	    break;
+	case RIN_SLOW_DIGESTION:
+            if (dmgtype(youmonst.data, AD_DGST))
+		rc = 25;
+	    break;
+	}
+	old = which_armor(mon, W_RINGL); 
+	if (old) update_mon_intrinsics(mon, old, TRUE, TRUE); 
+	old = which_armor(mon, W_RINGR); 
+	if (old) update_mon_intrinsics(mon, old, TRUE, TRUE); 
+	return rc;
 }
 
 /*
</pre></body></html>