B01006 - containers hitting the floor
<Someone> noted that if you dropped a box while levitating, nothing would break. This is true for sacks too, which shouldn't be immune either. Throwing didn't break contained objects either, not mentioned in his report. Refactored out the code in kick_object that handled damage for objects contained in normal containers and added calls in hitfloor and throwit. kick_object still only calls it for boxes, but other callers will call it for any object letting it decide if damage is required. BoH objects aren't affected, since traditionally the inside of the BoH is "somewhere else".
This commit is contained in:
@@ -31,6 +31,7 @@ allow all tame monsters that eat to consider food thrown to them
|
||||
the screen display wasn't always up to date after map topology changes
|
||||
jumping over a sokobon pit would result in the player next to, not in, the pit
|
||||
don't let arrow, rock or dart traps provide an infinite number of objects
|
||||
dropping from height or throwing a normal container may damage contents
|
||||
|
||||
|
||||
Platform- and/or Interface-Specific Fixes
|
||||
|
||||
@@ -423,6 +423,7 @@ E void FDECL(wantdoor, (int,int,genericptr_t));
|
||||
/* ### dokick.c ### */
|
||||
|
||||
E boolean FDECL(ghitm, (struct monst *,struct obj *));
|
||||
E void FDECL(container_impact_dmg, (struct obj *));
|
||||
E int NDECL(dokick);
|
||||
E boolean FDECL(ship_object, (struct obj *,XCHAR_P,XCHAR_P,BOOLEAN_P));
|
||||
E void NDECL(obj_delivery);
|
||||
|
||||
108
src/dokick.c
108
src/dokick.c
@@ -330,16 +330,75 @@ register struct obj *gold;
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* 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)
|
||||
struct obj *obj;
|
||||
{
|
||||
struct monst *shkp;
|
||||
struct obj *otmp, *otmp2;
|
||||
long loss = 0L;
|
||||
boolean costly, insider;
|
||||
xchar x = obj->ox, y = obj->oy;
|
||||
|
||||
/* only consider normal containers */
|
||||
if (!Is_container(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);
|
||||
|
||||
for (otmp = obj->cobj; otmp; otmp = otmp2) {
|
||||
const char *result = (char *)0;
|
||||
|
||||
otmp2 = otmp->nobj;
|
||||
if (objects[otmp->otyp].oc_material == GLASS &&
|
||||
otmp->oclass != GEM_CLASS && !obj_resists(otmp, 33, 100)) {
|
||||
result = "shatter";
|
||||
} else if (otmp->otyp == EGG && !rn2(3)) {
|
||||
result = "cracking";
|
||||
}
|
||||
if (result) {
|
||||
if (otmp->otyp == MIRROR) change_luck(-2);
|
||||
|
||||
/* eggs laid by you. penalty is -1 per egg, max 5,
|
||||
* but it's always exactly 1 that breaks */
|
||||
if (otmp->otyp == EGG && otmp->spe && otmp->corpsenm >= LOW_PM)
|
||||
change_luck(-1);
|
||||
You_hear("a muffled %s.", result);
|
||||
if (costly)
|
||||
loss += stolen_value(otmp, x, y,
|
||||
(boolean)shkp->mpeaceful, TRUE);
|
||||
if (otmp->quan > 1L)
|
||||
useup(otmp);
|
||||
else {
|
||||
obj_extract_self(otmp);
|
||||
obfree(otmp, (struct obj *) 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (costly && loss) {
|
||||
if (!insider) {
|
||||
You("caused %ld %s worth of damage!", loss, currency(loss));
|
||||
make_angry_shk(shkp, x, y);
|
||||
} else {
|
||||
You("owe %s %ld %s for objects destroyed.",
|
||||
mon_nam(shkp), loss, currency(loss));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
STATIC_OVL int
|
||||
kick_object(x, y)
|
||||
xchar x, y;
|
||||
{
|
||||
int range;
|
||||
register struct monst *mon, *shkp;
|
||||
register struct obj *otmp;
|
||||
struct trap *trap;
|
||||
char bhitroom;
|
||||
boolean costly, insider, isgold, slide = FALSE;
|
||||
boolean costly, isgold, slide = FALSE;
|
||||
|
||||
/* if a pile, the "top" object gets kicked */
|
||||
kickobj = level.objects[x][y];
|
||||
@@ -405,8 +464,6 @@ xchar x, y;
|
||||
|
||||
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);
|
||||
isgold = (kickobj->oclass == COIN_CLASS);
|
||||
|
||||
if (IS_ROCK(levl[x][y].typ) || closed_door(x, y)) {
|
||||
@@ -442,51 +499,10 @@ xchar x, y;
|
||||
/* a box gets a chance of breaking open here */
|
||||
if(Is_box(kickobj)) {
|
||||
boolean otrp = kickobj->otrapped;
|
||||
struct obj *otmp2;
|
||||
long loss = 0L;
|
||||
|
||||
if(range < 2) pline("THUD!");
|
||||
|
||||
for(otmp = kickobj->cobj; otmp; otmp = otmp2) {
|
||||
const char *result = (char *)0;
|
||||
|
||||
otmp2 = otmp->nobj;
|
||||
if (objects[otmp->otyp].oc_material == GLASS
|
||||
&& otmp->oclass != GEM_CLASS
|
||||
&& !obj_resists(otmp, 33, 100)) {
|
||||
result = "shatter";
|
||||
} else if (otmp->otyp == EGG && !rn2(3)) {
|
||||
result = "cracking";
|
||||
}
|
||||
if (result) {
|
||||
if (otmp->otyp == MIRROR)
|
||||
change_luck(-2);
|
||||
/* eggs laid by you */
|
||||
/* penalty is -1 per egg, max 5, but it's always
|
||||
exactly 1 that breaks */
|
||||
if (otmp->otyp == EGG && otmp->spe && otmp->corpsenm >= LOW_PM)
|
||||
change_luck(-1);
|
||||
You_hear("a muffled %s.",result);
|
||||
if(costly) loss += stolen_value(otmp, x, y,
|
||||
(boolean)shkp->mpeaceful, TRUE);
|
||||
if (otmp->quan > 1L)
|
||||
useup(otmp);
|
||||
else {
|
||||
obj_extract_self(otmp);
|
||||
obfree(otmp, (struct obj *) 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(costly && loss) {
|
||||
if(!insider) {
|
||||
You("caused %ld %s worth of damage!",
|
||||
loss, currency(loss));
|
||||
make_angry_shk(shkp, x, y);
|
||||
} else {
|
||||
You("owe %s %ld %s for objects destroyed.",
|
||||
mon_nam(shkp), loss, currency(loss));
|
||||
}
|
||||
}
|
||||
container_impact_dmg(kickobj);
|
||||
|
||||
if (kickobj->olocked) {
|
||||
if (!rn2(5) || (martial() && !rn2(2))) {
|
||||
|
||||
@@ -340,6 +340,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);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1088,6 +1089,8 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user