unpaid object sanity checking
Handle items in gaps of a wall shared between adjacent shops. Make handling of shop boundaries more explicit: walls, the door, and the "free spot" by the door aren't classified as 'costly' but obj->unpaid and obj->no_charge are valid there. Move unpaid/no_charge checking into its own routine to unclutter objlist_sanity(). Pushing a shop-owned boulder to the free spot or doorway or gap in wall triggers the sanity check for the time being.
This commit is contained in:
@@ -2480,6 +2480,7 @@ extern boolean same_price(struct obj *, struct obj *);
|
|||||||
extern void shopper_financial_report(void);
|
extern void shopper_financial_report(void);
|
||||||
extern int inhishop(struct monst *);
|
extern int inhishop(struct monst *);
|
||||||
extern struct monst *shop_keeper(char);
|
extern struct monst *shop_keeper(char);
|
||||||
|
extern struct monst *find_objowner(struct obj *, coordxy x, coordxy y);
|
||||||
extern boolean tended_shop(struct mkroom *);
|
extern boolean tended_shop(struct mkroom *);
|
||||||
extern boolean onshopbill(struct obj *, struct monst *, boolean);
|
extern boolean onshopbill(struct obj *, struct monst *, boolean);
|
||||||
extern boolean is_unpaid(struct obj *);
|
extern boolean is_unpaid(struct obj *);
|
||||||
@@ -2518,6 +2519,7 @@ extern boolean is_fshk(struct monst *);
|
|||||||
extern void shopdig(int);
|
extern void shopdig(int);
|
||||||
extern void pay_for_damage(const char *, boolean);
|
extern void pay_for_damage(const char *, boolean);
|
||||||
extern boolean costly_spot(coordxy, coordxy);
|
extern boolean costly_spot(coordxy, coordxy);
|
||||||
|
extern boolean costly_adjacent(struct monst *, coordxy, coordxy);
|
||||||
extern struct obj *shop_object(coordxy, coordxy);
|
extern struct obj *shop_object(coordxy, coordxy);
|
||||||
extern void price_quote(struct obj *);
|
extern void price_quote(struct obj *);
|
||||||
extern void shk_chat(struct monst *);
|
extern void shk_chat(struct monst *);
|
||||||
|
|||||||
+62
-48
@@ -13,6 +13,7 @@ static void obj_timer_checks(struct obj *, coordxy, coordxy, int);
|
|||||||
static void container_weight(struct obj *);
|
static void container_weight(struct obj *);
|
||||||
static struct obj *save_mtraits(struct obj *, struct monst *);
|
static struct obj *save_mtraits(struct obj *, struct monst *);
|
||||||
static void objlist_sanity(struct obj *, int, const char *);
|
static void objlist_sanity(struct obj *, int, const char *);
|
||||||
|
static void shop_obj_sanity(struct obj *, const char *);
|
||||||
static void mon_obj_sanity(struct monst *, const char *);
|
static void mon_obj_sanity(struct monst *, const char *);
|
||||||
static void insane_obj_bits(struct obj *, struct monst *);
|
static void insane_obj_bits(struct obj *, struct monst *);
|
||||||
static boolean nomerge_exception(struct obj *);
|
static boolean nomerge_exception(struct obj *);
|
||||||
@@ -2722,10 +2723,7 @@ obj_sanity_check(void)
|
|||||||
static void
|
static void
|
||||||
objlist_sanity(struct obj *objlist, int wheretype, const char *mesg)
|
objlist_sanity(struct obj *objlist, int wheretype, const char *mesg)
|
||||||
{
|
{
|
||||||
struct obj *obj, *otmp;
|
struct obj *obj;
|
||||||
struct monst *shkp;
|
|
||||||
boolean costly;
|
|
||||||
const char *why;
|
|
||||||
|
|
||||||
for (obj = objlist; obj; obj = obj->nobj) {
|
for (obj = objlist; obj; obj = obj->nobj) {
|
||||||
if (obj->where != wheretype)
|
if (obj->where != wheretype)
|
||||||
@@ -2737,50 +2735,9 @@ objlist_sanity(struct obj *objlist, int wheretype, const char *mesg)
|
|||||||
mesg, (struct monst *) 0);
|
mesg, (struct monst *) 0);
|
||||||
check_contained(obj, mesg);
|
check_contained(obj, mesg);
|
||||||
}
|
}
|
||||||
why = (const char *) 0;
|
if (obj->unpaid || obj->no_charge) {
|
||||||
if (obj->no_charge && obj->unpaid) {
|
shop_obj_sanity(obj, mesg);
|
||||||
why = "%s obj both unpaid and no_charge! %s %s: %s";
|
}
|
||||||
} else if (obj->unpaid) {
|
|
||||||
/* unpaid is only applicable for directly carried objects and
|
|
||||||
for objects inside carried containers */
|
|
||||||
otmp = obj;
|
|
||||||
while (otmp->where == OBJ_CONTAINED)
|
|
||||||
otmp = otmp->ocontainer;
|
|
||||||
if (otmp != obj)
|
|
||||||
obj->ox = otmp->ox, obj->oy = otmp->oy;
|
|
||||||
|
|
||||||
if (otmp->where != OBJ_INVENT)
|
|
||||||
why = "%s unpaid obj not carried! %s %s: %s";
|
|
||||||
else if ((costly = costly_spot(obj->ox, obj->oy)) == FALSE)
|
|
||||||
why = "%s unpaid obj not inside shop! %s %s: %s";
|
|
||||||
else if ((shkp = shop_keeper(*in_rooms(obj->ox, obj->oy,
|
|
||||||
SHOPBASE))) == 0)
|
|
||||||
why = "%s unpaid obj inside untended shop! %s %s: %s";
|
|
||||||
else if (!onshopbill(obj, shkp, TRUE))
|
|
||||||
why = "%s unpaid obj not on shop bill! %s %s: %s";
|
|
||||||
} else if (obj->no_charge) {
|
|
||||||
/* no_charge is only applicable for floor objects in shops and
|
|
||||||
for objects inside floor containers in shops */
|
|
||||||
otmp = obj;
|
|
||||||
while (otmp->where == OBJ_CONTAINED)
|
|
||||||
otmp = otmp->ocontainer;
|
|
||||||
if (otmp != obj)
|
|
||||||
(void) get_obj_location(otmp, &obj->ox, &obj->oy, BURIED_TOO);
|
|
||||||
|
|
||||||
if (otmp->where != OBJ_FLOOR)
|
|
||||||
why = "%s no_charge obj not on floor! %s %s: %s";
|
|
||||||
else if ((costly = costly_spot(obj->ox, obj->oy)) == FALSE)
|
|
||||||
why = "%s no_charge obj not inside shop! %s %s: %s";
|
|
||||||
else if ((shkp = shop_keeper(*in_rooms(obj->ox, obj->oy,
|
|
||||||
SHOPBASE))) == 0)
|
|
||||||
why = "%s no_charge obj inside untended shop! %s %s: %s";
|
|
||||||
else if (onshopbill(obj, shkp, TRUE))
|
|
||||||
why = "%s no_charge obj on shop bill! %s %s: %s";
|
|
||||||
if (why)
|
|
||||||
insane_object(obj, why, mesg, (struct monst *) 0);
|
|
||||||
} /* unpaid and/or no_charge */
|
|
||||||
if (why)
|
|
||||||
insane_object(obj, why, mesg, (struct monst *) 0);
|
|
||||||
if (obj->owornmask) {
|
if (obj->owornmask) {
|
||||||
char maskbuf[40];
|
char maskbuf[40];
|
||||||
boolean bc_ok = FALSE;
|
boolean bc_ok = FALSE;
|
||||||
@@ -2819,6 +2776,63 @@ objlist_sanity(struct obj *objlist, int wheretype, const char *mesg)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* check obj->unpaid and obj->no_charge for shop sanity; caller has
|
||||||
|
verified that at least one of them is set */
|
||||||
|
static void
|
||||||
|
shop_obj_sanity(struct obj *obj, const char *mesg)
|
||||||
|
{
|
||||||
|
struct obj *otop;
|
||||||
|
struct monst *shkp;
|
||||||
|
const char *why;
|
||||||
|
boolean costly;
|
||||||
|
coordxy x = 0, y = 0;
|
||||||
|
|
||||||
|
/* if contained, get top-most container; we needs its location */
|
||||||
|
otop = obj;
|
||||||
|
while (otop->where == OBJ_CONTAINED)
|
||||||
|
otop = otop->ocontainer;
|
||||||
|
/* get obj's or its container's location; do not update obj->ox,oy
|
||||||
|
or otop->ox,oy because that would cause sanity checking to
|
||||||
|
produce side-effects that won't occur when not sanity checking;
|
||||||
|
no need for CONTAINED_TOO because we have a top level container */
|
||||||
|
(void) get_obj_location(otop, &x, &y, BURIED_TOO);
|
||||||
|
|
||||||
|
/* these will always be needed for the normal case, so don't bother
|
||||||
|
waiting until we find an insanity to fetch them */
|
||||||
|
shkp = find_objowner(obj, x, y);
|
||||||
|
costly = costly_spot(x, y) || costly_adjacent(shkp, x, y);
|
||||||
|
|
||||||
|
why = (const char *) 0;
|
||||||
|
if (obj->no_charge && obj->unpaid) {
|
||||||
|
why = "%s obj both unpaid and no_charge! %s %s: %s";
|
||||||
|
} else if (obj->unpaid) {
|
||||||
|
/* unpaid is only applicable for directly carried objects and
|
||||||
|
for objects inside carried containers */
|
||||||
|
if (otop->where != OBJ_INVENT)
|
||||||
|
why = "%s unpaid obj not carried! %s %s: %s";
|
||||||
|
else if (!costly)
|
||||||
|
why = "%s unpaid obj not inside tended shop! %s %s: %s";
|
||||||
|
else if (!shkp)
|
||||||
|
why = "%s unpaid obj inside untended shop! %s %s: %s";
|
||||||
|
else if (!onshopbill(obj, shkp, TRUE))
|
||||||
|
why = "%s unpaid obj not on shop bill! %s %s: %s";
|
||||||
|
} else if (obj->no_charge) {
|
||||||
|
/* no_charge is only applicable for floor objects in shops
|
||||||
|
and for objects inside floor containers in shops */
|
||||||
|
if (otop->where != OBJ_FLOOR)
|
||||||
|
why = "%s no_charge obj not on floor! %s %s: %s";
|
||||||
|
else if (!costly)
|
||||||
|
why = "%s no_charge obj not inside tended shop! %s %s: %s";
|
||||||
|
else if (!shkp)
|
||||||
|
why = "%s no_charge obj inside untended shop! %s %s: %s";
|
||||||
|
else if (onshopbill(obj, shkp, TRUE))
|
||||||
|
why = "%s no_charge obj on shop bill! %s %s: %s";
|
||||||
|
}
|
||||||
|
if (why)
|
||||||
|
insane_object(obj, why, mesg, (struct monst *) 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* sanity check for objects carried by all monsters in specified list */
|
/* sanity check for objects carried by all monsters in specified list */
|
||||||
static void
|
static void
|
||||||
mon_obj_sanity(struct monst *monlist, const char *mesg)
|
mon_obj_sanity(struct monst *monlist, const char *mesg)
|
||||||
|
|||||||
@@ -862,6 +862,32 @@ shop_keeper(char rmno)
|
|||||||
return shkp;
|
return shkp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* find the shopkeeper who owns 'obj'; needed to handle shared shop walls */
|
||||||
|
struct monst *
|
||||||
|
find_objowner(
|
||||||
|
struct obj *obj,
|
||||||
|
coordxy x, coordxy y) /* caller passes obj's location since obj->ox,oy
|
||||||
|
* might be stale; don't update coordinates here
|
||||||
|
* because if we're called duing sanity checking
|
||||||
|
* they shouldn't be modified */
|
||||||
|
{
|
||||||
|
struct monst *shkp, *deflt_shkp = 0;
|
||||||
|
char *roomindx, *where = in_rooms(x, y, SHOPBASE);
|
||||||
|
|
||||||
|
/* conceptually object could be inside up to four rooms simultaneously;
|
||||||
|
in practice it will usually be one room but can sometimes be two;
|
||||||
|
check shk and bill for each room rather than just the first;
|
||||||
|
fallback to the first shk if obj isn't on the relevant bill(s) */
|
||||||
|
for (roomindx = where; *roomindx; ++roomindx)
|
||||||
|
if ((shkp = shop_keeper(*roomindx)) != 0) {
|
||||||
|
if (onshopbill(obj, shkp, TRUE))
|
||||||
|
return shkp;
|
||||||
|
if (!deflt_shkp)
|
||||||
|
deflt_shkp = shkp;
|
||||||
|
}
|
||||||
|
return deflt_shkp;
|
||||||
|
}
|
||||||
|
|
||||||
boolean
|
boolean
|
||||||
tended_shop(struct mkroom *sroom)
|
tended_shop(struct mkroom *sroom)
|
||||||
{
|
{
|
||||||
@@ -4384,7 +4410,7 @@ pay_for_damage(const char* dmgstr, boolean cant_mollify)
|
|||||||
|
|
||||||
/* called in dokick.c when we kick an object that might be in a store */
|
/* called in dokick.c when we kick an object that might be in a store */
|
||||||
boolean
|
boolean
|
||||||
costly_spot(register coordxy x, register coordxy y)
|
costly_spot(coordxy x, coordxy y)
|
||||||
{
|
{
|
||||||
struct monst *shkp;
|
struct monst *shkp;
|
||||||
struct eshk *eshkp;
|
struct eshk *eshkp;
|
||||||
@@ -4399,6 +4425,24 @@ costly_spot(register coordxy x, register coordxy y)
|
|||||||
&& !(x == eshkp->shk.x && y == eshkp->shk.y));
|
&& !(x == eshkp->shk.x && y == eshkp->shk.y));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* called by sanity checking when an unpaid or no_charge item is not at a
|
||||||
|
costly_spot; it might still be within the boundary of the shop; if so,
|
||||||
|
those flags are still valid */
|
||||||
|
boolean
|
||||||
|
costly_adjacent(
|
||||||
|
struct monst *shkp,
|
||||||
|
coordxy x, coordxy y)
|
||||||
|
{
|
||||||
|
struct eshk *eshkp;
|
||||||
|
|
||||||
|
if (!shkp || !inhishop(shkp) || !isok(x, y))
|
||||||
|
return FALSE;
|
||||||
|
eshkp = ESHK(shkp);
|
||||||
|
/* adjacent if <x,y> is a shop wall spot, including door;
|
||||||
|
also treat "free spot" one step inside the door as adjacent */
|
||||||
|
return (levl[x][y].edge || (x == eshkp->shk.x && y == eshkp->shk.y));
|
||||||
|
}
|
||||||
|
|
||||||
/* called by dotalk(sounds.c) when #chatting; returns obj if location
|
/* called by dotalk(sounds.c) when #chatting; returns obj if location
|
||||||
contains shop goods and shopkeeper is willing & able to speak */
|
contains shop goods and shopkeeper is willing & able to speak */
|
||||||
struct obj *
|
struct obj *
|
||||||
|
|||||||
Reference in New Issue
Block a user