Shopkeepers hold a grudge against past thieves

When you steal from a shop, its shopkeeper will remember you as a thief
and charge you higher prices in the future (as well as be more curt and
less polite in interactions with you, though not outright hostile) even
if you pacify them, or die on the level and revisit it later as a bones
file.  This was an idea aosdict had, and I think it makes sense that a
shopkeeper doesn't forgive and forget, immediately returning to treating
you exactly like anyone else, just because you were terrorized into
paying her back.  Paying a shopkeeper off may cause her to stop actively
attacking you, but it feels like she'd have her eye on you as a known
thief going forward (and maybe would hang up a sign with your picture,
saying something like "DO NOT ACCEPT CHECKS FROM THIS HERO").

This surchage already existed, but since it was tied to active anger
(which typically causes a shopkeeper to quickly abandon their shop to
follow you) it was somewhat rare to see it in action.

I did not implement it here, but one possible further tweak might be to
clear the surcharge if the shopkeeper is pacified via taming magic
(which more-or-less magically brainwashes the target to feel positively
towards the hero) but not if you simply pay your debts.
This commit is contained in:
Michael Meyer
2022-07-26 14:31:34 -04:00
committed by Pasi Kallinen
parent 94e8141c01
commit 8a549b0a60

View File

@@ -28,7 +28,7 @@ static const char the_contents_of[] = "the contents of ";
static void append_honorific(char *);
static long addupbill(struct monst *);
static void pacify_shk(struct monst *);
static void pacify_shk(struct monst *, boolean);
static struct bill_x *onbill(struct obj *, struct monst *, boolean);
static struct monst *next_shkp(struct monst *, boolean);
static long shop_debt(struct eshk *);
@@ -166,10 +166,7 @@ next_shkp(register struct monst *shkp, boolean withbill)
}
if (shkp) {
if (NOTANGRY(shkp)) {
if (ESHK(shkp)->surcharge)
pacify_shk(shkp);
} else {
if (ANGRY(shkp)) {
if (!ESHK(shkp)->surcharge)
rile_shk(shkp);
}
@@ -246,7 +243,7 @@ restshk(struct monst* shkp, boolean ghostly)
if (ghostly) {
assign_level(&eshkp->shoplevel, &u.uz);
if (ANGRY(shkp) && strncmpi(eshkp->customer, g.plname, PL_NSIZ))
pacify_shk(shkp);
pacify_shk(shkp, TRUE);
}
}
}
@@ -413,15 +410,16 @@ u_left_shop(char *leavestring, boolean newlev)
* Player just stepped onto shop-boundary (known from above logic).
* Try to intimidate him into paying his bill
*/
boolean not_upset = !eshkp->surcharge;
if (!Deaf && !muteshk(shkp))
verbalize(NOTANGRY(shkp) ? "%s! Please pay before leaving."
: "%s! Don't you leave without paying!",
verbalize(not_upset ? "%s! Please pay before leaving."
: "%s! Don't you leave without paying!",
g.plname);
else
pline("%s %s that you need to pay before leaving%s",
Shknam(shkp),
NOTANGRY(shkp) ? "points out" : "makes it clear",
NOTANGRY(shkp) ? "." : "!");
not_upset ? "points out" : "makes it clear",
not_upset ? "." : "!");
return;
}
@@ -594,7 +592,7 @@ u_entered_shop(char* enterstring)
eshkp->visitct = 0;
eshkp->following = 0;
(void) strncpy(eshkp->customer, g.plname, PL_NSIZ);
pacify_shk(shkp);
pacify_shk(shkp, TRUE);
}
if (muteshk(shkp) || eshkp->following)
@@ -620,6 +618,13 @@ u_entered_shop(char* enterstring)
pline("%s seems %s over your return to %s %s!",
Shknam(shkp), angrytexts[rn2(SIZE(angrytexts))],
noit_mhis(shkp), shtypes[rt - SHOPBASE].name);
} else if (eshkp->surcharge) {
if (!Deaf && !muteshk(shkp))
verbalize("Back again, %s? I've got my %s on you.",
g.plname, mbodypart(shkp, EYE));
else
pline_The("atmosphere at %s %s seems unwelcoming.",
s_suffix(shkname(shkp)), shtypes[rt - SHOPBASE].name);
} else if (eshkp->robbed) {
if (!Deaf)
pline("%s mutters imprecations against shoplifters.",
@@ -640,7 +645,7 @@ u_entered_shop(char* enterstring)
}
/* can't do anything about blocking if teleported in */
if (!inside_shop(u.ux, u.uy)) {
boolean should_block;
boolean should_block, not_upset = !eshkp->surcharge;
int cnt;
const char *tool;
struct obj *pick = carrying(PICK_AXE),
@@ -667,25 +672,25 @@ u_entered_shop(char* enterstring)
makeknown(DWARVISH_MATTOCK);
}
if (!Deaf && !muteshk(shkp))
verbalize(NOTANGRY(shkp)
verbalize(not_upset
? "Will you please leave your %s%s outside?"
: "Leave the %s%s outside.",
tool, plur(cnt));
else
pline("%s %s to let you in with your %s%s.",
Shknam(shkp),
NOTANGRY(shkp) ? "is hesitant" : "refuses",
not_upset ? "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.",
verbalize(not_upset ? "Will you please leave %s outside?"
: "Leave %s outside.",
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",
not_upset ? "doesn't want" : "refuses",
y_monnam(u.usteed));
should_block = TRUE;
} else {
@@ -832,10 +837,7 @@ shop_keeper(char rmno)
shkp = (rmno >= ROOMOFFSET) ? g.rooms[rmno - ROOMOFFSET].resident : 0;
if (shkp) {
if (has_eshk(shkp)) {
if (NOTANGRY(shkp)) {
if (ESHK(shkp)->surcharge)
pacify_shk(shkp);
} else {
if (ANGRY(shkp)) {
if (!ESHK(shkp)->surcharge)
rile_shk(shkp);
}
@@ -1070,10 +1072,10 @@ angry_shk_exists(void)
/* remove previously applied surcharge from all billed items */
static void
pacify_shk(register struct monst* shkp)
pacify_shk(register struct monst* shkp, boolean clear_surcharge)
{
NOTANGRY(shkp) = TRUE; /* make peaceful */
if (ESHK(shkp)->surcharge) {
if (clear_surcharge && ESHK(shkp)->surcharge) {
register struct bill_x *bp = ESHK(shkp)->bill_p;
register int ct = ESHK(shkp)->billct;
@@ -1125,7 +1127,7 @@ make_happy_shk(register struct monst* shkp, register boolean silentkops)
boolean wasmad = ANGRY(shkp);
struct eshk *eshkp = ESHK(shkp);
pacify_shk(shkp);
pacify_shk(shkp, FALSE);
eshkp->following = 0;
eshkp->robbed = 0L;
if (!Role_if(PM_ROGUE))
@@ -1559,13 +1561,15 @@ dopay(void)
}
if (!ANGRY(shkp) && paid) {
if (!Deaf && !muteshk(shkp))
verbalize("Thank you for shopping in %s %s!",
verbalize("Thank you for shopping in %s %s%s",
s_suffix(shkname(shkp)),
shtypes[eshkp->shoptype - SHOPBASE].name);
shtypes[eshkp->shoptype - SHOPBASE].name,
!eshkp->surcharge ? "!" : ".");
else
pline("%s nods appreciatively at you for shopping in %s %s!",
Shknam(shkp), noit_mhis(shkp),
shtypes[eshkp->shoptype - SHOPBASE].name);
pline("%s nods%s at you for shopping in %s %s%s",
Shknam(shkp), !eshkp->surcharge ? " appreciatively" : "",
noit_mhis(shkp), shtypes[eshkp->shoptype - SHOPBASE].name,
!eshkp->surcharge ? "!" : ".");
}
return ECMD_TIME;
}
@@ -1865,7 +1869,7 @@ inherits(struct monst* shkp, int numsk, int croaked, boolean silently)
: "you ",
noit_mhim(shkp));
/* shopkeeper has now been paid in full */
pacify_shk(shkp);
pacify_shk(shkp, FALSE);
eshkp->following = 0;
eshkp->robbed = 0L;
}
@@ -2713,10 +2717,11 @@ addtobill(
} else {
long save_quan = obj->quan;
Strcpy(buf, "\"For you, ");
Strcpy(buf, "\"For you,");
if (ANGRY(shkp)) {
Strcat(buf, "scum;");
} else {
Strcat(buf, " scum;");
} else if (!ESHK(shkp)->surcharge) {
Strcat(buf, " ");
append_honorific(buf);
Strcat(buf, "; only");
}
@@ -4339,7 +4344,7 @@ pay_for_damage(const char* dmgstr, boolean cant_mollify)
pline("Mollified, %s accepts your restitution.", shkname(shkp));
/* move shk back to his home loc */
home_shk(shkp, FALSE);
pacify_shk(shkp);
pacify_shk(shkp, FALSE);
/* home_shk() suppresses rloc()'s vanish/appear messages */
if (shkp->mx != sx || shkp->my != sy) {
if (was_outside && canspotmon(shkp))
@@ -4569,6 +4574,10 @@ shk_chat(struct monst* shkp)
pline("%s %s about a recent robbery.",
Shknam(shkp),
(!Deaf && !muteshk(shkp)) ? "complains" : "indicates concern");
} else if (eshk->surcharge) {
pline("%s %s that %s is watching you carefully.", Shknam(shkp),
(!Deaf && !muteshk(shkp)) ? "warns you" : "indicates",
noit_mhe(shkp));
} else if ((shkmoney = money_cnt(shkp->minvent)) < 50L) {
pline("%s %s that business is bad.",
Shknam(shkp),