U162 - killing shopkeeper with unpaid thrown objects
While an object is being thrown, it isn't on any list. This means that killing a shopkeeper with an unpaid object wouldn't be able to clear the unpaid bit. By the time the object lands, the shopkeeper is gone, and then it's too late. Added a new global to track a thrown object, set it and later clear it in throwit(), also clear it as needed in dealloc_obj(), and check it in setpaid(). It should be possible to use this global to avoid losing thrown objects during hangup saves as well. But that can wait.
This commit is contained in:
@@ -383,6 +383,8 @@ avoid buffer overflow from long or too many -s params
|
||||
wake up first if trying to crawl out of water while asleep
|
||||
while waiting, don't try to change into were form when already in were form
|
||||
steed should remember traps encountered while mounted
|
||||
killing shopkeeper by throwing unpaid things would result in
|
||||
"item not on bill" impossible error
|
||||
|
||||
|
||||
Platform- and/or Interface-Specific Fixes
|
||||
|
||||
@@ -26,6 +26,8 @@ static NEARDATA const char toss_objs[] =
|
||||
static NEARDATA const char bullets[] =
|
||||
{ ALLOW_COUNT, COIN_CLASS, ALL_CLASSES, GEM_CLASS, 0 };
|
||||
|
||||
struct obj *thrownobj = 0; /* tracks an object until it lands */
|
||||
|
||||
extern boolean notonhead; /* for long worms */
|
||||
|
||||
|
||||
@@ -882,6 +884,8 @@ boolean twoweap; /* used to restore twoweapon mode if wielded weapon returns */
|
||||
u.dz = 1;
|
||||
}
|
||||
|
||||
thrownobj = obj;
|
||||
|
||||
if(u.uswallow) {
|
||||
mon = u.ustuck;
|
||||
bhitpos.x = mon->mx;
|
||||
@@ -901,6 +905,7 @@ boolean twoweap; /* used to restore twoweapon mode if wielded weapon returns */
|
||||
} else {
|
||||
hitfloor(obj);
|
||||
}
|
||||
thrownobj = (struct obj*)0;
|
||||
return;
|
||||
|
||||
} else if(obj->otyp == BOOMERANG && !Underwater) {
|
||||
@@ -915,6 +920,7 @@ boolean twoweap; /* used to restore twoweapon mode if wielded weapon returns */
|
||||
setworn(obj, wep_mask);
|
||||
u.twoweap = twoweap;
|
||||
}
|
||||
thrownobj = (struct obj*)0;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
@@ -972,8 +978,10 @@ boolean twoweap; /* used to restore twoweapon mode if wielded weapon returns */
|
||||
boolean obj_gone;
|
||||
|
||||
if (mon->isshk &&
|
||||
obj->where == OBJ_MINVENT && obj->ocarry == mon)
|
||||
obj->where == OBJ_MINVENT && obj->ocarry == mon) {
|
||||
thrownobj = (struct obj*)0;
|
||||
return; /* alert shk caught it */
|
||||
}
|
||||
(void) snuff_candle(obj);
|
||||
notonhead = (bhitpos.x != mon->mx || bhitpos.y != mon->my);
|
||||
obj_gone = thitmonst(mon, obj);
|
||||
@@ -1026,10 +1034,13 @@ boolean twoweap; /* used to restore twoweapon mode if wielded weapon returns */
|
||||
losehp(dmg, xname(obj),
|
||||
obj_is_pname(obj) ? KILLED_BY : KILLED_BY_AN);
|
||||
}
|
||||
if (ship_object(obj, u.ux, u.uy, FALSE))
|
||||
if (ship_object(obj, u.ux, u.uy, FALSE)) {
|
||||
thrownobj = (struct obj*)0;
|
||||
return;
|
||||
}
|
||||
dropy(obj);
|
||||
}
|
||||
thrownobj = (struct obj*)0;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1052,11 +1063,15 @@ boolean twoweap; /* used to restore twoweapon mode if wielded weapon returns */
|
||||
if(*u.ushops)
|
||||
check_shop_obj(obj, bhitpos.x, bhitpos.y, FALSE);
|
||||
(void) mpickobj(mon, obj); /* may merge and free obj */
|
||||
thrownobj = (struct obj*)0;
|
||||
return;
|
||||
}
|
||||
(void) snuff_candle(obj);
|
||||
if (!mon && ship_object(obj, bhitpos.x, bhitpos.y, FALSE))
|
||||
if (!mon && ship_object(obj, bhitpos.x, bhitpos.y, FALSE)) {
|
||||
thrownobj = (struct obj*)0;
|
||||
return;
|
||||
}
|
||||
thrownobj = (struct obj*)0;
|
||||
place_object(obj, bhitpos.x, bhitpos.y);
|
||||
if(*u.ushops && obj != uball)
|
||||
check_shop_obj(obj, bhitpos.x, bhitpos.y, FALSE);
|
||||
|
||||
@@ -16,6 +16,8 @@ STATIC_DCL void FDECL(check_contained, (struct obj *,const char *));
|
||||
#endif
|
||||
#endif /* OVL1 */
|
||||
|
||||
extern struct obj *thrownobj; /* defined in dothrow.c */
|
||||
|
||||
/*#define DEBUG_EFFECTS*/ /* show some messages for debugging */
|
||||
|
||||
struct icp {
|
||||
@@ -1483,6 +1485,8 @@ dealloc_obj(obj)
|
||||
if (obj_sheds_light(obj))
|
||||
del_light_source(LS_OBJECT, (genericptr_t) obj);
|
||||
|
||||
if (obj == thrownobj) thrownobj = (struct obj*)0;
|
||||
|
||||
free((genericptr_t) obj);
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ STATIC_DCL void FDECL(kops_gone, (BOOLEAN_P));
|
||||
#define IS_SHOP(x) (rooms[x].rtype >= SHOPBASE)
|
||||
|
||||
extern const struct shclass shtypes[]; /* defined in shknam.c */
|
||||
extern struct obj *thrownobj; /* defined in dothrow.c */
|
||||
|
||||
STATIC_VAR NEARDATA long int followmsg; /* last time of follow message */
|
||||
|
||||
@@ -285,6 +286,7 @@ register struct monst *shkp;
|
||||
clear_unpaid(invent);
|
||||
clear_unpaid(fobj);
|
||||
clear_unpaid(level.buriedobjlist);
|
||||
if (thrownobj) thrownobj->unpaid = 0;
|
||||
for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
|
||||
clear_unpaid(mtmp->minvent);
|
||||
for(mtmp = migrating_mons; mtmp; mtmp = mtmp->nmon)
|
||||
|
||||
Reference in New Issue
Block a user