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
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 <del> or <delete> to execute #terrain
assign M-X to #exploremode
make #herecmdmenu and #therecmdmenu autocomplete
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
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 */
/*
* 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,
#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-- */
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
}
}
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;
{
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;
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 */
}
|| 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)) {
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 {
/* 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);
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 *));
(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;
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.");
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;
}
} /* switch */
} else {
- not_chargable:
+ not_chargable:
You("have a feeling of loss.");
}
+
+ /* prevent enchantment from getting out of range */
+ cap_spe(obj);
}
/*
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)
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)
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)
: 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: {
/* 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;
}