fix github issue #1257 - nymph theft while blind

Issue reported by Meklon2007:  some theft feedback during nymph
attacks refers to the attacker as "she" and others as "it" if hero
is blind.

The "she" references are intentional.  However, mixing them with
"it" references when a series of messages occurs is jarring.  This
changes "it" to "someone", which is still different from "she" but
hopefully enough less so to be tolerable.

That resulted in monkeys also being referred to as "someone" because
they're classified as humanoid.  Change x_monnam()'s AUGMENT_IT
handling, which chooses between "someone" and "something" when the
monster is not seen, to override humanoid for animals (affects 'Y'
class) and for mindless (affects zombies, mummies, and golems).
So an unseen monkey will be "it" again.

The final message for current item was relying on a cached monster
name value.  If an unseen nymph or monkey stole a worn blindfold
so that hero's vision was restored:  "It <stole> item" before the
changes and "Someone|Something <stole> item" after.  So update the
cached name if sight gets regained, to give "<Mon> stole <item>."
(If the item is worn armor and the thief is a nymph, it was and
still is "She stole <item>".)

The message for having any worn item be stolen, which got split
into two parts within the past year, was giving "<Mon> takes off
<alt weapon>".  When not dual-wielded, the alternate weapon isn't
really worn.  Rather than suppress it outright, change the message
for uwep/uswapwep/uquiver to say "disarms" instead of "takes off".
For accessories, change "takes off" to "removes".  Those are more
or less interchangeable these days but "removes" matches R instead
of T.

While testing, my pet evidently killed a nymph (I was blinded and
couldn't see it happen) while she stole my gloves and the next
message I got was "You finish taking off your suit."  The gloves
weren't worn anymore so equipname() defaulted to suit.  Get rid of
equipname() altogether and switch to armor_simple_name() which
doesn't rely on the worn-armor pointers.

Fixes #1257
This commit is contained in:
PatR
2024-07-13 12:30:59 -07:00
parent 6c0ae092c6
commit 72d2b0414c
4 changed files with 43 additions and 36 deletions
+7 -1
View File
@@ -1,4 +1,4 @@
NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.1450 $ $NHDT-Date: 1720074479 2024/07/04 06:27:59 $ NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.1455 $ $NHDT-Date: 1720895738 2024/07/13 18:35:38 $
General Fixes and Modified Features General Fixes and Modified Features
----------------------------------- -----------------------------------
@@ -1439,6 +1439,12 @@ using #loot -> 'i'n to put multiple items into a shop-owned container would
don't-sell state was being reset for each item so 'a' and 'q' didn't don't-sell state was being reset for each item so 'a' and 'q' didn't
stick beyond the current one stick beyond the current one
join wall "spines" with walls of water and lava join wall "spines" with walls of water and lava
some theft messages by nymphs force "she", others use default monster naming
which yields "it" when unseen; change the latter to "someone" which
still differs from "she" in a series of messages but isn't as jarring
if a nymph stole worn armor and got killed (perhaps by pet) before hero's next
turn, feedback would be "You finish taking off your suit." regardless
of the type of armor being taken off
Fixes to 3.7.0-x General Problems Exposed Via git Repository Fixes to 3.7.0-x General Problems Exposed Via git Repository
+5 -2
View File
@@ -1,4 +1,4 @@
/* NetHack 3.7 do_name.c $NHDT-Date: 1720128164 2024/07/04 21:22:44 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.319 $ */ /* NetHack 3.7 do_name.c $NHDT-Date: 1720895738 2024/07/13 18:35:38 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.320 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Pasi Kallinen, 2018. */ /*-Copyright (c) Pasi Kallinen, 2018. */
/* NetHack may be freely redistributed. See license for details. */ /* NetHack may be freely redistributed. See license for details. */
@@ -870,8 +870,11 @@ x_monnam(
/* unseen monsters, etc.; usually "it" but sometimes more specific; /* unseen monsters, etc.; usually "it" but sometimes more specific;
when hallucinating, the more specific values might be inverted */ when hallucinating, the more specific values might be inverted */
if (do_it) { if (do_it) {
/* !is_animal excludes all Y; !mindless excludes Z, M, \' */
boolean s_one = humanoid(mdat) && !is_animal(mdat) && !mindless(mdat);
Strcpy(buf, !augment_it ? "it" Strcpy(buf, !augment_it ? "it"
: (!do_hallu ? humanoid(mdat) : !rn2(2)) ? "someone" : (!do_hallu ? s_one : !rn2(2)) ? "someone"
: "something"); : "something");
return buf; return buf;
} }
+3 -2
View File
@@ -1,4 +1,4 @@
/* NetHack 3.7 do_wear.c $NHDT-Date: 1702017586 2023/12/08 06:39:46 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.175 $ */ /* NetHack 3.7 do_wear.c $NHDT-Date: 1720895740 2024/07/13 18:35:40 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.188 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Robert Patrick Rankin, 2012. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */
/* NetHack may be freely redistributed. See license for details. */ /* NetHack may be freely redistributed. See license for details. */
@@ -1853,7 +1853,8 @@ armoroff(struct obj *otmp)
} }
if (what) { if (what) {
/* sizeof offdelaybuf == 60; increase it if this becomes longer */ /* sizeof offdelaybuf == 60; increase it if this becomes longer */
Sprintf(offdelaybuf, "You finish taking off your %s.", what); Snprintf(offdelaybuf, sizeof offdelaybuf,
"You finish taking off your %s.", what);
gn.nomovemsg = offdelaybuf; gn.nomovemsg = offdelaybuf;
} }
} else { } else {
+28 -31
View File
@@ -1,27 +1,14 @@
/* NetHack 3.7 steal.c $NHDT-Date: 1707122967 2024/02/05 08:49:27 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.121 $ */ /* NetHack 3.7 steal.c $NHDT-Date: 1720895742 2024/07/13 18:35:42 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.132 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Robert Patrick Rankin, 2012. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */
/* NetHack may be freely redistributed. See license for details. */ /* NetHack may be freely redistributed. See license for details. */
#include "hack.h" #include "hack.h"
staticfn const char *equipname(struct obj *);
staticfn int unstolenarm(void); staticfn int unstolenarm(void);
staticfn int stealarm(void); staticfn int stealarm(void);
staticfn void worn_item_removal(struct monst *, struct obj *); staticfn void worn_item_removal(struct monst *, struct obj *);
staticfn const char *
equipname(struct obj *otmp)
{
return ((otmp == uarmu) ? shirt_simple_name(otmp)
: (otmp == uarmf) ? boots_simple_name(otmp)
: (otmp == uarms) ? shield_simple_name(otmp)
: (otmp == uarmg) ? gloves_simple_name(otmp)
: (otmp == uarmc) ? cloak_simple_name(otmp)
: (otmp == uarmh) ? helm_simple_name(otmp)
: suit_simple_name(otmp));
}
/* proportional subset of gold; return value actually fits in an int */ /* proportional subset of gold; return value actually fits in an int */
long long
somegold(long lmoney) somegold(long lmoney)
@@ -168,7 +155,7 @@ unstolenarm(void)
break; break;
gs.stealoid = 0; gs.stealoid = 0;
if (obj) { if (obj) {
You("finish taking off your %s.", equipname(obj)); You("finish taking off your %s.", armor_simple_name(obj));
} }
return 0; return 0;
} }
@@ -319,6 +306,7 @@ worn_item_removal(
struct obj *obj) struct obj *obj)
{ {
char objbuf[BUFSZ], article[20], *p; char objbuf[BUFSZ], article[20], *p;
const char *verb;
int strip_art; int strip_art;
Strcpy(objbuf, doname(obj)); Strcpy(objbuf, doname(obj));
@@ -342,7 +330,13 @@ worn_item_removal(
&& (!strncmp(p + 5, "left ", 5) || !strncmp(p + 5, "right ", 6))) && (!strncmp(p + 5, "left ", 5) || !strncmp(p + 5, "right ", 6)))
(void) strsubst(p + 2, "on", "from"); (void) strsubst(p + 2, "on", "from");
pline("%s takes off %s.", Monnam(mon), objbuf); /* slightly iffy for alternate weapon that isn't actively dual-wielded,
but it's better to alert the player to the change in equipment than
to suppress the message for that case */
verb = ((obj->owornmask & W_WEAPONS) != 0L) ? "disarms"
: ((obj->owornmask & W_ACCESSORY) != 0L) ? "removes"
: "takes off";
pline("%s %s %s.", Some_Monnam(mon), verb, objbuf);
iflags.last_msg = PLNMSG_MON_TAKES_OFF_ITEM; iflags.last_msg = PLNMSG_MON_TAKES_OFF_ITEM;
/* removal might trigger more messages (due to loss of Lev|Fly; /* removal might trigger more messages (due to loss of Lev|Fly;
descending happens before the theft in progress finishes) */ descending happens before the theft in progress finishes) */
@@ -363,6 +357,7 @@ steal(struct monst *mtmp, char *objnambuf)
int tmp, could_petrify, armordelay, olddelay, icnt, int tmp, could_petrify, armordelay, olddelay, icnt,
named = 0, retrycnt = 0; named = 0, retrycnt = 0;
boolean monkey_business = is_animal(mtmp->data), boolean monkey_business = is_animal(mtmp->data),
seen = canspotmon(mtmp),
was_doffing, was_punished = Punished; was_doffing, was_punished = Punished;
if (objnambuf) if (objnambuf)
@@ -375,10 +370,9 @@ steal(struct monst *mtmp, char *objnambuf)
teleporting to safety could result in a previously visible thief teleporting to safety could result in a previously visible thief
no longer being visible; it could also be a case of a blinded no longer being visible; it could also be a case of a blinded
hero being able to see via wearing the Eyes of the Overworld and hero being able to see via wearing the Eyes of the Overworld and
having those stolen; remember the name in order to avoid "It" having those stolen; remember the name as it is now; if unseen,
in the eventual "<Monnam> stole <item>" message; (the name might monkeys will be "It" and nymphs will be "Someone" */
already be "It"; if so, that's ok) */ Strcpy(Monnambuf, Some_Monnam(mtmp));
Strcpy(Monnambuf, Monnam(mtmp));
/* food being eaten might already be used up but will not have /* food being eaten might already be used up but will not have
been removed from inventory yet; we don't want to steal that, been removed from inventory yet; we don't want to steal that,
@@ -496,7 +490,7 @@ steal(struct monst *mtmp, char *objnambuf)
pline("%s tries to %s %s%s but gives up.", Monnambuf, pline("%s tries to %s %s%s but gives up.", Monnambuf,
ROLL_FROM(how), ROLL_FROM(how),
(otmp->owornmask & W_ARMOR) ? "your " : "", (otmp->owornmask & W_ARMOR) ? "your " : "",
(otmp->owornmask & W_ARMOR) ? equipname(otmp) (otmp->owornmask & W_ARMOR) ? armor_simple_name(otmp)
: yname(otmp)); : yname(otmp));
/* the fewer items you have, the less likely the thief /* the fewer items you have, the less likely the thief
is going to stick around to try again (0) instead of is going to stick around to try again (0) instead of
@@ -541,7 +535,6 @@ steal(struct monst *mtmp, char *objnambuf)
} else { } else {
int curssv = otmp->cursed; int curssv = otmp->cursed;
int slowly; int slowly;
boolean seen = canspotmon(mtmp);
otmp->cursed = 0; otmp->cursed = 0;
slowly = (armordelay >= 1 || gm.multi < 0); slowly = (armordelay >= 1 || gm.multi < 0);
@@ -552,7 +545,7 @@ steal(struct monst *mtmp, char *objnambuf)
: !slowly ? "hand over" : !slowly ? "hand over"
: was_doffing ? "continue removing" : was_doffing ? "continue removing"
: "start removing", : "start removing",
equipname(otmp)); armor_simple_name(otmp));
else else
urgent_pline("%s seduces you and %s off your %s.", urgent_pline("%s seduces you and %s off your %s.",
!seen ? "She" : Adjmonnam(mtmp, "beautiful"), !seen ? "She" : Adjmonnam(mtmp, "beautiful"),
@@ -560,7 +553,7 @@ steal(struct monst *mtmp, char *objnambuf)
: !slowly ? "you take" : !slowly ? "you take"
: was_doffing ? "you continue taking" : was_doffing ? "you continue taking"
: "you start taking", : "you start taking",
equipname(otmp)); armor_simple_name(otmp));
named++; named++;
/* the following is to set multi for later on */ /* the following is to set multi for later on */
nomul(-armordelay); nomul(-armordelay);
@@ -580,6 +573,10 @@ steal(struct monst *mtmp, char *objnambuf)
impossible("Tried to steal a strange worn thing. [%d]", impossible("Tried to steal a strange worn thing. [%d]",
otmp->oclass); otmp->oclass);
} }
/* hero's blindfold might have just been stolen; if so, replace
cached "It" or "Someone" with Monnam */
if (!seen && canspotmon(mtmp))
Strcpy(Monnambuf, Monnam(mtmp));
} else if (otmp->owornmask) { /* weapon or ball&chain */ } else if (otmp->owornmask) { /* weapon or ball&chain */
struct obj *item = otmp; struct obj *item = otmp;
@@ -750,29 +747,29 @@ stealamulet(struct monst *mtmp)
/* take off outer gear if we're targeting [hypothetical] /* take off outer gear if we're targeting [hypothetical]
quest artifact suit, shirt, gloves, or rings */ quest artifact suit, shirt, gloves, or rings */
if ((otmp == uarm || otmp == uarmu) && uarmc) if ((otmp == uarm || otmp == uarmu) && uarmc)
remove_worn_item(uarmc, FALSE); worn_item_removal(mtmp, uarmc);
if (otmp == uarmu && uarm) if (otmp == uarmu && uarm)
remove_worn_item(uarm, FALSE); worn_item_removal(mtmp, uarm);
if ((otmp == uarmg || ((otmp == uright || otmp == uleft) && uarmg)) if ((otmp == uarmg || ((otmp == uright || otmp == uleft) && uarmg))
&& uwep) { && uwep) {
/* gloves are about to be unworn; unwield weapon(s) first */ /* gloves are about to be unworn; unwield weapon(s) first */
if (u.twoweap) /* remove_worn_item(uswapwep) indirectly */ if (u.twoweap) /* remove_worn_item(uswapwep) indirectly */
remove_worn_item(uswapwep, FALSE); /* clears u.twoweap */ worn_item_removal(mtmp, uswapwep); /* clears u.twoweap */
remove_worn_item(uwep, FALSE); worn_item_removal(mtmp, uwep);
} }
if ((otmp == uright || otmp == uleft) && uarmg) if ((otmp == uright || otmp == uleft) && uarmg)
/* calls Gloves_off() to handle wielded cockatrice corpse */ /* calls Gloves_off() to handle wielded cockatrice corpse */
remove_worn_item(uarmg, FALSE); worn_item_removal(mtmp, uarmg);
/* finally, steal the target item */ /* finally, steal the target item */
if (otmp->owornmask) if (otmp->owornmask)
remove_worn_item(otmp, TRUE); worn_item_removal(mtmp, otmp);
if (otmp->unpaid) if (otmp->unpaid)
subfrombill(otmp, shop_keeper(*u.ushops)); subfrombill(otmp, shop_keeper(*u.ushops));
freeinv(otmp); freeinv(otmp);
Strcpy(buf, doname(otmp)); Strcpy(buf, doname(otmp));
(void) mpickobj(mtmp, otmp); /* could merge and free otmp but won't */ (void) mpickobj(mtmp, otmp); /* could merge and free otmp but won't */
pline("%s steals %s!", Monnam(mtmp), buf); pline("%s steals %s!", Some_Monnam(mtmp), buf);
if (can_teleport(mtmp->data) && !tele_restrict(mtmp)) if (can_teleport(mtmp->data) && !tele_restrict(mtmp))
(void) rloc(mtmp, RLOC_MSG); (void) rloc(mtmp, RLOC_MSG);
(void) encumber_msg(); (void) encumber_msg();