fix issue #875 - contnr-to-contnr tip explosion

Issue reported by k2:  tipping a wand of cancellation, bag of
holding, or bag of tricks from a non-magic container into a bag of
holding causes the bag of holding to explode but it wasn't dealing
out explosion damage nor being logged for livelog/chronicle the way
putting the item directly into a bag of holding is handled.

This fixes the described issues but bones handling leaves a lot to
be desired.

Fixes #875
This commit is contained in:
PatR
2022-09-16 16:14:20 -07:00
parent a4f7bf2101
commit e4ff874e0b
+30 -11
View File
@@ -2314,6 +2314,7 @@ do_boh_explosion(struct obj *boh, boolean on_floor)
{ {
struct obj *otmp, *nobj; struct obj *otmp, *nobj;
boh->in_use = 1; /* in case scatter() leads to bones creation */
for (otmp = boh->cobj; otmp; otmp = nobj) { for (otmp = boh->cobj; otmp; otmp = nobj) {
nobj = otmp->nobj; nobj = otmp->nobj;
if (is_boh_item_gone()) { if (is_boh_item_gone()) {
@@ -2324,6 +2325,7 @@ do_boh_explosion(struct obj *boh, boolean on_floor)
(void) scatter(u.ux, u.uy, 4, MAY_HIT | MAY_DESTROY, otmp); (void) scatter(u.ux, u.uy, 4, MAY_HIT | MAY_DESTROY, otmp);
} }
} }
/* boh is about to be deleted so no need to reset its in_use flag here */
} }
static long static long
@@ -2447,6 +2449,7 @@ in_container(struct obj *obj)
(void) stop_timer(SHRINK_GLOB, obj_to_any(obj)); (void) stop_timer(SHRINK_GLOB, obj_to_any(obj));
} }
} else if (Is_mbag(g.current_container) && mbag_explodes(obj, 0)) { } else if (Is_mbag(g.current_container) && mbag_explodes(obj, 0)) {
livelog_printf(LL_ACHIEVE, "just blew up %s bag of holding", uhis());
/* explicitly mention what item is triggering the explosion */ /* explicitly mention what item is triggering the explosion */
urgent_pline( urgent_pline(
"As you put %s inside, you are blasted by a magical explosion!", "As you put %s inside, you are blasted by a magical explosion!",
@@ -2455,9 +2458,8 @@ in_container(struct obj *obj)
if (was_unpaid) if (was_unpaid)
addtobill(obj, FALSE, FALSE, TRUE); addtobill(obj, FALSE, FALSE, TRUE);
if (obj->otyp == BAG_OF_HOLDING) /* one bag of holding into another */ if (obj->otyp == BAG_OF_HOLDING) /* one bag of holding into another */
do_boh_explosion(obj, (obj->where == OBJ_FLOOR)); do_boh_explosion(obj, (boolean) (obj->where == OBJ_FLOOR));
obfree(obj, (struct obj *) 0); obfree(obj, (struct obj *) 0);
livelog_printf(LL_ACHIEVE, "just blew up %s bag of holding", uhis());
/* if carried, shop goods will be flagged 'unpaid' and obfree() will /* if carried, shop goods will be flagged 'unpaid' and obfree() will
handle bill issues, but if on floor, we need to put them on bill handle bill issues, but if on floor, we need to put them on bill
before deleting them (non-shop items will be flagged 'no_charge') */ before deleting them (non-shop items will be flagged 'no_charge') */
@@ -3434,7 +3436,7 @@ static void
tipcontainer(struct obj *box) /* or bag */ tipcontainer(struct obj *box) /* or bag */
{ {
coordxy ox = u.ux, oy = u.uy; /* #tip only works at hero's location */ coordxy ox = u.ux, oy = u.uy; /* #tip only works at hero's location */
boolean held = FALSE, maybeshopgoods; boolean srcheld = FALSE, dstheld = FALSE, maybeshopgoods;
struct obj *targetbox = (struct obj *) 0; struct obj *targetbox = (struct obj *) 0;
boolean cancelled = FALSE; boolean cancelled = FALSE;
@@ -3479,7 +3481,8 @@ tipcontainer(struct obj *box) /* or bag */
cursed_mbag = (Is_mbag(box) && box->cursed); cursed_mbag = (Is_mbag(box) && box->cursed);
long loss = 0L; long loss = 0L;
held = carried(box) || (targetbox && carried(targetbox)); srcheld = carried(box);
dstheld = (targetbox && carried(targetbox));
if (u.uswallow) if (u.uswallow)
highdrop = altarizing = FALSE; highdrop = altarizing = FALSE;
terse = !(highdrop || altarizing || costly_spot(box->ox, box->oy)); terse = !(highdrop || altarizing || costly_spot(box->ox, box->oy));
@@ -3506,7 +3509,7 @@ tipcontainer(struct obj *box) /* or bag */
if (box->otyp == ICE_BOX) { if (box->otyp == ICE_BOX) {
removed_from_icebox(otmp); /* resume rotting for corpse */ removed_from_icebox(otmp); /* resume rotting for corpse */
} else if (cursed_mbag && is_boh_item_gone()) { } else if (cursed_mbag && is_boh_item_gone()) {
loss += mbag_item_gone(held, otmp, FALSE); loss += mbag_item_gone(srcheld, otmp, FALSE);
/* abbreviated drop format is no longer appropriate */ /* abbreviated drop format is no longer appropriate */
terse = FALSE; terse = FALSE;
continue; continue;
@@ -3518,17 +3521,33 @@ tipcontainer(struct obj *box) /* or bag */
if (targetbox) { if (targetbox) {
if (Is_mbag(targetbox) && mbag_explodes(otmp, 0)) { if (Is_mbag(targetbox) && mbag_explodes(otmp, 0)) {
livelog_printf(LL_ACHIEVE,
"just blew up %s bag of holding via tipping",
uhis());
/* explicitly mention what item is triggering explosion */ /* explicitly mention what item is triggering explosion */
urgent_pline( urgent_pline(
"As %s %s inside, you are blasted by a magical explosion!", "As %s %s inside, you are blasted by a magical explosion!",
doname(otmp), otense(otmp, "tumble")); doname(otmp), otense(otmp, "tumble"));
do_boh_explosion(targetbox, held);
nobj = 0; /* stop tipping; want loop to exit 'normally' */ /* if putting one bag of holding into another, first
if (held) blow up the one going in, then (below) blow up the
one it's going into */
if (otmp->otyp == BAG_OF_HOLDING) /* BoH into another */
do_boh_explosion(otmp, !srcheld);
/* always delete the item which triggered the explosion */
obfree(otmp, (struct obj *) 0); /* where==OBJ_FREE */
/* [assumes targetbox is carried, otherwise shop bill
handling becomes necessary here] */
do_boh_explosion(targetbox, !dstheld);
if (dstheld)
useup(targetbox); useup(targetbox);
else else
useupf(targetbox, targetbox->quan); useupf(targetbox, targetbox->quan);
targetbox = 0; /* it's gone */ targetbox = 0; /* it's gone */
nobj = 0; /* stop tipping; want loop to exit 'normally' */
losehp(d(6, 6), "magical explosion", KILLED_BY_AN);
} else { } else {
(void) add_to_container(targetbox, otmp); (void) add_to_container(targetbox, otmp);
} }
@@ -3558,11 +3577,11 @@ tipcontainer(struct obj *box) /* or bag */
box->owt = weight(box); /* mbag_item_gone() doesn't update this */ box->owt = weight(box); /* mbag_item_gone() doesn't update this */
if (targetbox) if (targetbox)
targetbox->owt = weight(targetbox); targetbox->owt = weight(targetbox);
if (held) if (srcheld || dstheld)
(void) encumber_msg(); (void) encumber_msg();
} }
if (held) if (srcheld || dstheld)
update_inventory(); update_inventory();
} }
@@ -3590,7 +3609,7 @@ count_target_containers(
} }
#endif #endif
/* ask user for a carried container where they want box to be emptied; /* ask user for a carried container into which they want box to be emptied;
cancelled is TRUE if user cancelled the menu pick; hands aren't required cancelled is TRUE if user cancelled the menu pick; hands aren't required
when tipping to the floor but are when tipping into another container */ when tipping to the floor but are when tipping into another container */
static struct obj * static struct obj *