diff --git a/include/extern.h b/include/extern.h index 0adb68192..32b88d989 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1490,7 +1490,7 @@ extern void add_to_buried(struct obj *); extern void dealloc_obj(struct obj *); extern void obj_ice_effects(coordxy, coordxy, boolean); extern long peek_at_iced_corpse_age(struct obj *); -extern int hornoplenty(struct obj *, boolean); +extern int hornoplenty(struct obj *, boolean, struct obj *); extern void obj_sanity_check(void); extern struct obj *obj_nexto(struct obj *); extern struct obj *obj_nexto_xy(struct obj *, coordxy, coordxy, boolean); diff --git a/src/apply.c b/src/apply.c index 0b07f7d56..fc00ac4d8 100644 --- a/src/apply.c +++ b/src/apply.c @@ -4115,7 +4115,7 @@ doapply(void) res = do_play_instrument(obj); break; case HORN_OF_PLENTY: /* not a musical instrument */ - (void) hornoplenty(obj, FALSE); + (void) hornoplenty(obj, FALSE, (struct obj *) 0); break; case LAND_MINE: case BEARTRAP: diff --git a/src/mkobj.c b/src/mkobj.c index 8b59223e9..18ac0fe7e 100644 --- a/src/mkobj.c +++ b/src/mkobj.c @@ -2547,7 +2547,8 @@ dealloc_obj(struct obj *obj) int hornoplenty( struct obj *horn, - boolean tipping) /* caller emptying entire contents; affects shop mesgs */ + boolean tipping, /* caller emptying entire contents; affects shop mesgs */ + struct obj *targetbox) /* if non-Null, container to tip into */ { int objcount = 0; @@ -2597,6 +2598,14 @@ hornoplenty( : "Oops! %s to the floor!", The(aobjnam(obj, "slip")), (char *) 0); nhUse(obj); + } else if (targetbox) { + add_to_container(targetbox, obj); + /* add to container doesn't update the weight */ + targetbox->owt = weight(targetbox); + /* item still in magic horn was weightless; when it's now in + a carried container, hero's encumbrance could change */ + if (carried(targetbox)) + (void) encumber_msg(); } else { /* assumes this is taking place at hero's location */ if (!can_reach_floor(TRUE)) { diff --git a/src/pickup.c b/src/pickup.c index 6acc20e21..e5f7f69b6 100644 --- a/src/pickup.c +++ b/src/pickup.c @@ -42,7 +42,7 @@ static int menu_loot(int, boolean); static int tip_ok(struct obj *); static int count_containers(struct obj *); static struct obj *tipcontainer_gettarget(struct obj *, boolean *); -static int tipcontainer_checks(struct obj *, boolean); +static int tipcontainer_checks(struct obj *, struct obj *, boolean); static char in_or_out_menu(const char *, struct obj *, boolean, boolean, boolean, boolean); static boolean able_to_loot(coordxy, coordxy, boolean); @@ -3463,9 +3463,9 @@ tipcontainer(struct obj *box) /* or bag */ to reduce the chance of exhausting shk's billing capacity. */ maybeshopgoods = !carried(box) && costly_spot(box->ox, box->oy); - if (tipcontainer_checks(box, FALSE) != TIPCHECK_OK) + if (tipcontainer_checks(box, targetbox, FALSE) != TIPCHECK_OK) return; - if (targetbox && tipcontainer_checks(targetbox, TRUE) != TIPCHECK_OK) + if (targetbox && tipcontainer_checks(targetbox, NULL, TRUE) != TIPCHECK_OK) return; { @@ -3588,16 +3588,22 @@ tipcontainer_gettarget(struct obj *box, boolean *cancelled) char buf[BUFSZ]; menu_item *pick_list = (menu_item *) 0; struct obj dummyobj, *otmp; - int n_conts = count_containers(g.invent); + int n_conts; int clr = 0; - /* we're carrying the box, don't count it as possible target */ - if (box->where == OBJ_INVENT) + /* if tipping a known bag of tricks, don't prompt for destination */ + if (box->otyp == BAG_OF_TRICKS && box->dknown + && objects[box->otyp].oc_name_known) + return (struct obj *) 0; + + n_conts = count_containers(g.invent); + /* when we're carrying the box, don't count it as possible target; + note: 'box' might be a horn so not be included in the count */ + if (carried(box) && Is_container(box)) n_conts--; if (n_conts < 1) { - if (cancelled) - *cancelled = FALSE; + *cancelled = FALSE; return (struct obj *) 0; } @@ -3613,15 +3619,22 @@ tipcontainer_gettarget(struct obj *box, boolean *cancelled) add_menu(win, &nul_glyphinfo, &any, 0, 0, ATR_NONE, clr, "", MENU_ITEMFLAGS_NONE); - for (otmp = g.invent; otmp; otmp = otmp->nobj) - if (Is_container(otmp) && otmp != box - /* don't include any container that's known to be locked */ - && (!otmp->olocked || !otmp->lknown)) { + for (otmp = g.invent; otmp; otmp = otmp->nobj) { + if (otmp == box) + continue; + /* bag of tricks passes Is_container() test; don't include it if + it is known to be a bag of tricks */ + if (otmp->otyp == BAG_OF_TRICKS && otmp->dknown + && objects[otmp->otyp].oc_name_known) + continue; + /* include any container unless it's known to be locked */ + if (Is_container(otmp) && !(otmp->olocked && otmp->lknown)) { any = cg.zeroany; any.a_obj = otmp; add_menu(win, &nul_glyphinfo, &any, otmp->invlet, 0, ATR_NONE, clr, doname(otmp), MENU_ITEMFLAGS_NONE); } + } Sprintf(buf, "Where to tip the contents of %s", doname(box)); end_menu(win, buf); @@ -3633,8 +3646,7 @@ tipcontainer_gettarget(struct obj *box, boolean *cancelled) otmp = pick_list[1].item.a_obj; if (pick_list) free((genericptr_t) pick_list); - if (cancelled) - *cancelled = (n == -1); + *cancelled = (boolean) (n == -1); if (otmp && otmp != &dummyobj) return otmp; @@ -3645,7 +3657,10 @@ tipcontainer_gettarget(struct obj *box, boolean *cancelled) Returns one of TIPCHECK_foo values. If allowempty if TRUE, return TIPCHECK_OK instead of TIPCHECK_EMPTY. */ static int -tipcontainer_checks(struct obj *box, boolean allowempty) +tipcontainer_checks( + struct obj *box, /* container player wants to tip */ + struct obj *targetbox, /* destination (used here for horn of plenty) */ + boolean allowempty) /* affects result when box is empty */ { /* caveat: this assumes that cknown, lknown, olocked, and otrapped fields haven't been overloaded to mean something special for the @@ -3657,7 +3672,7 @@ tipcontainer_checks(struct obj *box, boolean allowempty) } if (box->olocked) { - pline("It's locked."); + pline("%s is locked.", upstart(thesimpleoname(box))); return TIPCHECK_LOCKED; } else if (box->otrapped) { @@ -3672,11 +3687,18 @@ tipcontainer_checks(struct obj *box, boolean allowempty) return TIPCHECK_TRAPPED; } else if (box->otyp == BAG_OF_TRICKS || box->otyp == HORN_OF_PLENTY) { - boolean bag = box->otyp == BAG_OF_TRICKS; + int res = TIPCHECK_OK; + boolean bag = (box->otyp == BAG_OF_TRICKS); int old_spe = box->spe, seen = 0; - boolean maybeshopgoods = !carried(box) && costly_spot(box->ox, box->oy); + boolean maybeshopgoods = (!carried(box) + && costly_spot(box->ox, box->oy)); coordxy ox = u.ux, oy = u.uy; + if (targetbox + && ((res = tipcontainer_checks(targetbox, NULL, TRUE)) + != TIPCHECK_OK)) + return res; + if (get_obj_location(box, &ox, &oy, 0)) box->ox = ox, box->oy = oy; @@ -3686,7 +3708,7 @@ tipcontainer_checks(struct obj *box, boolean allowempty) (if the latter occurs, force the former...) */ do { if (!(bag ? bagotricks(box, TRUE, &seen) - : hornoplenty(box, TRUE))) + : hornoplenty(box, TRUE, targetbox))) break; } while (box->spe > 0); @@ -3703,7 +3725,7 @@ tipcontainer_checks(struct obj *box, boolean allowempty) } if (maybeshopgoods && !box->no_charge) subfrombill(box, shop_keeper(*in_rooms(ox, oy, SHOPBASE))); - return TIPCHECK_CANNOT; + return TIPCHECK_CANNOT; /* actually means 'already done' */ } else if (SchroedingersBox(box)) { char yourbuf[BUFSZ];