From 8ce81a27ef26e8d741946616edbd2db40c1fc6cb Mon Sep 17 00:00:00 2001 From: PatR Date: Mon, 24 Sep 2018 15:15:04 -0700 Subject: [PATCH] fix #H7397 - pronoun for unseen shopkeeper Most shop messages accurately identify the shopkeeper even when he or she can't be seen, but some also include a pronoun reference that ended up as "it" or "its" when not seen. Extend pronoun selection so that visibility can be ignored: noit_mhe(mon), noit_mhim(mon), and noit_mhis(mon). Note that despite being called noit_foo(), those will still return "it" if mon is neuter. "Accurately identify shopkeeper" is misleading if the hero is hallucinating; a random shopkeeper name is used then. noit_foo() yields the pronoun applicable to the actual shopkeeper and might not match the gender of a hallucinatory name. That could be fixed in a couple of ways (add shk_mhe()/shk_mhim()/shk_mhis() and either pass them the randomly chosen name so that they can figure out the appropriate gender, or just have them use a random gender whenever hallucinating) but I don't think that's worth bothering with. A bunch of shop messages needed noit_foo(); only a couple of those have actually been tested. A bunch more were using shkname() at the beginning of a sentence where Shknam() should be used instead. (All the existing shk names are already capitalized so there's no noticeable difference.) The three places outside shk.c and vault.c which directly use pronoun_gender() have been successfully tested. --- doc/fixes36.2 | 2 + include/extern.h | 2 +- include/you.h | 12 +++-- src/apply.c | 9 ++-- src/dothrow.c | 6 +-- src/mhitm.c | 7 +-- src/mhitu.c | 2 +- src/mondata.c | 7 ++- src/shk.c | 130 +++++++++++++++++++++++------------------------ src/vault.c | 7 +-- 10 files changed, 94 insertions(+), 90 deletions(-) diff --git a/doc/fixes36.2 b/doc/fixes36.2 index 727a067ea..479c7287b 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -140,6 +140,8 @@ known bear trap was being forgotten about by a player polymorphed into a flying monster if the player unsuccessfully tried to #untrap it and moved onto the trap square as a result no leash-related message is given when a leashed pet yellow light explodes +shop messages refer to shk by name even when shk is not visible but some + used pronoun "it" or "its" in same sentence; ditto for vault guards Fixes to Post-3.6.1 Problems that Were Exposed Via git Repository diff --git a/include/extern.h b/include/extern.h index b241ac074..bf3f801bd 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1458,7 +1458,7 @@ E int FDECL(monsndx, (struct permonst *)); E int FDECL(name_to_mon, (const char *)); E int FDECL(name_to_monclass, (const char *, int *)); E int FDECL(gender, (struct monst *)); -E int FDECL(pronoun_gender, (struct monst *)); +E int FDECL(pronoun_gender, (struct monst *, BOOLEAN_P)); E boolean FDECL(levl_follower, (struct monst *)); E int FDECL(little_to_big, (int)); E int FDECL(big_to_little, (int)); diff --git a/include/you.h b/include/you.h index 15fb5f9b3..461b9656f 100644 --- a/include/you.h +++ b/include/you.h @@ -236,12 +236,18 @@ struct Gender { increment to 3 if you allow neuter roles */ extern const struct Gender genders[]; /* table of available genders */ +/* pronouns for the hero */ #define uhe() (genders[flags.female ? 1 : 0].he) #define uhim() (genders[flags.female ? 1 : 0].him) #define uhis() (genders[flags.female ? 1 : 0].his) -#define mhe(mtmp) (genders[pronoun_gender(mtmp)].he) -#define mhim(mtmp) (genders[pronoun_gender(mtmp)].him) -#define mhis(mtmp) (genders[pronoun_gender(mtmp)].his) +/* corresponding pronouns for monsters; yields "it" when mtmp can't be seen */ +#define mhe(mtmp) (genders[pronoun_gender(mtmp, FALSE)].he) +#define mhim(mtmp) (genders[pronoun_gender(mtmp, FALSE)].him) +#define mhis(mtmp) (genders[pronoun_gender(mtmp, FALSE)].his) +/* override "it" if reason is lack of visibility rather than neuter species */ +#define noit_mhe(mtmp) (genders[pronoun_gender(mtmp, TRUE)].he) +#define noit_mhim(mtmp) (genders[pronoun_gender(mtmp, TRUE)].him) +#define noit_mhis(mtmp) (genders[pronoun_gender(mtmp, TRUE)].his) /*** Unified structure specifying alignment information ***/ struct Align { diff --git a/src/apply.c b/src/apply.c index 61a9db19d..0fa842636 100644 --- a/src/apply.c +++ b/src/apply.c @@ -215,12 +215,9 @@ int rx, ry, *resp; /* (most corpses don't retain the monster's sex, so we're usually forced to use generic pronoun here) */ if (mtmp) { - mptr = &mons[mtmp->mnum]; - /* can't use mhe() here; it calls pronoun_gender() which - expects monster to be on the map (visibility check) */ - if ((humanoid(mptr) || (mptr->geno & G_UNIQ) - || type_is_pname(mptr)) && !is_neuter(mptr)) - gndr = (int) mtmp->female; + mptr = mtmp->data = &mons[mtmp->mnum]; + /* TRUE: override visibility check--it's not on the map */ + gndr = pronoun_gender(mtmp, TRUE); } else { mptr = &mons[corpse->corpsenm]; if (is_female(mptr)) diff --git a/src/dothrow.c b/src/dothrow.c index 00978165f..5a559ae4e 100644 --- a/src/dothrow.c +++ b/src/dothrow.c @@ -664,12 +664,8 @@ int x, y; mon->mundetected = 0; /* wakeup() will handle mimic */ mnam = a_monnam(mon); /* after unhiding */ - pronoun = mhim(mon); + pronoun = noit_mhim(mon); if (!strcmp(mnam, "it")) { - /* mhim() uses pronoun_gender() which forces neuter if monster - can't be seen; we want him/her for humanoid sensed by touch */ - if (!strcmp(pronoun, "it") && humanoid(mon->data)) - pronoun = genders[mon->female].him; mnam = !strcmp(pronoun, "it") ? "something" : "someone"; } if (!glyph_is_monster(glyph) && !glyph_is_invisible(glyph)) diff --git a/src/mhitm.c b/src/mhitm.c index 87ee54e21..dfff12b26 100644 --- a/src/mhitm.c +++ b/src/mhitm.c @@ -47,9 +47,10 @@ mon_nam_too(outbuf, mon, other_mon) char *outbuf; struct monst *mon, *other_mon; { - Strcpy(outbuf, mon_nam(mon)); - if (mon == other_mon) - switch (pronoun_gender(mon)) { + if (mon != other_mon) + Strcpy(outbuf, mon_nam(mon)); + else + switch (pronoun_gender(mon, FALSE)) { case 0: Strcpy(outbuf, "himself"); break; diff --git a/src/mhitu.c b/src/mhitu.c index 97229ba60..7ae3ff103 100644 --- a/src/mhitu.c +++ b/src/mhitu.c @@ -2613,7 +2613,7 @@ struct monst *mon; ; } else if (rn2(20) < ACURR(A_CHA)) { pline("%s demands that you pay %s, but you refuse...", - noit_Monnam(mon), Blind ? (fem ? "her" : "him") : mhim(mon)); + noit_Monnam(mon), noit_mhim(mon)); } else if (u.umonnum == PM_LEPRECHAUN) { pline("%s tries to take your money, but fails...", noit_Monnam(mon)); } else { diff --git a/src/mondata.c b/src/mondata.c index 9a65c1480..ffffb9e85 100644 --- a/src/mondata.c +++ b/src/mondata.c @@ -900,10 +900,13 @@ register struct monst *mtmp; /* Like gender(), but lower animals and such are still "it". This is the one we want to use when printing messages. */ int -pronoun_gender(mtmp) +pronoun_gender(mtmp, override_vis) register struct monst *mtmp; +boolean override_vis; /* if True then 'no it' unless neuter */ { - if (is_neuter(mtmp->data) || !canspotmon(mtmp)) + if (!override_vis && !canspotmon(mtmp)) + return 2; + if (is_neuter(mtmp->data)) return 2; return (humanoid(mtmp->data) || (mtmp->data->geno & G_UNIQ) || type_is_pname(mtmp->data)) ? (int) mtmp->female : 2; diff --git a/src/shk.c b/src/shk.c index e0b7cae8b..6eb4ab71a 100644 --- a/src/shk.c +++ b/src/shk.c @@ -435,9 +435,9 @@ boolean newlev; plname); else pline("%s %s that you need to pay before leaving%s", - Shknam(shkp), - NOTANGRY(shkp) ? "points out" : "makes it clear", - NOTANGRY(shkp) ? "." : "!"); + Shknam(shkp), + NOTANGRY(shkp) ? "points out" : "makes it clear", + NOTANGRY(shkp) ? "." : "!"); return; } @@ -580,12 +580,12 @@ char *enterstring; return; /* no dialog */ if (Invis) { - pline("%s senses your presence.", shkname(shkp)); + pline("%s senses your presence.", Shknam(shkp)); if (!Deaf && !muteshk(shkp)) verbalize("Invisible customers are not welcome!"); else pline("%s stands firm as if %s knows you are there.", - Shknam(shkp), mhe(shkp)); + Shknam(shkp), noit_mhe(shkp)); return; } @@ -594,21 +594,18 @@ char *enterstring; if (ANGRY(shkp)) { if (!Deaf && !muteshk(shkp)) verbalize("So, %s, you dare return to %s %s?!", plname, - s_suffix(shkname(shkp)), shtypes[rt - SHOPBASE].name); + s_suffix(shkname(shkp)), shtypes[rt - SHOPBASE].name); else pline("%s seems %s over your return to %s %s!", - Shknam(shkp), - angrytexts[rn2(SIZE(angrytexts))], - mhis(shkp), - shtypes[rt - SHOPBASE].name); + Shknam(shkp), angrytexts[rn2(SIZE(angrytexts))], + noit_mhis(shkp), shtypes[rt - SHOPBASE].name); } else if (eshkp->robbed) { if (!Deaf) pline("%s mutters imprecations against shoplifters.", - shkname(shkp)); + Shknam(shkp)); else pline("%s is combing through %s inventory list.", - Shknam(shkp), - mhis(shkp)); + Shknam(shkp), noit_mhis(shkp)); } else { if (!Deaf && !muteshk(shkp)) verbalize("%s, %s! Welcome%s to %s %s!", Hello(shkp), plname, @@ -655,20 +652,20 @@ char *enterstring; tool, plur(cnt)); else pline("%s %s to let you in with your %s%s.", - Shknam(shkp), - NOTANGRY(shkp) ? "is hesitant" : "refuses", - tool, plur(cnt)); + Shknam(shkp), + NOTANGRY(shkp) ? "is hesitant" : "refuses", + tool, plur(cnt)); should_block = TRUE; } else if (u.usteed) { if (!Deaf && !muteshk(shkp)) verbalize(NOTANGRY(shkp) ? "Will you please leave %s outside?" : "Leave %s outside.", - y_monnam(u.usteed)); + y_monnam(u.usteed)); else pline("%s %s to let you in while you're riding %s.", - Shknam(shkp), - NOTANGRY(shkp) ? "doesn't want" : "refuses", - y_monnam(u.usteed)); + Shknam(shkp), + NOTANGRY(shkp) ? "doesn't want" : "refuses", + y_monnam(u.usteed)); should_block = TRUE; } else { should_block = @@ -1343,7 +1340,7 @@ proceed: } else { if (umoney > ltmp) { You("give %s the %ld gold piece%s %s asked for.", - shkname(shkp), ltmp, plur(ltmp), mhe(shkp)); + shkname(shkp), ltmp, plur(ltmp), noit_mhe(shkp)); pay(ltmp, shkp); } else { You("give %s all your%s gold.", shkname(shkp), @@ -1353,7 +1350,8 @@ proceed: pline("But you have hidden gold!"); } if ((umoney < ltmp / 2L) || (umoney < ltmp && stashed_gold)) - pline("Unfortunately, %s doesn't look satisfied.", mhe(shkp)); + pline("Unfortunately, %s doesn't look satisfied.", + noit_mhe(shkp)); else make_happy_shk(shkp, FALSE); } @@ -1373,13 +1371,14 @@ proceed: if (!umoney) pline(no_money, stashed_gold ? " seem to" : ""); else - pline(not_enough_money, mhim(shkp)); + pline(not_enough_money, noit_mhim(shkp)); return 1; } - pline("But since %s shop has been robbed recently,", mhis(shkp)); + pline("But since %s shop has been robbed recently,", + noit_mhis(shkp)); pline("you %scompensate %s for %s losses.", (umoney < ltmp) ? "partially " : "", shkname(shkp), - mhis(shkp)); + noit_mhis(shkp)); pay(umoney < ltmp ? umoney : ltmp, shkp); make_happy_shk(shkp, FALSE); } else { @@ -1390,11 +1389,14 @@ proceed: if (!umoney) pline(no_money, stashed_gold ? " seem to" : ""); else - pline(not_enough_money, mhim(shkp)); + pline(not_enough_money, noit_mhim(shkp)); return 1; } You("try to appease %s by giving %s 1000 gold pieces.", - x_monnam(shkp, ARTICLE_THE, "angry", 0, FALSE), mhim(shkp)); + canspotmon(shkp) + ? x_monnam(shkp, ARTICLE_THE, "angry", 0, FALSE) + : shkname(shkp), + noit_mhim(shkp)); pay(1000L, shkp); if (strncmp(eshkp->customer, plname, PL_NSIZ) || rn2(3)) make_happy_shk(shkp, FALSE); @@ -1538,13 +1540,13 @@ proceed: } if (!ANGRY(shkp) && paid) { if (!Deaf && !muteshk(shkp)) - verbalize("Thank you for shopping in %s %s!", s_suffix(shkname(shkp)), - shtypes[eshkp->shoptype - SHOPBASE].name); + verbalize("Thank you for shopping in %s %s!", + s_suffix(shkname(shkp)), + shtypes[eshkp->shoptype - SHOPBASE].name); else pline("%s nods appreciatively at you for shopping in %s %s!", - Shknam(shkp), - mhis(shkp), - shtypes[eshkp->shoptype - SHOPBASE].name); + Shknam(shkp), noit_mhis(shkp), + shtypes[eshkp->shoptype - SHOPBASE].name); } return 1; } @@ -1778,7 +1780,7 @@ int croaked; if (cansee(shkp->mx, shkp->my) && croaked) { takes[0] = '\0'; if (has_head(shkp->data) && !rn2(2)) - Sprintf(takes, ", shakes %s %s,", mhis(shkp), + Sprintf(takes, ", shakes %s %s,", noit_mhis(shkp), mbodypart(shkp, HEAD)); pline("%s %slooks at your corpse%s and %s.", Shknam(shkp), (!shkp->mcanmove || shkp->msleeping) ? "wakes up, " : "", @@ -1797,7 +1799,7 @@ int croaked; taken = (invent != 0); if (taken) pline("%s gratefully inherits all your possessions.", - shkname(shkp)); + Shknam(shkp)); set_repo_loc(shkp); goto clear; } @@ -1828,7 +1830,7 @@ int croaked; if (umoney > 0) money2mon(shkp, umoney); context.botl = 1; - pline("%s %s all your possessions.", shkname(shkp), takes); + pline("%s %s all your possessions.", Shknam(shkp), takes); taken = TRUE; /* where to put player's invent (after disclosure) */ set_repo_loc(shkp); @@ -1838,7 +1840,7 @@ int croaked; pline("%s %s the %ld %s %sowed %s.", Shknam(shkp), takes, loss, currency(loss), strncmp(eshkp->customer, plname, PL_NSIZ) ? "" : "you ", - mhim(shkp)); + noit_mhim(shkp)); /* shopkeeper has now been paid in full */ pacify_shk(shkp); eshkp->following = 0; @@ -2218,9 +2220,8 @@ boolean quietly; verbalize("I won't stock that. Take it out of here!"); else pline("%s shakes %s %s in refusal.", - Shknam(shkp), - mhis(shkp), - mbodypart(shkp, HEAD)); + Shknam(shkp), noit_mhis(shkp), + mbodypart(shkp, HEAD)); } } return TRUE; @@ -3010,7 +3011,7 @@ xchar x, y; if (sell_how == SELL_NORMAL || auto_credit) { c = sell_response = 'y'; } else if (sell_response != 'n') { - pline("%s cannot pay you at present.", shkname(shkp)); + pline("%s cannot pay you at present.", Shknam(shkp)); Sprintf(qbuf, "Will you accept %ld %s in credit for ", tmpcr, currency(tmpcr)); c = ynaq(safe_qbuf(qbuf, qbuf, "?", obj, doname, thesimpleoname, @@ -3079,7 +3080,7 @@ xchar x, y; "... your items in the . Sell them?" */ Sprintf(qbuf, "%s offers%s %ld gold piece%s for %s%s ", - shkname(shkp), short_funds ? " only" : "", offer, + Shknam(shkp), short_funds ? " only" : "", offer, plur(offer), (cltmp && !ltmp) ? ((yourc == 1L) ? "your item in " : "your items in ") @@ -3650,8 +3651,7 @@ struct monst *shkp; Hello(shkp), plname); else pline("%s holds out %s upturned %s.", - Shknam(shkp), - mhis(shkp), + Shknam(shkp), noit_mhis(shkp), mbodypart(shkp, HAND)); followmsg = moves; if (!rn2(9)) { @@ -3805,7 +3805,7 @@ register int fall; */ if (lang == 2) pline("%s curses %s inability to grab your backpack!", - shkname(shkp), mhim(shkp)); + Shknam(shkp), noit_mhim(shkp)); rile_shk(shkp); return; #endif @@ -3816,16 +3816,16 @@ register int fall; if (distu(shkp->mx, shkp->my) > 2) { if (lang == 2) pline("%s curses you in anger and frustration!", - shkname(shkp)); + Shknam(shkp)); else if (lang == 1) growl(shkp); rile_shk(shkp); return; } else - pline("%s %s, and %s your backpack!", shkname(shkp), + pline("%s %s, and %s your backpack!", Shknam(shkp), makeplural(locomotion(shkp->data, "leap")), grabs); } else - pline("%s %s your backpack!", shkname(shkp), grabs); + pline("%s %s your backpack!", Shknam(shkp), grabs); for (obj = invent; obj; obj = obj2) { obj2 = obj->nobj; @@ -3957,7 +3957,7 @@ boolean cant_mollify; if (uinshp) { if (um_dist(shkp->mx, shkp->my, 1) && !um_dist(shkp->mx, shkp->my, 3)) { - pline("%s leaps towards you!", shkname(shkp)); + pline("%s leaps towards you!", Shknam(shkp)); mnexto(shkp); } pursue = um_dist(shkp->mx, shkp->my, 1); @@ -4004,16 +4004,16 @@ boolean cant_mollify; else pline("%s is %s that you decided to %s %s %s!", Shknam(shkp), angrytexts[rn2(SIZE(angrytexts))], - dmgstr, mhis(shkp), dugwall ? "shop" : "door"); + dmgstr, noit_mhis(shkp), dugwall ? "shop" : "door"); } else { if (!Deaf) { - pline("%s shouts:", shkname(shkp)); + pline("%s shouts:", Shknam(shkp)); verbalize("Who dared %s my %s?", dmgstr, dugwall ? "shop" : "door"); } else { pline("%s is %s that someone decided to %s %s %s!", Shknam(shkp), angrytexts[rn2(SIZE(angrytexts))], - dmgstr, mhis(shkp), dugwall ? "shop" : "door"); + dmgstr, noit_mhis(shkp), dugwall ? "shop" : "door"); } } hot_pursuit(shkp); @@ -4039,10 +4039,8 @@ boolean cant_mollify; verbalize("Oh, yes! You'll pay!"); else pline("%s lunges %s %s toward your %s!", - Shknam(shkp), - mhis(shkp), - mbodypart(shkp, HAND), - body_part(NECK)); + Shknam(shkp), noit_mhis(shkp), + mbodypart(shkp, HAND), body_part(NECK)); } else growl(shkp); hot_pursuit(shkp); @@ -4221,9 +4219,9 @@ struct monst *shkp; eshk = ESHK(shkp); if (ANGRY(shkp)) { pline("%s %s how much %s dislikes %s customers.", - shkname(shkp), + Shknam(shkp), (!Deaf && !muteshk(shkp)) ? "mentions" : "indicates", - mhe(shkp), eshk->robbed ? "non-paying" : "rude"); + noit_mhe(shkp), eshk->robbed ? "non-paying" : "rude"); } else if (eshk->following) { if (strncmp(eshk->customer, plname, PL_NSIZ)) { if (!Deaf && !muteshk(shkp)) @@ -4242,35 +4240,35 @@ struct monst *shkp; register long total = addupbill(shkp) + eshk->debit; pline("%s %s that your bill comes to %ld %s.", - shkname(shkp), + Shknam(shkp), (!Deaf && !muteshk(shkp)) ? "says" : "indicates", total, currency(total)); } else if (eshk->debit) { pline("%s %s that you owe %s %ld %s.", - shkname(shkp), + Shknam(shkp), (!Deaf && !muteshk(shkp)) ? "reminds you" : "indicates", - mhim(shkp), eshk->debit, currency(eshk->debit)); + noit_mhim(shkp), eshk->debit, currency(eshk->debit)); } else if (eshk->credit) { pline("%s encourages you to use your %ld %s of credit.", - shkname(shkp), eshk->credit, currency(eshk->credit)); + Shknam(shkp), eshk->credit, currency(eshk->credit)); } else if (eshk->robbed) { pline("%s %s about a recent robbery.", Shknam(shkp), (!Deaf && !muteshk(shkp)) ? "complains" : "indicates concern"); } else if ((shkmoney = money_cnt(shkp->minvent)) < 50L) { pline("%s %s that business is bad.", - shkname(shkp), + Shknam(shkp), (!Deaf && !muteshk(shkp)) ? "complains" : "indicates"); } else if (shkmoney > 4000) { pline("%s %s that business is good.", - shkname(shkp), + Shknam(shkp), (!Deaf && !muteshk(shkp)) ? "says" : "indicates"); } else if (is_izchak(shkp, FALSE)) { if (!Deaf && !muteshk(shkp)) pline(Izchak_speaks[rn2(SIZE(Izchak_speaks))], shkname(shkp)); } else { if (!Deaf && !muteshk(shkp)) - pline("%s talks about the problem of shoplifters.", shkname(shkp)); + pline("%s talks about the problem of shoplifters.", Shknam(shkp)); } } @@ -4472,7 +4470,7 @@ register xchar x, y; && ESHK(shkp)->shd.y == y && shkp->mcanmove && !shkp->msleeping && (ESHK(shkp)->debit || ESHK(shkp)->billct || ESHK(shkp)->robbed)) { - pline("%s%s blocks your way!", shkname(shkp), + pline("%s%s blocks your way!", Shknam(shkp), Invis ? " senses your motion and" : ""); return TRUE; } @@ -4509,7 +4507,7 @@ register xchar x, y; && (x == sx - 1 || x == sx + 1 || y == sy - 1 || y == sy + 1) && (Invis || carrying(PICK_AXE) || carrying(DWARVISH_MATTOCK) || u.usteed)) { - pline("%s%s blocks your way!", shkname(shkp), + pline("%s%s blocks your way!", Shknam(shkp), Invis ? " senses your motion and" : ""); return TRUE; } diff --git a/src/vault.c b/src/vault.c index 22bf15e9c..eea24737d 100644 --- a/src/vault.c +++ b/src/vault.c @@ -452,7 +452,8 @@ invault() if (!Blind) pline( "%s holds out %s palm and beckons with %s other hand.", - noit_Monnam(guard), mhis(guard), mhis(guard)); + noit_Monnam(guard), noit_mhis(guard), + noit_mhis(guard)); } else { verbalize( "Most likely all your gold was stolen from this vault."); @@ -707,7 +708,7 @@ register struct monst *grd; if (Deaf) { if (!Blind) pline("%s holds out %s palm demandingly!", - noit_Monnam(grd), mhis(grd)); + noit_Monnam(grd), noit_mhis(grd)); } else { verbalize("Drop all your gold, scoundrel!"); } @@ -716,7 +717,7 @@ register struct monst *grd; if (Deaf) { if (!Blind) pline("%s rubs %s hands with enraged delight!", - noit_Monnam(grd), mhis(grd)); + noit_Monnam(grd), noit_mhis(grd)); } else { verbalize("So be it, rogue!"); }