From 71754910db3be6effface4de88c35a056fe70c2c Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Mon, 13 Apr 2020 21:49:16 +0300 Subject: [PATCH] Scatter bag of holding contents instead of deleting them Losing all of your items in one go is really frustrating. If you blow up your bag of holding, make the contents scatter around instead of outright deleting them. This will destroy fragile objects. --- doc/fixes37.0 | 1 + src/pickup.c | 47 +++++++++++++++++++++++++++++++++++++---------- 2 files changed, 38 insertions(+), 10 deletions(-) diff --git a/doc/fixes37.0 b/doc/fixes37.0 index 355c3708c..7b4b8e691 100644 --- a/doc/fixes37.0 +++ b/doc/fixes37.0 @@ -128,6 +128,7 @@ revival via undead turning of corpse carried by hero said "your corpse comes alive" even when revived monster was undead prevent searching or waiting next to a hostile monster - override with 'm' allow random mimics to show up mimicing more furniture than just stairs +scatter exploding bag of holding contents instead of outright deleting them Fixes to 3.7.0-x Problems that Were Exposed Via git Repository diff --git a/src/pickup.c b/src/pickup.c index 70162d976..9e398c5fc 100644 --- a/src/pickup.c +++ b/src/pickup.c @@ -32,11 +32,12 @@ static int FDECL(lift_object, (struct obj *, struct obj *, long *, BOOLEAN_P)); static boolean FDECL(mbag_explodes, (struct obj *, int)); static boolean NDECL(is_boh_item_gone); -static long FDECL(boh_loss, (struct obj *container, int)); +static void FDECL(do_boh_explosion, (struct obj *, BOOLEAN_P)); +static long FDECL(boh_loss, (struct obj *, int)); static int FDECL(in_container, (struct obj *)); static int FDECL(out_container, (struct obj *)); static void FDECL(removed_from_icebox, (struct obj *)); -static long FDECL(mbag_item_gone, (int, struct obj *)); +static long FDECL(mbag_item_gone, (int, struct obj *, BOOLEAN_P)); static void FDECL(explain_container_prompt, (BOOLEAN_P)); static int FDECL(traditional_loot, (BOOLEAN_P)); static int FDECL(menu_loot, (int, BOOLEAN_P)); @@ -2219,6 +2220,28 @@ is_boh_item_gone() return (boolean) (!rn2(13)); } +/* Scatter most of Bag of holding contents around. + Some items will be destroyed with the same chance as looting a cursed bag. + */ +static void +do_boh_explosion(boh, on_floor) +struct obj *boh; +boolean on_floor; +{ + struct obj *otmp, *nobj; + + for (otmp = boh->cobj; otmp; otmp = nobj) { + nobj = otmp->nobj; + if (is_boh_item_gone()) { + obj_extract_self(otmp); + mbag_item_gone(!on_floor, otmp, TRUE); + } else { + otmp->ox = u.ux, otmp->oy = u.uy; + (void) scatter(u.ux, u.uy, 4, MAY_HIT | MAY_DESTROY, otmp); + } + } +} + static long boh_loss(container, held) struct obj *container; @@ -2233,7 +2256,7 @@ int held; otmp = curr->nobj; if (is_boh_item_gone()) { obj_extract_self(curr); - loss += mbag_item_gone(held, curr); + loss += mbag_item_gone(held, curr, FALSE); } } return loss; @@ -2365,7 +2388,8 @@ register struct obj *obj; so that useupf() doesn't double bill */ g.current_container->no_charge = save_no_charge.no_charge; } - delete_contents(g.current_container); + do_boh_explosion(g.current_container, floor_container); + if (!floor_container) useup(g.current_container); else if (obj_here(g.current_container, u.ux, u.uy)) @@ -2481,17 +2505,20 @@ struct obj *obj; /* an object inside a cursed bag of holding is being destroyed */ static long -mbag_item_gone(held, item) +mbag_item_gone(held, item, silent) int held; struct obj *item; +boolean silent; { struct monst *shkp; long loss = 0L; - if (item->dknown) - pline("%s %s vanished!", Doname2(item), otense(item, "have")); - else - You("%s %s disappear!", Blind ? "notice" : "see", doname(item)); + if (!silent) { + if (item->dknown) + pline("%s %s vanished!", Doname2(item), otense(item, "have")); + else + You("%s %s disappear!", Blind ? "notice" : "see", doname(item)); + } if (*u.ushops && (shkp = shop_keeper(*u.ushops)) != 0) { if (held ? (boolean) item->unpaid : costly_spot(u.ux, u.uy)) @@ -3348,7 +3375,7 @@ struct obj *box; /* or bag */ if (box->otyp == ICE_BOX) { removed_from_icebox(otmp); /* resume rotting for corpse */ } else if (cursed_mbag && is_boh_item_gone()) { - loss += mbag_item_gone(held, otmp); + loss += mbag_item_gone(held, otmp, FALSE); /* abbreviated drop format is no longer appropriate */ terse = FALSE; continue;