fix #H4094 - shopkeeper "it" message
Most shop messages use shkname() to give the shopkeeper's accurate name (or hallucinatory substitute) even if he or she can't be seen. stolen_value() was using mon_nam(), which calls shkname() if the monster is a shopkeeper who can be seen, but produces "it" when not seen. Change it to use shkname() like the rest of the shop routines. Also, replace Monnam() (quite a few instances) with new Shknam() to do the same duty when the name is at the start of a sentence. There was also a very obscure bug where if you could see two shopkeepers at the same time, you could probe the map one spot at a time with repeated use of the 'p' command to locate monsters in general and other shopkeepers in particular. Very tedious and not very useful, but now fixed.
This commit is contained in:
@@ -144,6 +144,10 @@ if a non-cursed spellbook being read becomes cursed and hero recognizes that
|
||||
if a non-cursed spellbook being read becomes cursed and hero doesn't notice,
|
||||
don't leave it flagged as in-use (hence to be deleted during the
|
||||
next save/restore cycle) if contact-poison cursed book effect occurs
|
||||
stolen_value, used when breaking shop items from outside the shop among other
|
||||
times, could describe the shopkeeper as "it" when not seen
|
||||
when two or more shopkeepers were visible at once, 'p' command could be used
|
||||
to probe map for locations of other shopkeepers and arbitrary monsters
|
||||
|
||||
|
||||
Platform- and/or Interface-Specific Fixes
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* NetHack 3.6 extern.h $NHDT-Date: 1454033598 2016/01/29 02:13:18 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.543 $ */
|
||||
/* NetHack 3.6 extern.h $NHDT-Date: 1454485430 2016/02/03 07:43:50 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.545 $ */
|
||||
/* Copyright (c) Steve Creps, 1988. */
|
||||
/* NetHack may be freely redistributed. See license for details. */
|
||||
|
||||
@@ -2147,7 +2147,8 @@ E void FDECL(free_eshk, (struct monst *));
|
||||
E void FDECL(stock_room, (int, struct mkroom *));
|
||||
E boolean FDECL(saleable, (struct monst *, struct obj *));
|
||||
E int FDECL(get_shop_item, (int));
|
||||
E const char *FDECL(shkname, (struct monst *));
|
||||
E char *FDECL(Shknam, (struct monst *));
|
||||
E char *FDECL(shkname, (struct monst *));
|
||||
E boolean FDECL(shkname_is_pname, (struct monst *));
|
||||
E boolean FDECL(is_izchak, (struct monst *, BOOLEAN_P));
|
||||
|
||||
|
||||
82
src/shk.c
82
src/shk.c
@@ -1,4 +1,4 @@
|
||||
/* NetHack 3.6 shk.c $NHDT-Date: 1451838768 2016/01/03 16:32:48 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.119 $ */
|
||||
/* NetHack 3.6 shk.c $NHDT-Date: 1454485431 2016/02/03 07:43:51 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.122 $ */
|
||||
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
|
||||
/* NetHack may be freely redistributed. See license for details. */
|
||||
|
||||
@@ -1030,7 +1030,7 @@ boolean verbosely;
|
||||
if (!shkp->mcanmove || shkp->msleeping) {
|
||||
/* greed induced recovery... */
|
||||
if (verbosely && canspotmon(shkp))
|
||||
pline("%s %s.", Monnam(shkp),
|
||||
pline("%s %s.", Shknam(shkp),
|
||||
shkp->msleeping ? "wakes up" : "can move again");
|
||||
shkp->msleeping = 0;
|
||||
shkp->mfrozen = 0;
|
||||
@@ -1055,7 +1055,7 @@ register boolean silentkops;
|
||||
char shk_nam[BUFSZ];
|
||||
boolean vanished = canseemon(shkp);
|
||||
|
||||
Strcpy(shk_nam, mon_nam(shkp));
|
||||
Strcpy(shk_nam, shkname(shkp));
|
||||
if (on_level(&eshkp->shoplevel, &u.uz)) {
|
||||
home_shk(shkp, FALSE);
|
||||
/* didn't disappear if shk can still be seen */
|
||||
@@ -1077,7 +1077,7 @@ register boolean silentkops;
|
||||
if (vanished)
|
||||
pline("Satisfied, %s suddenly disappears!", shk_nam);
|
||||
} else if (wasmad)
|
||||
pline("%s calms down.", Monnam(shkp));
|
||||
pline("%s calms down.", Shknam(shkp));
|
||||
|
||||
make_happy_shoppers(silentkops);
|
||||
}
|
||||
@@ -1105,17 +1105,16 @@ register struct monst *shkp;
|
||||
ESHK(shkp)->following = 1;
|
||||
}
|
||||
|
||||
/* used when the shkp is teleported or falls (ox == 0) out of his shop,
|
||||
* or when the player is not on a costly_spot and he
|
||||
* damages something inside the shop. these conditions
|
||||
* must be checked by the calling function.
|
||||
*/
|
||||
/* Used when the shkp is teleported or falls (ox == 0) out of his shop, or
|
||||
when the player is not on a costly_spot and he damages something inside
|
||||
the shop. These conditions must be checked by the calling function. */
|
||||
/*ARGSUSED*/
|
||||
void
|
||||
make_angry_shk(shkp, ox, oy)
|
||||
register struct monst *shkp;
|
||||
register xchar ox, oy;
|
||||
struct monst *shkp;
|
||||
xchar ox UNUSED; /* <ox,oy> predate 'noit_Monnam()', let alone Shknam() */
|
||||
xchar oy UNUSED;
|
||||
{
|
||||
xchar sx, sy;
|
||||
struct eshk *eshkp = ESHK(shkp);
|
||||
|
||||
/* all pending shop transactions are now "past due" */
|
||||
@@ -1128,15 +1127,7 @@ register xchar ox, oy;
|
||||
setpaid(shkp);
|
||||
}
|
||||
|
||||
/* If you just used a wand of teleportation to send the shk away, you
|
||||
might not be able to see her any more. Monnam would yield "it",
|
||||
which makes this message look pretty silly, so temporarily restore
|
||||
her original location during the call to Monnam. */
|
||||
sx = shkp->mx, sy = shkp->my;
|
||||
if (isok(ox, oy) && cansee(ox, oy) && !cansee(sx, sy))
|
||||
shkp->mx = ox, shkp->my = oy;
|
||||
pline("%s %s!", Monnam(shkp), !ANGRY(shkp) ? "gets angry" : "is furious");
|
||||
shkp->mx = sx, shkp->my = sy;
|
||||
pline("%s %s!", Shknam(shkp), !ANGRY(shkp) ? "gets angry" : "is furious");
|
||||
hot_pursuit(shkp);
|
||||
}
|
||||
|
||||
@@ -1219,7 +1210,7 @@ dopay()
|
||||
break;
|
||||
if (shkp != resident && distu(shkp->mx, shkp->my) > 2) {
|
||||
pline("%s is not near enough to receive your payment.",
|
||||
Monnam(shkp));
|
||||
Shknam(shkp));
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
@@ -1243,6 +1234,10 @@ dopay()
|
||||
return 0;
|
||||
}
|
||||
mtmp = m_at(cx, cy);
|
||||
if (!cansee(cx, cy) && (!mtmp || !canspotmon(mtmp))) {
|
||||
You("can't %s anyone there.", !Blind ? "see" : "sense");
|
||||
return 0;
|
||||
}
|
||||
if (!mtmp) {
|
||||
There("is no one there to receive your payment.");
|
||||
return 0;
|
||||
@@ -1252,7 +1247,7 @@ dopay()
|
||||
return 0;
|
||||
}
|
||||
if (mtmp != resident && distu(mtmp->mx, mtmp->my) > 2) {
|
||||
pline("%s is too far to receive your payment.", Monnam(mtmp));
|
||||
pline("%s is too far to receive your payment.", Shknam(mtmp));
|
||||
return 0;
|
||||
}
|
||||
shkp = mtmp;
|
||||
@@ -1271,7 +1266,7 @@ proceed:
|
||||
rouse_shk(shkp, TRUE);
|
||||
|
||||
if (!shkp->mcanmove || shkp->msleeping) { /* still asleep/paralyzed */
|
||||
pline("%s %s.", Monnam(shkp),
|
||||
pline("%s %s.", Shknam(shkp),
|
||||
rn2(2) ? "seems to be napping" : "doesn't respond");
|
||||
return 0;
|
||||
}
|
||||
@@ -1279,7 +1274,7 @@ proceed:
|
||||
if (shkp != resident && NOTANGRY(shkp)) {
|
||||
umoney = money_cnt(invent);
|
||||
if (!ltmp)
|
||||
You("do not owe %s anything.", mon_nam(shkp));
|
||||
You("do not owe %s anything.", shkname(shkp));
|
||||
else if (!umoney) {
|
||||
You("%shave no money.", stashed_gold ? "seem to " : "");
|
||||
if (stashed_gold)
|
||||
@@ -1329,7 +1324,7 @@ proceed:
|
||||
} else {
|
||||
/* shopkeeper is angry, but has not been robbed --
|
||||
* door broken, attacked, etc. */
|
||||
pline("%s is after your hide, not your money!", Monnam(shkp));
|
||||
pline("%s is after your hide, not your money!", Shknam(shkp));
|
||||
if (umoney < 1000L) {
|
||||
if (!umoney)
|
||||
pline(no_money, stashed_gold ? " seem to" : "");
|
||||
@@ -1709,7 +1704,7 @@ int croaked;
|
||||
if (has_head(shkp->data) && !rn2(2))
|
||||
Sprintf(takes, ", shakes %s %s,", mhis(shkp),
|
||||
mbodypart(shkp, HEAD));
|
||||
pline("%s %slooks at your corpse%s and %s.", Monnam(shkp),
|
||||
pline("%s %slooks at your corpse%s and %s.", Shknam(shkp),
|
||||
(!shkp->mcanmove || shkp->msleeping) ? "wakes up, " : "",
|
||||
takes, !inhishop(shkp) ? "disappears" : "sighs");
|
||||
}
|
||||
@@ -1764,10 +1759,10 @@ int croaked;
|
||||
} else {
|
||||
money2mon(shkp, loss);
|
||||
context.botl = 1;
|
||||
pline("%s %s the %ld %s %sowed %s.", Monnam(shkp), takes, loss,
|
||||
currency(loss),
|
||||
pline("%s %s the %ld %s %sowed %s.", Shknam(shkp),
|
||||
takes, loss, currency(loss),
|
||||
strncmp(eshkp->customer, plname, PL_NSIZ) ? "" : "you ",
|
||||
shkp->female ? "her" : "him");
|
||||
mhim(shkp));
|
||||
/* shopkeeper has now been paid in full */
|
||||
pacify_shk(shkp);
|
||||
eshkp->following = 0;
|
||||
@@ -2458,7 +2453,7 @@ boolean ininv, dummy, silent;
|
||||
char buf[BUFSZ];
|
||||
|
||||
if (!ltmp) {
|
||||
pline("%s has no interest in %s.", Monnam(shkp), the(xname(obj)));
|
||||
pline("%s has no interest in %s.", Shknam(shkp), the(xname(obj)));
|
||||
return;
|
||||
}
|
||||
if (!ininv) {
|
||||
@@ -2491,7 +2486,7 @@ boolean ininv, dummy, silent;
|
||||
(contentscount && obj->unpaid) ? and_its_contents : "",
|
||||
ltmp, currency(ltmp), (obj->quan > 1L) ? " each" : "");
|
||||
else
|
||||
pline("%s does not notice.", Monnam(shkp));
|
||||
pline("%s does not notice.", Shknam(shkp));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2727,19 +2722,19 @@ boolean peaceful, silent;
|
||||
still = "still ";
|
||||
}
|
||||
if (obj->oclass == COIN_CLASS)
|
||||
You("%sowe %s %ld %s!", still, mon_nam(shkp), value,
|
||||
You("%sowe %s %ld %s!", still, shkname(shkp), value,
|
||||
currency(value));
|
||||
else
|
||||
You("%sowe %s %ld %s for %s!", still, mon_nam(shkp), value,
|
||||
currency(value), obj->quan > 1L ? "them" : "it");
|
||||
You("%sowe %s %ld %s for %s!", still, shkname(shkp),
|
||||
value, currency(value), (obj->quan > 1L) ? "them" : "it");
|
||||
}
|
||||
} else {
|
||||
ESHK(shkp)->robbed += value;
|
||||
|
||||
if (!silent) {
|
||||
if (cansee(shkp->mx, shkp->my)) {
|
||||
Norep("%s booms: \"%s, you are a thief!\"", Monnam(shkp),
|
||||
plname);
|
||||
if (canseemon(shkp)) {
|
||||
Norep("%s booms: \"%s, you are a thief!\"",
|
||||
Shknam(shkp), plname);
|
||||
} else
|
||||
Norep("You hear a scream, \"Thief!\"");
|
||||
}
|
||||
@@ -2823,7 +2818,7 @@ xchar x, y;
|
||||
|
||||
if (!unpaid && (sell_how != SELL_DONTSELL)
|
||||
&& !special_stock(obj, shkp, FALSE))
|
||||
pline("%s seems uninterested.", Monnam(shkp));
|
||||
pline("%s seems uninterested.", Shknam(shkp));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2900,7 +2895,7 @@ xchar x, y;
|
||||
|| offer == 0L || (obj->oclass == FOOD_CLASS && obj->oeaten)
|
||||
|| (Is_candle(obj)
|
||||
&& obj->age < 20L * (long) objects[obj->otyp].oc_cost)) {
|
||||
pline("%s seems uninterested%s.", Monnam(shkp),
|
||||
pline("%s seems uninterested%s.", Shknam(shkp),
|
||||
cgold ? " in the rest" : "");
|
||||
if (container)
|
||||
dropped_container(obj, shkp, FALSE);
|
||||
@@ -3179,7 +3174,7 @@ register xchar x, y;
|
||||
if (mnearto(shkp, x, y, TRUE) && !muteshk(shkp))
|
||||
verbalize("Out of my way, scum!");
|
||||
if (cansee(x, y)) {
|
||||
pline("%s nimbly%s catches %s.", Monnam(shkp),
|
||||
pline("%s nimbly%s catches %s.", Shknam(shkp),
|
||||
(x == shkp->mx && y == shkp->my) ? "" : " reaches over and",
|
||||
the(xname(obj)));
|
||||
if (!canspotmon(shkp))
|
||||
@@ -3517,7 +3512,7 @@ register struct monst *shkp;
|
||||
|| (omx == u.ux || omy == u.uy))) {
|
||||
if (ANGRY(shkp) || (Conflict && !resist(shkp, RING_CLASS, 0, 0))) {
|
||||
if (Displaced)
|
||||
Your("displaced image doesn't fool %s!", mon_nam(shkp));
|
||||
Your("displaced image doesn't fool %s!", shkname(shkp));
|
||||
(void) mattacku(shkp);
|
||||
return 0;
|
||||
}
|
||||
@@ -3536,7 +3531,7 @@ register struct monst *shkp;
|
||||
followmsg = moves;
|
||||
if (!rn2(9)) {
|
||||
pline("%s doesn't like customers who don't pay.",
|
||||
Monnam(shkp));
|
||||
Shknam(shkp));
|
||||
rile_shk(shkp);
|
||||
}
|
||||
}
|
||||
@@ -4063,6 +4058,7 @@ struct monst *shkp;
|
||||
{
|
||||
struct eshk *eshk;
|
||||
long shkmoney;
|
||||
|
||||
if (!shkp->isshk) {
|
||||
/* The monster type is shopkeeper, but this monster is
|
||||
not actually a shk, which could happen if someone
|
||||
|
||||
75
src/shknam.c
75
src/shknam.c
@@ -1,4 +1,4 @@
|
||||
/* NetHack 3.6 shknam.c $NHDT-Date: 1450306213 2015/12/16 22:50:13 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.39 $ */
|
||||
/* NetHack 3.6 shknam.c $NHDT-Date: 1454485432 2016/02/03 07:43:52 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.41 $ */
|
||||
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
|
||||
/* NetHack may be freely redistributed. See license for details. */
|
||||
|
||||
@@ -815,35 +815,64 @@ int type;
|
||||
return shp->iprobs[i].itype;
|
||||
}
|
||||
|
||||
const char *
|
||||
/* version of shkname() for beginning of sentence */
|
||||
char *
|
||||
Shknam(mtmp)
|
||||
struct monst *mtmp;
|
||||
{
|
||||
char *nam = shkname(mtmp);
|
||||
|
||||
/* 'nam[]' is almost certainly already capitalized, but be sure */
|
||||
nam[0] = highc(nam[0]);
|
||||
return nam;
|
||||
}
|
||||
|
||||
/* shopkeeper's name, without any visibility constraint; if hallucinating,
|
||||
will yield some other shopkeeper's name (not necessarily one residing
|
||||
in the current game's dungeon, or who keeps same type of shop) */
|
||||
char *
|
||||
shkname(mtmp)
|
||||
struct monst *mtmp;
|
||||
{
|
||||
const char *shknm = ESHK(mtmp)->shknam;
|
||||
char *nam;
|
||||
unsigned save_isshk = mtmp->isshk;
|
||||
|
||||
if (Hallucination && !program_state.gameover) {
|
||||
const char *const *nlp;
|
||||
int num;
|
||||
mtmp->isshk = 0; /* don't want mon_nam() calling shkname() */
|
||||
/* get a modifiable name buffer along with fallback result */
|
||||
nam = noit_mon_nam(mtmp);
|
||||
mtmp->isshk = save_isshk;
|
||||
|
||||
/* count the number of non-unique shop types;
|
||||
pick one randomly, ignoring shop generation probabilities;
|
||||
pick a name at random from that shop type's list */
|
||||
for (num = 0; num < SIZE(shtypes); num++)
|
||||
if (shtypes[num].prob == 0)
|
||||
break;
|
||||
if (num > 0) {
|
||||
nlp = shtypes[rn2(num)].shknms;
|
||||
for (num = 0; nlp[num]; num++)
|
||||
continue;
|
||||
if (num > 0)
|
||||
shknm = nlp[rn2(num)];
|
||||
if (!mtmp->isshk) {
|
||||
impossible("shkname: \"%s\" is not a shopkeeper.", nam);
|
||||
} else if (!has_eshk(mtmp)) {
|
||||
panic("shkname: shopkeeper \"%s\" lacks 'eshk' data.", nam);
|
||||
} else {
|
||||
const char *shknm = ESHK(mtmp)->shknam;
|
||||
|
||||
if (Hallucination && !program_state.gameover) {
|
||||
const char *const *nlp;
|
||||
int num;
|
||||
|
||||
/* count the number of non-unique shop types;
|
||||
pick one randomly, ignoring shop generation probabilities;
|
||||
pick a name at random from that shop type's list */
|
||||
for (num = 0; num < SIZE(shtypes); num++)
|
||||
if (shtypes[num].prob == 0)
|
||||
break;
|
||||
if (num > 0) {
|
||||
nlp = shtypes[rn2(num)].shknms;
|
||||
for (num = 0; nlp[num]; num++)
|
||||
continue;
|
||||
if (num > 0)
|
||||
shknm = nlp[rn2(num)];
|
||||
}
|
||||
}
|
||||
/* strip prefix if present */
|
||||
if (!letter(*shknm))
|
||||
++shknm;
|
||||
Strcpy(nam, shknm);
|
||||
}
|
||||
|
||||
/* strip prefix if present */
|
||||
if (!letter(*shknm))
|
||||
++shknm;
|
||||
return shknm;
|
||||
return nam;
|
||||
}
|
||||
|
||||
boolean
|
||||
|
||||
Reference in New Issue
Block a user