From d8a45a57b500e70c26ce15b22d248edca59270be Mon Sep 17 00:00:00 2001 From: "nethack.rankin" Date: Tue, 29 Jan 2008 04:17:03 +0000 Subject: [PATCH] ring discovery (trunk only) Picking up and putting on a +1 ring of protection while blind resulted in having a "+1 ring (on {left|right} hand)" in inventory and having ring of protection show up in the discoveries list. The problem is the same as the one for wands which has been previously addressed (but not 100% fixed...): when using an item whose effect is observable, the item's type became discovered based upon that observation even if the item itself had never been seen. The code for removing ring of protection lacked its break statement and fell into the case for removing ring of protection from shapechangers, but didn't cause any noticeable problem. --- doc/fixes35.0 | 1 + include/extern.h | 1 + src/attrib.c | 28 +++++++++++++ src/do_wear.c | 100 +++++++++++++++++++++++++++++++---------------- 4 files changed, 97 insertions(+), 33 deletions(-) diff --git a/doc/fixes35.0 b/doc/fixes35.0 index 1690cfcdf..cf138ce96 100644 --- a/doc/fixes35.0 +++ b/doc/fixes35.0 @@ -114,6 +114,7 @@ fix monsndx panic which happened after currently moving monster expelled no longer replaces monster reduced message verbosity when re-entering a temple reduced message verbosity when monster with multiple attacks missed wildly +putting on a never seen ring while blinded won't make the ring a discovery zapping a never seen wand while blinded won't make the wand a discovery zapping an unID'd wand of teleportation at self will discover it (usually) zapping unlocking magic at self while punished will remove attached chain diff --git a/include/extern.h b/include/extern.h index 699d9bf8c..43575394a 100644 --- a/include/extern.h +++ b/include/extern.h @@ -108,6 +108,7 @@ E void FDECL(adjabil, (int,int)); E int NDECL(newhp); E schar FDECL(acurr, (int)); E schar NDECL(acurrstr); +E boolean FDECL(extremeattr, (int)); E void FDECL(adjalign, (int)); E int FDECL(is_innate, (int)); E char *FDECL(from_what, (int)); diff --git a/src/attrib.c b/src/attrib.c index 0326c6f8a..eb1fd8811 100644 --- a/src/attrib.c +++ b/src/attrib.c @@ -900,6 +900,34 @@ acurrstr() else return((schar)(str - 100)); } +/* when wearing (or taking off) an unID'd item, this routine is used + to distinguish between observable +0 result and no-visible-effect + due to an attribute not being able to exceed maximum or minimun */ +boolean +extremeattr(attrindx) /* does attrindx's value match its max or min? */ +int attrindx; +{ + /* Fixed_abil and racial MINATTR/MAXATTR aren't relevant here */ + int lolimit = 3, hilimit = 25, curval = ACURR(attrindx); + + /* upper limit for Str is 25 but its value is encoded differently */ + if (attrindx == A_STR) { + hilimit = STR19(25); /* 125 */ + /* lower limit for Str can also be 25 */ + if (uarmg && uarmg->otyp == GAUNTLETS_OF_POWER) + lolimit = hilimit; + } + /* this exception is hypothetical; the only other worn item affecting + Int or Wis is another helmet so can't be in use at the same time */ + if (attrindx == A_INT || attrindx == A_WIS) { + if (uarmh && uarmh->otyp == DUNCE_CAP) + hilimit = lolimit = 6; + } + + /* are we currently at either limit? */ + return (curval == lolimit || curval == hilimit) ? TRUE : FALSE; +} + /* avoid possible problems with alignment overflow, and provide a centralized * location for any future alignment limits */ diff --git a/src/do_wear.c b/src/do_wear.c index ad0d6168b..ba5027931 100644 --- a/src/do_wear.c +++ b/src/do_wear.c @@ -41,6 +41,7 @@ STATIC_PTR int NDECL(Shield_on); STATIC_PTR int NDECL(Shirt_on); #endif STATIC_DCL void NDECL(Amulet_on); +STATIC_DCL void FDECL(learnring, (struct obj *,BOOLEAN_P)); STATIC_DCL void FDECL(Ring_off_or_gone, (struct obj *, BOOLEAN_P)); STATIC_PTR int FDECL(select_off, (struct obj *)); STATIC_DCL struct obj *NDECL(do_takeoff); @@ -699,12 +700,45 @@ Amulet_off() return; } +/* handle ring discovery; comparable to learnwand() */ +STATIC_OVL void +learnring(ring, observed) +struct obj *ring; +boolean observed; +{ + int ringtype = ring->otyp; + + /* if effect was observeable then we usually discover the type */ + if (observed) { + /* if we already know the ring type which accomplishes this + effect (assumes there is at most one type for each effect), + mark this ring as having been seen (no need for makeknown); + otherwise if we have seen this ring, discover its type */ + if (objects[ringtype].oc_name_known) + ring->dknown = 1; + else if (ring->dknown) + makeknown(ringtype); +#if 0 /* see learnwand() */ + else + ring->eknown = 1; +#endif + } + + /* make enchantment of charged ring known (might be +0) and update + perm invent window if we've seen this ring and know its type */ + if (ring->dknown && objects[ringtype].oc_name_known) { + if (objects[ringtype].oc_charged) ring->known = 1; + update_inventory(); + } +} + void Ring_on(obj) register struct obj *obj; { long oldprop = u.uprops[objects[obj->otyp].oc_oprop].extrinsic; int old_attrib, which; + boolean observable; /* make sure ring isn't wielded; can't use remove_worn_item() here because it has already been set worn in a ring slot */ @@ -751,12 +785,12 @@ register struct obj *obj; !perceives(youmonst.data) && !Blind) { newsym(u.ux,u.uy); pline("Suddenly you are transparent, but there!"); - makeknown(RIN_SEE_INVISIBLE); + learnring(obj, TRUE); } break; case RIN_INVISIBILITY: if (!oldprop && !HInvis && !BInvis && !Blind) { - makeknown(RIN_INVISIBILITY); + learnring(obj, TRUE); newsym(u.ux,u.uy); self_invis_message(); } @@ -764,7 +798,7 @@ register struct obj *obj; case RIN_LEVITATION: if (!oldprop && !HLevitation) { float_up(); - makeknown(RIN_LEVITATION); + learnring(obj, TRUE); spoteffects(FALSE); /* for sinks */ } break; @@ -779,14 +813,15 @@ register struct obj *obj; 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)) { - context.botl = 1; - makeknown(obj->otyp); - obj->known = 1; - update_inventory(); - } + observable = (old_attrib != ACURR(which)); + /* if didn't change, usually means ring is +0 but might + be because nonzero couldn't go below min or above max; + learn +0 enchantment if attribute value is not stuck + at a limit [and ring has been seen and its type is + already discovered, both handled by learnring()] */ + if (observable || !extremeattr(which)) + learnring(obj, observable); + context.botl = 1; break; case RIN_INCREASE_ACCURACY: /* KMH */ u.uhitinc += obj->spe; @@ -798,12 +833,12 @@ register struct obj *obj; rescham(); break; case RIN_PROTECTION: - if (obj->spe || objects[RIN_PROTECTION].oc_name_known) { - context.botl = 1; - makeknown(RIN_PROTECTION); - obj->known = 1; - update_inventory(); - } + /* usually learn enchantment and discover type; + won't happen if ring is unseen or if it's +0 + and the type hasn't been discovered yet */ + observable = (obj->spe != 0); + learnring(obj, observable); + if (obj->spe) find_ac(); /* updates botl */ break; } } @@ -815,6 +850,7 @@ boolean gone; { long mask = (obj->owornmask & W_RING); int old_attrib, which; + boolean observable; context.takeoff.mask &= ~mask; if(!(u.uprops[objects[obj->otyp].oc_oprop].extrinsic & mask)) @@ -858,7 +894,7 @@ boolean gone; if (Invisible && !Blind) { newsym(u.ux,u.uy); pline("Suddenly you cannot see yourself."); - makeknown(RIN_SEE_INVISIBLE); + learnring(obj, TRUE); } break; case RIN_INVISIBILITY: @@ -866,12 +902,12 @@ boolean gone; newsym(u.ux,u.uy); Your("body seems to unfade%s.", See_invisible ? " completely" : ".."); - makeknown(RIN_INVISIBILITY); + learnring(obj, TRUE); } break; case RIN_LEVITATION: (void) float_down(0L, 0L); - if (!Levitation) makeknown(RIN_LEVITATION); + if (!Levitation) learnring(obj, TRUE); break; case RIN_GAIN_STRENGTH: which = A_STR; @@ -884,12 +920,11 @@ boolean gone; adjust_attrib: old_attrib = ACURR(which); ABON(which) -= obj->spe; - if (ACURR(which) != old_attrib) { - context.botl = 1; - makeknown(obj->otyp); - obj->known = 1; - update_inventory(); - } + observable = (old_attrib != ACURR(which)); + /* same criteria as Ring_on() */ + if (observable || !extremeattr(which)) + learnring(obj, observable); + context.botl = 1; break; case RIN_INCREASE_ACCURACY: /* KMH */ u.uhitinc -= obj->spe; @@ -898,13 +933,12 @@ boolean gone; u.udaminc -= obj->spe; break; case RIN_PROTECTION: - /* might have forgotten it due to amnesia */ - if (obj->spe) { - context.botl = 1; - makeknown(RIN_PROTECTION); - obj->known = 1; - update_inventory(); - } + /* might have been put on while blind and we can now see + or perhaps been forgotten due to amnesia */ + observable = (obj->spe != 0); + learnring(obj, observable); + if (obj->spe) find_ac(); /* updates botl */ + break; case RIN_PROTECTION_FROM_SHAPE_CHAN: /* If you're no longer protected, let the chameleons * change shape again -dgk