fix the "big abuse" reported a few days ago
It was possible to get a shopkeeper to carry the Amulet from the
bottom of the dungeon up to the location of his shop, thereby bypassing
the usual labor of lugging it up yourself. [Drop the Amulet somewhere;
rob a shop so that the Kops are summoned and the shk comes after you;
when shk is next you, level teleport to the Amulet (probably two hops,
one to the Valley and another deeper into Gehennom); walk to the vicinity
of the Amulet; shk will eventually pick it up (shopkeepers like to pick
up magic items); now, pay him for the stolen goods--he'll be pacified
and migrate back to his shop, taking his inventory with him; lastly,
return to his shop and relieve him of his burder.] This patch makes
shopkeepers drop the Amulet or invocation tools if/when they set set to
migrate to their normal location.
Also fix another long standing risk that a monster that is sent
away (nurse when healing, Kops when you pacify a shopkeeper) might be
carrying the Amulet or one of the invocation tools and make the game
unwinnable. I doubt that that's ever actually happened but I think it'd
be possible if a monster that likes magic items ever got polymorphed
into a Kop. Such dismissed monsters will now drop the same stuff as
the shk above prior to leaving the game.
This commit is contained in:
@@ -102,6 +102,8 @@ attempting to drop a subset of a stack of multiple cursed loadstones could
|
|||||||
"miss" message was missing for thrown or kicked gold not caught by a monster
|
"miss" message was missing for thrown or kicked gold not caught by a monster
|
||||||
prevent recursive impossible() and panic() calls from leading to a stack overflow
|
prevent recursive impossible() and panic() calls from leading to a stack overflow
|
||||||
tainted meat didn't invoke cannibalism
|
tainted meat didn't invoke cannibalism
|
||||||
|
shopkeepers can't act as porters for the Amulet
|
||||||
|
dismissed monsters can't remove special items from play
|
||||||
|
|
||||||
|
|
||||||
Platform- and/or Interface-Specific Fixes
|
Platform- and/or Interface-Specific Fixes
|
||||||
|
|||||||
@@ -1956,6 +1956,7 @@ E void FDECL(remove_worn_item, (struct obj *,BOOLEAN_P));
|
|||||||
E int FDECL(steal, (struct monst *, char *));
|
E int FDECL(steal, (struct monst *, char *));
|
||||||
E int FDECL(mpickobj, (struct monst *,struct obj *));
|
E int FDECL(mpickobj, (struct monst *,struct obj *));
|
||||||
E void FDECL(stealamulet, (struct monst *));
|
E void FDECL(stealamulet, (struct monst *));
|
||||||
|
E void FDECL(mdrop_special_objs, (struct monst *));
|
||||||
E void FDECL(relobj, (struct monst *,int,BOOLEAN_P));
|
E void FDECL(relobj, (struct monst *,int,BOOLEAN_P));
|
||||||
#ifdef GOLDOBJ
|
#ifdef GOLDOBJ
|
||||||
E struct obj *FDECL(findgold, (struct obj *));
|
E struct obj *FDECL(findgold, (struct obj *));
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/* SCCS Id: @(#)mon.c 3.4 2003/11/26 */
|
/* SCCS Id: @(#)mon.c 3.4 2003/12/04 */
|
||||||
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
|
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
|
||||||
/* NetHack may be freely redistributed. See license for details. */
|
/* NetHack may be freely redistributed. See license for details. */
|
||||||
|
|
||||||
@@ -1583,13 +1583,18 @@ void
|
|||||||
mongone(mdef)
|
mongone(mdef)
|
||||||
register struct monst *mdef;
|
register struct monst *mdef;
|
||||||
{
|
{
|
||||||
|
mdef->mhp = 0; /* can skip some inventory bookkeeping */
|
||||||
#ifdef STEED
|
#ifdef STEED
|
||||||
/* Player is thrown from his steed when it disappears */
|
/* Player is thrown from his steed when it disappears */
|
||||||
if (mdef == u.usteed)
|
if (mdef == u.usteed)
|
||||||
dismount_steed(DISMOUNT_GENERIC);
|
dismount_steed(DISMOUNT_GENERIC);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
discard_minvent(mdef); /* release monster's inventory */
|
/* drop special items like the Amulet so that a dismissed Kop or nurse
|
||||||
|
can't remove them from the game */
|
||||||
|
mdrop_special_objs(mdef);
|
||||||
|
/* release rest of monster's inventory--it is removed from game */
|
||||||
|
discard_minvent(mdef);
|
||||||
#ifndef GOLDOBJ
|
#ifndef GOLDOBJ
|
||||||
mdef->mgold = 0L;
|
mdef->mgold = 0L;
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/* SCCS Id: @(#)shk.c 3.4 2003/08/18 */
|
/* SCCS Id: @(#)shk.c 3.4 2003/12/04 */
|
||||||
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
|
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
|
||||||
/* NetHack may be freely redistributed. See license for details. */
|
/* NetHack may be freely redistributed. See license for details. */
|
||||||
|
|
||||||
@@ -975,6 +975,9 @@ register boolean silentkops;
|
|||||||
} else {
|
} else {
|
||||||
/* if sensed, does disappear regardless whether seen */
|
/* if sensed, does disappear regardless whether seen */
|
||||||
if (sensemon(shkp)) vanished = TRUE;
|
if (sensemon(shkp)) vanished = TRUE;
|
||||||
|
/* can't act as porter for the Amulet, even if shk
|
||||||
|
happens to be going farther down rather than up */
|
||||||
|
mdrop_special_objs(shkp);
|
||||||
/* arrive near shop's door */
|
/* arrive near shop's door */
|
||||||
migrate_to_level(shkp, ledger_no(&eshkp->shoplevel),
|
migrate_to_level(shkp, ledger_no(&eshkp->shoplevel),
|
||||||
MIGR_APPROX_XY, &eshkp->shd);
|
MIGR_APPROX_XY, &eshkp->shd);
|
||||||
|
|||||||
+59
-22
@@ -1,4 +1,4 @@
|
|||||||
/* SCCS Id: @(#)steal.c 3.4 2003/11/14 */
|
/* SCCS Id: @(#)steal.c 3.4 2003/12/04 */
|
||||||
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
|
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
|
||||||
/* NetHack may be freely redistributed. See license for details. */
|
/* NetHack may be freely redistributed. See license for details. */
|
||||||
|
|
||||||
@@ -7,6 +7,7 @@
|
|||||||
STATIC_PTR int NDECL(stealarm);
|
STATIC_PTR int NDECL(stealarm);
|
||||||
|
|
||||||
STATIC_DCL const char *FDECL(equipname, (struct obj *));
|
STATIC_DCL const char *FDECL(equipname, (struct obj *));
|
||||||
|
STATIC_DCL void FDECL(mdrop_obj, (struct monst *,struct obj *,BOOLEAN_P));
|
||||||
|
|
||||||
STATIC_OVL const char *
|
STATIC_OVL const char *
|
||||||
equipname(otmp)
|
equipname(otmp)
|
||||||
@@ -508,6 +509,59 @@ struct monst *mtmp;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* drop one object taken from a (possibly dead) monster's inventory */
|
||||||
|
STATIC_OVL void
|
||||||
|
mdrop_obj(mon, obj, verbosely)
|
||||||
|
struct monst *mon;
|
||||||
|
struct obj *obj;
|
||||||
|
boolean verbosely;
|
||||||
|
{
|
||||||
|
int omx = mon->mx, omy = mon->my;
|
||||||
|
|
||||||
|
if (obj->owornmask) {
|
||||||
|
/* perform worn item handling if the monster is still alive */
|
||||||
|
if (mon->mhp > 0) {
|
||||||
|
mon->misc_worn_check &= ~obj->owornmask;
|
||||||
|
update_mon_intrinsics(mon, obj, FALSE, TRUE);
|
||||||
|
/* obj_no_longer_held(obj); -- done by place_object */
|
||||||
|
if (obj->owornmask & W_WEP) setmnotwielded(mon, obj);
|
||||||
|
#ifdef STEED
|
||||||
|
/* don't charge for an owned saddle on dead steed */
|
||||||
|
} else if (mon->mtame && (obj->owornmask & W_SADDLE) &&
|
||||||
|
!obj->unpaid && costly_spot(omx, omy)) {
|
||||||
|
obj->no_charge = 1;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
obj->owornmask = 0L;
|
||||||
|
}
|
||||||
|
if (verbosely && cansee(omx, omy))
|
||||||
|
pline("%s drops %s.", Monnam(mon), distant_name(obj, doname));
|
||||||
|
if (!flooreffects(obj, omx, omy, "fall")) {
|
||||||
|
place_object(obj, omx, omy);
|
||||||
|
stackobj(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* some monsters bypass the normal rules for moving between levels or
|
||||||
|
even leaving the game entirely; when that happens, prevent them from
|
||||||
|
taking the Amulet or invocation tools with them */
|
||||||
|
void
|
||||||
|
mdrop_special_objs(mon)
|
||||||
|
struct monst *mon;
|
||||||
|
{
|
||||||
|
struct obj *obj, *otmp;
|
||||||
|
|
||||||
|
for (obj = mon->minvent; obj; obj = otmp) {
|
||||||
|
otmp = obj->nobj;
|
||||||
|
/* the Amulet, invocation tools, and Rider corpses resist even when
|
||||||
|
artifacts and ordinary objects are given 0% resistance chance */
|
||||||
|
if (obj_resists(obj, 0, 0)) {
|
||||||
|
obj_extract_self(obj);
|
||||||
|
mdrop_obj(mon, obj, FALSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* release the objects the creature is carrying */
|
/* release the objects the creature is carrying */
|
||||||
void
|
void
|
||||||
relobj(mtmp,show,is_pet)
|
relobj(mtmp,show,is_pet)
|
||||||
@@ -525,11 +579,12 @@ boolean is_pet; /* If true, pet should keep wielded/worn items */
|
|||||||
item1 = item2 = TRUE;
|
item1 = item2 = TRUE;
|
||||||
if (!tunnels(mtmp->data) || !needspick(mtmp->data))
|
if (!tunnels(mtmp->data) || !needspick(mtmp->data))
|
||||||
item1 = TRUE;
|
item1 = TRUE;
|
||||||
|
|
||||||
while ((otmp = mtmp->minvent) != 0) {
|
while ((otmp = mtmp->minvent) != 0) {
|
||||||
obj_extract_self(otmp);
|
obj_extract_self(otmp);
|
||||||
/* special case: pick-axe and unicorn horn are non-worn */
|
/* special case: pick-axe and unicorn horn are non-worn */
|
||||||
/* items that we also want pets to keep 1 of */
|
/* items that we also want pets to keep 1 of */
|
||||||
/* (It is a coincidence that these can also be wielded. */
|
/* (It is a coincidence that these can also be wielded.) */
|
||||||
if (otmp->owornmask || otmp == wep ||
|
if (otmp->owornmask || otmp == wep ||
|
||||||
((!item1 && otmp->otyp == PICK_AXE) ||
|
((!item1 && otmp->otyp == PICK_AXE) ||
|
||||||
(!item2 && otmp->otyp == UNICORN_HORN && !otmp->cursed))) {
|
(!item2 && otmp->otyp == UNICORN_HORN && !otmp->cursed))) {
|
||||||
@@ -542,28 +597,10 @@ boolean is_pet; /* If true, pet should keep wielded/worn items */
|
|||||||
keepobj = otmp;
|
keepobj = otmp;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
mtmp->misc_worn_check &= ~(otmp->owornmask);
|
|
||||||
#ifdef STEED
|
|
||||||
/* don't charge for an owned saddle on dead pet */
|
|
||||||
if (mtmp->mtame && mtmp->mhp == 0 &&
|
|
||||||
(otmp->owornmask & W_SADDLE) && !otmp->unpaid &&
|
|
||||||
costly_spot(mtmp->mx, mtmp->my))
|
|
||||||
otmp->no_charge = 1;
|
|
||||||
#endif
|
|
||||||
if (otmp->owornmask)
|
|
||||||
update_mon_intrinsics(mtmp, otmp, FALSE, TRUE);
|
|
||||||
/* obj_no_longer_held(otmp); -- done by place_object */
|
|
||||||
if (otmp->owornmask & W_WEP)
|
|
||||||
setmnotwielded(mtmp, otmp);
|
|
||||||
otmp->owornmask = 0L;
|
|
||||||
}
|
}
|
||||||
if (is_pet && cansee(omx, omy) && flags.verbose)
|
mdrop_obj(mtmp, otmp, is_pet && flags.verbose);
|
||||||
pline("%s drops %s.", Monnam(mtmp),
|
|
||||||
distant_name(otmp, doname));
|
|
||||||
if (flooreffects(otmp, omx, omy, "fall")) continue;
|
|
||||||
place_object(otmp, omx, omy);
|
|
||||||
stackobj(otmp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* put kept objects back */
|
/* put kept objects back */
|
||||||
while ((otmp = keepobj) != (struct obj *)0) {
|
while ((otmp = keepobj) != (struct obj *)0) {
|
||||||
keepobj = otmp->nobj;
|
keepobj = otmp->nobj;
|
||||||
|
|||||||
Reference in New Issue
Block a user