diff --git a/include/extern.h b/include/extern.h index 3f5eb9f48..96a043505 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1038,7 +1038,7 @@ E void FDECL(mimic_hit_msg, (struct monst *, SHORT_P)); #ifdef GOLDOBJ E void FDECL(mkmonmoney, (struct monst *, long)); #endif -E int FDECL(bagotricks, (struct obj *,BOOLEAN_P)); +E int FDECL(bagotricks, (struct obj *,BOOLEAN_P,int *)); E boolean FDECL(propagate, (int, BOOLEAN_P,BOOLEAN_P)); E boolean FDECL(usmellmon, (struct permonst *)); diff --git a/src/apply.c b/src/apply.c index 4010540c4..0b4103fd2 100644 --- a/src/apply.c +++ b/src/apply.c @@ -2996,7 +2996,7 @@ doapply() res = use_container(&obj, 1); break; case BAG_OF_TRICKS: - (void) bagotricks(obj, FALSE); + (void) bagotricks(obj, FALSE, (int *)0); break; case CAN_OF_GREASE: use_grease(obj); diff --git a/src/makemon.c b/src/makemon.c index 3536dce42..047463261 100644 --- a/src/makemon.c +++ b/src/makemon.c @@ -1818,9 +1818,10 @@ assign_sym: /* release a monster from a bag of tricks; return number of monsters created */ int -bagotricks(bag, tipping) +bagotricks(bag, tipping, seencount) struct obj *bag; boolean tipping; /* caller emptying entire contents; affects shop handling */ +int *seencount; /* secondary output */ { int moncount = 0; @@ -1832,8 +1833,7 @@ boolean tipping; /* caller emptying entire contents; affects shop handling */ if (bag->dknown && objects[bag->otyp].oc_name_known) bag->cknown = 1; } else { struct monst *mtmp; - boolean sawone = FALSE; - int creatcnt = 1; + int creatcnt = 1, seecount = 0; consume_obj_charge(bag, !tipping); @@ -1842,18 +1842,18 @@ boolean tipping; /* caller emptying entire contents; affects shop handling */ mtmp = makemon((struct permonst *)0, u.ux, u.uy, NO_MM_FLAGS); if (mtmp) { ++moncount; - if (canspotmon(mtmp)) sawone = TRUE; + if (canspotmon(mtmp)) ++seecount; } } while (--creatcnt > 0); - if (sawone) { + if (seecount) { + if (seencount) *seencount += seecount; /* don't set contents-known flag if we just used last charge (such suppression doesn't actually gain us much since player can now deduce that the bag has become empty) */ if (bag->spe > 0) bag->cknown = 1; if (bag->dknown) makeknown(BAG_OF_TRICKS); - } else { - /* #tip while blind can trigger this successive times */ - Norep("Nothing seems to happen."); + } else if (!tipping) { + pline(!moncount ? nothing_happens : "Nothing seems to happen."); } } return moncount; diff --git a/src/mkobj.c b/src/mkobj.c index 5eea5b698..f0985d19b 100644 --- a/src/mkobj.c +++ b/src/mkobj.c @@ -1828,8 +1828,7 @@ boolean tipping; /* caller emptying entire contents; affects shop handling */ obj->owt = weight(obj); /* using a shop's horn of plenty entails a usage fee and also confers ownership of the created item to the shopkeeper */ - if (carried(horn) ? horn->unpaid : - (costly_spot(u.ux, u.uy) && !horn->no_charge)) + if (horn->unpaid) addtobill(obj, FALSE, FALSE, tipping); /* if it ended up on bill, we don't want "(unpaid, N zorkids)" being included in its formatted name during next message */ diff --git a/src/pickup.c b/src/pickup.c index 320efa849..61315c3c6 100644 --- a/src/pickup.c +++ b/src/pickup.c @@ -2529,7 +2529,21 @@ STATIC_OVL void tipcontainer(box) struct obj *box; /* or bag */ { - boolean empty_it = FALSE; + xchar ox = u.ux, oy = u.uy; /* #tip only works at hero's location */ + boolean empty_it = FALSE, + /* Shop handling: can't rely on the container's own unpaid + or no_charge status because contents might differ with it. + A carried container's contents will be flagged as unpaid + or not, as appropriate, and need no special handling here. + Items owned by the hero get sold to the shop without + confirmation as with other uncontrolled drops. A floor + container's contents will be marked no_charge if owned by + hero, otherwise they're owned by the shop. By passing + the contents through shop billing, they end up getting + treated the same as in the carried case. We do so one + item at a time instead of doing whole container at once + to reduce the chance of exhausting shk's billing capacity. */ + maybeshopgoods = !carried(box) && costly_spot(ox, oy); /* caveat: this assumes that cknown, lknown, olocked, and otrapped fields haven't been overloaded to mean something special for the @@ -2547,22 +2561,29 @@ struct obj *box; /* or bag */ } } else if (box->otyp == BAG_OF_TRICKS || box->otyp == HORN_OF_PLENTY) { boolean bag = box->otyp == BAG_OF_TRICKS; - int old_spe = box->spe; + int old_spe = box->spe, seen = 0; + if (maybeshopgoods && !box->no_charge) + addtobill(box, FALSE, FALSE, TRUE); /* apply this bag/horn until empty or monster/object creation fails (if the latter occurs, force the former...) */ do { - if (!(bag ? bagotricks(box, TRUE) : hornoplenty(box, TRUE))) + if (!(bag ? bagotricks(box, TRUE, &seen) : hornoplenty(box, TRUE))) break; } while (box->spe > 0); if (box->spe < old_spe) { + if (bag) pline((seen == 0) ? "Nothing seems to happen." : + (seen == 1) ? "A monster appears." : + "Monsters appear!"); /* check_unpaid wants to see a non-zero charge count */ box->spe = old_spe; check_unpaid_usage(box, TRUE); box->spe = 0; /* empty */ box->cknown = 1; } + if (maybeshopgoods && !box->no_charge) + subfrombill(box, shop_keeper(*in_rooms(ox, oy, SHOPBASE))); } else if (box->spe) { char yourbuf[BUFSZ]; @@ -2584,7 +2605,7 @@ struct obj *box; /* or bag */ struct obj *otmp, *nobj; boolean verbose = FALSE, highdrop = !can_reach_floor(TRUE), - altarizing = IS_ALTAR(levl[u.ux][u.uy].typ), + altarizing = IS_ALTAR(levl[ox][oy].typ), cursed_mbag = (Is_mbag(box) && box->cursed); int held = carried(box); long loss = 0L; @@ -2600,7 +2621,15 @@ struct obj *box; /* or bag */ loss += mbag_item_gone(held, otmp); /* abbreviated drop format is no longer appropriate */ verbose = TRUE; - } else if (highdrop) { + continue; + } + + if (maybeshopgoods) { + addtobill(otmp, FALSE, FALSE, TRUE); + iflags.suppress_price++; /* doname formatting */ + } + + if (highdrop) { /* might break or fall down stairs; handles altars itself */ hitfloor(otmp); } else { @@ -2608,11 +2637,12 @@ struct obj *box; /* or bag */ doaltarobj(otmp); else if (verbose) pline("%s %s to the %s.", Doname2(otmp), - otense(otmp, "drop"), surface(u.ux, u.uy)); + otense(otmp, "drop"), surface(ox, oy)); else pline("%s%c", doname(otmp), nobj ? ',' : '.'); dropy(otmp); } + if (maybeshopgoods) iflags.suppress_price--; /* reset */ } if (loss) /* magic bag lost some shop goods */ You("owe %ld %s for lost merchandise.", loss, currency(loss));