streamlined container interface (trunk only)

Reduce the number of questions issued when applying or looting a
container, and offer the opportunity to put things inside before taking
things out.  Instead of "Do you want to take something out?  [:ynq]",
followed by "Do you want to put something in? [ynq]", this gives just one
prompt; the result is similar to menustyle:full where you start out by
choosing between out, in, and both.  There are now two additional choices:
reversed, for both in the opposite order, and stash, to put a single item
inside.  Prompt phrasing is rather clumsy; I wanted to keep it short:
"Do what with <the container>? [:oibrsq or ?]", where picking '?' pops
up a brief help window.  Inappropriate choices (like 'o'and 'b' when
container is empty) are suppressed from the prompt but still acceptable as
input; " or ?" is suppressed if the cmdassist option has been toggled off,
but entering '?' still works to get help.

     Menu mode wouldn't allow 'b' when inventory was empty, despite the
fact that first taking things out might change that.  Now 'b' is a viable
choice if the container isn't empty, and the new 'r' is a vialble choice
when inventory isn't empty even if the container is.
This commit is contained in:
nethack.rankin
2007-01-04 06:15:25 +00:00
parent c45ce7a999
commit 448b7cc7b6
3 changed files with 324 additions and 192 deletions
+1
View File
@@ -274,6 +274,7 @@ the Amulet can be offered to Moloch
javelins and spears now share the same weapon skill javelins and spears now share the same weapon skill
all stackable weapons are capable of being thrown/shot for multi-shot volleys all stackable weapons are capable of being thrown/shot for multi-shot volleys
worm teeth and crysknives have become stackable worm teeth and crysknives have become stackable
improved container interface
Platform- and/or Interface-Specific New Features Platform- and/or Interface-Specific New Features
+32 -6
View File
@@ -781,7 +781,9 @@ register const char *let,*word;
register int foo = 0; register int foo = 0;
register char *bp = buf; register char *bp = buf;
xchar allowcnt = 0; /* 0, 1 or 2 */ xchar allowcnt = 0; /* 0, 1 or 2 */
struct obj *firstobj = invent;
#ifndef GOLDOBJ #ifndef GOLDOBJ
struct obj *u_gold = 0;
boolean allowgold = FALSE; /* can't use gold because they don't have any */ boolean allowgold = FALSE; /* can't use gold because they don't have any */
#endif #endif
boolean usegold = FALSE; /* can't use gold because its illegal */ boolean usegold = FALSE; /* can't use gold because its illegal */
@@ -797,6 +799,13 @@ register const char *let,*word;
#ifndef GOLDOBJ #ifndef GOLDOBJ
if(*let == COIN_CLASS) let++, if(*let == COIN_CLASS) let++,
usegold = TRUE, allowgold = (u.ugold ? TRUE : FALSE); usegold = TRUE, allowgold = (u.ugold ? TRUE : FALSE);
if (firstobj && firstobj->oclass == COIN_CLASS) {
/* gold has been inserted into inventory; skip it during
inventory letter collection */
u_gold = firstobj;
firstobj = u_gold->nobj;
allowgold = usegold;
}
#else #else
if(*let == COIN_CLASS) let++, usegold = TRUE; if(*let == COIN_CLASS) let++, usegold = TRUE;
#endif #endif
@@ -835,7 +844,7 @@ register const char *let,*word;
if (!flags.invlet_constant) reassign(); if (!flags.invlet_constant) reassign();
for (otmp = invent; otmp; otmp = otmp->nobj) { for (otmp = firstobj; otmp; otmp = otmp->nobj) {
if (&bp[foo] == &buf[sizeof buf - 1] || if (&bp[foo] == &buf[sizeof buf - 1] ||
ap == &altlets[sizeof altlets - 1]) { ap == &altlets[sizeof altlets - 1]) {
/* we must have a huge number of NOINVSYM items somehow */ /* we must have a huge number of NOINVSYM items somehow */
@@ -937,6 +946,7 @@ register const char *let,*word;
|| (!strcmp(word, "sacrifice") && || (!strcmp(word, "sacrifice") &&
/* (!astral && amulet) || (astral && !amulet) */ /* (!astral && amulet) || (astral && !amulet) */
(!Is_astralevel(&u.uz) ^ (otmp->oclass != AMULET_CLASS))) (!Is_astralevel(&u.uz) ^ (otmp->oclass != AMULET_CLASS)))
|| (!strcmp(word, "stash") && !ck_bag(otmp))
) { ) {
/* acceptable but not listed as likely candidate */ /* acceptable but not listed as likely candidate */
foo--; foo--;
@@ -1032,7 +1042,11 @@ register const char *let,*word;
#ifndef GOLDOBJ #ifndef GOLDOBJ
if(!(allowcnt == 2 && cnt < u.ugold)) if(!(allowcnt == 2 && cnt < u.ugold))
cnt = u.ugold; cnt = u.ugold;
return(mkgoldobj(cnt)); if (!u_gold)
u_gold = mkgoldobj(cnt);
else if (cnt < u_gold->quan)
u_gold = splitobj(u_gold, cnt);
return u_gold;
#endif #endif
} }
if(ilet == '?' || ilet == '*') { if(ilet == '?' || ilet == '*') {
@@ -1424,14 +1438,17 @@ register int FDECL((*fn),(OBJ_P)), FDECL((*ckfn),(OBJ_P));
struct obj *otmp, *otmp2, *otmpo; struct obj *otmp, *otmp2, *otmpo;
register char sym, ilet; register char sym, ilet;
register int cnt = 0, dud = 0, tmp; register int cnt = 0, dud = 0, tmp;
boolean takeoff, nodot, ident, ininv; boolean takeoff, nodot, ident, take_out, put_in, first, ininv;
char qbuf[BUFSZ]; char qbuf[QBUFSZ], qpfx[QBUFSZ];
takeoff = taking_off(word); takeoff = taking_off(word);
ident = !strcmp(word, "identify"); ident = !strcmp(word, "identify");
take_out = !strcmp(word, "take out");
put_in = !strcmp(word, "put in");
nodot = (!strcmp(word, "nodot") || !strcmp(word, "drop") || nodot = (!strcmp(word, "nodot") || !strcmp(word, "drop") ||
ident || takeoff); ident || takeoff || take_out || put_in);
ininv = (*objchn == invent); ininv = (*objchn == invent);
first = TRUE;
/* Changed so the askchain is interrogated in the order specified. /* Changed so the askchain is interrogated in the order specified.
* For example, if a person specifies =/ then first all rings will be * For example, if a person specifies =/ then first all rings will be
* asked about followed by all wands -dgk * asked about followed by all wands -dgk
@@ -1450,7 +1467,16 @@ nextclass:
if (!allflag) { if (!allflag) {
safeq_xprn_ctx.let = ilet; safeq_xprn_ctx.let = ilet;
safeq_xprn_ctx.dot = !nodot; safeq_xprn_ctx.dot = !nodot;
(void)safe_qbuf(qbuf, (char *)0, "?", *qpfx = '\0';
if (first) {
/* traditional_loot() skips prompting when only one
class of objects is involved, so prefix the first
object being queried here with an explanation why */
if (take_out || put_in)
Sprintf(qpfx, "%s: ", word), *qpfx = highc(*qpfx);
first = FALSE;
}
(void)safe_qbuf(qbuf, qpfx, "?",
otmp, ininv ? safeq_xprname : doname, otmp, ininv ? safeq_xprname : doname,
ininv ? safeq_shortxprname : ansimpleoname, ininv ? safeq_shortxprname : ansimpleoname,
"item"); "item");
+291 -186
View File
@@ -1,4 +1,4 @@
/* SCCS Id: @(#)pickup.c 3.5 2006/10/16 */ /* SCCS Id: @(#)pickup.c 3.5 2007/01/02 */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */ /* NetHack may be freely redistributed. See license for details. */
@@ -33,8 +33,11 @@ STATIC_PTR int FDECL(in_container,(struct obj *));
STATIC_PTR int FDECL(out_container,(struct obj *)); STATIC_PTR int FDECL(out_container,(struct obj *));
STATIC_DCL long FDECL(mbag_item_gone, (int,struct obj *)); STATIC_DCL long FDECL(mbag_item_gone, (int,struct obj *));
STATIC_DCL void FDECL(observe_quantum_cat, (struct obj *)); STATIC_DCL void FDECL(observe_quantum_cat, (struct obj *));
STATIC_DCL void NDECL(explain_container_prompt);
STATIC_DCL int FDECL(traditional_loot, (BOOLEAN_P));
STATIC_DCL int FDECL(menu_loot, (int,BOOLEAN_P)); STATIC_DCL int FDECL(menu_loot, (int,BOOLEAN_P));
STATIC_DCL int FDECL(in_or_out_menu, (const char *,struct obj *, BOOLEAN_P, BOOLEAN_P)); STATIC_DCL char FDECL(in_or_out_menu, (const char *,struct obj *,
BOOLEAN_P,BOOLEAN_P));
STATIC_DCL int FDECL(container_at, (int, int, BOOLEAN_P)); STATIC_DCL int FDECL(container_at, (int, int, BOOLEAN_P));
STATIC_DCL boolean FDECL(able_to_loot, (int,int,BOOLEAN_P)); STATIC_DCL boolean FDECL(able_to_loot, (int,int,BOOLEAN_P));
STATIC_DCL boolean FDECL(mon_beside, (int, int)); STATIC_DCL boolean FDECL(mon_beside, (int, int));
@@ -2053,6 +2056,36 @@ int FDECL((*fn), (OBJ_P));
return ((fn == in_container || fn == out_container) && !current_container); return ((fn == in_container || fn == out_container) && !current_container);
} }
STATIC_OVL void
explain_container_prompt()
{
static const char * const explaintext[] = {
"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
};
const char * const *txtpp;
winid win;
/* "Do what with <container>? [:oibrsq or ?] (q)" */
if ((win = create_nhwindow(NHW_TEXT)) != WIN_ERR) {
for (txtpp = explaintext; *txtpp; ++txtpp) putstr(win, 0, *txtpp);
display_nhwindow(win, FALSE);
destroy_nhwindow(win);
}
}
static const char stashable[] = { ALLOW_COUNT, COIN_CLASS, ALL_CLASSES, 0 };
int int
use_container(objp, held) use_container(objp, held)
struct obj **objp; struct obj **objp;
@@ -2062,21 +2095,21 @@ int held;
#ifndef GOLDOBJ #ifndef GOLDOBJ
struct obj *u_gold = (struct obj *)0; struct obj *u_gold = (struct obj *)0;
#endif #endif
boolean one_by_one, allflag, quantum_cat = FALSE, boolean quantum_cat, cursed_mbag,
loot_out = FALSE, loot_in = FALSE; loot_out, loot_in, loot_in_first, stash_one,
char selection[MAXOCLASSES+1]; inokay, outokay, outmaybe;
char qbuf[BUFSZ], emptymsg[BUFSZ], pbuf[QBUFSZ]; char c, emptymsg[BUFSZ],
long loss = 0L; qbuf[QBUFSZ], pbuf[QBUFSZ], xbuf[QBUFSZ];
int cnt = 0, used = 0, long loss;
menu_on_request; int cnt, used = 0;
emptymsg[0] = '\0'; emptymsg[0] = '\0';
if (nohands(youmonst.data)) { if (nohands(youmonst.data)) {
You("have no hands!"); /* not `body_part(HAND)' */ You("have no hands!"); /* not `body_part(HAND)' */
return 0; return 0;
} else if (!freehand()) { } else if (!freehand()) {
You("have no free %s.", body_part(HAND)); You("have no free %s.", body_part(HAND));
return 0; return 0;
} }
if (obj->olocked) { if (obj->olocked) {
pline("%s locked.", Tobjnam(obj, "are")); pline("%s locked.", Tobjnam(obj, "are"));
@@ -2099,16 +2132,19 @@ int held;
current_container = obj; /* for use by in/out_container */ 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 */
if (obj->spe == 1) { /* check for Schroedinger's Cat */
observe_quantum_cat(obj); quantum_cat = (current_container->spe == 1); /* "it's _now_ empty" */
if (quantum_cat) {
observe_quantum_cat(current_container);
used = 1; used = 1;
quantum_cat = TRUE; /* for adjusting "it's empty" message */
} }
/* Count the number of contained objects. Sometimes toss objects if */ /* count the number of contained objects;
/* a cursed magic bag. */ sometimes toss objects if a cursed magic bag */
for (curr = obj->cobj; curr; curr = otmp) { cursed_mbag = Is_mbag(current_container) && current_container->cursed;
cnt = 0, loss = 0L;
for (curr = current_container->cobj; curr; curr = otmp) {
otmp = curr->nobj; otmp = curr->nobj;
if (Is_mbag(obj) && obj->cursed && !rn2(13)) { if (cursed_mbag && !rn2(13)) {
obj_extract_self(curr); obj_extract_self(curr);
loss += mbag_item_gone(held, curr); loss += mbag_item_gone(held, curr);
used = 1; used = 1;
@@ -2116,170 +2152,159 @@ int held;
cnt++; cnt++;
} }
} }
if (cursed_mbag) { /* magic bag might have lost some contents */
if (loss) /* magic bag lost some shop goods */ if (loss)
You("owe %ld %s for lost merchandise.", loss, currency(loss)); You("owe %ld %s for lost merchandise.", loss, currency(loss));
obj->owt = weight(obj); /* in case any items were lost */ current_container->owt = weight(current_container);
}
if (!cnt) { inokay = (invent != 0 &&
Sprintf(emptymsg, "%s is %sempty.", Ysimple_name2(obj), !(invent == current_container && !current_container->nobj));
#ifndef GOLDOBJ
if (u.ugold) inokay = TRUE;
#endif
outokay = (cnt > 0);
if (!outokay) /* preformat the empty-container message */
Sprintf(emptymsg, "%s is %sempty.",
Ysimple_name2(current_container),
quantum_cat ? "now " : ""); quantum_cat ? "now " : "");
}
if (cnt || flags.menu_style == MENU_FULL) { /*
(void)safe_qbuf(qbuf, "Do you want to take something out of ", "?", * What-to-do prompt's list of possible actions:
obj, yname, ysimple_name, "it"); * always include the look-inside choice (':');
if (flags.menu_style != MENU_TRADITIONAL) { * include the take-out choice ('o') if container
if (flags.menu_style == MENU_FULL) { * has anything in it or if player doesn't yet know
int t; * that it's empty (latter can change on subsequent
char menuprompt[BUFSZ]; * iterations if player picks ':' response);
boolean outokay = (cnt != 0), * include the put-in choices ('i','s') if hero
inokay = (invent != 0); * carries any inventory (including gold);
* include do-both when 'o' is available, even if
#ifndef GOLDOBJ * inventory is empty--taking out could alter that;
if (u.ugold) inokay = TRUE; * include do-both-reversed when 'i' is available,
#endif * even if container is empty--for similar reason;
if (!cnt) obj->cknown = 1; /* will be giving emptymsg */ * always include the quit choice ('q').
* include the help choice (" or ?") if `cmdassist'
if (!outokay && !inokay) { * run-time option is set;
pline("%s", emptymsg); * (Player can pick any of (o,i,b,r,s,?) even when
You("don't have anything to put in."); * they're not listed among the available actions.)
goto containerdone; *
} * Do what with <the/your/Shk's container>? [:oibrsq or ?] (q)
menuprompt[0] = '\0'; * or
if (!cnt) Sprintf(menuprompt, "%s ", emptymsg); * <The/Your/Shk's container> is empty. Do what with it? [:irsq or ?]
Strcat(menuprompt, "Do what?"); */
t = in_or_out_menu(menuprompt, current_container, for (;;) { /* repeats if '?' or ":' gets chosen */
outokay, inokay); outmaybe = (outokay || !current_container->cknown);
if (t <= 0) { if (!outmaybe)
used = 0; (void)safe_qbuf(qbuf, (char *)0,
goto containerdone; " is empty. Do what with it?",
} current_container,
loot_out = (t & 0x01) != 0; Yname2, Ysimple_name2, "This");
loot_in = (t & 0x02) != 0; else
} else { /* MENU_COMBINATION or MENU_PARTIAL */ (void)safe_qbuf(qbuf, "Do what with ", "?",
loot_out = (yn_function(qbuf, "ynq", 'n') == 'y'); current_container, yname, ysimple_name, "it");
/* ask player about what to do with this container */
if (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);
} }
if (loot_out) { } else { /* TRADITIONAL, COMBINATION, or PARTIAL */
add_valid_menu_class(0); /* reset */ xbuf[0] = '\0'; /* list of extra acceptable responses */
used |= menu_loot(0, FALSE) > 0; Strcpy(pbuf, ":"); /* look inside */
} Strcat(outmaybe ? pbuf : xbuf, "o"); /* take out */
} else { Strcat(inokay ? pbuf : xbuf, "i"); /* put in */
/* traditional code */ Strcat(outmaybe ? pbuf : xbuf, "b"); /* both */
ask_again2: Strcat(inokay ? pbuf : xbuf, "rs"); /* reversed, stash */
menu_on_request = 0; Strcat(pbuf, "q"); /* quit */
add_valid_menu_class(0); /* reset */ if (iflags.cmdassist) Strcat(pbuf, " or ?"); /* help */
Strcpy(pbuf, ":ynq"); else Strcat(xbuf, "?");
if (cnt) Strcat(pbuf, "m"); if (*xbuf) Strcat(strcat(pbuf, "\033"), xbuf);
switch (yn_function(qbuf, pbuf, 'n')) { c = yn_function(qbuf, pbuf, 'q');
case ':': } /* FULL vs other modes */
container_contents(current_container, FALSE, FALSE, TRUE);
goto ask_again2;
case 'y':
if (query_classes(selection, &one_by_one, &allflag,
"take out", current_container->cobj,
FALSE,
#ifndef GOLDOBJ
FALSE,
#endif
&menu_on_request)) {
if (askchain((struct obj **)&current_container->cobj,
(one_by_one ? (char *)0 : selection),
allflag, out_container,
(int FDECL((*),(OBJ_P)))0,
0, "nodot"))
used = 1;
} else if (menu_on_request < 0) {
used |= menu_loot(menu_on_request, FALSE) > 0;
}
/*FALLTHRU*/
case 'n':
break;
case 'm':
menu_on_request = -2; /* triggers ALL_CLASSES */
used |= menu_loot(menu_on_request, FALSE) > 0;
break;
case 'q':
default:
goto containerdone;
}
}
} else {
pline("%s", emptymsg); /* <whatever> is empty. */
obj->cknown = 1;
}
#ifndef GOLDOBJ if (c == '?') {
if (!invent && u.ugold == 0) { explain_container_prompt();
#else } else if (c == ':') { /* note: will set obj->cknown */
if (!invent) { if (!current_container->cknown) used = 1; /* gaining info */
#endif container_contents(current_container, FALSE, FALSE, TRUE);
/* nothing to put in, but some feedback is necessary */ } else
You("don't have anything to put in."); break;
} /* loop until something other than '?' or ':' is picked */
if (c == 'q') /* [not strictly needed; falling through works] */
goto containerdone; goto containerdone;
} loot_out = (c == 'o' || c == 'b' || c == 'r');
if (flags.menu_style != MENU_FULL) { loot_in = (c == 'i' || c == 'b' || c == 'r');
Sprintf(qbuf, "Do you wish to put %s in?", something); loot_in_first = (c == 'r'); /* both, reversed */
Strcpy(pbuf, ynqchars); stash_one = (c == 's');
if (flags.menu_style == MENU_TRADITIONAL && invent && inv_cnt() > 0)
Strcat(pbuf, "m"); /* out-only or out before in */
switch (yn_function(qbuf, pbuf, 'n')) { if (loot_out && !loot_in_first) {
case 'y': if (!Has_contents(current_container)) {
loot_in = TRUE; pline("%s", emptymsg); /* <whatever> is empty. */
break; if (!current_container->cknown) used = 1;
case 'n': current_container->cknown = 1;
break; } else {
case 'm': add_valid_menu_class(0); /* reset */
add_valid_menu_class(0); /* reset */ if (flags.menu_style == MENU_TRADITIONAL)
menu_on_request = -2; /* triggers ALL_CLASSES */ used |= traditional_loot(FALSE);
used |= menu_loot(menu_on_request, TRUE) > 0; else
break; used |= (menu_loot(0, FALSE) > 0);
case 'q':
default:
goto containerdone;
} }
} }
#ifndef GOLDOBJ
if ((loot_in ||stash_one) && u.ugold) {
/*
* Hack: gold is not in the inventory, so make a gold object
* and put it at the head of the inventory list.
*/
u_gold = mkgoldobj(u.ugold); /* removes from u.ugold */
u_gold->in_use = TRUE;
u.ugold = u_gold->quan; /* put the gold back */
assigninvlet(u_gold); /* might end up as NOINVSYM */
u_gold->nobj = invent;
invent = u_gold;
u_gold->where = OBJ_INVENT;
}
#endif
if ((loot_in || stash_one) &&
(!invent || (invent == current_container && !invent->nobj))) {
You("don't have anything%s to %s.",
invent ? " else" : "", stash_one ? "stash" : "put in");
loot_in = stash_one = FALSE;
}
/* /*
* Gone: being nice about only selecting food if we know we are * Gone: being nice about only selecting food if we know we are
* putting things in an ice chest. * putting things in an ice chest.
*/ */
if (loot_in) { if (loot_in) {
#ifndef GOLDOBJ add_valid_menu_class(0); /* reset */
if (u.ugold) { if (flags.menu_style == MENU_TRADITIONAL)
/* used |= traditional_loot(TRUE);
* Hack: gold is not in the inventory, so make a gold object else
* and put it at the head of the inventory list. used |= (menu_loot(0, TRUE) > 0);
*/ } else if (stash_one) {
u_gold = mkgoldobj(u.ugold); /* removes from u.ugold */ /* put one item into container */
u_gold->in_use = TRUE; if ((otmp = getobj(stashable, "stash")) != 0) {
u.ugold = u_gold->quan; /* put the gold back */ if (in_container(otmp)) {
assigninvlet(u_gold); /* might end up as NOINVSYM */
u_gold->nobj = invent;
invent = u_gold;
u_gold->where = OBJ_INVENT;
}
#endif
add_valid_menu_class(0); /* reset */
if (flags.menu_style != MENU_TRADITIONAL) {
used |= menu_loot(0, TRUE) > 0;
} else {
/* traditional code */
menu_on_request = 0;
if (query_classes(selection, &one_by_one, &allflag, "put in",
invent, FALSE,
#ifndef GOLDOBJ
(u.ugold != 0L),
#endif
&menu_on_request)) {
(void) askchain((struct obj **)&invent,
(one_by_one ? (char *)0 : selection), allflag,
in_container, ck_bag, 0, "nodot");
used = 1; used = 1;
} else if (menu_on_request < 0) { } else {
used |= menu_loot(menu_on_request, TRUE) > 0; /* 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);
} }
} }
} }
/* putting something in might have triggered magic bag explosion */
if (!current_container) loot_out = FALSE;
#ifndef GOLDOBJ #ifndef GOLDOBJ
if (u_gold && invent && invent->oclass == COIN_CLASS) { if (u_gold && invent && invent->oclass == COIN_CLASS) {
@@ -2292,19 +2317,74 @@ ask_again2:
} }
#endif #endif
/* out after in */
if (loot_out && loot_in_first) {
if (!Has_contents(current_container)) {
pline("%s", emptymsg); /* <whatever> is empty. */
if (!current_container->cknown) used = 1;
current_container->cknown = 1;
} else {
add_valid_menu_class(0); /* reset */
if (flags.menu_style == MENU_TRADITIONAL)
used |= traditional_loot(FALSE);
else
used |= (menu_loot(0, FALSE) > 0);
}
}
containerdone: containerdone:
/* Not completely correct; if we put something in without knowing /* Not completely correct; if we put something in without knowing
whatever was already inside, now we suddenly do. That can't be whatever was already inside, now we suddenly do. That can't be
helped unless we want to track things item by item and then deal helped unless we want to track things item by item and then deal
with containers whose contents are "partly known". */ with containers whose contents are "partly known". */
if (used) obj->cknown = 1; if (used && current_container) current_container->cknown = 1;
*objp = current_container; /* might have become null */ *objp = current_container; /* might have become null */
current_container = 0; /* avoid hanging on to stale pointer */ current_container = 0; /* avoid hanging on to stale pointer */
return used; return used;
} }
/* Loot current_container (take things out, put things in), using a menu. */ /* loot current_container (take things out or put things in), by prompting */
STATIC_OVL int
traditional_loot(put_in)
boolean put_in;
{
int FDECL((*actionfunc), (OBJ_P)),
FDECL((*checkfunc), (OBJ_P));
struct obj **objlist;
char selection[MAXOCLASSES+1];
const char *action;
boolean one_by_one, allflag;
int used = 0, menu_on_request = 0;
if (put_in) {
action = "put in";
objlist = &invent;
actionfunc = in_container;
checkfunc = ck_bag;
} else {
action = "take out";
objlist = &(current_container->cobj);
actionfunc = out_container;
checkfunc = (int FDECL((*), (OBJ_P)))0;
}
if (query_classes(selection, &one_by_one, &allflag,
action, *objlist, FALSE,
#ifndef GOLDOBJ
put_in ? (boolean)(u.ugold != 0L) : FALSE,
#endif
&menu_on_request)) {
if (askchain(objlist, (one_by_one ? (char *)0 : selection),
allflag, actionfunc, checkfunc, 0, action))
used = 1;
} else if (menu_on_request < 0) {
used = (menu_loot(menu_on_request, put_in) > 0);
}
return used;
}
/* loot current_container (take things out or put things in), using a menu */
STATIC_OVL int STATIC_OVL int
menu_loot(retry, put_in) menu_loot(retry, put_in)
int retry; int retry;
@@ -2383,48 +2463,73 @@ boolean put_in;
return n_looted; return n_looted;
} }
STATIC_OVL int STATIC_OVL char
in_or_out_menu(prompt, obj, outokay, inokay) in_or_out_menu(prompt, obj, outokay, inokay)
const char *prompt; const char *prompt;
struct obj *obj; struct obj *obj;
boolean outokay, inokay; boolean outokay, inokay;
{ {
/* underscore is not a choice; it's used to skip element [0] */
static const char lootchars[] = "_:oibrsq",
abc_chars[] = "_:abcdeq";
winid win; winid win;
anything any; anything any;
menu_item *pick_list; menu_item *pick_list;
char buf[BUFSZ]; char buf[BUFSZ];
int n; int n;
const char *menuselector = flags.lootabc ? "abc" : "oib"; const char *menuselector = flags.lootabc ? abc_chars : lootchars;
any = zeroany; any = zeroany;
win = create_nhwindow(NHW_MENU); win = create_nhwindow(NHW_MENU);
start_menu(win); start_menu(win);
any.a_int = 1; /* ':' */
Sprintf(buf, "Look inside %s", thesimpleoname(obj));
add_menu(win, NO_GLYPH, &any, menuselector[any.a_int], 0, ATR_NONE,
buf, MENU_UNSELECTED);
if (outokay) { if (outokay) {
any.a_int = 1; any.a_int = 2; /* 'o' */
Sprintf(buf,"Take %s out of %s", something, the(xname(obj))); Sprintf(buf, "take %s out", something);
add_menu(win, NO_GLYPH, &any, *menuselector, 0, ATR_NONE, add_menu(win, NO_GLYPH, &any, menuselector[any.a_int], 0, ATR_NONE,
buf, MENU_UNSELECTED); buf, MENU_UNSELECTED);
} }
menuselector++;
if (inokay) { if (inokay) {
any.a_int = 2; any.a_int = 3; /* 'i' */
Sprintf(buf,"Put %s into %s", something, the(xname(obj))); Sprintf(buf, "put %s in", something);
add_menu(win, NO_GLYPH, &any, *menuselector, 0, ATR_NONE, buf, MENU_UNSELECTED); add_menu(win, NO_GLYPH, &any, menuselector[any.a_int], 0, ATR_NONE,
buf, MENU_UNSELECTED);
} }
menuselector++; if (outokay) {
if (outokay && inokay) { any.a_int = 4; /* 'b' */
any.a_int = 3; Sprintf(buf, "%stake out, then put in", inokay ? "both; " : "");
add_menu(win, NO_GLYPH, &any, *menuselector, 0, ATR_NONE, add_menu(win, NO_GLYPH, &any, menuselector[any.a_int], 0, ATR_NONE,
"Both of the above", MENU_UNSELECTED); buf, MENU_UNSELECTED);
} }
if (inokay) {
any.a_int = 5; /* 'r' */
Sprintf(buf, "%sput in, then take out",
outokay ? "both reversed; " : "");
add_menu(win, NO_GLYPH, &any, menuselector[any.a_int], 0, ATR_NONE,
buf, MENU_UNSELECTED);
any.a_int = 6; /* 's' */
Sprintf(buf, "stash one item into %s", thesimpleoname(obj));
add_menu(win, NO_GLYPH, &any, menuselector[any.a_int], 0, ATR_NONE,
buf, MENU_UNSELECTED);
}
any.a_int = 7; /* 'q' */
Strcpy(buf, "do nothing");
add_menu(win, NO_GLYPH, &any, menuselector[any.a_int], 0, ATR_NONE,
buf, MENU_SELECTED);
end_menu(win, prompt); end_menu(win, prompt);
n = select_menu(win, PICK_ONE, &pick_list); n = select_menu(win, PICK_ONE, &pick_list);
destroy_nhwindow(win); destroy_nhwindow(win);
if (n > 0) { if (n > 0) {
n = pick_list[0].item.a_int; n = pick_list[0].item.a_int;
free((genericptr_t) pick_list); free((genericptr_t) pick_list);
return lootchars[n]; /* :,o,i,b,r,s,q */
} }
return n; return 'q'; /* quit */
} }
static const char tippables[] = { ALL_CLASSES, TOOL_CLASS, 0 }; static const char tippables[] = { ALL_CLASSES, TOOL_CLASS, 0 };