-/* NetHack 3.6 pickup.c $NHDT-Date: 1445556881 2015/10/22 23:34:41 $ $NHDT-Branch: master $:$NHDT-Revision: 1.162 $ */
+/* NetHack 3.6 pickup.c $NHDT-Date: 1576282488 2019/12/14 00:14:48 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.237 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/*-Copyright (c) Robert Patrick Rankin, 2012. */
/* NetHack may be freely redistributed. See license for details. */
/* JNetHack Copyright */
/* (c) Issei Numata, Naoki Hamada, Shigehiro Miyashita, 1994-2000 */
-/* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2016 */
+/* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2020 */
/* JNetHack may be freely redistributed. See license for details. */
/*
- * Contains code for picking objects up, and container use.
+ * Contains code for picking objects up, and container use.
*/
#include "hack.h"
#define CONTAINED_SYM '>' /* from invent.c */
STATIC_DCL void FDECL(simple_look, (struct obj *, BOOLEAN_P));
-STATIC_DCL boolean
-FDECL(query_classes, (char *, boolean *, boolean *, const char *,
- struct obj *, BOOLEAN_P, int *));
+STATIC_DCL boolean FDECL(query_classes, (char *, boolean *, boolean *,
+ const char *, struct obj *,
+ BOOLEAN_P, int *));
STATIC_DCL boolean FDECL(fatal_corpse_mistake, (struct obj *, BOOLEAN_P));
STATIC_DCL void FDECL(check_here, (BOOLEAN_P));
STATIC_DCL boolean FDECL(n_or_more, (struct obj *));
#endif
STATIC_DCL int FDECL(autopick, (struct obj *, int, menu_item **));
STATIC_DCL int FDECL(count_categories, (struct obj *, int));
+STATIC_DCL int FDECL(delta_cwt, (struct obj *, struct obj *));
STATIC_DCL long FDECL(carry_count, (struct obj *, struct obj *, long,
BOOLEAN_P, int *, int *));
-STATIC_DCL int FDECL(lift_object,
- (struct obj *, struct obj *, long *, BOOLEAN_P));
+STATIC_DCL int FDECL(lift_object, (struct obj *, struct obj *, long *,
+ BOOLEAN_P));
STATIC_DCL boolean FDECL(mbag_explodes, (struct obj *, int));
+STATIC_DCL long FDECL(boh_loss, (struct obj *container, int));
STATIC_PTR int FDECL(in_container, (struct obj *));
STATIC_PTR int FDECL(out_container, (struct obj *));
+STATIC_DCL void FDECL(removed_from_icebox, (struct obj *));
STATIC_DCL long FDECL(mbag_item_gone, (int, struct obj *));
-STATIC_DCL void FDECL(observe_quantum_cat, (struct obj *));
-STATIC_DCL void NDECL(explain_container_prompt);
+STATIC_DCL void FDECL(explain_container_prompt, (BOOLEAN_P));
STATIC_DCL int FDECL(traditional_loot, (BOOLEAN_P));
STATIC_DCL int FDECL(menu_loot, (int, BOOLEAN_P));
STATIC_DCL char FDECL(in_or_out_menu, (const char *, struct obj *, BOOLEAN_P,
- BOOLEAN_P, BOOLEAN_P));
-STATIC_DCL int FDECL(container_at, (int, int, BOOLEAN_P));
+ BOOLEAN_P, BOOLEAN_P, BOOLEAN_P));
STATIC_DCL boolean FDECL(able_to_loot, (int, int, BOOLEAN_P));
STATIC_DCL boolean NDECL(reverse_loot);
STATIC_DCL boolean FDECL(mon_beside, (int, int));
-STATIC_DCL int FDECL(do_loot_cont, (struct obj **));
+STATIC_DCL int FDECL(do_loot_cont, (struct obj **, int, int));
STATIC_DCL void FDECL(tipcontainer, (struct obj *));
/* define for query_objlist() and autopickup() */
#define FOLLOW(curr, flags) \
- (((flags) &BY_NEXTHERE) ? (curr)->nexthere : (curr)->nobj)
+ (((flags) & BY_NEXTHERE) ? (curr)->nexthere : (curr)->nobj)
-/*
- * How much the weight of the given container will change when the given
- * object is removed from it. This calculation must match the one used
- * by weight() in mkobj.c.
- */
-#define DELTA_CWT(cont, obj) \
- ((cont)->cursed ? (obj)->owt * 2 : (cont)->blessed \
- ? ((obj)->owt + 3) / 4 \
- : ((obj)->owt + 1) / 2)
#define GOLD_WT(n) (((n) + 50L) / 100L)
/* if you can figure this out, give yourself a hearty pat on the back... */
#define GOLD_CAPACITY(w, n) (((w) * -100L) - ((n) + 50L) - 1L)
-/* A variable set in use_container(), to be used by the callback routines */
-/* in_container() and out_container() from askchain() and use_container(). */
-/* Also used by menu_loot() and container_gone(). */
+/* A variable set in use_container(), to be used by the callback routines
+ in_container() and out_container() from askchain() and use_container().
+ Also used by menu_loot() and container_gone(). */
static NEARDATA struct obj *current_container;
+static NEARDATA boolean abort_looting;
#define Icebox (current_container->otyp == ICE_BOX)
+static const char
/*JP
-static const char moderateloadmsg[] = "You have a little trouble lifting";
+ moderateloadmsg[] = "You have a little trouble lifting",
*/
-static const char moderateloadmsg[] = "\82ð\8e\9d\82Á\82½\82ç\8f\82µ\82Ó\82ç\82Â\82¢\82½";
+ moderateloadmsg[] = "\82ð\8e\9d\82Á\82½\82ç\8f\82µ\82Ó\82ç\82Â\82¢\82½",
/*JP
-static const char nearloadmsg[] = "You have much trouble lifting";
+ nearloadmsg[] = "You have much trouble lifting",
*/
-static const char nearloadmsg[] = "\82Í\82¸\82Á\82µ\82è\82Æ\8c¨\82É\82Ì\82µ\82©\82©\82Á\82½";
+ nearloadmsg[] = "\82Í\82¸\82Á\82µ\82è\82Æ\8c¨\82É\82Ì\82µ\82©\82©\82Á\82½",
/*JP
-static const char overloadmsg[] = "You have extreme difficulty lifting";
+ overloadmsg[] = "You have extreme difficulty lifting";
*/
-static const char overloadmsg[] = "\82ð\8e\9d\82¿\82 \82°\82é\82Ì\82Í\82Æ\82Ä\82à\82Â\82ç\82¢";
+ overloadmsg[] = "\82ð\8e\9d\82¿\82 \82°\82é\82Ì\82Í\82Æ\82Ä\82à\82Â\82ç\82¢";
/* BUG: this lets you look at cockatrice corpses while blind without
touching them */
pline1(doname(otmp));
} else {
winid tmpwin = create_nhwindow(NHW_MENU);
+
putstr(tmpwin, 0, "");
do {
putstr(tmpwin, 0, doname(otmp));
/*
* Suppose some '?' and '!' objects are present, but '/' objects aren't:
- * "a" picks all items without further prompting;
- * "A" steps through all items, asking one by one;
- * "?" steps through '?' items, asking, and ignores '!' ones;
- * "/" becomes 'A', since no '/' present;
- * "?a" or "a?" picks all '?' without further prompting;
- * "/a" or "a/" becomes 'A' since there aren't any '/'
- * (bug fix: 3.1.0 thru 3.1.3 treated it as "a");
- * "?/a" or "a?/" or "/a?",&c picks all '?' even though no '/'
- * (ie, treated as if it had just been "?a").
+ * "a" picks all items without further prompting;
+ * "A" steps through all items, asking one by one;
+ * "?" steps through '?' items, asking, and ignores '!' ones;
+ * "/" becomes 'A', since no '/' present;
+ * "?a" or "a?" picks all '?' without further prompting;
+ * "/a" or "a/" becomes 'A' since there aren't any '/'
+ * (bug fix: 3.1.0 thru 3.1.3 treated it as "a");
+ * "?/a" or "a?/" or "/a?",&c picks all '?' even though no '/'
+ * (ie, treated as if it had just been "?a").
*/
/*JP CHECK: 3.4.3 \82Å\82Ì\8cÄ\82Ñ\8fo\82µ\8c³
pickup.c:572:("\8fE\82¤") if (!query_classes(oclasses, &selective, &all_of_a_type,
boolean here;
int *menu_on_demand;
{
- char ilets[30], inbuf[BUFSZ]; /* FIXME: hardcoded ilets[] length */
+ char ilets[36], inbuf[BUFSZ] = DUMMY; /* FIXME: hardcoded ilets[] length */
int iletct, oclassct;
- boolean not_everything;
+ boolean not_everything, filtered;
char qbuf[QBUFSZ];
boolean m_seen;
- int itemcount;
+ int itemcount, bcnt, ucnt, ccnt, xcnt, ocnt;
oclasses[oclassct = 0] = '\0';
*one_at_a_time = *everything = m_seen = FALSE;
+ if (menu_on_demand)
+ *menu_on_demand = 0;
iletct = collect_obj_classes(ilets, objs, here,
(boolean FDECL((*), (OBJ_P))) 0, &itemcount);
- if (iletct == 0) {
+ if (iletct == 0)
return FALSE;
- } else if (iletct == 1) {
+
+ if (iletct == 1) {
oclasses[0] = def_char_to_objclass(ilets[0]);
oclasses[1] = '\0';
- if (itemcount && menu_on_demand) {
- ilets[iletct++] = 'm';
- *menu_on_demand = 0;
- ilets[iletct] = '\0';
- }
} else { /* more than one choice available */
- const char *where = 0;
- register char sym, oc_of_sym, *p;
/* additional choices */
ilets[iletct++] = ' ';
ilets[iletct++] = 'a';
ilets[iletct++] = 'A';
ilets[iletct++] = (objs == invent ? 'i' : ':');
- if (menu_on_demand) {
- ilets[iletct++] = 'm';
- *menu_on_demand = 0;
- }
- ilets[iletct] = '\0';
- ask_again:
+ }
+ if (itemcount && menu_on_demand)
+ ilets[iletct++] = 'm';
+ if (count_unpaid(objs))
+ ilets[iletct++] = 'u';
+
+ tally_BUCX(objs, here, &bcnt, &ucnt, &ccnt, &xcnt, &ocnt);
+ if (bcnt)
+ ilets[iletct++] = 'B';
+ if (ucnt)
+ ilets[iletct++] = 'U';
+ if (ccnt)
+ ilets[iletct++] = 'C';
+ if (xcnt)
+ ilets[iletct++] = 'X';
+ ilets[iletct] = '\0';
+
+ if (iletct > 1) {
+ const char *where = 0;
+ char sym, oc_of_sym, *p;
+
+ ask_again:
oclasses[oclassct = 0] = '\0';
*one_at_a_time = *everything = FALSE;
- not_everything = FALSE;
-#if 0 /*JP*/
+ not_everything = filtered = FALSE;
+#if 0 /*JP:T*/
Sprintf(qbuf, "What kinds of thing do you want to %s? [%s]", action,
ilets);
#else
if (*inbuf == '\033')
return FALSE;
- for (p = inbuf; (sym = *p++);) {
- /* new A function (selective all) added by GAN 01/09/87 */
+ for (p = inbuf; (sym = *p++) != 0; ) {
if (sym == ' ')
continue;
else if (sym == 'A')
goto ask_again;
} else if (sym == 'm') {
m_seen = TRUE;
+ } else if (index("uBUCX", sym)) {
+ add_valid_menu_class(sym); /* 'u' or 'B','U','C',or 'X' */
+ filtered = TRUE;
} else {
oc_of_sym = def_char_to_objclass(sym);
if (index(ilets, sym)) {
oclasses[oclassct] = '\0';
} else {
if (!where)
- where =
-/*JP
- !strcmp(action, "pick up")
-*/
- !strcmp(action, "\8fE\82¤")
/*JP
- ? "here"
+ where = !strcmp(action, "pick up") ? "here"
*/
- ? "\82±\82±"
+ where = !strcmp(action, "\8fE\82¤") ? "\82±\82±"
/*JP
: !strcmp(action, "take out") ? "inside" : "";
*/
not_everything = TRUE;
}
}
- }
+ } /* for p:sym in inbuf */
+
if (m_seen && menu_on_demand) {
- *menu_on_demand = (*everything || !oclassct) ? -2 : -3;
+ *menu_on_demand = (((*everything || !oclassct) && !filtered)
+ ? -2 : -3);
return FALSE;
}
if (!oclassct && (!*everything || not_everything)) {
static char valid_menu_classes[MAXOCLASSES + 1 + 4 + 1];
static boolean class_filter, bucx_filter, shop_filter;
+/* check valid_menu_classes[] for an entry; also used by askchain() */
+boolean
+menu_class_present(c)
+int c;
+{
+ return (c && index(valid_menu_classes, c)) ? TRUE : FALSE;
+}
+
void
add_valid_menu_class(c)
int c;
if (c == 0) { /* reset */
vmc_count = 0;
class_filter = bucx_filter = shop_filter = FALSE;
- } else {
+ } else if (!menu_class_present(c)) {
valid_menu_classes[vmc_count++] = (char) c;
/* categorize the new class */
switch (c) {
allow_category(obj)
struct obj *obj;
{
- /* unpaid and BUC checks don't apply to coins */
+ /* For coins, if any class filter is specified, accept if coins
+ * are included regardless of whether either unpaid or BUC-status
+ * is also specified since player has explicitly requested coins.
+ * If no class filtering is specified but bless/curse state is,
+ * coins are either unknown or uncursed based on an option setting.
+ */
if (obj->oclass == COIN_CLASS)
- return index(valid_menu_classes, COIN_CLASS) ? TRUE : FALSE;
+ return class_filter
+ ? (index(valid_menu_classes, COIN_CLASS) ? TRUE : FALSE)
+ : shop_filter /* coins are never unpaid, but check anyway */
+ ? (obj->unpaid ? TRUE : FALSE)
+ : bucx_filter
+ ? (index(valid_menu_classes, iflags.goldX ? 'X' : 'U')
+ ? TRUE : FALSE)
+ : TRUE; /* catchall: no filters specified, so accept */
+
+ if (Role_if(PM_PRIEST) && !obj->bknown)
+ set_bknown(obj, 1);
- if (Role_if(PM_PRIEST))
- obj->bknown = TRUE;
/*
* There are three types of filters possible and the first and
* third can have more than one entry:
* in accepting all scrolls and potions regardless of bless/curse
* state plus all blessed non-scroll, non-potion objects.)
*/
+
/* if class is expected but obj's class is not in the list, reject */
if (class_filter && !index(valid_menu_classes, obj->oclass))
return FALSE;
/* check for particular bless/curse state */
if (bucx_filter) {
/* first categorize this object's bless/curse state */
- char bucx =
- !obj->bknown ? 'X' : obj->blessed ? 'B' : obj->cursed ? 'C' : 'U';
+ char bucx = !obj->bknown ? 'X'
+ : obj->blessed ? 'B' : obj->cursed ? 'C' : 'U';
/* if its category is not in the list, reject */
if (!index(valid_menu_classes, bucx))
struct obj *obj;
{
if (obj != uchain
- && ((index(valid_menu_classes,'u') && obj->unpaid)
+ && ((index(valid_menu_classes, 'u') && obj->unpaid)
|| index(valid_menu_classes, obj->oclass)))
- return TRUE;
- else
- return FALSE;
+ return TRUE;
+ return FALSE;
}
#endif
is_worn_by_type(otmp)
register struct obj *otmp;
{
- return (boolean) (!!(otmp->owornmask & (W_ARMOR | W_ACCESSORY | W_WEAPON))
- && index(valid_menu_classes, otmp->oclass) != 0);
+ return (is_worn(otmp) && allow_category(otmp)) ? TRUE : FALSE;
}
/*
* or a monster's inventory if swallowed.
*
* Arg what:
- * >0 autopickup
- * =0 interactive
- * <0 pickup count of something
+ * >0 autopickup
+ * =0 interactive
+ * <0 pickup count of something
*
* Returns 1 if tried to pick something up, whether
* or not it succeeded.
int i, n, res, count, n_tried = 0, n_picked = 0;
menu_item *pick_list = (menu_item *) 0;
boolean autopickup = what > 0;
- struct obj *objchain;
+ struct obj **objchain_p;
int traverse_how;
/* we might have arrived here while fainted or sleeping, via
count = 0;
if (!u.uswallow) {
- struct trap *ttmp = t_at(u.ux, u.uy);
+ struct trap *ttmp;
+
/* no auto-pick if no-pick move, nothing there, or in a pool */
if (autopickup && (context.nopick || !OBJ_AT(u.ux, u.uy)
|| (is_pool(u.ux, u.uy) && !Underwater)
read_engr_at(u.ux, u.uy);
return 0;
}
-
/* no pickup if levitating & not on air or water level */
if (!can_reach_floor(TRUE)) {
if ((multi && !context.run) || (autopickup && !flags.pickup)
- || (ttmp && uteetering_at_seen_pit(ttmp)))
+ || ((ttmp = t_at(u.ux, u.uy)) != 0
+ && (uteetering_at_seen_pit(ttmp) || uescaped_shaft(ttmp))))
read_engr_at(u.ux, u.uy);
return 0;
}
add_valid_menu_class(0); /* reset */
if (!u.uswallow) {
- objchain = level.objects[u.ux][u.uy];
+ objchain_p = &level.objects[u.ux][u.uy];
traverse_how = BY_NEXTHERE;
} else {
- objchain = u.ustuck->minvent;
+ objchain_p = &u.ustuck->minvent;
traverse_how = 0; /* nobj */
}
/*
* to make things less confusing.
*/
if (autopickup) {
- n = autopick(objchain, traverse_how, &pick_list);
+ n = autopick(*objchain_p, traverse_how, &pick_list);
goto menu_pickup;
}
if (flags.menu_style != MENU_TRADITIONAL || iflags.menu_requested) {
/* use menus exclusively */
+ traverse_how |= AUTOSELECT_SINGLE
+ | (flags.sortpack ? INVORDER_SORT : 0);
if (count) { /* looking for N of something */
- char buf[QBUFSZ];
+ char qbuf[QBUFSZ];
+
/*JP
- Sprintf(buf, "Pick %d of what?", count);
+ Sprintf(qbuf, "Pick %d of what?", count);
*/
- Sprintf(buf, "\89½\82ð%d\8cÂ\8fE\82¢\82Ü\82·\82©\81H", count);
+ Sprintf(qbuf, "\89½\82ð%d\8cÂ\8fE\82¢\82Ü\82·\82©\81H", count);
val_for_n_or_more = count; /* set up callback selector */
- n = query_objlist(buf, objchain, traverse_how | AUTOSELECT_SINGLE
- | INVORDER_SORT,
+ n = query_objlist(qbuf, objchain_p, traverse_how,
&pick_list, PICK_ONE, n_or_more);
/* correct counts, if any given */
for (i = 0; i < n; i++)
pick_list[i].count = count;
} else {
-/*JP
- n = query_objlist("Pick up what?", objchain,
-*/
- n = query_objlist("\89½\82ð\8fE\82¢\82Ü\82·\82©\81H", objchain,
- traverse_how | AUTOSELECT_SINGLE | INVORDER_SORT
- | FEEL_COCKATRICE,
+#if 0 /*JP:T*/
+ n = query_objlist("Pick up what?", objchain_p,
+ (traverse_how | FEEL_COCKATRICE),
+ &pick_list, PICK_ANY, all_but_uchain);
+#else
+ n = query_objlist("\89½\82ð\8fE\82¢\82Ü\82·\82©\81H", objchain_p,
+ (traverse_how | FEEL_COCKATRICE),
&pick_list, PICK_ANY, all_but_uchain);
+#endif
}
- menu_pickup:
+
+ menu_pickup:
n_tried = n;
for (n_picked = i = 0; i < n; i++) {
res = pickup_object(pick_list[i].item.a_obj, pick_list[i].count,
/* old style interface */
int ct = 0;
long lcount;
- boolean all_of_a_type, selective;
- char oclasses[MAXOCLASSES];
+ boolean all_of_a_type, selective, bycat;
+ char oclasses[MAXOCLASSES + 10]; /* +10: room for B,U,C,X plus slop */
struct obj *obj, *obj2;
oclasses[0] = '\0'; /* types to consider (empty for all) */
selective = FALSE; /* ask for each item */
/* check for more than one object */
- for (obj = objchain; obj;
- obj = (traverse_how == BY_NEXTHERE) ? obj->nexthere : obj->nobj)
+ for (obj = *objchain_p; obj; obj = FOLLOW(obj, traverse_how))
ct++;
if (ct == 1 && count) {
/* if only one thing, then pick it */
- obj = objchain;
+ obj = *objchain_p;
lcount = min(obj->quan, (long) count);
n_tried++;
if (pickup_object(obj, lcount, FALSE) > 0)
There("are %s objects here.", (ct <= 10) ? "several" : "many");
*/
pline("\82±\82±\82É\82Í%s\82à\82Ì\82ª\82 \82é\81D", (ct <= 10) ? "\82¢\82\82Â\82©" : "\91ò\8eR\82Ì");
+#if 0 /*JP:T*/
if (!query_classes(oclasses, &selective, &all_of_a_type,
-/*JP
- "pick up", objchain,
-*/
- "\8fE\82¤", objchain,
- traverse_how == BY_NEXTHERE, &via_menu)) {
+ "pick up", *objchain_p,
+ (traverse_how & BY_NEXTHERE) ? TRUE : FALSE,
+ &via_menu)) {
+#else
+ if (!query_classes(oclasses, &selective, &all_of_a_type,
+ "\8fE\82¤", *objchain_p,
+ (traverse_how & BY_NEXTHERE) ? TRUE : FALSE,
+ &via_menu)) {
+#endif
if (!via_menu)
- return 0;
- n = query_objlist(
-/*JP
- "Pick up what?", objchain,
-*/
- "\89½\82ð\8fE\82¢\82Ü\82·\82©\81H", objchain,
- traverse_how | (selective ? 0 : INVORDER_SORT),
- &pick_list, PICK_ANY,
- via_menu == -2 ? allow_all : allow_category);
+ goto pickupdone;
+ if (selective)
+ traverse_how |= INVORDER_SORT;
+#if 0 /*JP:T*/
+ n = query_objlist("Pick up what?", objchain_p, traverse_how,
+ &pick_list, PICK_ANY,
+ (via_menu == -2) ? allow_all
+ : allow_category);
+#else
+ n = query_objlist("\89½\82ð\8fE\82¢\82Ü\82·\82©\81H", objchain_p, traverse_how,
+ &pick_list, PICK_ANY,
+ (via_menu == -2) ? allow_all
+ : allow_category);
+#endif
goto menu_pickup;
}
}
-
- for (obj = objchain; obj; obj = obj2) {
- if (traverse_how == BY_NEXTHERE)
- obj2 = obj->nexthere; /* perhaps obj will be picked up */
- else
- obj2 = obj->nobj;
- lcount = -1L;
-
- if (!selective && oclasses[0] && !index(oclasses, obj->oclass))
+ bycat = (menu_class_present('B') || menu_class_present('U')
+ || menu_class_present('C') || menu_class_present('X'));
+
+ for (obj = *objchain_p; obj; obj = obj2) {
+ obj2 = FOLLOW(obj, traverse_how);
+ if (bycat ? !allow_category(obj)
+ : (!selective && oclasses[0]
+ && !index(oclasses, obj->oclass)))
continue;
+ lcount = -1L;
if (!all_of_a_type) {
char qbuf[BUFSZ];
-#if 0 /*JP*/
+#if 0 /*JP:T*/
(void) safe_qbuf(qbuf, "Pick up ", "?", obj, doname,
ansimpleoname, something);
#else
lcount = (long) yn_number;
if (lcount > obj->quan)
lcount = obj->quan;
- /* fall thru */
+ /*FALLTHRU*/
default: /* 'y' */
break;
}
break;
n_picked += res;
}
- end_query:
- ; /* semicolon needed by brain-damaged compilers */
+ end_query:
+ ; /* statement required after label */
}
if (!u.uswallow) {
/* position may need updating (invisible hero) */
if (n_picked)
- newsym(u.ux, u.uy);
+ newsym_force(u.ux, u.uy);
/* check if there's anything else here after auto-pickup is done */
if (autopickup)
check_here(n_picked > 0);
}
+ pickupdone:
+ add_valid_menu_class(0); /* reset */
return (n_tried > 0);
}
-boolean
-is_autopickup_exception(obj, grab)
+struct autopickup_exception *
+check_autopickup_exceptions(obj)
struct obj *obj;
-boolean grab; /* forced pickup, rather than forced leave behind? */
{
/*
* Does the text description of this match an exception?
*/
- char *objdesc = makesingular(doname(obj));
- struct autopickup_exception *ape =
- (grab) ? iflags.autopickup_exceptions[AP_GRAB]
- : iflags.autopickup_exceptions[AP_LEAVE];
- while (ape) {
- if (regex_match(objdesc, ape->regex))
- return TRUE;
- ape = ape->next;
+ struct autopickup_exception *ape = apelist;
+
+ if (ape) {
+ char *objdesc = makesingular(doname(obj));
+
+ while (ape && !regex_match(objdesc, ape->regex))
+ ape = ape->next;
}
- return FALSE;
+ return ape;
+}
+
+boolean
+autopick_testobj(otmp, calc_costly)
+struct obj *otmp;
+boolean calc_costly;
+{
+ struct autopickup_exception *ape;
+ static boolean costly = FALSE;
+ const char *otypes = flags.pickup_types;
+ boolean pickit;
+
+ /* calculate 'costly' just once for a given autopickup operation */
+ if (calc_costly)
+ costly = (otmp->where == OBJ_FLOOR
+ && costly_spot(otmp->ox, otmp->oy));
+
+ /* first check: reject if an unpaid item in a shop */
+ if (costly && !otmp->no_charge)
+ return FALSE;
+
+ /* check for pickup_types */
+ pickit = (!*otypes || index(otypes, otmp->oclass));
+
+ /* check for autopickup exceptions */
+ ape = check_autopickup_exceptions(otmp);
+ if (ape)
+ pickit = ape->grab;
+
+ /* pickup_thrown overrides pickup_types and exceptions */
+ if (!pickit)
+ pickit = (flags.pickup_thrown && otmp->was_thrown);
+ return pickit;
}
/*
menu_item *pi; /* pick item */
struct obj *curr;
int n;
- boolean pickit;
- const char *otypes = flags.pickup_types;
+ boolean check_costly = TRUE;
/* first count the number of eligible items */
for (n = 0, curr = olist; curr; curr = FOLLOW(curr, follow)) {
- pickit = (!*otypes || index(otypes, curr->oclass));
- /* check for "always pick up */
- if (!pickit)
- pickit = is_autopickup_exception(curr, TRUE);
- /* then for "never pick up */
- if (pickit)
- pickit = !is_autopickup_exception(curr, FALSE);
- /* pickup_thrown overrides pickup_types and exceptions */
- if (!pickit)
- pickit = (flags.pickup_thrown && curr->was_thrown);
- /* finally, do we count this object? */
- if (pickit)
+ if (autopick_testobj(curr, check_costly))
++n;
+ check_costly = FALSE; /* only need to check once per autopickup */
}
if (n) {
- *pick_list = pi = (menu_item *) alloc(sizeof(menu_item) * n);
+ *pick_list = pi = (menu_item *) alloc(sizeof (menu_item) * n);
for (n = 0, curr = olist; curr; curr = FOLLOW(curr, follow)) {
- pickit = (!*otypes || index(otypes, curr->oclass));
- if (!pickit)
- pickit = is_autopickup_exception(curr, TRUE);
- if (pickit)
- pickit = !is_autopickup_exception(curr, FALSE);
- if (!pickit)
- pickit = (flags.pickup_thrown && curr->was_thrown);
- if (pickit) {
+ if (autopick_testobj(curr, FALSE)) {
pi[n].item.a_obj = curr;
pi[n].count = curr->quan;
n++;
* returned counts are guaranteed to be in bounds and non-zero.
*
* Query flags:
- * BY_NEXTHERE - Follow object list via nexthere instead of nobj.
- * AUTOSELECT_SINGLE - Don't ask if only 1 object qualifies - just
- * use it.
- * USE_INVLET - Use object's invlet.
- * INVORDER_SORT - Use hero's pack order.
- * INCLUDE_HERO - Showing engulfer's invent; show hero too.
- * SIGNAL_NOMENU - Return -1 rather than 0 if nothing passes "allow".
- * SIGNAL_ESCAPE - Return -1 rather than 0 if player uses ESC to
- * pick nothing.
+ * BY_NEXTHERE - Follow object list via nexthere instead of nobj.
+ * AUTOSELECT_SINGLE - Don't ask if only 1 object qualifies - just
+ * use it.
+ * USE_INVLET - Use object's invlet.
+ * INVORDER_SORT - Use hero's pack order.
+ * INCLUDE_HERO - Showing engulfer's invent; show hero too.
+ * SIGNAL_NOMENU - Return -1 rather than 0 if nothing passes "allow".
+ * SIGNAL_ESCAPE - Return -1 rather than 0 if player uses ESC to
+ * pick nothing.
+ * FEEL_COCKATRICE - touch corpse.
*/
int
-query_objlist(qstr, olist, qflags, pick_list, how, allow)
+query_objlist(qstr, olist_p, qflags, pick_list, how, allow)
const char *qstr; /* query string */
-struct obj *olist; /* the list to pick from */
+struct obj **olist_p; /* the list to pick from */
int qflags; /* options to control the query */
menu_item **pick_list; /* return list of items picked */
int how; /* type of query */
boolean FDECL((*allow), (OBJ_P)); /* allow function */
{
- int i, n, actualn;
+ int i, n;
winid win;
- struct obj *curr, *last, fake_hero_object;
- struct obj **oarray;
+ struct obj *curr, *last, fake_hero_object, *olist = *olist_p;
char *pack;
anything any;
- boolean printed_type_name, sorted = (qflags & INVORDER_SORT) != 0,
- engulfer = (qflags & INCLUDE_HERO) != 0;
+ boolean printed_type_name, first,
+ sorted = (qflags & INVORDER_SORT) != 0,
+ engulfer = (qflags & INCLUDE_HERO) != 0,
+ engulfer_minvent;
+ unsigned sortflags;
+ Loot *sortedolist, *srtoli;
*pick_list = (menu_item *) 0;
if (!olist && !engulfer)
last = curr;
n++;
}
- actualn = n;
+ /* can't depend upon 'engulfer' because that's used to indicate whether
+ hero should be shown as an extra, fake item */
+ engulfer_minvent = (olist && olist->where == OBJ_MINVENT
+ && u.uswallow && olist->ocarry == u.ustuck);
+ if (engulfer_minvent && n == 1 && olist->owornmask != 0L) {
+ qflags &= ~AUTOSELECT_SINGLE;
+ }
if (engulfer) {
++n;
/* don't autoselect swallowed hero if it's the only choice */
return (qflags & SIGNAL_NOMENU) ? -1 : 0;
if (n == 1 && (qflags & AUTOSELECT_SINGLE)) {
- *pick_list = (menu_item *) alloc(sizeof(menu_item));
+ *pick_list = (menu_item *) alloc(sizeof (menu_item));
(*pick_list)->item.a_obj = last;
(*pick_list)->count = last->quan;
return 1;
}
- oarray = objarr_init(actualn);
- /* Add objects to the array */
- i = 0;
- for (curr = olist; curr; curr = FOLLOW(curr, qflags)) {
- if ((*allow)(curr)) {
- objarr_set(curr, i++, oarray, (flags.sortloot == 'f'
- || (flags.sortloot == 'l'
- && !(qflags & USE_INVLET))));
- }
- }
+ sortflags = (((flags.sortloot == 'f'
+ || (flags.sortloot == 'l' && !(qflags & USE_INVLET)))
+ ? SORTLOOT_LOOT
+ : ((qflags & USE_INVLET) ? SORTLOOT_INVLET : 0))
+ | (flags.sortpack ? SORTLOOT_PACK : 0)
+ | ((qflags & FEEL_COCKATRICE) ? SORTLOOT_PETRIFY : 0));
+ sortedolist = sortloot(&olist, sortflags,
+ (qflags & BY_NEXTHERE) ? TRUE : FALSE, allow);
win = create_nhwindow(NHW_MENU);
start_menu(win);
any = zeroany;
-
/*
* Run through the list and add the objects to the menu. If
* INVORDER_SORT is set, we'll run through the list once for
- * each type so we can group them. The allow function will only
- * be called once per object in the list.
+ * each type so we can group them. The allow function was
+ * called by sortloot() and will be called once per item here.
*/
pack = flags.inv_order;
+ first = TRUE;
do {
printed_type_name = FALSE;
- for (i = 0; i < actualn; i++) {
- curr = oarray[i];
+ for (srtoli = sortedolist; ((curr = srtoli->obj) != 0); ++srtoli) {
+ if (sorted && curr->oclass != *pack)
+ continue;
if ((qflags & FEEL_COCKATRICE) && curr->otyp == CORPSE
&& will_feel_cockatrice(curr, FALSE)) {
destroy_nhwindow(win); /* stop the menu and revert */
(void) look_here(0, FALSE);
+ unsortloot(&sortedolist);
return 0;
}
- if ((!sorted || curr->oclass == *pack) && (*allow)(curr)) {
+ if ((*allow)(curr)) {
/* if sorting, print type name (once only) */
if (sorted && !printed_type_name) {
any = zeroany;
add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
let_to_name(*pack, FALSE,
- (how != PICK_NONE)
- && iflags.menu_head_objsym),
+ ((how != PICK_NONE)
+ && iflags.menu_head_objsym)),
MENU_UNSELECTED);
printed_type_name = TRUE;
}
any.a_obj = curr;
- add_menu(win, obj_to_glyph(curr), &any,
- (qflags & USE_INVLET) ? curr->invlet : 0,
+ add_menu(win, obj_to_glyph(curr, rn2_on_display_rng), &any,
+ (qflags & USE_INVLET) ? curr->invlet
+ : (first && curr->oclass == COIN_CLASS) ? '$' : 0,
def_oc_syms[(int) objects[curr->otyp].oc_class].sym,
ATR_NONE, doname_with_price(curr), MENU_UNSELECTED);
+ first = FALSE;
}
}
pack++;
} while (sorted && *pack);
- free(oarray);
+ unsortloot(&sortedolist);
if (engulfer) {
char buf[BUFSZ];
any = zeroany;
if (sorted && n > 1) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
Sprintf(buf, "%s Creatures",
is_animal(u.ustuck->data) ? "Swallowed" : "Engulfed");
#else
fake_hero_object = zeroobj;
fake_hero_object.quan = 1L; /* not strictly necessary... */
any.a_obj = &fake_hero_object;
- add_menu(win, mon_to_glyph(&youmonst), &any,
+ add_menu(win, mon_to_glyph(&youmonst, rn2_on_display_rng), &any,
/* fake inventory letter, no group accelerator */
CONTAINED_SYM, 0, ATR_NONE, an(self_lookat(buf)),
MENU_UNSELECTED);
/* fix up counts: -1 means no count used => pick all;
if fake_hero_object was picked, discard that choice */
for (i = k = 0, mi = *pick_list; i < n; i++, mi++) {
- if (mi->item.a_obj == &fake_hero_object)
+ curr = mi->item.a_obj;
+ if (curr == &fake_hero_object) {
+ /* this isn't actually possible; fake item representing
+ hero is only included for look here (':'), not pickup,
+ and that's PICK_NONE so we can't get here from there */
+/*JP
+ You_cant("pick yourself up!");
+*/
+ You_cant("\8e©\95ª\8e©\90g\82Í\8fE\82¦\82È\82¢\81I");
continue;
- if (mi->count == -1L || mi->count > mi->item.a_obj->quan)
- mi->count = mi->item.a_obj->quan;
+ }
+ if (engulfer_minvent && curr->owornmask != 0L) {
+/*JP
+ You_cant("pick %s up.", ysimple_name(curr));
+*/
+ You_cant("%s\82ð\8fE\82¦\82È\82¢\81D", ysimple_name(curr));
+ continue;
+ }
+ if (mi->count == -1L || mi->count > curr->quan)
+ mi->count = curr->quan;
if (k < i)
(*pick_list)[k] = *mi;
++k;
*pick_list = 0;
n = 0;
} else if (k < n) {
- /* other stuff plus fake_hero; last slot is now unused */
- (*pick_list)[k].item = zeroany;
- (*pick_list)[k].count = 0L;
- n = k;
+ /* other stuff plus fake_hero; last slot is now unused
+ (could be more than one if player tried to pick items
+ worn by engulfer) */
+ while (n > k) {
+ --n;
+ (*pick_list)[n].item = zeroany;
+ (*pick_list)[n].count = 0L;
+ }
}
} else if (n < 0) {
/* -1 is used for SIGNAL_NOMENU, so callers don't expect it
boolean collected_type_name;
char invlet;
int ccount;
+ boolean FDECL((*ofilter), (OBJ_P)) = (boolean FDECL((*), (OBJ_P))) 0;
boolean do_unpaid = FALSE;
boolean do_blessed = FALSE, do_cursed = FALSE, do_uncursed = FALSE,
do_buc_unknown = FALSE;
return 0;
if ((qflags & UNPAID_TYPES) && count_unpaid(olist))
do_unpaid = TRUE;
- if ((qflags & BUC_BLESSED) && count_buc(olist, BUC_BLESSED)) {
+ if (qflags & WORN_TYPES)
+ ofilter = is_worn;
+ if ((qflags & BUC_BLESSED) && count_buc(olist, BUC_BLESSED, ofilter)) {
do_blessed = TRUE;
num_buc_types++;
}
- if ((qflags & BUC_CURSED) && count_buc(olist, BUC_CURSED)) {
+ if ((qflags & BUC_CURSED) && count_buc(olist, BUC_CURSED, ofilter)) {
do_cursed = TRUE;
num_buc_types++;
}
- if ((qflags & BUC_UNCURSED) && count_buc(olist, BUC_UNCURSED)) {
+ if ((qflags & BUC_UNCURSED) && count_buc(olist, BUC_UNCURSED, ofilter)) {
do_uncursed = TRUE;
num_buc_types++;
}
- if ((qflags & BUC_UNKNOWN) && count_buc(olist, BUC_UNKNOWN)) {
+ if ((qflags & BUC_UNKNOWN) && count_buc(olist, BUC_UNKNOWN, ofilter)) {
do_buc_unknown = TRUE;
num_buc_types++;
}
if (ccount == 1 && !do_unpaid && num_buc_types <= 1
&& !(qflags & BILLED_TYPES)) {
for (curr = olist; curr; curr = FOLLOW(curr, qflags)) {
- if ((qflags & WORN_TYPES)
- && !(curr->owornmask & (W_ARMOR | W_ACCESSORY | W_WEAPON)))
+ if (ofilter && !(*ofilter)(curr))
continue;
break;
}
if (curr) {
*pick_list = (menu_item *) alloc(sizeof(menu_item));
(*pick_list)->item.a_int = curr->oclass;
- return 1;
+ n = 1;
} else {
debugpline0("query_category: no single object match");
+ n = 0;
}
- return 0;
+ /* early return is ok; there's no temp window yet */
+ return n;
}
win = create_nhwindow(NHW_MENU);
start_menu(win);
pack = flags.inv_order;
+
+ if (qflags & CHOOSE_ALL) {
+ invlet = 'A';
+ any = zeroany;
+ any.a_int = 'A';
+ add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE,
+/*JP
+ (qflags & WORN_TYPES) ? "Auto-select every item being worn"
+*/
+ (qflags & WORN_TYPES) ? "\90g\82É\82Â\82¯\82ç\82ê\82é\95¨\91S\82Ä"
+/*JP
+ : "Auto-select every item",
+*/
+ : "\91S\82Ä",
+ MENU_UNSELECTED);
+
+ any = zeroany;
+ add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED);
+ }
+
if ((qflags & ALL_TYPES) && (ccount > 1)) {
invlet = 'a';
any = zeroany;
collected_type_name = FALSE;
for (curr = olist; curr; curr = FOLLOW(curr, qflags)) {
if (curr->oclass == *pack) {
- if ((qflags & WORN_TYPES)
- && !(curr->owornmask & (W_ARMOR | W_ACCESSORY | W_WEAPON)))
+ if (ofilter && !(*ofilter)(curr))
continue;
if (!collected_type_name) {
any = zeroany;
pack++;
if (invlet >= 'u') {
impossible("query_category: too many categories");
- return 0;
+ n = 0;
+ goto query_done;
}
} while (*pack);
+
+ if (do_unpaid || (qflags & BILLED_TYPES) || do_blessed || do_cursed
+ || do_uncursed || do_buc_unknown) {
+ any = zeroany;
+ add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED);
+ }
+
/* unpaid items if there are any */
if (do_unpaid) {
invlet = 'u';
*/
"\96¢\95¥\82Å\8eg\82Á\82Ä\82µ\82Ü\82Á\82½\82à\82Ì", MENU_UNSELECTED);
}
- if (qflags & CHOOSE_ALL) {
- invlet = 'A';
- any = zeroany;
- any.a_int = 'A';
- add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE,
-/*JP
- (qflags & WORN_TYPES) ? "Auto-select every item being worn"
-*/
- (qflags & WORN_TYPES) ? "\90g\82É\82Â\82¯\82ç\82ê\82é\95¨\91S\82Ä"
-/*JP
- : "Auto-select every item",
-*/
- : "\91S\82Ä",
- MENU_UNSELECTED);
- }
- /* items with b/u/c/unknown if there are any */
+
+ /* items with b/u/c/unknown if there are any;
+ this cluster of menu entries is in alphabetical order,
+ reversing the usual sequence of 'U' and 'C' in BUCX */
if (do_blessed) {
invlet = 'B';
any = zeroany;
invlet = 'X';
any = zeroany;
any.a_int = 'X';
+#if 0 /*JP:T*/
+ add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE,
+ "Items of unknown Bless/Curse status", MENU_UNSELECTED);
+#else
add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE,
-/*JP
- "Items of unknown B/C/U status", MENU_UNSELECTED);
-*/
"\8fj\95\9f\81^\8eô\82¢\82ª\82í\82©\82ç\82È\82¢\82à\82Ì", MENU_UNSELECTED);
+#endif
}
end_menu(win, qstr);
n = select_menu(win, how, pick_list);
+ query_done:
destroy_nhwindow(win);
if (n < 0)
n = 0; /* caller's don't expect -1 */
for (curr = olist; curr; curr = FOLLOW(curr, qflags)) {
if (curr->oclass == *pack) {
if ((qflags & WORN_TYPES)
- && !(curr->owornmask & (W_ARMOR | W_ACCESSORY | W_WEAPON)))
+ && !(curr->owornmask & (W_ARMOR | W_ACCESSORY
+ | W_WEAPONS)))
continue;
if (!counted_category) {
ccount++;
return ccount;
}
+/*
+ * How much the weight of the given container will change when the given
+ * object is removed from it. Use before and after weight amounts rather
+ * than trying to match the calculation used by weight() in mkobj.c.
+ */
+STATIC_OVL int
+delta_cwt(container, obj)
+struct obj *container, *obj;
+{
+ struct obj **prev;
+ int owt, nwt;
+
+ if (container->otyp != BAG_OF_HOLDING)
+ return obj->owt;
+
+ owt = nwt = container->owt;
+ /* find the object so that we can remove it */
+ for (prev = &container->cobj; *prev; prev = &(*prev)->nobj)
+ if (*prev == obj)
+ break;
+ if (!*prev) {
+ panic("delta_cwt: obj not inside container?");
+ } else {
+ /* temporarily remove the object and calculate resulting weight */
+ *prev = obj->nobj;
+ nwt = weight(container);
+ *prev = obj; /* put the object back; obj->nobj is still valid */
+ }
+ return owt - nwt;
+}
+
/* could we carry `obj'? if not, could we carry some of it/them? */
STATIC_OVL long
carry_count(obj, container, count, telekinesis, wt_before, wt_after)
}
wt = iw + (int) obj->owt;
if (adjust_wt)
- wt -= (container->otyp == BAG_OF_HOLDING)
- ? (int) DELTA_CWT(container, obj)
- : (int) obj->owt;
+ wt -= delta_cwt(container, obj);
/* This will go with silver+copper & new gold weight */
if (is_gold) /* merged gold might affect cumulative weight */
wt -= (GOLD_WT(umoney) + GOLD_WT(count) - GOLD_WT(umoney + count));
obj->quan = qq;
obj->owt = (unsigned) GOLD_WT(qq);
ow = (int) GOLD_WT(umoney + qq);
- ow -= (container->otyp == BAG_OF_HOLDING)
- ? (int) DELTA_CWT(container, obj)
- : (int) obj->owt;
+ ow -= delta_cwt(container, obj);
if (iw + ow >= 0)
break;
oow = ow;
* object and calling weight.
*
* This works for containers only because containers
- * don't merge. -dean
+ * don't merge. -dean
*/
for (qq = 1L; qq <= count; qq++) {
obj->quan = qq;
obj->owt = (unsigned) (ow = weight(obj));
if (adjust_wt)
- ow -= (container->otyp == BAG_OF_HOLDING)
- ? (int) DELTA_CWT(container, obj)
- : (int) obj->owt;
+ ow -= delta_cwt(container, obj);
if (iw + ow >= 0)
break;
wt = iw + ow;
/* we can carry qq of them */
if (qq > 0) {
if (qq < count)
-#if 0 /*JP*/
+#if 0 /*JP:T*/
You("can only %s %s of the %s %s.", verb,
(qq == 1L) ? "one" : "some", obj_nambuf, where);
#else
}
if (!container)
-#if 0 /*JP*/
+#if 0 /*JP:T*/
Strcpy(where, "here"); /* slightly shorter form */
#else
Strcpy(where, "\82±\82±\82É\82Í"); /* slightly shorter form */
int result, old_wt, new_wt, prev_encumbr, next_encumbr;
if (obj->otyp == BOULDER && Sokoban) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
You("cannot get your %s around this %s.", body_part(HAND),
xname(obj));
#else
return 1; /* lift regardless of current situation */
/* if we reach here, we're out of slots and already have at least
one of these, so treat this one more like a normal item */
-#if 0 /*JP*/
+#if 0 /*JP:T*/
You("are carrying too much stuff to pick up %s %s.",
(obj->quan == 1L) ? "another" : "more", simpleonames(obj));
#else
return -1;
}
- *cnt_p =
- carry_count(obj, container, *cnt_p, telekinesis, &old_wt, &new_wt);
+ *cnt_p = carry_count(obj, container, *cnt_p, telekinesis,
+ &old_wt, &new_wt);
if (*cnt_p < 1L) {
result = -1; /* nothing lifted */
} else if (obj->oclass != COIN_CLASS
/* [exception for gold coins will have to change
if silver/copper ones ever get implemented] */
&& inv_cnt(FALSE) >= 52 && !merge_choice(invent, obj)) {
-/*JP
- Your("knapsack cannot accommodate any more items.");
-*/
- Your("\83i\83b\83v\83U\83b\83N\82Í\82±\82ê\88È\8fã\83A\83C\83e\83\80\82ð\8bl\82ß\8d\9e\82ß\82È\82¢\81D");
+ /* if there is some gold here (and we haven't already skipped it),
+ we aren't limited by the 52 item limit for it, but caller and
+ "grandcaller" aren't prepared to skip stuff and then pickup
+ just gold, so the best we can do here is vary the message */
+#if 0 /*JP*/
+ Your("knapsack cannot accommodate any more items%s.",
+ /* floor follows by nexthere, otherwise container so by nobj */
+ nxtobj(obj, GOLD_PIECE, (boolean) (obj->where == OBJ_FLOOR))
+ ? " (except gold)" : "");
+#else
+ Your("\83i\83b\83v\83U\83b\83N\82Í%s\82±\82ê\88È\8fã\83A\83C\83e\83\80\82ð\8bl\82ß\8d\9e\82ß\82È\82¢\81D",
+ /* floor follows by nexthere, otherwise container so by nobj */
+ nxtobj(obj, GOLD_PIECE, (boolean) (obj->where == OBJ_FLOOR))
+ ? "(\8bà\89Ý\88È\8aO)" : "");
+#endif
result = -1; /* nothing lifted */
} else {
result = 1;
if (obj == uchain) { /* do not pick up attached chain */
return 0;
+ } else if (obj->where == OBJ_MINVENT && obj->owornmask != 0L
+ && u.uswallow && obj->ocarry == u.ustuck) {
+/*JP
+ You_cant("pick %s up.", ysimple_name(obj));
+*/
+ You_cant("%s\82ð\8fE\82¦\82È\82¢\81D", ysimple_name(obj));
+ return 0;
} else if (obj->oartifact && !touch_artifact(obj, &youmonst)) {
return 0;
} else if (obj->otyp == CORPSE) {
else if (!obj->spe && !obj->cursed)
obj->spe = 1;
else {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline_The("scroll%s %s to dust as you %s %s up.", plur(obj->quan),
otense(obj, "turn"), telekinesis ? "raise" : "pick",
(obj->quan == 1L) ? "it" : "them");
pick_obj(otmp)
struct obj *otmp;
{
+ struct obj *result;
+ int ox = otmp->ox, oy = otmp->oy;
+ boolean robshop = (!u.uswallow && otmp != uball && costly_spot(ox, oy));
+
obj_extract_self(otmp);
- if (!u.uswallow && otmp != uball && costly_spot(otmp->ox, otmp->oy)) {
+ newsym(ox, oy);
+
+ /* for shop items, addinv() needs to be after addtobill() (so that
+ object merger can take otmp->unpaid into account) but before
+ remote_robbery() (which calls rob_shop() which calls setpaid()
+ after moving costs of unpaid items to shop debt; setpaid()
+ calls clear_unpaid() for lots of object chains, but 'otmp' isn't
+ on any of those between obj_extract_self() and addinv(); for
+ 3.6.0, 'otmp' remained flagged as an unpaid item in inventory
+ and triggered impossible() every time inventory was examined) */
+ if (robshop) {
char saveushops[5], fakeshop[2];
/* addtobill cares about your location rather than the object's;
usually they'll be the same, but not when using telekinesis
(if ever implemented) or a grappling hook */
Strcpy(saveushops, u.ushops);
- fakeshop[0] = *in_rooms(otmp->ox, otmp->oy, SHOPBASE);
+ fakeshop[0] = *in_rooms(ox, oy, SHOPBASE);
fakeshop[1] = '\0';
Strcpy(u.ushops, fakeshop);
/* sets obj->unpaid if necessary */
addtobill(otmp, TRUE, FALSE, FALSE);
Strcpy(u.ushops, saveushops);
- /* if you're outside the shop, make shk notice */
- if (!index(u.ushops, *fakeshop))
- remote_burglary(otmp->ox, otmp->oy);
+ robshop = otmp->unpaid && !index(u.ushops, *fakeshop);
}
- newsym(otmp->ox, otmp->oy);
- return addinv(otmp); /* might merge it with other objects */
+
+ result = addinv(otmp);
+ /* if you're taking a shop item from outside the shop, make shk notice */
+ if (robshop)
+ remote_burglary(ox, oy);
+
+ return result;
}
/*
You("\89×\95¨\82Ì\92Þ\8d\87\82ð\82Æ\82è\92¼\82µ\82½\82ª\81C\93®\82«\82É\82\82¢\81D");
break;
case 3:
-#if 0 /*JP*/
+#if 0 /*JP:T*/
You("%s under your heavy load. Movement is very hard.",
stagger(youmonst.data, "stagger"));
#else
- You("\89×\95¨\82Ì\8fd\82Ý\82Å\82Ì\82½\82¤\82¿\82Ü\82í\82Á\82½\81D\93®\82\82Ì\82ª\94ñ\8fí\82É\82«\82Â\82¢\81D");
+ You("\89×\95¨\82Ì\8fd\82Ý\82Å\82æ\82ë\82æ\82ë\82µ\82½\81D\93®\82\82Ì\82ª\94ñ\8fí\82É\82«\82Â\82¢\81D");
#endif
break;
default:
-#if 0 /*JP*/
+#if 0 /*JP:T*/
You("%s move a handspan with this load!",
newcap == 4 ? "can barely" : "can't even");
#else
You("\89×\95¨\82Ì\92Þ\8d\87\82ð\82Æ\82è\92¼\82µ\82½\81D\82¾\82ª\82Ü\82¾\93®\82\82Ì\82Í\82«\82Â\82¢\81D");
break;
case 3:
-#if 0 /*JP*/
+#if 0 /*JP:T*/
You("%s under your load. Movement is still very hard.",
stagger(youmonst.data, "stagger"));
#else
- You("\89×\95¨\82Ì\8fd\82Ý\82ª\82¸\82Á\82µ\82è\82Æ\8c¨\82É\82\82é\81D\82Ü\82¾\93®\82\82Ì\82ª\94ñ\8fí\82É\82«\82Â\82¢\81D");
+ You("\89×\95¨\82Ì\8fd\82Ý\82ª\82¸\82Á\82µ\82è\82Æ\82\82é\81D\82Ü\82¾\93®\82\82Ì\82ª\94ñ\8fí\82É\82«\82Â\82¢\81D");
#endif
break;
}
}
/* Is there a container at x,y. Optional: return count of containers at x,y */
-STATIC_OVL int
+int
container_at(x, y, countem)
int x, y;
boolean countem;
} else if ((is_pool(x, y) && (looting || !Underwater)) || is_lava(x, y)) {
/* at present, can't loot in water even when Underwater;
can tip underwater, but not when over--or stuck in--lava */
-#if 0 /*JP*/
+#if 0 /*JP:T*/
You("cannot %s things that are deep in the %s.", verb,
- is_lava(x, y) ? "lava" : "water");
+ hliquid(is_lava(x, y) ? "lava" : "water"));
#else
You("%s\82É\90[\82\82É\92¾\82ñ\82¾\82à\82Ì\82ð%s\82±\82Æ\82Í\82Å\82«\82È\82¢\81D",
- is_lava(u.ux, u.uy) ? "\97n\8aâ" : "\90\85", verb);
+ hliquid(is_lava(u.ux, u.uy) ? "\97n\8aâ" : "\90\85"), verb);
#endif
return FALSE;
} else if (nolimbs(youmonst.data)) {
int x, y;
{
int i, j, nx, ny;
+
for (i = -1; i <= 1; i++)
for (j = -1; j <= 1; j++) {
nx = x + i;
return FALSE;
}
-int
-do_loot_cont(cobjp)
+STATIC_OVL int
+do_loot_cont(cobjp, cindex, ccount)
struct obj **cobjp;
+int cindex, ccount; /* index of this container (1..N), number of them (N) */
{
struct obj *cobj = *cobjp;
+
if (!cobj)
return 0;
if (cobj->olocked) {
-#if 0 /*JP*/
- pline("%s locked.",
- cobj->lknown ? "It is" : "Hmmm, it turns out to be");
+ if (ccount < 2)
+#if 0 /*JP:T*/
+ pline("%s locked.",
+ cobj->lknown ? "It is" : "Hmmm, it turns out to be");
#else
- pline("%s\8c®\82ª\82©\82©\82Á\82Ä\82¢\82é\81D", cobj->lknown ? "" : "\82Þ\81[\82ñ\81C");
+ pline("%s\8c®\82ª\82©\82©\82Á\82Ä\82¢\82é\81D",
+ cobj->lknown ? "" : "\82Þ\81[\82ñ\81C");
#endif
+ else if (cobj->lknown)
+/*JP
+ pline("%s is locked.", The(xname(cobj)));
+*/
+ pline("%s\82Í\8c®\82ª\82©\82©\82Á\82Ä\82¢\82é\81D", xname(cobj));
+ else
+/*JP
+ pline("Hmmm, %s turns out to be locked.", the(xname(cobj)));
+*/
+ pline("\82Þ\81[\82ñ\81C%s\82Í\8c®\82ª\82©\82©\82Á\82Ä\82¢\82é\81D", xname(cobj));
cobj->lknown = 1;
return 0;
}
- cobj->lknown = 1;
+ cobj->lknown = 1; /* floor container, so no need for update_inventory() */
if (cobj->otyp == BAG_OF_TRICKS) {
int tmp;
+
/*JP
- You("carefully open the bag...");
+ You("carefully open %s...", the(xname(cobj)));
*/
- You("\90T\8fd\82É\8a\93\82ð\8aJ\82¯\82½\81D\81D\81D");
+ You("\90T\8fd\82É%s\82ð\8aJ\82¯\82½\81D\81D\81D", xname(cobj));
/*JP
pline("It develops a huge set of teeth and bites you!");
*/
*/
losehp(Maybe_Half_Phys(tmp), "\90H\93÷\8a\93\82É\8a\9a\82Ü\82ê\82Ä", KILLED_BY_AN);
makeknown(BAG_OF_TRICKS);
+ abort_looting = TRUE;
return 1;
}
*/
You("%s%s\82ð\8aJ\82¯\82½\81D\81D\81D", (!cobj->cknown || !cobj->lknown) ? "\90T\8fd\82É" : "",
the(xname(cobj)));
- return use_container(cobjp, 0);
+ return use_container(cobjp, 0, (boolean) (cindex < ccount));
}
/* loot a container on the floor or loot saddle from mon. */
char qbuf[BUFSZ];
int prev_inquiry = 0;
boolean prev_loot = FALSE;
- int num_conts;
+ int num_conts = 0;
+
+ abort_looting = FALSE;
if (check_capacity((char *) 0)) {
/* "Can't do that while carrying so much stuff." */
return 0;
}
if (nohands(youmonst.data)) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
You("have no hands!"); /* not `body_part(HAND)' */
#else
pline("\82 \82È\82½\82É\82Í\8eè\82ª\82È\82¢\81I");
cc.x = u.ux;
cc.y = u.uy;
-lootcont:
+ if (iflags.menu_requested)
+ goto lootmon;
+ lootcont:
if ((num_conts = container_at(cc.x, cc.y, TRUE)) > 0) {
boolean anyfound = FALSE;
if (!able_to_loot(cc.x, cc.y, TRUE))
return 0;
+ if (Blind && !uarmg) {
+ /* if blind and without gloves, attempting to #loot at the
+ location of a cockatrice corpse is fatal before asking
+ whether to manipulate any containers */
+ for (nobj = sobj_at(CORPSE, cc.x, cc.y); nobj;
+ nobj = nxtobj(nobj, CORPSE, TRUE))
+ if (will_feel_cockatrice(nobj, FALSE)) {
+ feel_cockatrice(nobj, FALSE);
+ /* if life-saved (or poly'd into stone golem),
+ terminate attempt to loot */
+ return 1;
+ }
+ }
+
if (num_conts > 1) {
/* use a menu to loot many containers */
int n, i;
winid win;
anything any;
- menu_item *pick_list = NULL;
+ menu_item *pick_list = (menu_item *) 0;
any.a_void = 0;
win = create_nhwindow(NHW_MENU);
destroy_nhwindow(win);
if (n > 0) {
- for (i = 0; i < n; i++) {
- timepassed |= do_loot_cont(&pick_list[i].item.a_obj);
- if (multi < 0 || !pick_list[i].item.a_obj) {
+ for (i = 1; i <= n; i++) {
+ cobj = pick_list[i - 1].item.a_obj;
+ timepassed |= do_loot_cont(&cobj, i, n);
+ if (abort_looting) {
+ /* chest trap or magic bag explosion or <esc> */
free((genericptr_t) pick_list);
- return 1;
+ return timepassed;
}
}
- }
- if (pick_list)
free((genericptr_t) pick_list);
+ }
if (n != 0)
c = 'y';
} else {
nobj = cobj->nexthere;
if (Is_container(cobj)) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
c = ynq(safe_qbuf(qbuf, "There is ", " here, loot it?",
cobj, doname, ansimpleoname,
"a container"));
continue;
anyfound = TRUE;
- timepassed |= do_loot_cont(&cobj);
- /* might have triggered chest trap or magic bag explosion
- */
- if (multi < 0 || !cobj)
- return 1;
+ timepassed |= do_loot_cont(&cobj, 1, 1);
+ if (abort_looting)
+ /* chest trap or magic bag explosion or <esc> */
+ return timepassed;
}
}
if (anyfound)
*/
You("\95æ\8dr\82ç\82µ\82ð\82·\82é\82É\82Í\8c@\82ç\82È\82\82Ä\82Í\81D\81D\81D");
}
+
/*
* 3.3.1 introduced directional looting for some things.
*/
+ lootmon:
if (c != 'y' && mon_beside(u.ux, u.uy)) {
/*JP
if (!get_adjacent_loc("Loot in what direction?",
} else
underfoot = FALSE;
if (u.dz < 0) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
You("%s to loot on the %s.", dont_find_anything,
ceiling(cc.x, cc.y));
#else
if (!underfoot) {
if (container_at(cc.x, cc.y, FALSE)) {
if (mtmp) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
You_cant("loot anything %sthere with %s in the way.",
prev_inquiry ? "else " : "", mon_nam(mtmp));
#else
#endif
return timepassed;
} else {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
You("have to be at a container to loot it.");
#else
You("\82Í\94 \82ð\8aJ\82¯\82é\82½\82ß\82É\82Í\93¯\82¶\88Ê\92u\82É\82¢\82È\82¯\82ê\82Î\82È\82ç\82È\82¢\81D");
#endif
}
} else {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
You("%s %sthere to loot.", dont_find_anything,
(prev_inquiry || prev_loot) ? "else " : "");
#else
}
}
} else if (c != 'y' && c != 'n') {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
You("%s %s to loot.", dont_find_anything,
underfoot ? "here" : "there");
#else
*/
pline("\83I\81[\83P\81[\81C\82±\82±\82É\98d\98G\82ð\92u\82¢\82Ä\82¨\82±\82¤\81D");
} else {
- /* find original coffers chest if present, otherwise use nearest one
- */
+ /* find original coffers chest if present, otherwise use nearest one */
otmp = 0;
for (coffers = fobj; coffers; coffers = coffers->nobj)
if (coffers->otyp == CHEST) {
boxdummy = zeroobj, boxdummy.otyp = SPE_WIZARD_LOCK;
(void) boxlock(coffers, &boxdummy);
}
- } else if (levl[x][y].looted != T_LOOTED &&
- (mon = makemon(courtmon(), x, y, NO_MM_FLAGS)) != 0) {
+ } else if (levl[x][y].looted != T_LOOTED
+ && (mon = makemon(courtmon(), x, y, NO_MM_FLAGS)) != 0) {
freeinv(goldob);
add_to_minv(mon, goldob);
/*JP
struct obj *otmp;
char qbuf[QBUFSZ];
- /* 3.3.1 introduced the ability to remove saddle from a steed */
- /* *passed_info is set to TRUE if a loot query was given. */
- /* *prev_loot is set to TRUE if something was actually acquired in here.
+ /* 3.3.1 introduced the ability to remove saddle from a steed.
+ * *passed_info is set to TRUE if a loot query was given.
+ * *prev_loot is set to TRUE if something was actually acquired in here.
*/
if (mtmp && mtmp != u.usteed && (otmp = which_armor(mtmp, W_SADDLE))) {
long unwornmask;
+
if (passed_info)
*passed_info = 1;
- Sprintf(
-/*JP
- qbuf, "Do you want to remove the saddle from %s?",
-*/
- qbuf, "%s\82©\82ç\88Æ\82ð\82Í\82¸\82µ\82Ü\82·\82©\81H",
- x_monnam(mtmp, ARTICLE_THE, (char *) 0, SUPPRESS_SADDLE, FALSE));
+#if 0 /*JP:T*/
+ Sprintf(qbuf, "Do you want to remove the saddle from %s?",
+ x_monnam(mtmp, ARTICLE_THE, (char *) 0,
+ SUPPRESS_SADDLE, FALSE));
+#else
+ Sprintf(qbuf, "%s\82©\82ç\88Æ\82ð\82Í\82¸\82µ\82Ü\82·\82©\81H",
+ x_monnam(mtmp, ARTICLE_THE, (char *) 0,
+ SUPPRESS_SADDLE, FALSE));
+#endif
if ((c = yn_function(qbuf, ynqchars, 'n')) == 'y') {
if (nolimbs(youmonst.data)) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
You_cant("do that without limbs."); /* not body_part(HAND) */
#else
You_cant("\8eè\82ª\82È\82¢\82Æ\82Å\82«\82È\82¢\81D");
You("can't. The saddle seems to be stuck to %s.",
*/
pline("\88Æ\82Í%s\82É\82\82Á\82Â\82¢\82Ä\82¢\82é\82æ\82¤\82¾\81D",
- x_monnam(mtmp, ARTICLE_THE, (char *) 0, SUPPRESS_SADDLE,
- FALSE));
+ x_monnam(mtmp, ARTICLE_THE, (char *) 0,
+ SUPPRESS_SADDLE, FALSE));
/* the attempt costs you time */
return 1;
}
*/
otmp = hold_another_object(otmp, "%s\82ð\97\8e\82Æ\82µ\82½\81I", doname(otmp),
(const char *) 0);
+ nhUse(otmp);
timepassed = rnd(3);
if (prev_loot)
*prev_loot = TRUE;
return 0;
}
}
- /* 3.4.0 introduced the ability to pick things up from within swallower's
- * stomach */
+ /* 3.4.0 introduced ability to pick things up from swallower's stomach */
if (u.uswallow) {
int count = passed_info ? *passed_info : 0;
+
timepassed = pickup(count);
}
return timepassed;
return FALSE;
}
+STATIC_OVL long
+boh_loss(container, held)
+struct obj *container;
+int held;
+{
+ /* sometimes toss objects if a cursed magic bag */
+ if (Is_mbag(container) && container->cursed && Has_contents(container)) {
+ long loss = 0L;
+ struct obj *curr, *otmp;
+
+ for (curr = container->cobj; curr; curr = otmp) {
+ otmp = curr->nobj;
+ if (!rn2(13)) {
+ obj_extract_self(curr);
+ loss += mbag_item_gone(held, curr);
+ }
+ }
+ return loss;
+ }
+ return 0;
+}
+
/* Returns: -1 to stop, 1 item was inserted, 0 item was not inserted. */
STATIC_PTR int
in_container(obj)
pline("\82»\82ê\82Í\8b»\96¡\82ð\82»\82»\82ç\82ê\82é\83g\83|\83\8d\83W\81[\82Ì\96â\91è\82¾\81D");
return 0;
} else if (obj->owornmask & (W_ARMOR | W_ACCESSORY)) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
Norep("You cannot %s %s you are wearing.",
Icebox ? "refrigerate" : "stash", something);
#else
#endif
return 0;
} else if ((obj->otyp == LOADSTONE) && obj->cursed) {
- obj->bknown = 1;
+ set_bknown(obj, 1);
/*JP
pline_The("stone%s won't leave your person.", plur(obj->quan));
*/
return 0;
}
setuwep((struct obj *) 0);
+ /* This uwep check is obsolete. It dates to 3.0 and earlier when
+ * unwielding Firebrand would be fatal in hell if hero had no other
+ * fire resistance. Life-saving would force it to be re-wielded.
+ */
if (uwep)
return 0; /* unwielded, died, rewielded */
} else if (obj == uswapwep) {
setuswapwep((struct obj *) 0);
- if (uswapwep)
- return 0; /* unwielded, died, rewielded */
} else if (obj == uquiver) {
setuqwep((struct obj *) 0);
- if (uquiver)
- return 0; /* unwielded, died, rewielded */
}
if (fatal_corpse_mistake(obj, FALSE))
(void) snuff_lit(obj);
if (floor_container && costly_spot(u.ux, u.uy)) {
- if (current_container->no_charge && !obj->unpaid) {
- /* don't sell when putting the item into your own container */
- obj->no_charge = 1;
- } else if (obj->oclass != COIN_CLASS) {
- /* sellobj() will take an unpaid item off the shop bill
- * note: coins are handled later */
+ /* defer gold until after put-in message */
+ if (obj->oclass != COIN_CLASS) {
+ /* sellobj() will take an unpaid item off the shop bill */
was_unpaid = obj->unpaid ? TRUE : FALSE;
- sellobj_state(SELL_DELIBERATE);
+ /* don't sell when putting the item into your own container,
+ * but handle billing correctly */
+ sellobj_state(current_container->no_charge
+ ? SELL_DONTSELL : SELL_DELIBERATE);
sellobj(obj, u.ux, u.uy);
sellobj_state(SELL_NORMAL);
}
/* stop any corpse timeouts when frozen */
if (obj->otyp == CORPSE && obj->timed) {
long rot_alarm = stop_timer(ROT_CORPSE, obj_to_any(obj));
+
(void) stop_timer(REVIVE_MON, obj_to_any(obj));
/* mark a non-reviving corpse as such */
if (rot_alarm)
if (was_unpaid)
addtobill(obj, FALSE, FALSE, TRUE);
obfree(obj, (struct obj *) 0);
+ /* 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
+ before deleting them (non-shop items will be flagged 'no_charge') */
+ if (floor_container
+ && costly_spot(current_container->ox, current_container->oy)) {
+ struct obj save_no_charge;
+
+ save_no_charge.no_charge = current_container->no_charge;
+ addtobill(current_container, FALSE, FALSE, FALSE);
+ /* addtobill() clears no charge; we need to set it back
+ so that useupf() doesn't double bill */
+ current_container->no_charge = save_no_charge.no_charge;
+ }
delete_contents(current_container);
if (!floor_container)
useup(current_container);
* update status immediately.
*/
bot();
-
return (current_container ? 1 : -1);
}
+/* askchain() filter used by in_container();
+ * returns True if the container is intact and 'obj' isn't it, False if
+ * container is gone (magic bag explosion) or 'obj' is the container itself;
+ * also used by getobj() when picking a single item to stash
+ */
int
ck_bag(obj)
struct obj *obj;
{
- return current_container && obj != current_container;
+ return (current_container && obj != current_container);
}
/* Returns: -1 to stop, 1 item was removed, 0 item was not removed. */
obj_extract_self(obj);
current_container->owt = weight(current_container);
- if (Icebox && !age_is_relative(obj)) {
- obj->age = monstermoves - obj->age; /* actual age */
- if (obj->otyp == CORPSE)
- start_corpse_timeout(obj);
- }
- /* simulated point of time */
+ if (Icebox)
+ removed_from_icebox(obj);
if (!obj->unpaid && !carried(current_container)
&& costly_spot(current_container->ox, current_container->oy)) {
otmp = addinv(obj);
loadlev = near_capacity();
- prinv(loadlev
+ prinv(loadlev ? ((loadlev < MOD_ENCUMBER)
/*JP
- ? (loadlev < MOD_ENCUMBER ? "You have a little trouble removing"
+ ? "You have a little trouble removing"
*/
- ? (loadlev < MOD_ENCUMBER ? "\82ð\89^\82Ô\82Ì\82Í\8f\81X\8d¢\93ï\82¾\81D"
+ ? "\82ð\89^\82Ô\82Ì\82Í\8f\81X\8d¢\93ï\82¾\81D"
/*JP
- : "You have much trouble removing")
+ : "You have much trouble removing")
*/
- : "\82ð\89^\82Ô\82Ì\82Í\82©\82È\82è\8d¢\93ï\82¾\81D")
- : (char *) 0,
+ : "\82ð\89^\82Ô\82Ì\82Í\82©\82È\82è\8d¢\93ï\82¾\81D")
+ : (char *) 0,
otmp, count);
if (is_gold) {
return 1;
}
+/* taking a corpse out of an ice box needs a couple of adjustments */
+STATIC_OVL void
+removed_from_icebox(obj)
+struct obj *obj;
+{
+ if (!age_is_relative(obj)) {
+ obj->age = monstermoves - obj->age; /* actual age */
+ if (obj->otyp == CORPSE)
+ start_corpse_timeout(obj);
+ }
+}
+
/* an object inside a cursed bag of holding is being destroyed */
STATIC_OVL long
mbag_item_gone(held, item)
*/
pline("%s\82Í\8fÁ\82¦\8b\8e\82Á\82½\81I", Doname2(item));
else
-#if 0 /*JP*/
+#if 0 /*JP:T*/
You("%s %s disappear!", Blind ? "notice" : "see", doname(item));
#else
You("%s\82ª\8c©\82¦\82È\82\82È\82é\82Ì%s\81D", doname(item), Blind ? "\82É\8bC\82Ã\82¢\82½" : "\82ð\8c©\82½");
return loss;
}
-STATIC_OVL void
-observe_quantum_cat(box)
+/* used for #loot/apply, #tip, and final disclosure */
+void
+observe_quantum_cat(box, makecat, givemsg)
struct obj *box;
+boolean makecat, givemsg;
{
/*JP
static NEARDATA const char sc[] = "Schroedinger's Cat";
*/
static NEARDATA const char sc[] = "\83V\83\85\83\8c\83f\83B\83\93\83K\81[\82Ì\94L";
struct obj *deadcat;
- struct monst *livecat;
+ struct monst *livecat = 0;
xchar ox, oy;
+ boolean itsalive = !rn2(2);
- box->spe = 0; /* box->owt will be updated below */
if (get_obj_location(box, &ox, &oy, 0))
box->ox = ox, box->oy = oy; /* in case it's being carried */
/* this isn't really right, since any form of observation
(telepathic or monster/object/food detection) ought to
- force the determination of alive vs dead state; but basing
- it just on opening the box is much simpler to cope with */
- livecat = rn2(2)
- ? makemon(&mons[PM_HOUSECAT], box->ox, box->oy, NO_MINVENT)
- : 0;
- if (livecat) {
- livecat->mpeaceful = 1;
- set_malign(livecat);
- if (!canspotmon(livecat))
-/*JP
- You("think %s brushed your %s.", something, body_part(FOOT));
-*/
- You("%s\82ª\82 \82È\82½\82Ì%s\82ð\82\82·\82®\82Á\82½\81D", something, body_part(FOOT));
- else
-/*JP
- pline("%s inside the box is still alive!", Monnam(livecat));
-*/
- pline("\94 \82Ì\82È\82©\82Ì%s\82Í\82Ü\82¾\90¶\82«\82Ä\82¢\82é\81I", Monnam(livecat));
- (void) christen_monst(livecat, sc);
+ force the determination of alive vs dead state; but basing it
+ just on opening or disclosing the box is much simpler to cope with */
+
+ /* SchroedingersBox already has a cat corpse in it */
+ deadcat = box->cobj;
+ if (itsalive) {
+ if (makecat)
+ livecat = makemon(&mons[PM_HOUSECAT], box->ox, box->oy,
+ NO_MINVENT | MM_ADJACENTOK);
+ if (livecat) {
+ livecat->mpeaceful = 1;
+ set_malign(livecat);
+ if (givemsg) {
+ if (!canspotmon(livecat))
+#if 0 /*JP:T*/
+ You("think %s brushed your %s.", something,
+ body_part(FOOT));
+#else
+ You("%s\82ª\82 \82È\82½\82Ì%s\82ð\82\82·\82®\82Á\82½\82Æ\8ev\82Á\82½\81D", something,
+ body_part(FOOT));
+#endif
+ else
+#if 0 /*JP:T*/
+ pline("%s inside the box is still alive!",
+ Monnam(livecat));
+#else
+ pline("\94 \82Ì\82È\82©\82Ì%s\82Í\82Ü\82¾\90¶\82«\82Ä\82¢\82é\81I",
+ Monnam(livecat));
+#endif
+ }
+ (void) christen_monst(livecat, sc);
+ if (deadcat) {
+ obj_extract_self(deadcat);
+ obfree(deadcat, (struct obj *) 0), deadcat = 0;
+ }
+ box->owt = weight(box);
+ box->spe = 0;
+ }
} else {
- deadcat =
- mk_named_object(CORPSE, &mons[PM_HOUSECAT], box->ox, box->oy, sc);
+ box->spe = 0; /* now an ordinary box (with a cat corpse inside) */
if (deadcat) {
- obj_extract_self(deadcat);
- (void) add_to_container(box, deadcat);
+ /* set_corpsenm() will start the rot timer that was removed
+ when makemon() created SchroedingersBox; start it from
+ now rather than from when this special corpse got created */
+ deadcat->age = monstermoves;
+ set_corpsenm(deadcat, PM_HOUSECAT);
+ deadcat = oname(deadcat, sc);
}
-#if 0 /*JP*/
- pline_The("%s inside the box is dead!",
- Hallucination ? rndmonnam(NULL) : "housecat");
+ if (givemsg)
+#if 0 /*JP:T*/
+ pline_The("%s inside the box is dead!",
+ Hallucination ? rndmonnam((char *) 0) : "housecat");
#else
- pline_The("\94 \82Ì\92\86\82Ì%s\82Í\8e\80\82ñ\82Å\82¢\82é\81I",
- Hallucination ? rndmonnam(NULL) : "\94L");
+ pline_The("\94 \82Ì\92\86\82Ì%s\82Í\8e\80\82ñ\82Å\82¢\82é\81I",
+ Hallucination ? rndmonnam((char *) 0) : "\94L");
#endif
}
- box->owt = weight(box);
+ nhUse(deadcat);
return;
}
}
STATIC_OVL void
-explain_container_prompt()
+explain_container_prompt(more_containers)
+boolean more_containers;
{
static const char *const explaintext[] = {
-#if 0 /*JP*/
- "Container actions:", "", " : -- Look: examine contents",
- " o -- Out: take things out", " i -- In: put things in",
+#if 0 /*JP:T*/
+ "Container actions:",
+ "",
+ " : -- Look: examine contents",
+ " o -- Out: take things out",
+ " i -- In: put things in",
" b -- Both: first take things out, then put things in",
" r -- Reversed: put things in, then take things out",
- " s -- Stash: put one item in", " q -- Quit: do nothing",
- " ? -- Help: display this text.", "", 0
+ " s -- Stash: put one item in", "",
+ " n -- Next: loot next selected container",
+ " q -- Quit: finished",
+ " ? -- Help: display this text.",
+ "", 0
#else
- "\93ü\82ê\95¨\82Ö\82Ì\8ds\93®\81F", "", " : -- Look: \92\86\90g\82ð\92²\82×\82é",
- " o -- Out: \95¨\82ð\8fo\82·", " i -- In: \95¨\82ð\93ü\82ê\82é",
+ "\93ü\82ê\95¨\82Ö\82Ì\8ds\93®\81F",
+ "",
+ " : -- Look: \92\86\90g\82ð\92²\82×\82é",
+ " o -- Out: \95¨\82ð\8fo\82·",
+ " i -- In: \95¨\82ð\93ü\82ê\82é",
" b -- Both: \82Ü\82¸\95¨\82ð\8fo\82µ\81A\82»\82ê\82©\82ç\95¨\82ð\93ü\82ê\82é",
" r -- Reversed: \95¨\82ð\93ü\82ê\81A\82»\82ê\82©\82ç\95¨\82ð\8fo\82·",
- " s -- Stash: \95¨\82ð\88ê\82Â\93ü\82ê\82é", " q -- Quit: \89½\82à\82µ\82È\82¢",
- " ? -- Help: \82±\82ê\82ð\95\\8e¦\82·\82é", "", 0
+ " s -- Stash: \95¨\82ð\88ê\82Â\93ü\82ê\82é",
+ " n -- Next: \8e\9f\82É\91I\82ñ\82¾\93ü\82ê\95¨\82ð\92²\82×\82é",
+ " q -- Quit: \89½\82à\82µ\82È\82¢",
+ " ? -- Help: \82±\82ê\82ð\95\\8e¦\82·\82é",
+ "", 0
#endif
};
const char *const *txtpp;
/* "Do what with <container>? [:oibrsq or ?] (q)" */
if ((win = create_nhwindow(NHW_TEXT)) != WIN_ERR) {
- for (txtpp = explaintext; *txtpp; ++txtpp)
+ for (txtpp = explaintext; *txtpp; ++txtpp) {
+ if (!more_containers && !strncmp(*txtpp, " n ", 3))
+ continue;
putstr(win, 0, *txtpp);
+ }
display_nhwindow(win, FALSE);
destroy_nhwindow(win);
}
u_handsy()
{
if (nohands(youmonst.data)) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
You("have no hands!"); /* not `body_part(HAND)' */
#else
pline("\82 \82È\82½\82É\82Í\8eè\82ª\82È\82¢\81I"); /* not `body_part(HAND)' */
static const char stashable[] = { ALLOW_COUNT, COIN_CLASS, ALL_CLASSES, 0 };
int
-use_container(objp, held)
+use_container(objp, held, more_containers)
struct obj **objp;
int held;
+boolean more_containers; /* True iff #loot multiple and this isn't last one */
{
- struct obj *curr, *otmp, *obj = *objp;
+ struct obj *otmp, *obj = *objp;
boolean quantum_cat, cursed_mbag, loot_out, loot_in, loot_in_first,
stash_one, inokay, outokay, outmaybe;
char c, emptymsg[BUFSZ], qbuf[QBUFSZ], pbuf[QBUFSZ], xbuf[QBUFSZ];
int used = 0;
+ long loss;
+ abort_looting = FALSE;
emptymsg[0] = '\0';
if (!u_handsy())
return 0;
+ if (!obj->lknown) { /* do this in advance */
+ obj->lknown = 1;
+ if (held)
+ update_inventory();
+ }
if (obj->olocked) {
/*JP
pline("%s locked.", Tobjnam(obj, "are"));
You("must put it down to unlock.");
*/
if (held) pline("\89º\82É\92u\82©\82È\82¢\82±\82Æ\82É\82Í\8c®\82ð\82Í\82¸\82¹\82È\82¢\81D");
- obj->lknown = 1;
return 0;
} else if (obj->otrapped) {
if (held)
You("open %s...", the(xname(obj)));
*/
You("%s\82ð\8aJ\82¯\82½\81D\81D\81D", the(xname(obj)));
- obj->lknown = 1;
(void) chest_trap(obj, HAND, FALSE);
/* even if the trap fails, you've used up this turn */
if (multi >= 0) { /* in case we didn't become paralyzed */
multi_reason = "\94 \82ð\8aJ\82¯\82Ä\82¢\82é\8e\9e\82É";
nomovemsg = "";
}
+ abort_looting = TRUE;
return 1;
}
- obj->lknown = 1;
current_container = obj; /* for use by in/out_container */
- /* from here on out, all early returns go through containerdone */
+ /*
+ * From here on out, all early returns go through 'containerdone:'.
+ */
/* check for Schroedinger's Cat */
quantum_cat = SchroedingersBox(current_container);
if (quantum_cat) {
- observe_quantum_cat(current_container);
+ observe_quantum_cat(current_container, TRUE, TRUE);
used = 1;
}
- /* sometimes toss objects if a cursed magic bag */
- cursed_mbag = (Is_mbag(current_container) && current_container->cursed
- && Has_contents(current_container));
- if (cursed_mbag) {
- long loss = 0L;
- for (curr = current_container->cobj; curr; curr = otmp) {
- otmp = curr->nobj;
- if (!rn2(13)) {
- obj_extract_self(curr);
- loss += mbag_item_gone(held, curr);
- used = 1;
- }
- }
- if (loss)
+ cursed_mbag = Is_mbag(current_container)
+ && current_container->cursed
+ && Has_contents(current_container);
+ if (cursed_mbag
+ && (loss = boh_loss(current_container, held)) != 0) {
+ used = 1;
/*JP
- You("owe %ld %s for lost merchandise.", loss, currency(loss));
+ You("owe %ld %s for lost merchandise.", loss, currency(loss));
*/
- You("\8e¸\82Á\82½\8f¤\95i\82Ì\82½\82ß\82É%ld%s\82Ì\95\89\8dÂ\82ð\95\89\82Á\82½\81D", loss, currency(loss));
+ You("\8e¸\82Á\82½\8f¤\95i\82Ì\82½\82ß\82É%ld%s\82Ì\95\89\8dÂ\82ð\95\89\82Á\82½\81D", loss, currency(loss));
current_container->owt = weight(current_container);
}
inokay = (invent != 0
* inventory is empty--taking out could alter that;
* include do-both-reversed when 'i' is available,
* even if container is empty--for similar reason;
- * always include the quit choice ('q').
+ * include the next container choice ('n') when
+ * relevant, and make it the default;
+ * always include the quit choice ('q'), and make
+ * it the default if there's no next containter;
* include the help choice (" or ?") if `cmdassist'
* run-time option is set;
- * (Player can pick any of (o,i,b,r,s,?) even when
+ * (Player can pick any of (o,i,b,r,n,s,?) even when
* they're not listed among the available actions.)
*
- * Do what with <the/your/Shk's container>? [:oibrsq or ?] (q)
+ * Do what with <the/your/Shk's container>? [:oibrs nq or ?] (q)
* or
- * <The/Your/Shk's container> is empty. Do what with it? [:irsq or ?]
+ * <The/Your/Shk's container> is empty. Do what with it? [:irs nq or ?]
*/
- for (;;) { /* repeats if '?' or ":' gets chosen */
+ for (;;) { /* repeats iff '?' or ':' gets chosen */
outmaybe = (outokay || !current_container->cknown);
if (!outmaybe)
-#if 0 /*JP*/
+#if 0 /*JP:T*/
(void) safe_qbuf(qbuf, (char *) 0, " is empty. Do what with it?",
current_container, Yname2, Ysimple_name2,
"This");
"\82±\82ê");
#endif
else
-#if 0 /*JP*/
+#if 0 /*JP:T*/
(void) safe_qbuf(qbuf, "Do what with ", "?", current_container,
yname, ysimple_name, "it");
#else
yname, ysimple_name, "\82±\82ê");
#endif
/* ask player about what to do with this container */
- if (flags.menu_style == MENU_FULL) {
+ if (flags.menu_style == MENU_PARTIAL
+ || flags.menu_style == MENU_FULL) {
if (!inokay && !outmaybe) {
/* nothing to take out, nothing to put in;
trying to do both will yield proper feedback */
c = 'b';
} else {
c = in_or_out_menu(qbuf, current_container, outmaybe, inokay,
- (used != 0));
+ (boolean) (used != 0), more_containers);
}
- } else { /* TRADITIONAL, COMBINATION, or PARTIAL */
- xbuf[0] = '\0'; /* list of extra acceptable responses */
- Strcpy(pbuf, ":"); /* look inside */
+ } else { /* TRADITIONAL or COMBINATION */
+ xbuf[0] = '\0'; /* list of extra acceptable responses */
+ Strcpy(pbuf, ":"); /* look inside */
Strcat(outmaybe ? pbuf : xbuf, "o"); /* take out */
Strcat(inokay ? pbuf : xbuf, "i"); /* put in */
Strcat(outmaybe ? pbuf : xbuf, "b"); /* both */
Strcat(inokay ? pbuf : xbuf, "rs"); /* reversed, stash */
+ Strcat(pbuf, " "); /* separator */
+ Strcat(more_containers ? pbuf : xbuf, "n"); /* next container */
Strcat(pbuf, "q"); /* quit */
if (iflags.cmdassist)
+ /* this unintentionally allows user to answer with 'o' or
+ 'r'; fortunately, those are already valid choices here */
+#if 0 /*JP:T*/
Strcat(pbuf, " or ?"); /* help */
+#else
+ Strcat(pbuf, "\82Ü\82½\82Í?"); /* help */
+#endif
else
Strcat(xbuf, "?");
if (*xbuf)
Strcat(strcat(pbuf, "\033"), xbuf);
- c = yn_function(qbuf, pbuf, 'q');
- } /* FULL vs other modes */
+ c = yn_function(qbuf, pbuf, more_containers ? 'n' : 'q');
+ } /* PARTIAL|FULL vs other modes */
if (c == '?') {
- explain_container_prompt();
+ explain_container_prompt(more_containers);
} else if (c == ':') { /* note: will set obj->cknown */
if (!current_container->cknown)
used = 1; /* gaining info */
break;
} /* loop until something other than '?' or ':' is picked */
- if (c == 'q') /* [not strictly needed; falling through works] */
+ if (c == 'q')
+ abort_looting = TRUE;
+ if (c == 'n' || c == 'q') /* [not strictly needed; falling thru works] */
goto containerdone;
loot_out = (c == 'o' || c == 'b' || c == 'r');
loot_in = (c == 'i' || c == 'b' || c == 'r');
used |= traditional_loot(FALSE);
else
used |= (menu_loot(0, FALSE) > 0);
+ add_valid_menu_class(0);
}
}
if ((loot_in || stash_one)
&& (!invent || (invent == current_container && !invent->nobj))) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
You("don't have anything%s to %s.", invent ? " else" : "",
stash_one ? "stash" : "put in");
#else
used |= traditional_loot(TRUE);
else
used |= (menu_loot(0, TRUE) > 0);
+ add_valid_menu_class(0);
} else if (stash_one) {
/* put one item into container */
if ((otmp = getobj(stashable, "stash")) != 0) {
} else {
/* couldn't put selected item into container for some
reason; might need to undo splitobj() */
- for (curr = invent; curr; curr = curr->nobj)
- if (curr->nobj == otmp)
- break;
- if (curr && curr->invlet == otmp->invlet)
- (void) merged(&curr, &otmp);
+ (void) unsplitobj(otmp);
}
}
}
used |= traditional_loot(FALSE);
else
used |= (menu_loot(0, FALSE) > 0);
+ add_valid_menu_class(0);
}
}
-containerdone:
+ containerdone:
if (used) {
/* Not completely correct; if we put something in without knowing
whatever was already inside, now we suddenly do. That can't
}
*objp = current_container; /* might have become null */
- current_container = 0; /* avoid hanging on to stale pointer */
+ if (current_container)
+ current_container = 0; /* avoid hanging on to stale pointer */
+ else
+ abort_looting = TRUE;
return used;
}
{
int FDECL((*actionfunc), (OBJ_P)), FDECL((*checkfunc), (OBJ_P));
struct obj **objlist;
- char selection[MAXOCLASSES + 1];
+ char selection[MAXOCLASSES + 10]; /* +10: room for B,U,C,X plus slop */
const char *action;
boolean one_by_one, allflag;
int used = 0, menu_on_request = 0;
Sprintf(buf, "%s what type of objects?", action);
*/
Sprintf(buf, "\82Ç\82Ì\8eí\97Þ\82Ì\82à\82Ì\82ð%s\81H", action);
- mflags = put_in
- ? ALL_TYPES | BUC_ALLBKNOWN | BUC_UNKNOWN
- : ALL_TYPES | CHOOSE_ALL | BUC_ALLBKNOWN | BUC_UNKNOWN;
+ mflags = (ALL_TYPES | UNPAID_TYPES | BUCX_TYPES | CHOOSE_ALL);
n = query_category(buf, put_in ? invent : current_container->cobj,
mflags, &pick_list, PICK_ANY);
if (!n)
}
if (loot_everything) {
- current_container->cknown = 1;
- for (otmp = current_container->cobj; otmp; otmp = otmp2) {
- otmp2 = otmp->nobj;
- res = out_container(otmp);
- if (res < 0)
- break;
+ if (!put_in) {
+ current_container->cknown = 1;
+ for (otmp = current_container->cobj; otmp; otmp = otmp2) {
+ otmp2 = otmp->nobj;
+ res = out_container(otmp);
+ if (res < 0)
+ break;
+ n_looted += res;
+ }
+ } else {
+ for (otmp = invent; otmp && current_container; otmp = otmp2) {
+ otmp2 = otmp->nobj;
+ res = in_container(otmp);
+ if (res < 0)
+ break;
+ n_looted += res;
+ }
}
} else {
mflags = INVORDER_SORT;
Sprintf(buf, "%s what?", action);
*/
Sprintf(buf, "\89½\82ð%s\81H", action);
- n = query_objlist(buf, put_in ? invent : current_container->cobj,
+ n = query_objlist(buf, put_in ? &invent : &(current_container->cobj),
mflags, &pick_list, PICK_ANY,
all_categories ? allow_all : allow_category);
if (n) {
}
STATIC_OVL char
-in_or_out_menu(prompt, obj, outokay, inokay, alreadyused)
+in_or_out_menu(prompt, obj, outokay, inokay, alreadyused, more_containers)
const char *prompt;
struct obj *obj;
-boolean outokay, inokay, alreadyused;
+boolean outokay, inokay, alreadyused, more_containers;
{
/* underscore is not a choice; it's used to skip element [0] */
- static const char lootchars[] = "_:oibrsq", abc_chars[] = "_:abcdeq";
+ static const char lootchars[] = "_:oibrsnq", abc_chars[] = "_:abcdenq";
winid win;
anything any;
menu_item *pick_list;
}
if (inokay) {
any.a_int = 5; /* 'r' */
-#if 0 /*JP*/
+#if 0 /*JP:T*/
Sprintf(buf, "%sput in, then take out",
outokay ? "both reversed; " : "");
#else
add_menu(win, NO_GLYPH, &any, menuselector[any.a_int], 0, ATR_NONE,
buf, MENU_UNSELECTED);
}
- any.a_int = 7; /* 'q' */
+ any.a_int = 0;
+ add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED);
+ if (more_containers) {
+ any.a_int = 7; /* 'n' */
+#if 0 /*JP:T*/
+ add_menu(win, NO_GLYPH, &any, menuselector[any.a_int], 0, ATR_NONE,
+ "loot next container", MENU_SELECTED);
+#else
+ add_menu(win, NO_GLYPH, &any, menuselector[any.a_int], 0, ATR_NONE,
+ "\8e\9f\82Ì\94 \82ð\8aJ\82¯\82é", MENU_SELECTED);
+#endif
+ }
+ any.a_int = 8; /* 'q' */
/*JP
Strcpy(buf, alreadyused ? "done" : "do nothing");
*/
Strcpy(buf, alreadyused ? "\8fI\82í\82é" : "\89½\82à\82µ\82È\82¢");
add_menu(win, NO_GLYPH, &any, menuselector[any.a_int], 0, ATR_NONE, buf,
- MENU_SELECTED);
+ more_containers ? MENU_UNSELECTED : MENU_SELECTED);
end_menu(win, prompt);
n = select_menu(win, PICK_ONE, &pick_list);
destroy_nhwindow(win);
if (n > 0) {
- n = pick_list[0].item.a_int;
+ int k = pick_list[0].item.a_int;
+
+ if (n > 1 && k == (more_containers ? 7 : 8))
+ k = pick_list[1].item.a_int;
free((genericptr_t) pick_list);
- return lootchars[n]; /* :,o,i,b,r,s,q */
+ return lootchars[k]; /* :,o,i,b,r,s,n,q */
}
- return 'q'; /* quit */
+ return (n == 0 && more_containers) ? 'n' : 'q'; /* next or quit */
}
static const char tippables[] = { ALL_CLASSES, TOOL_CLASS, 0 };
/* check floor container(s) first; at most one will be accessed */
if ((boxes = container_at(cc.x, cc.y, TRUE)) > 0) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
Sprintf(buf, "You can't tip %s while carrying so much.",
!flags.verbose ? "a container" : (boxes > 1) ? "one" : "it");
#else
int n, i;
winid win;
anything any;
- menu_item *pick_list = NULL;
+ menu_item *pick_list = (menu_item *) 0;
struct obj dummyobj, *otmp;
any = zeroany;
/* use 'i' for inventory unless there are so many
containers that it's already being used */
i = (i <= 'i' - 'a' && !flags.lootabc) ? 'i' : 0;
+#if 0 /*JP:T*/
add_menu(win, NO_GLYPH, &any, i, 0, ATR_NONE,
"tip something being carried", MENU_SELECTED);
+#else
+ add_menu(win, NO_GLYPH, &any, i, 0, ATR_NONE,
+ "\93ü\82ê\95¨\82ð\82Ð\82Á\82\82è\82©\82¦\82·", MENU_SELECTED);
+#endif
}
+/*JP
end_menu(win, "Tip which container?");
+*/
+ end_menu(win, "\82Ç\82Ì\93ü\82ê\95¨\82ð\82Ð\82Á\82\82è\82©\82¦\82·\81H");
n = select_menu(win, PICK_ONE, &pick_list);
destroy_nhwindow(win);
/*
nobj = cobj->nexthere;
if (!Is_container(cobj))
continue;
-#if 0 /*JP*/
+#if 0 /*JP:T*/
c = ynq(safe_qbuf(qbuf, "There is ", " here, tip it?",
cobj,
doname, ansimpleoname, "container"));
*/
Strcpy(buf, "\82»\82µ\82Ä\8f\99\81X\82É\8eU\82Á\82Ä\82¢\82Á\82½\81D");
else if (is_lava(u.ux, u.uy))
-#if 0 /*JP*/
+#if 0 /*JP:T*/
Sprintf(buf, " and immediately %s away",
vtense(spillage, "burn"));
#else
Strcpy(buf, "\82»\82µ\82Ä\82·\82®\82É\94R\82¦\82Â\82«\82½\81D");
#endif
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("Some %s %s onto the %s%s.", spillage,
vtense(spillage, "spill"), surface(u.ux, u.uy), buf);
#else
struct obj *box; /* or bag */
{
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);
+ boolean empty_it = FALSE, maybeshopgoods;
+
+ /* box is either held or on floor at hero's spot; no need to check for
+ nesting; when held, we need to update its location to match hero's;
+ for floor, the coordinate updating is redundant */
+ if (get_obj_location(box, &ox, &oy, 0))
+ box->ox = ox, box->oy = oy;
+
+ /* 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(box->ox, box->oy);
/* caveat: this assumes that cknown, lknown, olocked, and otrapped
fields haven't been overloaded to mean something special for the
non-standard "container" horn of plenty */
- box->lknown = 1;
+ if (!box->lknown) {
+ box->lknown = 1;
+ if (carried(box))
+ update_inventory(); /* jumping the gun slightly; hope that's ok */
+ }
if (box->olocked) {
/*JP
pline("It's locked.");
if (box->spe < old_spe) {
if (bag)
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline((seen == 0) ? "Nothing seems to happen."
: (seen == 1) ? "A monster appears."
: "Monsters appear!");
} else if (SchroedingersBox(box)) {
char yourbuf[BUFSZ];
- observe_quantum_cat(box);
+ observe_quantum_cat(box, TRUE, TRUE);
if (!Has_contents(box)) /* evidently a live cat came out */
/* container type of "large box" is inferred */
/*JP
pline("%sbox is now empty.", Shk_Your(yourbuf, box));
*/
pline("%s\94 \82Í\8bó\82É\82È\82Á\82½\81D", Shk_Your(yourbuf, box));
- else /* holds cat corpse or other random stuff */
+ else /* holds cat corpse */
empty_it = TRUE;
box->cknown = 1;
} else if (!Has_contents(box)) {
if (empty_it) {
struct obj *otmp, *nobj;
- boolean verbose = FALSE, highdrop = !can_reach_floor(TRUE),
+ boolean terse, highdrop = !can_reach_floor(TRUE),
altarizing = IS_ALTAR(levl[ox][oy].typ),
cursed_mbag = (Is_mbag(box) && box->cursed);
int held = carried(box);
if (u.uswallow)
highdrop = altarizing = FALSE;
+ terse = !(highdrop || altarizing || costly_spot(box->ox, box->oy));
box->cknown = 1;
-#if 0 /*JP*/
+ /* Terse formatting is
+ * "Objects spill out: obj1, obj2, obj3, ..., objN."
+ * If any other messages intervene between objects, we revert to
+ * "ObjK drops to the floor.", "ObjL drops to the floor.", &c.
+ */
+#if 0 /*JP:T*/
pline("%s out%c",
box->cobj->nobj ? "Objects spill" : "An object spills",
- !(highdrop || altarizing) ? ':' : '.');
+ terse ? ':' : '.');
#else
pline("\92\86\90g\82ª\8fo\82Ä\82«\82½%s",
!(highdrop || altarizing) ? "\81F" : "\81D");
for (otmp = box->cobj; otmp; otmp = nobj) {
nobj = otmp->nobj;
obj_extract_self(otmp);
- if (cursed_mbag && !rn2(13)) {
+ otmp->ox = box->ox, otmp->oy = box->oy;
+
+ if (box->otyp == ICE_BOX) {
+ removed_from_icebox(otmp); /* resume rotting for corpse */
+ } else if (cursed_mbag && !rn2(13)) {
loss += mbag_item_gone(held, otmp);
/* abbreviated drop format is no longer appropriate */
- verbose = TRUE;
+ terse = FALSE;
continue;
}
if (highdrop) {
/* might break or fall down stairs; handles altars itself */
- hitfloor(otmp);
+ hitfloor(otmp, TRUE);
} else {
- if (altarizing)
+ if (altarizing) {
doaltarobj(otmp);
- else if (verbose)
-#if 0 /*JP*/
+ } else if (!terse) {
+#if 0 /*JP:T*/
pline("%s %s to the %s.", Doname2(otmp),
otense(otmp, "drop"), surface(ox, oy));
#else
pline("%s\82Í%s\82Ì\8fã\82É\97\8e\82¿\82½\81D", Doname2(otmp),
surface(ox, oy));
#endif
- else
+ } else {
/*JP
pline("%s%c", doname(otmp), nobj ? ',' : '.');
*/
pline("%s%s", doname(otmp), nobj ? "\81C" : "\81D");
+ iflags.last_msg = PLNMSG_OBJNAM_ONLY;
+ }
dropy(otmp);
+ if (iflags.last_msg != PLNMSG_OBJNAM_ONLY)
+ terse = FALSE; /* terse formatting has been interrupted */
}
if (maybeshopgoods)
iflags.suppress_price--; /* reset */
if (held)
(void) encumber_msg();
}
+ if (carried(box)) /* box is now empty with cknown set */
+ update_inventory();
}
/*pickup.c*/