diff --git a/doc/fixes37.0 b/doc/fixes37.0 index 23868980b..9c4f6f44a 100644 --- a/doc/fixes37.0 +++ b/doc/fixes37.0 @@ -341,6 +341,9 @@ when protection from shape changers begins, force mimic out of concealment even if hero can't see its location; for locations that can be seen, don't make double-trouble Wizard concealed as another monster--or pet temporarily mimicking something while eating mimic corpse--fall asleep +best possible armor class reduced from -127 to -99; worst from +127 to +99; + charged or enchanted individual items also capped at +/- 99 (affects + wizard mode wishing, negligible effect on normal play) Fixes to 3.7.0-x Problems that Were Exposed Via git Repository @@ -676,8 +679,8 @@ mild zombie apocalypse list lamps and lanterns in charging prompt let tourists read conical hats when "?i" (show key bindings) displays commands and their keys, also show - commands without any key (so useable via '#', or possibly menu, only; - the majority are debugging commands) + commands without any key (so ones useable via '#', or possibly menu, + only; the majority are debugging commands) assign default key binding for or to execute #terrain assign M-X to #exploremode make #herecmdmenu and #therecmdmenu autocomplete diff --git a/include/obj.h b/include/obj.h index 89d932251..9205c8151 100644 --- a/include/obj.h +++ b/include/obj.h @@ -40,16 +40,19 @@ struct obj { unsigned owt; long quan; /* number of items */ +#define SPE_LIM 99 /* abs(obj->spe) <= 99, cap for enchanted and charged + * objects (and others; named fruit index excepted) */ schar spe; /* quality of weapon, weptool, armor or ring (+ or -); - number of charges for wand or charged tool ( >= -1 ); - number of candles attached to candelabrum; - marks your eggs, tin variety and spinach tins; - candy bar wrapper index; - Schroedinger's Box (1) or royal coffers for a court (2); - tells which fruit a fruit is; - special for uball and amulet; - scroll of mail (normal==0, bones or wishing==1, written==2); - historic and gender for statues */ + * number of charges for wand or charged tool ( >= -1 ); + * number of candles attached to candelabrum; + * marks your eggs, tin variety and spinach tins; + * candy bar wrapper index; + * Schroedinger's Box (1) or royal coffers for a court (2); + * tells which fruit a fruit is; + * special for uball and amulet; + * scroll of mail (normal==0, bones or wishing==1, written==2); + * splash of venom (normal==0, wishing==1); + * historic and gender for statues */ #define STATUE_HISTORIC 0x01 #define STATUE_MALE 0x02 #define STATUE_FEMALE 0x04 diff --git a/include/you.h b/include/you.h index c8d4c4fe6..0d9686f88 100644 --- a/include/you.h +++ b/include/you.h @@ -93,7 +93,9 @@ enum achivements { ACH_NOVL = 20, /* read at least one passage from a Discworld novel */ ACH_SOKO = 21, /* entered Sokoban */ ACH_BGRM = 22, /* entered Bigroom (not guaranteed to be in every dgn) */ - /* 23..30 are negated if hero is female at the time new rank is gained */ + /* role's rank titles, beyond first (#0 at level one, not an achievement); + 23..30 are negated if hero is female at the time new rank is gained + so that disclosing them can use the gender which applied at the time */ ACH_RNK1 = 23, ACH_RNK2 = 24, ACH_RNK3 = 25, ACH_RNK4 = 26, ACH_RNK5 = 27, ACH_RNK6 = 28, ACH_RNK7 = 29, ACH_RNK8 = 30, /* foo=31, 1 available potential achievement; #32 currently off-limits */ @@ -102,6 +104,8 @@ enum achivements { /* * Other potential achievements to track (this comment briefly resided * in encodeachieve(topten.c) and has been revised since moving here: + * AC <= 0, AC <= -10, AC <= -20 (stop there; lower is better but + * not something to encourage with achievements), * got quest summons, * entered quest branch, * chatted with leader, @@ -431,14 +435,18 @@ struct you { #define A_CURRENT 0 aligntyp ualignbase[CONVERT]; /* for ualign conversion record */ schar uluck, moreluck; /* luck and luck bonus */ + /* default u.uluck is 0 except on special days (full moon: +1, Fri 13: -1, + both: 0); equilibrium for luck timeout is changed to those values, + but Luck max and min stay at 10+3 and -10-3 even on those days */ #define Luck (u.uluck + u.moreluck) #define LUCKADD 3 /* value of u.moreluck when carrying luck stone; - + when blessed or uncursed, - when cursed */ -#define LUCKMAX 10 /* maximum value of u.ulUck */ + * +3 when blessed or uncursed, -3 when cursed */ +#define LUCKMAX 10 /* maximum value of u.uluck */ #define LUCKMIN (-10) /* minimum value of u.uluck */ schar uhitinc; schar udaminc; schar uac; +#define AC_MAX 99 /* abs(u.uac) <= 99; likewise for monster AC */ uchar uspellprot; /* protection by SPE_PROTECTION */ uchar usptime; /* #moves until uspellprot-- */ uchar uspmtime; /* #moves between uspellprot-- */ diff --git a/src/do_wear.c b/src/do_wear.c index 77e7251ae..670fc6aa8 100644 --- a/src/do_wear.c +++ b/src/do_wear.c @@ -2213,19 +2213,26 @@ find_ac() uac -= u.ublessed; uac -= u.uspellprot; - /* [The magic binary numbers 127 and -128 should be replaced with the - * mystic decimal numbers 99 and -99 which require no explanation to - * the uninitiated and would cap the width of a status line value at - * one less character.] - */ - if (uac < -128) - uac = -128; /* u.uac is an schar */ - else if (uac > 127) - uac = 127; /* for completeness */ + /* put a cap on armor class [3.7: was +127,-128, now reduced to +/- 99 */ + if (abs(uac) > AC_MAX) + uac = sgn(uac) * AC_MAX; if (uac != u.uac) { u.uac = uac; g.context.botl = 1; +#if 0 + /* these could conceivably be achieved out of order (by being near + threshold and putting on +N dragon scale mail from bones, for + instance), but if that happens, that's the order it happened; + also, testing for these in the usual order would result in more + record_achievement() attempts and rejects for duplication */ + if (u.uac <= -20) + record_achievement(ACH_AC_20); + else if (u.uac <= -10) + record_achievement(ACH_AC_10); + else if (u.uac <= 0) + record_achievement(ACH_AC_00); +#endif } } diff --git a/src/insight.c b/src/insight.c index b95791968..57cd5596e 100644 --- a/src/insight.c +++ b/src/insight.c @@ -590,7 +590,11 @@ int final; you_have(buf, ""); } + find_ac(); /* enforces AC_MAX cap */ Sprintf(buf, "%d", u.uac); + if (abs(u.uac) == AC_MAX) + Sprintf(eos(buf), ", the %s possible", + (u.uac < 0) ? "best" : "worst"); enl_msg("Your armor class ", "is ", "was ", buf, ""); /* gold; similar to doprgold(#seegold) but without shop billing info; diff --git a/src/objnam.c b/src/objnam.c index 9efcd4fc6..a99523ef5 100644 --- a/src/objnam.c +++ b/src/objnam.c @@ -3431,8 +3431,11 @@ struct _readobjnam_data *d; { if (strlen(d->bp) > 1 && (d->p = rindex(d->bp, '(')) != 0) { boolean keeptrailingchars = TRUE; + int idx = 0; - d->p[(d->p > d->bp && d->p[-1] == ' ') ? -1 : 0] = '\0'; /*terminate bp */ + if (d->p > d->bp && d->p[-1] == ' ') + idx = -1; + d->p[idx] = '\0'; /* terminate bp */ ++d->p; /* advance past '(' */ if (!strncmpi(d->p, "lit)", 4)) { d->islit = 1; @@ -3478,8 +3481,9 @@ struct _readobjnam_data *d; d->spesgn = -1; /* cheaters get what they deserve */ d->spe = abs(d->spe); } - if (d->spe > SCHAR_LIM) - d->spe = SCHAR_LIM; + /* cap on obj->spe is independent of (and less than) SCHAR_LIM */ + if (d->spe > SPE_LIM) + d->spe = SPE_LIM; /* slime mold uses d.ftype, so not affected */ if (d->rechrg < 0 || d->rechrg > 7) d->rechrg = 7; /* recharge_limit */ } @@ -4225,13 +4229,11 @@ struct obj *no_wish; || d.typ == ROCK || is_missile(d.otmp))))) d.otmp->quan = (long) d.cnt; - if (d.oclass == VENOM_CLASS) - d.otmp->spe = 1; - if (d.spesgn == 0) { + /* spe not specifed; retain the randomly assigned value */ d.spe = d.otmp->spe; } else if (wizard) { - ; /* no alteration to spe */ + ; /* no restrictions except SPE_LIM */ } else if (d.oclass == ARMOR_CLASS || d.oclass == WEAPON_CLASS || is_weptool(d.otmp) || (d.oclass == RING_CLASS && objects[d.typ].oc_charged)) { @@ -4240,7 +4242,8 @@ struct obj *no_wish; if (d.spe > 2 && Luck < 0) d.spesgn = -1; } else { - if (d.oclass == WAND_CLASS) { + /* crystal ball cancels like a wand, to (n:-1) */ + if (d.oclass == WAND_CLASS || d.typ == CRYSTAL_BALL) { if (d.spe > 1 && d.spesgn == -1) d.spe = 1; } else { @@ -4281,12 +4284,16 @@ struct obj *no_wish; /* otmp->cobj already done in mksobj() */ break; #ifdef MAIL_STRUCTURES + /* scroll of mail: 0: delivered in-game via external event (or randomly + for fake mail); 1: from bones or wishing; 2: written with marker */ case SCR_MAIL: - /* 0: delivered in-game via external event (or randomly for fake mail); - 1: from bones or wishing; 2: written with marker */ + /*FALLTHRU*/ +#endif + /* splash of venom: 0: normal, and transitory; 1: wishing */ + case ACID_VENOM: + case BLINDING_VENOM: d.otmp->spe = 1; break; -#endif case WAN_WISHING: if (!wizard) { d.otmp->spe = (rn2(10) ? -1 : 0); diff --git a/src/read.c b/src/read.c index 0c41973aa..6f8505dba 100644 --- a/src/read.c +++ b/src/read.c @@ -17,6 +17,7 @@ static NEARDATA const char readable[] = { ALL_CLASSES, SCROLL_CLASS, static const char all_count[] = { ALLOW_COUNT, ALL_CLASSES, 0 }; static boolean FDECL(learnscrolltyp, (SHORT_P)); +static void FDECL(cap_spe, (struct obj *)); static char *FDECL(erode_obj_text, (struct obj *, char *)); static void FDECL(stripspe, (struct obj *)); static void FDECL(p_glow1, (struct obj *)); @@ -54,6 +55,17 @@ struct obj *sobj; (void) learnscrolltyp(sobj->otyp); } +/* max spe is +99, min is -99 */ +static void +cap_spe(obj) +struct obj *obj; +{ + if (obj) { + if (abs(obj->spe) > SPE_LIM) + obj->spe = sgn(obj->spe) * SPE_LIM; + } +} + static char * erode_obj_text(otmp, buf) struct obj *otmp; @@ -679,11 +691,10 @@ int curse_bless; case MAGIC_MARKER: case TINNING_KIT: case EXPENSIVE_CAMERA: - if (is_cursed) + if (is_cursed) { stripspe(obj); - else if (rechrg - && obj->otyp - == MAGIC_MARKER) { /* previously recharged */ + } else if (rechrg && obj->otyp == MAGIC_MARKER) { + /* previously recharged */ obj->recharged = 1; /* override increment done above */ if (obj->spe < 3) Your("marker seems permanently dried out."); @@ -709,8 +720,9 @@ int curse_bless; obj->spe = 50; else { int chrg = (int) obj->spe; - if ((chrg + n) > 127) - obj->spe = 127; + + if (chrg + n > SPE_LIM) + obj->spe = SPE_LIM; else obj->spe += n; } @@ -824,9 +836,12 @@ int curse_bless; } /* switch */ } else { - not_chargable: + not_chargable: You("have a feeling of loss."); } + + /* prevent enchantment from getting out of range */ + cap_spe(obj); } /* @@ -1039,6 +1054,7 @@ struct obj *sobj; /* scroll, or fake spellbook object for scroll-like spell */ otmp->otyp += GRAY_DRAGON_SCALE_MAIL - GRAY_DRAGON_SCALES; if (sblessed) { otmp->spe++; + cap_spe(otmp); if (!otmp->blessed) bless(otmp); } else if (otmp->cursed) @@ -1050,7 +1066,7 @@ struct obj *sobj; /* scroll, or fake spellbook object for scroll-like spell */ break; } pline("%s %s%s%s%s for a %s.", Yname2(otmp), - s == 0 ? "violently " : "", + (s == 0) ? "violently " : "", otense(otmp, Blind ? "vibrate" : "glow"), (!Blind && !same_color) ? " " : "", (Blind || same_color) @@ -1067,8 +1083,15 @@ struct obj *sobj; /* scroll, or fake spellbook object for scroll-like spell */ else if (!scursed && otmp->cursed) uncurse(otmp); if (s) { + int oldspe = otmp->spe; + /* despite being schar, it shouldn't be possible for spe to wrap + here because it has been capped at 99 and s is quite small; + however, might need to change s if it takes spe past 99 */ otmp->spe += s; - adj_abon(otmp, s); + cap_spe(otmp); /* make sure that it doesn't exceed SPE_LIM */ + s = otmp->spe - oldspe; /* cap_spe() might have throttled 's' */ + if (s) /* skip if it got changed to 0 */ + adj_abon(otmp, s); /* adjust armor bonus for Dex or Int+Wis */ g.known = otmp->known; /* update shop bill to reflect new higher price */ if (s > 0 && otmp->unpaid) @@ -1331,6 +1354,8 @@ struct obj *sobj; /* scroll, or fake spellbook object for scroll-like spell */ : sblessed ? rnd(3 - uwep->spe / 3) : 1)) sobj = 0; /* nothing enchanted: strange_feeling -> useup */ + if (uwep) + cap_spe(uwep); break; case SCR_TAMING: case SPE_CHARM_MONSTER: { diff --git a/src/worn.c b/src/worn.c index f5c4c3a1d..82abcf26c 100644 --- a/src/worn.c +++ b/src/worn.c @@ -472,6 +472,9 @@ register struct monst *mon; /* since ARM_BONUS is positive, subtracting it increases AC */ } } + /* same cap as for hero [find_ac(do_wear.c)] */ + if (abs(base) > AC_MAX) + base = sgn(base) * AC_MAX; return base; }