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