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->data) && !humanoid(mtmp->data) && - (!mtmp->minvis || perceives(mtmp->data)) && rn2(5)) { + (!mtmp->minvis || mon_prop(mtmp,SEE_INVIS)) && 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->minvis && !See_invisible) ; - else if ((mtmp->minvis && !perceives(mtmp->data)) + else if ((mtmp->minvis && !mon_prop(mtmp,SEE_INVIS)) || !haseyes(mtmp->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 && otmp->cursed) { + if (gotit && will_weld(otmp)) { pline("%s welded to %s %s%c", (otmp->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 && (arti->spfx & abil))); + if (arti && (arti->spfx & abil)) return TRUE; + return(boolean)(arti && (arti->cspfx & 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->data)) imv /= 20; + if (!mon_prop(mtmp,REGENERATION)) imv /= 20; if (mtmp->mhp + imv >= mtmp->mhpmax) mtmp->mhp = mtmp->mhpmax; else mtmp->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->m_lev >= (int)mtmp->m_lev+2 || (mtmp2->data == &mons[PM_FLOATING_EYE] && rn2(10) && mtmp->mcansee && haseyes(mtmp->data) && mtmp2->mcansee - && (perceives(mtmp->data) || !mtmp2->minvis)) || + && (mon_prop(mtmp,SEE_INVIS) || !mtmp2->minvis)) || (mtmp2->data==&mons[PM_GELATINOUS_CUBE] && rn2(10)) || (max_passive_dmg(mtmp2, mtmp) >= mtmp->mhp) || ((mtmp->mhp*4 < mtmp->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 && !perceives(mtmp->data) && + else if ((Invis && !mon_prop(mtmp,SEE_INVIS) && (mtmp->mux != u.ux || mtmp->muy != u.uy)) || (youmonst.m_ap_type == M_AP_OBJECT && youmonst.mappearance == STRANGE_OBJECT) || @@ -238,7 +238,7 @@ pline("%s casts a spell%s!", canspotmon(mtmp) ? Monnam(mtmp) : "Something", is_undirected_spell(mattk->adtyp, spellnum) ? "" : - (Invisible && !perceives(mtmp->data) && + (Invisible && !mon_prop(mtmp,SEE_INVIS) && (mtmp->mux != u.ux || mtmp->muy != u.uy)) ? " at a spot near you" : (Displaced && (mtmp->mux != u.ux || mtmp->muy != u.uy)) ? @@ -368,7 +368,7 @@ /* messages not quite right if plural monsters created but only a single monster is seen */ - if (Invisible && !perceives(mtmp->data) && + if (Invisible && !mon_prop(mtmp,SEE_INVIS) && (mtmp->mux != u.ux || mtmp->muy != u.uy)) pline("%s around a spot near you!", mappear); else if (Displaced && (mtmp->mux != u.ux || mtmp->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 && !perceives(mtmp->data) && + else if (Invisible && !mon_prop(mtmp,SEE_INVIS) && (mtmp->mux != u.ux || mtmp->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->msleeping = 0; } + /* find rings of increase accuracy */ + { + struct obj *o; + for (o = magr->minvent; o; o = o->nobj) + if (o->owornmask && o->otyp == RIN_INCREASE_ACCURACY) + tmp += o->spe; + } /* undetect monsters become un-hidden if they are attacked */ if (mdef->mundetected) { @@ -448,7 +457,7 @@ } if (magr->mcan || !magr->mcansee || - (magr->minvis && !perceives(mdef->data)) || + (magr->minvis && !mon_prop(mdef,SEE_INVIS)) || !mdef->mcansee || mdef->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->minvis && !perceives(magr->data)) { + if (mdef->minvis && !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 & 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->minvent) { + struct obj *o; + for (o = magr->minvent; o; o = o->nobj) + if (o->owornmask && o->otyp == RIN_INCREASE_DAMAGE) + tmp += o->spe; + } /* cancellation factor is the same as when attacking the hero */ armpro = magic_negation(mdef); @@ -622,6 +645,8 @@ switch(mattk->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->data)) { if (vis) @@ -922,7 +947,8 @@ tmp = 0; break; case AD_HALU: - if (!magr->mcan && haseyes(pd) && mdef->mcansee) { + if (!magr->mcan && haseyes(pd) && mdef->mcansee + && !mon_prop(mdef,HALLUC_RES)) { if (vis) pline("%s looks %sconfused.", Monnam(mdef), mdef->mconf ? "more " : ""); mdef->mconf = 1; @@ -1326,7 +1352,7 @@ if (mddat == &mons[PM_FLOATING_EYE]) { if (!rn2(4)) tmp = 127; if (magr->mcansee && haseyes(madat) && mdef->mcansee && - (perceives(madat) || !mdef->minvis)) { + (!mdef->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->adtyp == AD_SEDU || mattk->adtyp == AD_SSEX) && could_seduce(mtmp, &youmonst, (struct attack *)0); - if (!mtmp->mcansee || (Invis && !perceives(mtmp->data))) { + if (!mtmp->mcansee || (Invis && !mon_prop(mtmp,SEE_INVIS))) { const char *swings = mattk->aatyp == AT_BITE ? "snaps" : mattk->aatyp == AT_KICK ? "kicks" : @@ -463,11 +463,20 @@ tmp = AC_VALUE(u.uac) + 10; /* tmp ~= 0 - 20 */ tmp += mtmp->m_lev; if(multi < 0) tmp += 4; - if((Invis && !perceives(mdat)) || !mtmp->mcansee) + if((Invis && !mon_prop(mtmp,SEE_INVIS)) || !mtmp->mcansee) tmp -= 2; if(mtmp->mtrapped) tmp -= 2; if(tmp <= 0) tmp = 1; + /* find rings of increase accuracy */ + { + struct obj *o; + for (o = mtmp->minvent; o; o = o->nobj) + if (o->owornmask && o->otyp == RIN_INCREASE_ACCURACY) + tmp += o->spe; + } + + /* make eels visible the moment they hit/miss us */ if(mdat->mlet == S_EEL && mtmp->minvis && cansee(mtmp->mx,mtmp->my)) { mtmp->minvis = 0; @@ -906,6 +915,13 @@ dmg = d((int)mattk->damn, (int)mattk->damd); if(is_undead(mdat) && midnight()) dmg += d((int)mattk->damn, (int)mattk->damd); /* extra damage */ + /* find rings of increase damage */ + { + struct obj *o; + for (o = mtmp->minvent; o; o = o->nobj) + if (o->owornmask && o->otyp == RIN_INCREASE_DAMAGE) + dmg += o->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 > 0) u.uswldtim -= 1; + if (u.uswldtim > 0) u.uswldtim -= 1; /* what about slow digestion? */ switch(mattk->adtyp) { @@ -2125,7 +2141,7 @@ defperc = (See_invisible != 0); gendef = poly_gender(); } else { - defperc = perceives(mdef->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->data == &mons[PM_SUCCUBUS]); /* otherwise incubus */ + long canputon = fem ? mfindringslot(mon, &oldring) : TRUE; char qbuf[QBUFSZ]; if (mon->mcan || mon->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->nobj; - if (ring->otyp != RIN_ADORNMENT) continue; - if (fem) { - if (rn2(20) < 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->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 && uright && uleft->otyp == RIN_ADORNMENT - && uright->otyp==RIN_ADORNMENT) - break; - if (ring==uleft || ring==uright) continue; - if (rn2(20) < 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->nobj; + if (ring->otyp != RIN_ADORNMENT || ring->spe < 0) continue; + if (fem && canputon) { + if (oldring && oldring->otyp == RIN_ADORNMENT && ring->spe < oldring->spe) + continue; + if (rn2(20) < 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->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->owornmask = 0L; + update_mon_intrinsics(mon, oldring, FALSE, FALSE); + } + mon->misc_worn_check |= canputon; + ring->owornmask |= canputon; + update_mon_intrinsics(mon, ring, TRUE, FALSE); + canputon = mfindringslot(mon, &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 && uright->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 && uleft->otyp != RIN_ADORNMENT) { - Strcpy(buf, xname(uleft)); - pline("%s replaces your %s with your %s.", + char buf[BUFSZ]; + + if (uleft && uright && uleft->otyp == RIN_ADORNMENT + && uright->otyp==RIN_ADORNMENT) + break; + if (ring==uleft || ring==uright) continue; + if (rn2(20) < 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->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 && uright->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 && uleft->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->mcansee && haseyes(mtmp->data) && rn2(3) && - (perceives(mtmp->data) || !Invis)) { + (mon_prop(mtmp,SEE_INVIS) || !Invis)) { if (Blind) pline("As a blind %s, you cannot defend yourself.", youmonst.data->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->data) && !is_swimmer(mtmp->data) && !amphibious(mtmp->data)) { - if (cansee(mtmp->mx,mtmp->my)) { - pline("%s drowns.", Monnam(mtmp)); + boolean canseem = cansee(mtmp->mx, mtmp->my); + if (!level.flags.noteleport && + mon_prop(mtmp, TELEPORT) && !mtmp->msleeping && + (rn2(2) || mon_prop(mtmp, TELEPORT_CONTROL))) { + /* The monster made its saving throw and teleported away! */ + if (u.uswallow && 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->minvent, FALSE, FALSE); + return 0; + } + if (canseem) { + pline("%s drowns.", Monnam(mtmp)); } if (u.ustuck && u.uswallow && 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->mx,mtmp->my)) continue; #ifdef INVISIBLE_OBJECTS - if (otmp->oinvis && !perceives(mtmp->data)) continue; + if (otmp->oinvis && !mon_prop(mtmp,SEE_INVIS)) continue; #endif if (cansee(mtmp->mx,mtmp->my) && flags.verbose) pline("%s picks up %s.", Monnam(mtmp), @@ -1080,7 +1095,7 @@ if((is_pool(nx,ny) == wantpool || poolok) && (lavaok || !is_lava(nx,ny))) { int dispx, dispy; - boolean monseeu = (mon->mcansee && (!Invis || perceives(mdat))); + boolean monseeu = (mon->mcansee && (!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->data)) return TRUE; + break; + case SEE_INVIS: + if (perceives(mon->data)) return TRUE; + break; + case TELEPORT: + if (can_teleport(mon->data) && !mon->mcan) return TRUE; + break; + case TELEPORT_CONTROL: + if (control_teleport(mon->data) || is_covetous(mon->data)) return TRUE; + if (mon->m_lev >= (attacktype(mon->data, AT_MAGC) ? 8 : 12)) return TRUE; + break; + case TELEPAT: + if (telepathic(mon->data)) return TRUE; + break; + case HALLUC_RES: + adtyp = AD_HALU; + break; + case JUMPING: + if (is_unicorn(mon->data)) return TRUE; + break; + case ANTIMAGIC: /* just in case */ + return (resists_magm(mon)); + } + /* Now check for extrinsics */ + for (o = mon->minvent; o; o = o->nobj) + if ((o->owornmask && objects[o->otyp].oc_oprop == prop) || + (o->oartifact && ((adtyp && protects(adtyp, o)) || + (arti_prop_spfx(prop) && 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->mhp < mon->mhpmax && - (moves % 20 == 0 || regenerates(mon->data))) mon->mhp++; + (moves % 20 == 0 || mon_prop(mon,REGENERATION))) mon->mhp++; if (mon->mspec_used) mon->mspec_used--; if (digest_meal) { if (mon->meating) mon->meating--; @@ -255,7 +255,7 @@ * running into you by accident but possibly attacking the spot * where it guesses you are. */ - if (!mtmp->mcansee || (Invis && !perceives(mtmp->data))) { + if (!mtmp->mcansee || (Invis && !mon_prop(mtmp,SEE_INVIS))) { seescaryx = mtmp->mux; seescaryy = mtmp->muy; } else { @@ -342,8 +342,8 @@ if (mtmp->mstun && !rn2(10)) mtmp->mstun = 0; /* some monsters teleport */ - if (mtmp->mflee && !rn2(40) && can_teleport(mdat) && !mtmp->iswiz && - !level.flags.noteleport) { + if (mtmp->mflee && !rn2(40) && mon_prop(mtmp,TELEPORT) + && !mtmp->iswiz && !level.flags.noteleport) { (void) rloc(mtmp, FALSE); return(0); } @@ -434,7 +434,7 @@ if (m2->mpeaceful == mtmp->mpeaceful) continue; if (mindless(m2->data)) continue; if (m2 == mtmp) continue; - if ((telepathic(m2->data) && + if ((mon_prop(m2,TELEPAT) && (rn2(2) || m2->mblinded)) || !rn2(10)) { if (cansee(m2->mx, m2->my)) pline("It locks on to %s.", mon_nam(m2)); @@ -698,9 +698,9 @@ #endif /* teleport if that lies in our nature */ - if(ptr == &mons[PM_TENGU] && !rn2(5) && !mtmp->mcan && - !tele_restrict(mtmp)) { - if(mtmp->mhp < 7 || mtmp->mpeaceful || rn2(2)) + if(mon_prop(mtmp,TELEPORT) && !rn2(ptr == &mons[PM_TENGU] ? 5 : 10) && + !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) <= 36)); if (!mtmp->mcansee || - (should_see && Invis && !perceives(ptr) && rn2(11)) || + (should_see && Invis && !mon_prop(mtmp,SEE_INVIS) && rn2(11)) || (youmonst.m_ap_type == M_AP_OBJECT && youmonst.mappearance == STRANGE_OBJECT) || u.uundetected || (youmonst.m_ap_type == M_AP_OBJECT && youmonst.mappearance == GOLD_PIECE && !likes_gold(ptr)) || (mtmp->mpeaceful && !mtmp->isshk) || /* allow shks to follow */ @@ -1257,7 +1257,7 @@ if you haven't moved away */ if (mx == u.ux && my == u.uy) goto found_you; - notseen = (!mtmp->mcansee || (Invis && !perceives(mtmp->data))); + notseen = (!mtmp->mcansee || (Invis && !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->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 < 2 && (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(&u.uz)) { if (vismon) pline("%s shudders for a moment.", @@ -1953,7 +1956,8 @@ mon->data == &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->minvis && !mon->invis_blkd && !attacktype(mon->data, AT_GAZE)); if (typ == WAN_SPEED_MONSTER || typ == POT_SPEED) return (boolean)(mon->mspeed != MFAST); @@ -2016,6 +2020,42 @@ if (typ == EGG) return (boolean)(touch_petrifies(&mons[obj->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->spe > 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->data->geno & G_UNIQ) + return (FALSE); + if (typ == RIN_INVISIBILITY) + return !(mon->minvis); + if (typ == RIN_TELEPORTATION) + return (!mon_prop(mon,TELEPORT)); + if (typ == RIN_ADORNMENT) + return (mon->data == &mons[PM_SUCCUBUS] && obj->spe > 0); + if (typ == RIN_POLYMORPH) /* matches test for jumping on poly trap */ + return (!mon->cham && monstr[monsndx(mon->data)] < 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) && couldsee(mtmp->mx, mtmp->my)) { looked++; - if (Invis && !perceives(mtmp->data)) + if (Invis && !mon_prop(mtmp,SEE_INVIS)) pline("%s seems not to notice your gaze.", Monnam(mtmp)); else if (mtmp->minvis && !See_invisible) You_cant("see where to gaze at %s.", Monnam(mtmp)); @@ -1092,7 +1092,7 @@ if(mtmp->mpeaceful) continue; u_sen = telepathic(mtmp->data) && !mtmp->mcansee; - if (u_sen || (telepathic(mtmp->data) && rn2(2)) || !rn2(10)) { + if (u_sen || (mon_prop(mtmp,TELEPAT) && rn2(2)) || !rn2(10)) { You("lock in on %s %s.", s_suffix(mon_nam(mtmp)), u_sen ? "telepathy" : telepathic(mtmp->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->nobj) if ((!uarm || otmp != uarmc) && otmp != uskin #ifdef INVISIBLE_OBJECTS - && (!otmp->oinvis || perceives(mtmp->data)) + && (!otmp->oinvis || mon_prop(mtmp,SEE_INVIS)) #endif ) tmp += ((otmp->owornmask & @@ -283,7 +283,7 @@ for(otmp = invent; otmp; otmp = otmp->nobj) if ((!uarm || otmp != uarmc) && otmp != uskin #ifdef INVISIBLE_OBJECTS - && (!otmp->oinvis || perceives(mtmp->data)) + && (!otmp->oinvis || mon_prop(mtmp,SEE_INVIS)) #endif ) if((tmp -= ((otmp->owornmask & @@ -314,6 +314,8 @@ ostuck = TRUE; /* effectively worn; curse is implicit */ else if (otmp == uquiver || (otmp == uswapwep && !u.twoweap)) ostuck = FALSE; /* not really worn; curse doesn't matter */ + else if (otmp->owornmask == W_WEP) + ostuck = will_weld(otmp); else ostuck = (otmp->cursed && otmp->owornmask); @@ -506,11 +508,11 @@ if (otmp->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->data) && !tele_restrict(mtmp)) + if (mon_prop(mtmp,TELEPORT) && !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->mtame) return TRUE; /* Teleport to player */ + /* Fleeing or peaceful non-pets just want to go anywhere but here */ + return !(mtmp->mhp < 7 || mtmp->mflee || mtmp->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->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(&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->data) && rn2(13) && + } else if (mon_prop(mtmp,TELEPORT_CONTROL) && rn2(13) && enexto(&cc, u.ux, u.uy, mtmp->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->data) && mdef->mcansee) { + if (haseyes(mdef->data) && mdef->mcansee + && !mon_prop(mdef,HALLUC_RES)) { pline("%s is affected by your flash of light!", Monnam(mdef)); mdef->mconf = 1; @@ -1763,6 +1764,14 @@ start_engulf(mdef); switch(mattk->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->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->oinvis && !perceives(ptr)) tmp += 3; + if (otmp->oinvis && !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 && mw_tmp->cursed && mw_tmp->otyp != CORPSE) { + if (mw_tmp && will_weld(mw_tmp)) { if (canseemon(mon)) { char welded_buf[BUFSZ]; const char *mon_hand = mbodypart(mon, HAND); @@ -663,7 +663,7 @@ mon->weapon_check = NEED_WEAPON; if (canseemon(mon)) { pline("%s wields %s!", Monnam(mon), doname(obj)); - if (obj->cursed && obj->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)->otyp == IRON_CHAIN) /* used by welded(), and also while wielding */ -#define will_weld(optr) ((optr)->cursed \ - && (erodeable_wep(optr) \ - || (optr)->otyp == TIN_OPENER)) +boolean +will_weld(optr) +register struct obj *optr; +{ + return (optr->cursed && (erodeable_wep(optr) || optr->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->misc_worn_check; for (obj = mon->minvent; obj; obj = obj->nobj) { - if (obj->owornmask & mwflags) + if (obj->owornmask & mwflags && + obj->otyp != RIN_INCREASE_DAMAGE && + obj->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->data) || mon->data->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->data) && mon->data->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 && mw->cursed) /* cursed gloves */ + return 0L; + mw = MON_WEP(mon); + if (mw && !will_weld(mw)) /* if it's not welded, we don't care */ + mw = (struct obj *)0; + if (mw && bimanual(mw)) + return 0L; + oleft = which_armor(mon, W_RINGL); + oright = which_armor(mon, W_RINGR); + if (!oleft) { + flag = W_RINGL; + } else if (!mw && (!oright || (oleft->cursed && !oright->cursed))) { + flag = W_RINGR; + } else if (oright->cursed && !oleft->cursed) { + flag = W_RINGL; + } else if (oright->cursed) { /* both rings cursed */ + return 0L; + } else if (!mw && (extra_pref(mon,oright) >= 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 && (racial_exception(mon, obj) < 1)) continue; break; + case W_RINGL: + case W_RINGR: + /* Monsters can put on only the following rings. */ + if (obj->oclass != RING_CLASS || + (obj->otyp != RIN_ADORNMENT && + obj->otyp != RIN_INVISIBILITY && + obj->otyp != RIN_FIRE_RESISTANCE && + obj->otyp != RIN_COLD_RESISTANCE && + obj->otyp != RIN_POISON_RESISTANCE && + obj->otyp != RIN_SHOCK_RESISTANCE && + obj->otyp != RIN_REGENERATION && + obj->otyp != RIN_TELEPORTATION && + obj->otyp != RIN_TELEPORT_CONTROL && + obj->otyp != RIN_POLYMORPH && + obj->otyp != RIN_SLOW_DIGESTION && + obj->otyp != RIN_INCREASE_DAMAGE && + obj->otyp != RIN_INCREASE_ACCURACY && + obj->otyp != RIN_PROTECTION)) + continue; + break; } if (obj->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->otyp == SPEED_BOOTS && mon->permspeed != MFAST) return 20; - } - return 0; + if (obj->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->otyp) { + case RIN_ADORNMENT: + if (mon->data == &mons[PM_SUCCUBUS] && obj->spe > 0) + rc = 100 + obj->spe; + break; + case RIN_FIRE_RESISTANCE: + if (!resists_fire(mon)) + rc = dmgtype(youmonst.data, AD_FIRE) + || (uwep && uwep->oartifact == ART_FIRE_BRAND) ? 20 : 12; + break; + case RIN_COLD_RESISTANCE: + if (!resists_cold(mon)) + rc = dmgtype(youmonst.data, AD_COLD) + || (uwep && uwep->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 && uwep->oartifact == ART_MJOLLNIR) ? 20 : 10; + break; + case RIN_REGENERATION: + rc = !mon_prop(mon,REGENERATION) ? 20 : 0; + break; + case RIN_INVISIBILITY: + if (mon->mtame || mon->mpeaceful) + rc = See_invisible ? 10 : 0; + else rc = 30; + break; + case RIN_INCREASE_DAMAGE: + case RIN_INCREASE_ACCURACY: + case RIN_PROTECTION: + if (obj->spe > 0) + rc = 10 + 3*(obj->spe); + else rc = 0; + break; + case RIN_TELEPORTATION: + if (!mon_prop(mon,TELEPORT)) + rc = (obj->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->cham && monstr[monsndx(mon->data)] < 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; } /*