fix #H6422 - hmonas against shades
I did much of this quite some time ago, as prequisite for a different bug report about monsters vs shades, then set it aside. It ended up being more complicated than I anticipated. When deciding whether various non-weapon attacks might hit a shade, hmonas() was not checking for blessed or silver armor that should have been applicable. It did check boots when kicking, but not gloves or rings (when no gloves) when touching, or outermost of cloak/suit/shirt when hugging, or helmet when head-butting. (The last one is actually moot because nothing with a head-butt attack is able to wear a helm.) The problem was more general than just whether attacks might hit and hurt shades. Various undead and/or demons are also affected by blessed and/or silver attack but weren't for non-weapon attacks by poly'd hero. At least two unrelated bugs are fixed: a rope golem's AT_HUGS attack gives feedback about choking but was fully effective against monsters which fail the can_be_strangled() test. And it was possible to hug a long worm's tail, rendering the entire worm immobile. The report also suggested that all artifacts be able to hit shades for full effect, but by the time shades are encountered everyone has an artifact so that would nullify a shade's most interesting ability. TODO: monster against hero and monster against other monster need to have similar changes.
This commit is contained in:
113
src/weapon.c
113
src/weapon.c
@@ -1,4 +1,4 @@
|
||||
/* NetHack 3.6 weapon.c $NHDT-Date: 1547025169 2019/01/09 09:12:49 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.68 $ */
|
||||
/* NetHack 3.6 weapon.c $NHDT-Date: 1548209744 2019/01/23 02:15:44 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.69 $ */
|
||||
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
|
||||
/*-Copyright (c) Robert Patrick Rankin, 2011. */
|
||||
/* NetHack may be freely redistributed. See license for details. */
|
||||
@@ -350,6 +350,117 @@ struct monst *mon;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/* check whether blessed and/or silver damage applies for *non-weapon* hit;
|
||||
return value is the amount of the extra damage */
|
||||
int
|
||||
special_dmgval(magr, mdef, armask, silverhit_p)
|
||||
struct monst *magr, *mdef;
|
||||
long armask; /* armor mask, multiple bits accepted for W_ARMC|W_ARM|W_ARMU
|
||||
* or W_ARMG|W_RINGL|W_RINGR only */
|
||||
long *silverhit_p; /* output flag mask for silver bonus */
|
||||
{
|
||||
struct obj *obj;
|
||||
struct permonst *ptr = mdef->data;
|
||||
boolean left_ring = (armask & W_RINGL) ? TRUE : FALSE,
|
||||
right_ring = (armask & W_RINGR) ? TRUE : FALSE;
|
||||
long silverhit = 0L;
|
||||
int bonus = 0;
|
||||
|
||||
obj = 0;
|
||||
if (armask & (W_ARMC | W_ARM | W_ARMU)) {
|
||||
if ((armask & W_ARMC) != 0L
|
||||
&& (obj = which_armor(magr, W_ARMC)) != 0)
|
||||
armask = W_ARMC;
|
||||
else if ((armask & W_ARM) != 0L
|
||||
&& (obj = which_armor(magr, W_ARM)) != 0)
|
||||
armask = W_ARM;
|
||||
else if ((armask & W_ARMU) != 0L
|
||||
&& (obj = which_armor(magr, W_ARMU)) != 0)
|
||||
armask = W_ARMU;
|
||||
else
|
||||
armask = 0L;
|
||||
} else if (armask & (W_ARMG | W_RINGL | W_RINGR)) {
|
||||
armask = ((obj = which_armor(magr, W_ARMG)) != 0) ? W_ARMG : 0L;
|
||||
} else {
|
||||
obj = which_armor(magr, armask);
|
||||
}
|
||||
|
||||
if (obj) {
|
||||
if (obj->blessed
|
||||
&& (is_undead(ptr) || is_demon(ptr) || is_vampshifter(mdef)))
|
||||
bonus += rnd(4);
|
||||
/* the only silver armor is shield of reflection (silver dragon
|
||||
scales refer to color, not material) and the only way to hit
|
||||
with one--aside from throwing--is to wield it and perform a
|
||||
weapon hit, but we include a general check here */
|
||||
if (objects[obj->otyp].oc_material == SILVER
|
||||
&& mon_hates_silver(mdef)) {
|
||||
bonus += rnd(20);
|
||||
silverhit |= armask;
|
||||
}
|
||||
|
||||
/* when no gloves we check for silver rings (blessed rings ignored) */
|
||||
} else if ((left_ring || right_ring) && magr == &youmonst) {
|
||||
if (left_ring && uleft) {
|
||||
if (objects[uleft->otyp].oc_material == SILVER
|
||||
&& mon_hates_silver(mdef)) {
|
||||
bonus += rnd(20);
|
||||
silverhit |= W_RINGL;
|
||||
}
|
||||
}
|
||||
if (right_ring && uright) {
|
||||
if (objects[uright->otyp].oc_material == SILVER
|
||||
&& mon_hates_silver(mdef)) {
|
||||
/* two silver rings don't give double silver damage
|
||||
but 'silverhit' messages might be adjusted for them */
|
||||
if (!(silverhit & W_RINGL))
|
||||
bonus += rnd(20);
|
||||
silverhit |= W_RINGR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (silverhit_p)
|
||||
*silverhit_p = silverhit;
|
||||
return bonus;
|
||||
}
|
||||
|
||||
/* give a "silver <item> sears <target>" message;
|
||||
not used for weapon hit, so we only handle rings */
|
||||
void
|
||||
silver_sears(magr, mdef, silverhit)
|
||||
struct monst *magr UNUSED;
|
||||
struct monst *mdef;
|
||||
long silverhit;
|
||||
{
|
||||
char rings[20]; /* plenty of room for "rings" */
|
||||
int ltyp = ((uleft && (silverhit & W_RINGL) != 0L)
|
||||
? uleft->otyp : STRANGE_OBJECT),
|
||||
rtyp = ((uright && (silverhit & W_RINGR) != 0L)
|
||||
? uright->otyp : STRANGE_OBJECT);
|
||||
boolean both,
|
||||
l_ag = (objects[ltyp].oc_material == SILVER && uleft->dknown),
|
||||
r_ag = (objects[rtyp].oc_material == SILVER && uright->dknown);
|
||||
|
||||
if ((silverhit & (W_RINGL | W_RINGR)) != 0L) {
|
||||
/* plural if both the same type (so not multi_claw and both rings
|
||||
are non-Null) and either both known or neither known, or both
|
||||
silver (in case there is ever more than one type of silver ring)
|
||||
and both known; singular if multi_claw (where one of ltyp or
|
||||
rtyp will always be STRANGE_OBJECT) even if both rings are known
|
||||
silver [see hmonas(uhitm.c) for explanation of 'multi_claw'] */
|
||||
both = ((ltyp == rtyp && uleft->dknown == uright->dknown)
|
||||
|| (l_ag && r_ag));
|
||||
Sprintf(rings, "ring%s", both ? "s" : "");
|
||||
Your("%s%s %s %s!",
|
||||
(l_ag || r_ag) ? "silver "
|
||||
: both ? ""
|
||||
: ((silverhit & W_RINGL) != 0L) ? "left "
|
||||
: "right ",
|
||||
rings, vtense(rings, "sear"), mon_nam(mdef));
|
||||
}
|
||||
}
|
||||
|
||||
STATIC_DCL struct obj *FDECL(oselect, (struct monst *, int));
|
||||
#define Oselect(x) \
|
||||
if ((otmp = oselect(mtmp, x)) != 0) \
|
||||
|
||||
Reference in New Issue
Block a user