drop all objects known to be cursed.
.PL DX
drop all objects of unknown B/U/C status.
+.PL DP
+drop objects picked up last.
.PL Da
drop all objects, without asking for confirmation.
.PL Di
list all items known to be cursed;
.PL IX
list all items whose bless/curse status is unknown;
+.PL IP
+list items picked up last;
.PL I$
count your money.
.PE
{\tt DU} --- drop all objects known to be uncursed.\\
{\tt DC} --- drop all objects known to be cursed.\\
{\tt DX} --- drop all objects of unknown B/U/C status.\\
+{\tt DP} --- drop objects picked up last.\\
{\tt Da} --- drop all objects, without asking for confirmation.\\
{\tt Di} --- examine your inventory before dropping anything.\\
{\tt Du} --- drop only unpaid objects (when in a shop).\\
{\tt IU} --- list all items known to be uncursed;\\
{\tt IC} --- list all items known to be cursed;\\
{\tt IX} --- list all items whose bless/curse status is unknown;\\
+{\tt IP} --- list items picked up last;\\
{\tt I\$} --- count your money.
%.ei
%.ed
vomiting on an altar provokes the deities wrath
branch stairs have a different glyph, show up in yellow color in tty
duration of confusion when drinking booze depends upon hunger state
+using 'D' allows dropping items picked up previously
Platform- and/or Interface-Specific New Features
boolean class_filter;
boolean bucx_filter;
boolean shop_filter;
+ boolean picked_filter;
+ boolean loot_reset_justpicked;
/* pline.c */
unsigned pline_flags;
extern int count_unpaid(struct obj *);
extern int count_buc(struct obj *, int, boolean(*)(struct obj *));
extern void tally_BUCX(struct obj *, boolean, int *, int *, int *, int *,
- int *);
+ int *, int *);
extern long count_contents(struct obj *, boolean, boolean, boolean, boolean);
extern void carry_obj_effects(struct obj *);
extern const char *currency(long);
extern boolean is_worn_by_type(struct obj *);
extern int ck_bag(struct obj *);
extern void removed_from_icebox(struct obj *);
+extern void reset_justpicked(struct obj *);
+extern int count_justpicked(struct obj *);
+extern struct obj *find_justpicked(struct obj *);
extern int pickup(int);
extern int pickup_object(struct obj *, long, boolean);
extern int query_category(const char *, struct obj *, int, menu_item **, int);
#define BUC_CURSED 0x0200
#define BUC_UNCURSED 0x0400
#define BUC_UNKNOWN 0x0800
+#define JUSTPICKED 0x1000
#define BUC_ALLBKNOWN (BUC_BLESSED | BUC_CURSED | BUC_UNCURSED)
#define BUCX_TYPES (BUC_ALLBKNOWN | BUC_UNKNOWN)
#define ALL_TYPES_SELECTED -2
Bitfield(cknown, 1); /* for containers (including statues): the contents
* are known; also applicable to tins */
Bitfield(lknown, 1); /* locked/unlocked status is known */
- /* 4 free bits */
+ Bitfield(pickup_prev, 1); /* was picked up previously */
+ /* 3 free bits */
int corpsenm; /* type of corpse is mons[corpsenm] */
#define leashmon corpsenm /* gets m_id of attached pet */
* Incrementing EDITLEVEL can be used to force invalidation of old bones
* and save files.
*/
-#define EDITLEVEL 40
+#define EDITLEVEL 41
/*
* Development status possibilities.
if (!resuming) { /* new game */
g.context.rndencode = rnd(9000);
set_wear((struct obj *) 0); /* for side-effects of starting gear */
+ reset_justpicked(g.invent);
(void) pickup(1); /* autopickup at initial location */
/* only matters if someday a character is able to start with
clairvoyance (wizard with cornuthaum perhaps?); without this,
UNDEFINED_VALUE, /* class_filter */
UNDEFINED_VALUE, /* bucx_filter */
UNDEFINED_VALUE, /* shop_filter */
+ UNDEFINED_VALUE, /* picked_filter */
+ UNDEFINED_VALUE, /* loot_reset_justpicked */
/* pline.c */
0, /* pline_flags */
static boolean teleport_sink(void);
static void dosinkring(struct obj *);
static int drop(struct obj *);
+static int menudrop_split(struct obj *, int);
static boolean engulfer_digests_food(struct obj *);
static int wipeoff(void);
static int menu_drop(int);
return result;
}
+static int
+menudrop_split(struct obj *otmp, int cnt)
+{
+ if (cnt && cnt < otmp->quan) {
+ if (welded(otmp)) {
+ ; /* don't split */
+ } else if (otmp->otyp == LOADSTONE && otmp->cursed) {
+ /* same kludge as getobj(), for canletgo()'s use */
+ otmp->corpsenm = (int) cnt; /* don't split */
+ } else {
+ otmp = splitobj(otmp, cnt);
+ }
+ }
+ return drop(otmp);
+}
+
/* Drop things from the hero's inventory, using a menu. */
static int
menu_drop(int retry)
{
int n, i, n_dropped = 0;
- long cnt;
struct obj *otmp, *otmp2;
menu_item *pick_list;
boolean all_categories = TRUE, drop_everything = FALSE, autopick = FALSE;
+ boolean drop_justpicked = FALSE;
+ long justpicked_quan = 0;
if (retry) {
all_categories = (retry == -2);
n = query_category("Drop what type of items?", g.invent,
(UNPAID_TYPES | ALL_TYPES | CHOOSE_ALL
| BUC_BLESSED | BUC_CURSED | BUC_UNCURSED
- | BUC_UNKNOWN | INCLUDE_VENOM),
+ | BUC_UNKNOWN | JUSTPICKED | INCLUDE_VENOM),
&pick_list, PICK_ANY);
if (!n)
goto drop_done;
all_categories = TRUE;
} else if (pick_list[i].item.a_int == 'A') {
drop_everything = autopick = TRUE;
+ } else if (pick_list[i].item.a_int == 'P') {
+ justpicked_quan = max(0, pick_list[i].count);
+ drop_justpicked = TRUE;
+ add_valid_menu_class(pick_list[i].item.a_int);
} else {
add_valid_menu_class(pick_list[i].item.a_int);
drop_everything = FALSE;
/* we might not have dropped everything (worn armor, welded weapon,
cursed loadstones), so reset any remaining inventory to normal */
bypass_objlist(g.invent, FALSE);
+ } else if (drop_justpicked && count_justpicked(g.invent) == 1) {
+ /* drop the just picked item automatically, if only one stack */
+ otmp = find_justpicked(g.invent);
+ if (otmp)
+ n_dropped += menudrop_split(otmp, justpicked_quan);
} else {
/* should coordinate with perm invent, maybe not show worn items */
n = query_objlist("What would you like to drop?", &g.invent,
if (!otmp2 || !otmp2->bypass)
continue;
/* found next selected invent item */
- cnt = pick_list[i].count;
- if (cnt < otmp->quan) {
- if (welded(otmp)) {
- ; /* don't split */
- } else if (otmp->otyp == LOADSTONE && otmp->cursed) {
- /* same kludge as getobj(), for canletgo()'s use */
- otmp->corpsenm = (int) cnt; /* don't split */
- } else {
- otmp = splitobj(otmp, cnt);
- }
- }
- n_dropped += drop(otmp);
+ n_dropped += menudrop_split(otmp, pick_list[i].count);
}
bypass_objlist(g.invent, FALSE); /* reset g.invent to normal */
free((genericptr_t) pick_list);
otmp = *potmp = oname(otmp, ONAME(obj));
obj_extract_self(obj);
+ if (obj->pickup_prev && otmp->where == OBJ_INVENT)
+ otmp->pickup_prev = 1;
+
/* really should merge the timeouts */
if (obj->lamplit)
obj_merge_light_sources(obj, otmp);
obj_was_thrown = obj->was_thrown;
obj->was_thrown = 0; /* not meaningful for invent */
+ if (g.loot_reset_justpicked) {
+ g.loot_reset_justpicked = FALSE;
+ reset_justpicked(g.invent);
+ }
+
addinv_core1(obj);
/* for addinv_before(); if something has been removed and is now being
&& (throwing_weapon(obj) || is_ammo(obj)))
setuqwep(obj);
added:
+ obj->pickup_prev = 1;
addinv_core2(obj);
carry_obj_effects(obj); /* carrying affects the obj */
if (update_perm_invent)
freeinv(struct obj *obj)
{
extract_nobj(obj, &g.invent);
+ obj->pickup_prev = 0;
freeinv_core(obj);
update_inventory();
}
boolean takeoff, ident, allflag, m_seen;
int itemcount;
int oletct, iletct, unpaid, oc_of_sym;
- char sym, *ip, olets[MAXOCLASSES + 5], ilets[MAXOCLASSES + 10];
+ char sym, *ip, olets[MAXOCLASSES + 6], ilets[MAXOCLASSES + 11];
char extra_removeables[3 + 1]; /* uwep,uswapwep,uquiver */
char buf[BUFSZ] = DUMMY, qbuf[QBUFSZ];
ilets[iletct++] = 'C';
if (count_buc(g.invent, BUC_UNKNOWN, ofilter))
ilets[iletct++] = 'X';
+ if (count_justpicked(g.invent))
+ ilets[iletct++] = 'P';
ilets[iletct++] = 'a';
}
ilets[iletct++] = 'i';
} else if (sym == 'u') {
add_valid_menu_class('u');
ckfn = ckunpaid;
- } else if (index("BUCX", sym)) {
- add_valid_menu_class(sym); /* 'B','U','C',or 'X' */
+ } else if (index("BUCXP", sym)) {
+ add_valid_menu_class(sym); /* 'B','U','C','X', or 'P' */
ckfn = ckvalidcat;
} else if (sym == 'm') {
m_seen = TRUE;
rather than looking for a specific type */
void
tally_BUCX(struct obj *list, boolean by_nexthere,
- int *bcp, int *ucp, int *ccp, int *xcp, int *ocp)
+ int *bcp, int *ucp, int *ccp, int *xcp, int *ocp, int *jcp)
{
/* Future extensions:
* Skip current_container when list is invent, uchain when
++(*ucp);
continue;
}
+ if (list->pickup_prev)
+ ++(*jcp);
/* ordinary items */
if (!list->bknown)
++(*xcp);
case 'X':
res = !obj->bknown;
break;
+ case 'P':
+ res = obj->pickup_prev;
+ break;
default:
break; /* use 'res' as-is */
}
int n, i = 0;
char *extra_types, types[BUFSZ];
int class_count, oclass, unpaid_count, itemcount;
- int bcnt, ccnt, ucnt, xcnt, ocnt;
+ int bcnt, ccnt, ucnt, xcnt, ocnt, jcnt;
boolean billx = *u.ushops && doinvbill(0);
menu_item *pick_list;
boolean traditional = TRUE;
return 0;
}
unpaid_count = count_unpaid(g.invent);
- tally_BUCX(g.invent, FALSE, &bcnt, &ucnt, &ccnt, &xcnt, &ocnt);
+ tally_BUCX(g.invent, FALSE, &bcnt, &ucnt, &ccnt, &xcnt, &ocnt, &jcnt);
if (flags.menu_style != MENU_TRADITIONAL) {
if (flags.menu_style == MENU_FULL
i |= BUC_CURSED;
if (xcnt)
i |= BUC_UNKNOWN;
+ if (jcnt)
+ i |= JUSTPICKED;
i |= INCLUDE_VENOM;
n = query_category(prompt, g.invent, i, &pick_list, PICK_ONE);
if (!n)
types[class_count++] = 'C';
if (xcnt)
types[class_count++] = 'X';
+ if (jcnt)
+ types[class_count++] = 'P';
types[class_count] = '\0';
/* add everything not already included; user won't see these */
extra_types = eos(types);
return 0;
}
if (traditional) {
- if (index("BUCX", c))
+ if (index("BUCXP", c))
oclass = c; /* not a class but understood by this_type_only() */
else
oclass = def_char_to_objclass(c); /* change to object class */
case 'X':
after = " whose blessed/uncursed/cursed status is unknown";
break; /* better phrasing is desirable */
+ case 'P':
+ after = " you just picked up";
+ break;
default:
/* 'c' is an object class, because we've already handled
all the non-class letters which were put into 'types[]';
otmp->quan = num;
otmp->owt = weight(otmp); /* -= obj->owt ? */
otmp->lua_ref_cnt = 0;
+ otmp->pickup_prev = 0;
g.context.objsplit.parent_oid = obj->o_id;
g.context.objsplit.child_oid = otmp->o_id;
unknow_object(otmp); /* set up dknown and known: non-0 for some things */
otmp->corpsenm = NON_PM;
otmp->lua_ref_cnt = 0;
+ otmp->pickup_prev = 0;
if (init) {
switch (let) {
static boolean reverse_loot(void);
static boolean mon_beside(int, int);
static int do_loot_cont(struct obj **, int, int);
+static int doloot_core(void);
static void tipcontainer(struct obj *);
/* define for query_objlist() and autopickup() */
boolean not_everything, filtered;
char qbuf[QBUFSZ];
boolean m_seen;
- int itemcount, bcnt, ucnt, ccnt, xcnt, ocnt;
+ int itemcount, bcnt, ucnt, ccnt, xcnt, ocnt, jcnt;
oclasses[oclassct = 0] = '\0';
*one_at_a_time = *everything = m_seen = FALSE;
if (count_unpaid(objs))
ilets[iletct++] = 'u';
- tally_BUCX(objs, here, &bcnt, &ucnt, &ccnt, &xcnt, &ocnt);
+ tally_BUCX(objs, here, &bcnt, &ucnt, &ccnt, &xcnt, &ocnt, &jcnt);
if (bcnt)
ilets[iletct++] = 'B';
if (ucnt)
ilets[iletct++] = 'C';
if (xcnt)
ilets[iletct++] = 'X';
+ if (jcnt)
+ ilets[iletct++] = 'P';
ilets[iletct] = '\0';
if (iletct > 1) {
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' */
+ } else if (index("uBUCXP", sym)) {
+ add_valid_menu_class(sym); /* 'u' or 'B','U','C','X','P' */
filtered = TRUE;
} else {
oc_of_sym = def_char_to_objclass(sym);
if (c == 0) { /* reset */
vmc_count = 0;
g.class_filter = g.bucx_filter = g.shop_filter = FALSE;
+ g.picked_filter = FALSE;
} else if (!menu_class_present(c)) {
g.valid_menu_classes[vmc_count++] = (char) c;
/* categorize the new class */
case 'X':
g.bucx_filter = TRUE;
break;
+ case 'P':
+ g.picked_filter = TRUE;
+ break;
case 'u':
g.shop_filter = TRUE;
break;
? (index(g.valid_menu_classes, COIN_CLASS) ? TRUE : FALSE)
: g.shop_filter /* coins are never unpaid, but check anyway */
? (obj->unpaid ? TRUE : FALSE)
+ : g.picked_filter
+ ? obj->pickup_prev
: g.bucx_filter
? (index(g.valid_menu_classes, flags.goldX ? 'X' : 'U')
? TRUE : FALSE)
if (!index(g.valid_menu_classes, bucx))
return FALSE;
}
+ if (g.picked_filter && !obj->pickup_prev)
+ return FALSE;
/* obj didn't fail any of the filter checks, so accept */
return TRUE;
}
return (is_worn(otmp) && allow_category(otmp)) ? TRUE : FALSE;
}
+/* reset last-picked-up flags */
+void
+reset_justpicked(struct obj *olist)
+{
+ struct obj *otmp;
+
+ for (otmp = olist; otmp; otmp = otmp->nobj)
+ otmp->pickup_prev = 0;
+}
+
+int
+count_justpicked(struct obj *olist)
+{
+ struct obj *otmp;
+ int cnt = 0;
+
+ for (otmp = olist; otmp; otmp = otmp->nobj)
+ if (otmp->pickup_prev)
+ cnt++;
+
+ return cnt;
+}
+
+struct obj *
+find_justpicked(struct obj *olist)
+{
+ struct obj *otmp;
+
+ for (otmp = olist; otmp; otmp = otmp->nobj)
+ if (otmp->pickup_prev)
+ return otmp;
+
+ return (struct obj *) 0;
+}
+
/*
* Have the hero pick things from the ground
* or a monster's inventory if swallowed.
nomul(0);
}
+ reset_justpicked(g.invent);
add_valid_menu_class(0); /* reset */
if (!u.uswallow) {
objchain_p = &g.level.objects[u.ux][u.uy];
do_buc_unknown = FALSE;
int num_buc_types = 0;
unsigned itemflags = MENU_ITEMFLAGS_NONE;
+ int num_justpicked = 0;
*pick_list = (menu_item *) 0;
if (!olist)
do_buc_unknown = TRUE;
num_buc_types++;
}
+ if (qflags & JUSTPICKED) {
+ num_justpicked = count_justpicked(olist);
+ }
ccount = count_categories(olist, qflags);
/* no point in actually showing a menu for a single category */
add_menu(win, &nul_glyphinfo, &any, invlet, 0, ATR_NONE,
"Items of unknown Bless/Curse status", itemflags);
}
+ if (num_justpicked) {
+ char tmpbuf[BUFSZ];
+
+ if (num_justpicked == 1)
+ Sprintf(tmpbuf, "%s", doname(find_justpicked(olist)));
+ else
+ Sprintf(tmpbuf, "Items you just picked up");
+ invlet = 'P';
+ any = cg.zeroany;
+ any.a_int = 'P';
+ add_menu(win, &nul_glyphinfo, &any, invlet, 0, ATR_NONE,
+ tmpbuf, itemflags);
+ }
end_menu(win, qstr);
n = select_menu(win, how, pick_list);
query_done:
return use_container(cobjp, 0, (boolean) (cindex < ccount));
}
-/* loot a container on the floor or loot saddle from mon. */
+/* #loot extended command */
int
doloot(void)
+{
+ int res;
+
+ g.loot_reset_justpicked = TRUE;
+ res = doloot_core();
+ g.loot_reset_justpicked = FALSE;
+ return res;
+}
+
+/* loot a container on the floor or loot saddle from mon. */
+static int
+doloot_core(void)
{
struct obj *cobj, *nobj;
register int c = -1;
int n, i, n_looted = 0;
boolean all_categories = TRUE, loot_everything = FALSE, autopick = FALSE;
char buf[BUFSZ];
+ boolean loot_justpicked = FALSE;
const char *action = put_in ? "Put in" : "Take out";
struct obj *otmp, *otmp2;
menu_item *pick_list;
} else if (flags.menu_style == MENU_FULL) {
all_categories = FALSE;
Sprintf(buf, "%s what type of objects?", action);
- mflags = (ALL_TYPES | UNPAID_TYPES | BUCX_TYPES | CHOOSE_ALL);
+ mflags = (ALL_TYPES | UNPAID_TYPES | BUCX_TYPES | CHOOSE_ALL
+ | JUSTPICKED );
n = query_category(buf, put_in ? g.invent : g.current_container->cobj,
mflags, &pick_list, PICK_ANY);
if (!n)
for (i = 0; i < n; i++) {
if (pick_list[i].item.a_int == 'A') {
loot_everything = autopick = TRUE;
+ } else if (put_in && pick_list[i].item.a_int == 'P') {
+ loot_justpicked = TRUE;
+ count = max(0, pick_list[i].count);
+ add_valid_menu_class(pick_list[i].item.a_int);
} else if (pick_list[i].item.a_int == ALL_TYPES_SELECTED) {
all_categories = TRUE;
} else {
n_looted += res;
}
}
+ } else if (put_in && loot_justpicked && count_justpicked(g.invent) == 1) {
+ otmp = find_justpicked(g.invent);
+ if (otmp) {
+ n_looted = 1;
+ if (count > 0 && count < otmp->quan) {
+ otmp = splitobj(otmp, count);
+ }
+ (void) in_container(otmp);
+ /* return value doesn't matter, even if container blew up */
+ }
} else {
mflags = INVORDER_SORT | INCLUDE_VENOM;
if (put_in && flags.invlet_constant)
mflags |= USE_INVLET;
+ if (put_in && loot_justpicked)
+ mflags |= JUSTPICKED;
if (!put_in)
g.current_container->cknown = 1;
Sprintf(buf, "%s what?", action);