diff --git a/include/extern.h b/include/extern.h index 0e7eb4420..e2b37fa18 100644 --- a/include/extern.h +++ b/include/extern.h @@ -349,6 +349,7 @@ E void FDECL(doaltarobj, (struct obj *)); E boolean FDECL(canletgo, (struct obj *,const char *)); E void FDECL(dropx, (struct obj *)); E void FDECL(dropy, (struct obj *)); +E void FDECL(dropz, (struct obj *,BOOLEAN_P)); E void FDECL(obj_no_longer_held, (struct obj *)); E int NDECL(doddrop); E int NDECL(dodown); @@ -486,7 +487,7 @@ E void FDECL(finish_meating,(struct monst *)); /* ### dokick.c ### */ E boolean FDECL(ghitm, (struct monst *,struct obj *)); -E void FDECL(container_impact_dmg, (struct obj *)); +E void FDECL(container_impact_dmg, (struct obj *,XCHAR_P,XCHAR_P)); E int NDECL(dokick); E boolean FDECL(ship_object, (struct obj *,XCHAR_P,XCHAR_P,BOOLEAN_P)); E void FDECL(obj_delivery, (BOOLEAN_P)); diff --git a/src/do.c b/src/do.c index 7818ec579..643a0de1d 100644 --- a/src/do.c +++ b/src/do.c @@ -511,8 +511,9 @@ register struct obj *obj; return(1); } -/* Called in several places - may produce output */ -/* eg ship_object() and dropy() -> sellobj() both produce output */ +/* dropx - take dropped item out of inventory; + called in several places - may produce output + (eg ship_object() and dropy() -> sellobj() both produce output) */ void dropx(obj) register struct obj *obj; @@ -532,9 +533,19 @@ register struct obj *obj; dropy(obj); } +/* dropy - put dropped object at its destination; called from lots of places */ void dropy(obj) -register struct obj *obj; +struct obj *obj; +{ + dropz(obj, FALSE); +} + +/* dropz - really put dropped object at its destination... */ +void +dropz(obj, with_impact) +struct obj *obj; +boolean with_impact; { if (obj == uwep) setuwep((struct obj *)0); if (obj == uquiver) setuqwep((struct obj *)0); @@ -580,6 +591,8 @@ register struct obj *obj; } } else { place_object(obj, u.ux, u.uy); + if (with_impact) + container_impact_dmg(obj, u.ux, u.uy); if (obj == uball) drop_ball(u.ux,u.uy); else if (level.flags.has_shop) diff --git a/src/dokick.c b/src/dokick.c index a8b82b8db..3dddd8b40 100644 --- a/src/dokick.c +++ b/src/dokick.c @@ -373,22 +373,24 @@ register struct obj *gold; /* container is kicked, dropped, thrown or otherwise impacted by player. * Assumes container is on floor. Checks contents for possible damage. */ void -container_impact_dmg(obj) +container_impact_dmg(obj, x, y) struct obj *obj; +xchar x, y; /* coordinates where object was before the impact, not after */ { struct monst *shkp; struct obj *otmp, *otmp2; long loss = 0L; - boolean costly, insider; - xchar x = obj->ox, y = obj->oy; + boolean costly, insider, frominv; /* only consider normal containers */ - if (!Is_container(obj) || Is_mbag(obj)) return; + if (!Is_container(obj) || !Has_contents(obj) || Is_mbag(obj)) return; costly = ((shkp = shop_keeper(*in_rooms(x, y, SHOPBASE))) && costly_spot(x, y)); insider = (*u.ushops && inside_shop(u.ux, u.uy) && *in_rooms(x, y, SHOPBASE) == *u.ushops); + /* if dropped or thrown, shop ownership flags are set on this obj */ + frominv = (obj != kickedobj); for (otmp = obj->cobj; otmp; otmp = otmp2) { const char *result = (char *)0; @@ -408,15 +410,19 @@ struct obj *obj; if (otmp->otyp == EGG && otmp->spe && otmp->corpsenm >= LOW_PM) change_luck(-1); You_hear("a muffled %s.", result); - if (costly) + if (costly) { + if (frominv && !otmp->unpaid) otmp->no_charge = 1; loss += stolen_value(otmp, x, y, (boolean)shkp->mpeaceful, TRUE); - if (otmp->quan > 1L) + } + if (otmp->quan > 1L) { useup(otmp); - else { + } else { obj_extract_self(otmp); obfree(otmp, (struct obj *) 0); } + /* contents of this container are no longer known */ + obj->cknown = 0; } } if (costly && loss) { @@ -559,7 +565,7 @@ xchar x, y; boolean otrp = kickedobj->otrapped; if (range < 2) pline("THUD!"); - container_impact_dmg(kickedobj); + container_impact_dmg(kickedobj, x, y); if (kickedobj->olocked) { if (!rn2(5) || (martial() && !rn2(2))) { You("break open the lock!"); diff --git a/src/dothrow.c b/src/dothrow.c index 93cc7a49c..f1461df6e 100644 --- a/src/dothrow.c +++ b/src/dothrow.c @@ -423,8 +423,7 @@ register struct obj *obj; if (hero_breaks(obj, u.ux, u.uy, TRUE)) return; if (ship_object(obj, u.ux, u.uy, FALSE)) return; - dropy(obj); - if (!u.uswallow) container_impact_dmg(obj); + dropz(obj, TRUE); } /* @@ -1194,6 +1193,14 @@ boolean twoweap; /* used to restore twoweapon mode if wielded weapon returns */ } thrownobj = (struct obj*)0; place_object(obj, bhitpos.x, bhitpos.y); + /* container contents might break; + do so before turning ownership of thrownobj over to shk + (container_impact_dmg handles item already owned by shop) */ + if (!IS_SOFT(levl[bhitpos.x][bhitpos.y].typ)) + /* is spot where you initiated throw, not bhitpos */ + container_impact_dmg(obj, u.ux, u.uy); + /* charge for items thrown out of shop; + shk takes possession for items thrown into one */ if ((*u.ushops || obj->unpaid) && obj != uball) check_shop_obj(obj, bhitpos.x, bhitpos.y, FALSE); @@ -1204,8 +1211,6 @@ boolean twoweap; /* used to restore twoweapon mode if wielded weapon returns */ newsym(bhitpos.x,bhitpos.y); if (obj_sheds_light(obj)) vision_full_recalc = 1; - if (!IS_SOFT(levl[bhitpos.x][bhitpos.y].typ)) - container_impact_dmg(obj); } }