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
|
||||
prevent recursive impossible() and panic() calls from leading to a stack overflow
|
||||
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
|
||||
|
||||
@@ -1956,6 +1956,7 @@ E void FDECL(remove_worn_item, (struct obj *,BOOLEAN_P));
|
||||
E int FDECL(steal, (struct monst *, char *));
|
||||
E int FDECL(mpickobj, (struct monst *,struct obj *));
|
||||
E void FDECL(stealamulet, (struct monst *));
|
||||
E void FDECL(mdrop_special_objs, (struct monst *));
|
||||
E void FDECL(relobj, (struct monst *,int,BOOLEAN_P));
|
||||
#ifdef GOLDOBJ
|
||||
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. */
|
||||
/* NetHack may be freely redistributed. See license for details. */
|
||||
|
||||
@@ -1583,13 +1583,18 @@ void
|
||||
mongone(mdef)
|
||||
register struct monst *mdef;
|
||||
{
|
||||
mdef->mhp = 0; /* can skip some inventory bookkeeping */
|
||||
#ifdef STEED
|
||||
/* Player is thrown from his steed when it disappears */
|
||||
if (mdef == u.usteed)
|
||||
dismount_steed(DISMOUNT_GENERIC);
|
||||
#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
|
||||
mdef->mgold = 0L;
|
||||
#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. */
|
||||
/* NetHack may be freely redistributed. See license for details. */
|
||||
|
||||
@@ -975,6 +975,9 @@ register boolean silentkops;
|
||||
} else {
|
||||
/* if sensed, does disappear regardless whether seen */
|
||||
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 */
|
||||
migrate_to_level(shkp, ledger_no(&eshkp->shoplevel),
|
||||
MIGR_APPROX_XY, &eshkp->shd);
|
||||
|
||||
81
src/steal.c
81
src/steal.c
@@ -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. */
|
||||
/* NetHack may be freely redistributed. See license for details. */
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
STATIC_PTR int NDECL(stealarm);
|
||||
|
||||
STATIC_DCL const char *FDECL(equipname, (struct obj *));
|
||||
STATIC_DCL void FDECL(mdrop_obj, (struct monst *,struct obj *,BOOLEAN_P));
|
||||
|
||||
STATIC_OVL const char *
|
||||
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 */
|
||||
void
|
||||
relobj(mtmp,show,is_pet)
|
||||
@@ -525,11 +579,12 @@ boolean is_pet; /* If true, pet should keep wielded/worn items */
|
||||
item1 = item2 = TRUE;
|
||||
if (!tunnels(mtmp->data) || !needspick(mtmp->data))
|
||||
item1 = TRUE;
|
||||
|
||||
while ((otmp = mtmp->minvent) != 0) {
|
||||
obj_extract_self(otmp);
|
||||
/* special case: pick-axe and unicorn horn are non-worn */
|
||||
/* 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 ||
|
||||
((!item1 && otmp->otyp == PICK_AXE) ||
|
||||
(!item2 && otmp->otyp == UNICORN_HORN && !otmp->cursed))) {
|
||||
@@ -542,28 +597,10 @@ boolean is_pet; /* If true, pet should keep wielded/worn items */
|
||||
keepobj = otmp;
|
||||
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)
|
||||
pline("%s drops %s.", Monnam(mtmp),
|
||||
distant_name(otmp, doname));
|
||||
if (flooreffects(otmp, omx, omy, "fall")) continue;
|
||||
place_object(otmp, omx, omy);
|
||||
stackobj(otmp);
|
||||
mdrop_obj(mtmp, otmp, is_pet && flags.verbose);
|
||||
}
|
||||
|
||||
/* put kept objects back */
|
||||
while ((otmp = keepobj) != (struct obj *)0) {
|
||||
keepobj = otmp->nobj;
|
||||
|
||||
Reference in New Issue
Block a user