When SEDUCE is disabled, instead of swapping attacks in mons[] once,
do it on the fly in getmattk() whenever needed.  That allows mons[]
to become readonly, although this doesn't declare it 'const' because
doing so will require a zillion 'struct permonst *' updates to match.

This seemed trickier than it should be, but that turned out to be
because the old behavior was broken.  Setting SEDUCE=0 in sysconf or
user's own configuration file resulted in all succubus and incubus
attacks being described as monster smiles engagingly or seductively
rather than hitting (while dishing out physical damage).  I didn't
try rebuilding 3.4.3 to see whether this was already broken before
being migrated to SYSCF.
This commit is contained in:
PatR
2019-01-10 03:10:35 -08:00
parent 79d40658c7
commit b1782b813f
6 changed files with 59 additions and 31 deletions

View File

@@ -1,4 +1,4 @@
/* NetHack 3.6 mhitu.c $NHDT-Date: 1545130893 2018/12/18 11:01:33 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.160 $ */
/* NetHack 3.6 mhitu.c $NHDT-Date: 1547118629 2019/01/10 11:10:29 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.161 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Robert Patrick Rankin, 2012. */
/* NetHack may be freely redistributed. See license for details. */
@@ -268,6 +268,23 @@ struct attack *alt_attk_buf;
struct attack *attk = &mptr->mattk[indx];
struct obj *weap = (magr == &youmonst) ? uwep : MON_WEP(magr);
/* honor SEDUCE=0 */
if (!SYSOPT_SEDUCE) {
extern const struct attack sa_no[NATTK];
/* if the first attack is for SSEX damage, all six attacks will be
substituted (expected succubus/incubus handling); if it isn't
but another one is, only that other one will be substituted */
if (mptr->mattk[0].adtyp == AD_SSEX) {
*alt_attk_buf = sa_no[indx];
attk = alt_attk_buf;
} else if (attk->adtyp == AD_SSEX) {
*alt_attk_buf = *attk;
attk = alt_attk_buf;
attk->adtyp = AD_DRLI;
}
}
/* prevent a monster with two consecutive disease or hunger attacks
from hitting with both of them on the same turn; if the first has
already hit, switch to a stun attack for the second */
@@ -1115,7 +1132,7 @@ register struct attack *mattk;
goto dopois;
case AD_DRCO:
ptmp = A_CON;
dopois:
dopois:
hitmsg(mtmp, mattk);
if (uncancelled && !rn2(8)) {
Sprintf(buf, "%s %s", s_suffix(Monnam(mtmp)),
@@ -1234,7 +1251,7 @@ register struct attack *mattk;
You_hear("%s hissing!", s_suffix(mon_nam(mtmp)));
if (!rn2(10)
|| (flags.moonphase == NEW_MOON && !have_lizard())) {
do_stone:
do_stone:
if (!Stoned && !Stone_resistance
&& !(poly_when_stoned(youmonst.data)
&& polymon(PM_STONE_GOLEM))) {
@@ -1326,7 +1343,10 @@ register struct attack *mattk;
break;
/* Continue below */
} else if (dmgtype(youmonst.data, AD_SEDU)
|| (SYSOPT_SEDUCE && dmgtype(youmonst.data, AD_SSEX))) {
/* !SYSOPT_SEDUCE: when hero is attacking and AD_SSEX
is disabled, it would be changed to another damage
type, but when defending, it remains as-is */
|| dmgtype(youmonst.data, AD_SSEX)) {
pline("%s %s.", Monnam(mtmp),
Deaf ? "says something but you can't hear it"
: mtmp->minvent
@@ -2019,7 +2039,7 @@ boolean ufound;
static analysis complains that 'physical_damage' is always
False when tested below; it's right, but having that in
place means one less thing to update if AD_PHYS gets added */
common:
common:
if (!not_affected) {
if (ACURR(A_DEX) > rnd(20)) {
@@ -2328,6 +2348,7 @@ struct attack *mattk;
struct permonst *pagr;
boolean agrinvis, defperc;
xchar genagr, gendef;
int adtyp = mattk ? mattk->adtyp : AD_PHYS;
if (is_animal(magr->data))
return 0;
@@ -2347,20 +2368,18 @@ struct attack *mattk;
defperc = perceives(mdef->data);
gendef = gender(mdef);
}
if (adtyp == AD_SSEX && !SYSOPT_SEDUCE)
adtyp = AD_SEDU;
if (agrinvis && !defperc
&& (!SYSOPT_SEDUCE || (mattk && mattk->adtyp != AD_SSEX)))
if (agrinvis && !defperc && adtyp == AD_SEDU)
return 0;
if (pagr->mlet != S_NYMPH
&& ((pagr != &mons[PM_INCUBUS] && pagr != &mons[PM_SUCCUBUS])
|| (SYSOPT_SEDUCE && mattk && mattk->adtyp != AD_SSEX)))
if ((pagr->mlet != S_NYMPH
&& pagr != &mons[PM_INCUBUS] && pagr != &mons[PM_SUCCUBUS])
|| (adtyp != AD_SEDU && adtyp != AD_SSEX))
return 0;
if (genagr == 1 - gendef)
return 1;
else
return (pagr->mlet == S_NYMPH) ? 2 : 0;
return (genagr == 1 - gendef) ? 1 : (pagr->mlet == S_NYMPH) ? 2 : 0;
}
/* returns 1 if monster teleported (or hero leaves monster's vicinity) */
@@ -2888,7 +2907,7 @@ struct attack *mattk;
else
tmp = 0;
assess_dmg:
assess_dmg:
if ((mtmp->mhp -= tmp) <= 0) {
pline("%s dies!", Monnam(mtmp));
xkilled(mtmp, XKILL_NOMSG);