-/* NetHack 3.6 invent.c $NHDT-Date: 1519672703 2018/02/26 19:18:23 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.225 $ */
+/* NetHack 3.6 invent.c $NHDT-Date: 1575245062 2019/12/02 00:04:22 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.267 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Derek S. Ray, 2015. */
/* 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-2018 */
+/* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2021 */
/* JNetHack may be freely redistributed. See license for details. */
#include "hack.h"
+#ifndef C /* same as cmd.c */
+#define C(c) (0x1f & (c))
+#endif
+
#define NOINVSYM '#'
#define CONTAINED_SYM '>' /* designator for inside a container */
#define HANDS_SYM '-'
+STATIC_DCL void FDECL(loot_classify, (Loot *, struct obj *));
+STATIC_DCL char *FDECL(loot_xname, (struct obj *));
STATIC_DCL int FDECL(CFDECLSPEC sortloot_cmp, (const genericptr,
const genericptr));
STATIC_DCL void NDECL(reorder_invent);
STATIC_DCL void FDECL(compactify, (char *));
STATIC_DCL boolean FDECL(taking_off, (const char *));
STATIC_DCL boolean FDECL(putting_on, (const char *));
-STATIC_PTR int FDECL(ckunpaid, (struct obj *));
STATIC_PTR int FDECL(ckvalidcat, (struct obj *));
+STATIC_PTR int FDECL(ckunpaid, (struct obj *));
STATIC_PTR char *FDECL(safeq_xprname, (struct obj *));
STATIC_PTR char *FDECL(safeq_shortxprname, (struct obj *));
STATIC_DCL char FDECL(display_pickinv, (const char *, const char *,
*/
static char venom_inv[] = { VENOM_CLASS, 0 }; /* (constant) */
-struct sortloot_item {
- struct obj *obj;
- int indx;
-};
-unsigned sortlootmode = 0;
+/* sortloot() classification; called at most once [per sort] for each object */
+STATIC_OVL void
+loot_classify(sort_item, obj)
+Loot *sort_item;
+struct obj *obj;
+{
+ /* we may eventually make this a settable option to always use
+ with sortloot instead of only when the 'sortpack' option isn't
+ set; it is similar to sortpack's inv_order but items most
+ likely to be picked up are moved to the front */
+ static char def_srt_order[MAXOCLASSES] = {
+ COIN_CLASS, AMULET_CLASS, RING_CLASS, WAND_CLASS, POTION_CLASS,
+ SCROLL_CLASS, SPBOOK_CLASS, GEM_CLASS, FOOD_CLASS, TOOL_CLASS,
+ WEAPON_CLASS, ARMOR_CLASS, ROCK_CLASS, BALL_CLASS, CHAIN_CLASS, 0,
+ };
+ static char armcat[8];
+ const char *classorder;
+ char *p;
+ int k, otyp = obj->otyp, oclass = obj->oclass;
+ boolean seen, discovered = objects[otyp].oc_name_known ? TRUE : FALSE;
+
+ /*
+ * For the value types assigned by this classification, sortloot()
+ * will put lower valued ones before higher valued ones.
+ */
+ if (!Blind)
+ obj->dknown = 1; /* xname(obj) does this; we want it sooner */
+ seen = obj->dknown ? TRUE : FALSE,
+ /* class order */
+ classorder = flags.sortpack ? flags.inv_order : def_srt_order;
+ p = index(classorder, oclass);
+ if (p)
+ k = 1 + (int) (p - classorder);
+ else
+ k = 1 + (int) strlen(classorder) + (oclass != VENOM_CLASS);
+ sort_item->orderclass = (xchar) k;
+ /* subclass designation; only a few classes have subclasses
+ and the non-armor ones we use are fairly arbitrary */
+ switch (oclass) {
+ case ARMOR_CLASS:
+ if (!armcat[7]) {
+ /* one-time init; we use a different order than the subclass
+ values defined by objclass.h */
+ armcat[ARM_HELM] = 1; /* [2] */
+ armcat[ARM_GLOVES] = 2; /* [3] */
+ armcat[ARM_BOOTS] = 3; /* [4] */
+ armcat[ARM_SHIELD] = 4; /* [1] */
+ armcat[ARM_CLOAK] = 5; /* [5] */
+ armcat[ARM_SHIRT] = 6; /* [6] */
+ armcat[ARM_SUIT] = 7; /* [0] */
+ armcat[7] = 8; /* sanity protection */
+ }
+ k = objects[otyp].oc_armcat;
+ /* oc_armcat overloads oc_subtyp which is an 'schar' so guard
+ against somebody assigning something unexpected to it */
+ if (k < 0 || k >= 7)
+ k = 7;
+ k = armcat[k];
+ break;
+ case WEAPON_CLASS:
+ /* for weapons, group by ammo (arrows, bolts), launcher (bows),
+ missile (darts, boomerangs), stackable (daggers, knives, spears),
+ 'other' (swords, axes, &c), polearms */
+ k = objects[otyp].oc_skill;
+ k = (k < 0) ? ((k >= -P_CROSSBOW && k <= -P_BOW) ? 1 : 3)
+ : ((k >= P_BOW && k <= P_CROSSBOW) ? 2
+ : (k == P_SPEAR || k == P_DAGGER || k == P_KNIFE) ? 4
+ : !is_pole(obj) ? 5 : 6);
+ break;
+ case TOOL_CLASS:
+ if (seen && discovered
+ && (otyp == BAG_OF_TRICKS || otyp == HORN_OF_PLENTY))
+ k = 2; /* known pseudo-container */
+ else if (Is_container(obj))
+ k = 1; /* regular container or unknown bag of tricks */
+ else
+ switch (otyp) {
+ case WOODEN_FLUTE:
+ case MAGIC_FLUTE:
+ case TOOLED_HORN:
+ case FROST_HORN:
+ case FIRE_HORN:
+ case WOODEN_HARP:
+ case MAGIC_HARP:
+ case BUGLE:
+ case LEATHER_DRUM:
+ case DRUM_OF_EARTHQUAKE:
+ case HORN_OF_PLENTY: /* not a musical instrument */
+ k = 3; /* instrument or unknown horn of plenty */
+ break;
+ default:
+ k = 4; /* 'other' tool */
+ break;
+ }
+ break;
+ case FOOD_CLASS:
+ /* [what about separating "partly eaten" within each group?] */
+ switch (otyp) {
+ case SLIME_MOLD:
+ k = 1;
+ break;
+ default:
+ /* [maybe separate one-bite foods from rations and such?] */
+ k = obj->globby ? 6 : 2;
+ break;
+ case TIN:
+ k = 3;
+ break;
+ case EGG:
+ k = 4;
+ break;
+ case CORPSE:
+ k = 5;
+ break;
+ }
+ break;
+ case GEM_CLASS:
+ /*
+ * Normally subclass takes priority over discovery status, but
+ * that would give away information for gems (assuming we'll
+ * group them as valuable gems, next glass, then gray stones,
+ * and finally rocks once they're all fully identified).
+ *
+ * Order:
+ * 1) unseen gems and glass ("gem")
+ * 2) seen but undiscovered gems and glass ("blue gem"),
+ * 3) discovered gems ("sapphire"),
+ * 4) discovered glass ("worthless pieced of blue glass"),
+ * 5) unseen gray stones and rocks ("stone"),
+ * 6) seen but undiscovered gray stones ("gray stone"),
+ * 7) discovered gray stones ("touchstone"),
+ * 8) seen rocks ("rock").
+ */
+ switch (objects[obj->otyp].oc_material) {
+ case GEMSTONE:
+ k = !seen ? 1 : !discovered ? 2 : 3;
+ break;
+ case GLASS:
+ k = !seen ? 1 : !discovered ? 2 : 4;
+ break;
+ default: /* MINERAL */
+ k = !seen ? 5 : (obj->otyp != ROCK) ? (!discovered ? 6 : 7) : 8;
+ break;
+ }
+ break;
+ default:
+ /* other classes don't have subclasses; we assign a nonzero
+ value because sortloot() uses 0 to mean 'not yet classified' */
+ k = 1; /* any non-zero would do */
+ break;
+ }
+ sort_item->subclass = (xchar) k;
+ /* discovery status */
+ k = !seen ? 1 /* unseen */
+ : (discovered || !OBJ_DESCR(objects[otyp])) ? 4
+ : (objects[otyp].oc_uname) ? 3 /* named (partially discovered) */
+ : 2; /* undiscovered */
+ sort_item->disco = (xchar) k;
+}
+
+/* sortloot() formatting routine; for alphabetizing, not shown to user */
+STATIC_OVL char *
+loot_xname(obj)
+struct obj *obj;
+{
+ struct obj saveo;
+ boolean save_debug;
+ char *res, *save_oname;
+
+ /*
+ * Deal with things that xname() includes as a prefix. We don't
+ * want such because they change alphabetical ordering. First,
+ * remember 'obj's current settings.
+ */
+ saveo.odiluted = obj->odiluted;
+ saveo.blessed = obj->blessed, saveo.cursed = obj->cursed;
+ saveo.spe = obj->spe;
+ saveo.owt = obj->owt;
+ save_oname = has_oname(obj) ? ONAME(obj) : 0;
+ save_debug = flags.debug;
+ /* suppress "diluted" for potions and "holy/unholy" for water;
+ sortloot() will deal with them using other criteria than name */
+ if (obj->oclass == POTION_CLASS) {
+ obj->odiluted = 0;
+ if (obj->otyp == POT_WATER)
+ obj->blessed = 0, obj->cursed = 0;
+ }
+ /* make "wet towel" and "moist towel" format as "towel" so that all
+ three group together */
+ if (obj->otyp == TOWEL)
+ obj->spe = 0;
+ /* group "<size> glob of <foo>" by <foo> rather than by <size> */
+ if (obj->globby)
+ obj->owt = 200; /* 200: weight of combined glob from ten creatures
+ (five or fewer is "small", more than fifteen is
+ "large", in between has no prefix) */
+ /* suppress user-assigned name */
+ if (save_oname && !obj->oartifact)
+ ONAME(obj) = 0;
+ /* avoid wizard mode formatting variations */
+ if (wizard) { /* flags.debug */
+ /* paranoia: before toggling off wizard mode, guard against a
+ panic in xname() producing a normal mode panic save file */
+ program_state.something_worth_saving = 0;
+ flags.debug = FALSE;
+ }
+
+ res = cxname_singular(obj);
+
+ if (save_debug) {
+ flags.debug = TRUE;
+ program_state.something_worth_saving = 1;
+ }
+ /* restore the object */
+ if (obj->oclass == POTION_CLASS) {
+ obj->odiluted = saveo.odiluted;
+ if (obj->otyp == POT_WATER)
+ obj->blessed = saveo.blessed, obj->cursed = saveo.cursed;
+ }
+ if (obj->otyp == TOWEL) {
+ obj->spe = saveo.spe;
+ /* give "towel" a suffix that will force wet ones to come first,
+ moist ones next, and dry ones last regardless of whether
+ they've been flagged as having spe known */
+ Strcat(res, is_wet_towel(obj) ? ((obj->spe >= 3) ? "x" : "y") : "z");
+ }
+ if (obj->globby) {
+ obj->owt = saveo.owt;
+ /* we've suppressed the size prefix (above); there normally won't
+ be more than one of a given creature type because they coalesce,
+ but globs with different bless/curse state won't merge so it is
+ feasible to have multiple at the same location; add a suffix to
+ get such sorted by size (small first) */
+ Strcat(res, (obj->owt <= 100) ? "a"
+ : (obj->owt <= 300) ? "b"
+ : (obj->owt <= 500) ? "c"
+ : "d");
+ }
+ if (save_oname && !obj->oartifact)
+ ONAME(obj) = save_oname;
+
+ return res;
+}
+
+/* set by sortloot() for use by sortloot_cmp(); reset by sortloot when done */
+static unsigned sortlootmode = 0;
/* qsort comparison routine for sortloot() */
STATIC_OVL int CFDECLSPEC
struct sortloot_item *sli1 = (struct sortloot_item *) vptr1,
*sli2 = (struct sortloot_item *) vptr2;
struct obj *obj1 = sli1->obj,
- *obj2 = sli2->obj,
- sav1, sav2;
- char *cls1, *cls2, nam1[BUFSZ], nam2[BUFSZ];
+ *obj2 = sli2->obj;
+ char *nam1, *nam2;
int val1, val2, c, namcmp;
- /* order by object class like inventory display */
- if ((sortlootmode & SORTLOOT_PACK) != 0) {
- cls1 = index(flags.inv_order, obj1->oclass);
- cls2 = index(flags.inv_order, obj2->oclass);
- if (cls1 != cls2)
- return (int) (cls1 - cls2);
-
- if ((sortlootmode & SORTLOOT_INVLET) != 0) {
- ; /* skip sub-classes when sorting by packorder+invlet */
-
- /* for armor, group by sub-category */
- } else if (obj1->oclass == ARMOR_CLASS) {
- static int armcat[7 + 1];
-
- if (!armcat[7]) {
- /* one-time init; we want to control the order */
- armcat[ARM_HELM] = 1; /* [2] */
- armcat[ARM_GLOVES] = 2; /* [3] */
- armcat[ARM_BOOTS] = 3; /* [4] */
- armcat[ARM_SHIELD] = 4; /* [1] */
- armcat[ARM_CLOAK] = 5; /* [5] */
- armcat[ARM_SHIRT] = 6; /* [6] */
- armcat[ARM_SUIT] = 7; /* [0] */
- armcat[7] = 8;
- }
- val1 = armcat[objects[obj1->otyp].oc_armcat];
- val2 = armcat[objects[obj2->otyp].oc_armcat];
+ /* order by object class unless we're doing by-invlet without sortpack */
+ if ((sortlootmode & (SORTLOOT_PACK | SORTLOOT_INVLET))
+ != SORTLOOT_INVLET) {
+ /* Classify each object at most once no matter how many
+ comparisons it is involved in. */
+ if (!sli1->orderclass)
+ loot_classify(sli1, obj1);
+ if (!sli2->orderclass)
+ loot_classify(sli2, obj2);
+
+ /* Sort by class. */
+ val1 = sli1->orderclass;
+ val2 = sli2->orderclass;
+ if (val1 != val2)
+ return (int) (val1 - val2);
+
+ /* skip sub-classes when ordering by sortpack+invlet */
+ if ((sortlootmode & SORTLOOT_INVLET) == 0) {
+ /* Class matches; sort by subclass. */
+ val1 = sli1->subclass;
+ val2 = sli2->subclass;
if (val1 != val2)
return val1 - val2;
- /* for weapons, group by ammo (arrows, bolts), launcher (bows),
- missile (dart, boomerang), stackable (daggers, knives, spears),
- 'other' (swords, axes, &c), polearm */
- } else if (obj1->oclass == WEAPON_CLASS) {
- val1 = objects[obj1->otyp].oc_skill;
- val1 = (val1 < 0)
- ? (val1 >= -P_CROSSBOW && val1 <= -P_BOW) ? 1 : 3
- : (val1 >= P_BOW && val1 <= P_CROSSBOW) ? 2
- : (val1 == P_SPEAR || val1 == P_DAGGER
- || val1 == P_KNIFE) ? 4 : !is_pole(obj1) ? 5 : 6;
- val2 = objects[obj2->otyp].oc_skill;
- val2 = (val2 < 0)
- ? (val2 >= -P_CROSSBOW && val2 <= -P_BOW) ? 1 : 3
- : (val2 >= P_BOW && val2 <= P_CROSSBOW) ? 2
- : (val2 == P_SPEAR || val2 == P_DAGGER
- || val2 == P_KNIFE) ? 4 : !is_pole(obj2) ? 5 : 6;
+ /* Class and subclass match; sort by discovery status:
+ * first unseen, then seen but not named or discovered,
+ * then named, lastly discovered.
+ * 1) potion
+ * 2) pink potion
+ * 3) dark green potion called confusion
+ * 4) potion of healing
+ * Multiple entries within each group will be put into
+ * alphabetical order below.
+ */
+ val1 = sli1->disco;
+ val2 = sli2->disco;
if (val1 != val2)
return val1 - val2;
}
/*
* Sort object names in lexicographical order, ignoring quantity.
+ *
+ * Each obj gets formatted at most once (per sort) no matter how many
+ * comparisons it gets subjected to.
*/
- /* Force diluted potions to come out after undiluted of same type;
- obj->odiluted overloads obj->oeroded. */
- sav1.odiluted = obj1->odiluted;
- sav2.odiluted = obj2->odiluted;
- if (obj1->oclass == POTION_CLASS)
- obj1->odiluted = 0;
- if (obj1->oclass == POTION_CLASS)
- obj2->odiluted = 0;
- /* Force holy and unholy water to sort adjacent to water rather
- than among 'h's and 'u's. BUCX order will keep them distinct. */
- Strcpy(nam1, cxname_singular(obj1));
- if (obj1->otyp == POT_WATER && obj1->bknown
- && (obj1->blessed || obj1->cursed))
- (void) strsubst(nam1, obj1->blessed ? "holy " : "unholy ", "");
- Strcpy(nam2, cxname_singular(obj2));
- if (obj2->otyp == POT_WATER && obj2->bknown
- && (obj2->blessed || obj2->cursed))
- (void) strsubst(nam2, obj2->blessed ? "holy " : "unholy ", "");
- obj1->odiluted = sav1.odiluted;
- obj2->odiluted = sav2.odiluted;
-
+ nam1 = sli1->str;
+ if (!nam1)
+ nam1 = sli1->str = dupstr(loot_xname(obj1));
+ nam2 = sli2->str;
+ if (!nam2)
+ nam2 = sli2->str = dupstr(loot_xname(obj2));
if ((namcmp = strcmpi(nam1, nam2)) != 0)
return namcmp;
return val2 - val1; /* bigger is better */
}
-tiebreak:
+ tiebreak:
/* They're identical, as far as we're concerned. We want
to force a deterministic order, and do so by producing a
stable sort: maintain the original order of equal items. */
return (sli1->indx - sli2->indx);
}
+/*
+ * sortloot() - the story so far...
+ *
+ * The original implementation constructed and returned an array
+ * of pointers to objects in the requested order. Callers had to
+ * count the number of objects, allocate the array, pass one
+ * object at a time to the routine which populates it, traverse
+ * the objects via stepping through the array, then free the
+ * array. The ordering process used a basic insertion sort which
+ * is fine for short lists but inefficient for long ones.
+ *
+ * 3.6.0 (and continuing with 3.6.1) changed all that so that
+ * sortloot was self-contained as far as callers were concerned.
+ * It reordered the linked list into the requested order and then
+ * normal list traversal was used to process it. It also switched
+ * to qsort() on the assumption that the C library implementation
+ * put some effort into sorting efficiently. It also checked
+ * whether the list was already sorted as it got ready to do the
+ * sorting, so re-examining inventory or a pile of objects without
+ * having changed anything would gobble up less CPU than a full
+ * sort. But it had at least two problems (aside from the ordinary
+ * complement of bugs):
+ * 1) some players wanted to get the original order back when they
+ * changed the 'sortloot' option back to 'none', but the list
+ * reordering made that infeasible;
+ * 2) object identification giving the 'ID whole pack' result
+ * would call makeknown() on each newly ID'd object, that would
+ * call update_inventory() to update the persistent inventory
+ * window if one existed, the interface would call the inventory
+ * display routine which would call sortloot() which might change
+ * the order of the list being traversed by the identify code,
+ * possibly skipping the ID of some objects. That could have been
+ * avoided by suppressing 'perm_invent' during identification
+ * (fragile) or by avoiding sortloot() during inventory display
+ * (more robust).
+ *
+ * As of 3.6.2: revert to the temporary array of ordered obj pointers
+ * but have sortloot() do the counting and allocation. Callers
+ * need to use array traversal instead of linked list traversal
+ * and need to free the temporary array when done. And the
+ * array contains 'struct sortloot_item' (aka 'Loot') entries
+ * instead of simple 'struct obj *' entries.
+ */
+Loot *
+sortloot(olist, mode, by_nexthere, filterfunc)
+struct obj **olist; /* previous version might have changed *olist, we don't */
+unsigned mode; /* flags for sortloot_cmp() */
+boolean by_nexthere; /* T: traverse via obj->nexthere, F: via obj->nobj */
+boolean FDECL((*filterfunc), (OBJ_P));
+{
+ Loot *sliarray;
+ struct obj *o;
+ unsigned n, i;
+ boolean augment_filter;
+
+ for (n = 0, o = *olist; o; o = by_nexthere ? o->nexthere : o->nobj)
+ ++n;
+ /* note: if there is a filter function, this might overallocate */
+ sliarray = (Loot *) alloc((n + 1) * sizeof *sliarray);
+
+ /* the 'keep cockatrice corpses' flag is overloaded with sort mode */
+ augment_filter = (mode & SORTLOOT_PETRIFY) ? TRUE : FALSE;
+ mode &= ~SORTLOOT_PETRIFY; /* remove flag, leaving mode */
+ /* populate aliarray[0..n-1] */
+ for (i = 0, o = *olist; o; o = by_nexthere ? o->nexthere : o->nobj) {
+ if (filterfunc && !(*filterfunc)(o)
+ /* caller may be asking us to override filterfunc (in order
+ to do a cockatrice corpse touch check during pickup even
+ if/when the filter rejects food class) */
+ && (!augment_filter || o->otyp != CORPSE
+ || !touch_petrifies(&mons[o->corpsenm])))
+ continue;
+ sliarray[i].obj = o, sliarray[i].indx = (int) i;
+ sliarray[i].str = (char *) 0;
+ sliarray[i].orderclass = sliarray[i].subclass = sliarray[i].disco = 0;
+ ++i;
+ }
+ n = i;
+ /* add a terminator so that we don't have to pass 'n' back to caller */
+ sliarray[n].obj = (struct obj *) 0, sliarray[n].indx = -1;
+ sliarray[n].str = (char *) 0;
+ sliarray[n].orderclass = sliarray[n].subclass = sliarray[n].disco = 0;
+
+ /* do the sort; if no sorting is requested, we'll just return
+ a sortloot_item array reflecting the current ordering */
+ if (mode && n > 1) {
+ sortlootmode = mode; /* extra input for sortloot_cmp() */
+ qsort((genericptr_t) sliarray, n, sizeof *sliarray, sortloot_cmp);
+ sortlootmode = 0; /* reset static mode flags */
+ /* if sortloot_cmp formatted any objects, discard their strings now */
+ for (i = 0; i < n; ++i)
+ if (sliarray[i].str)
+ free((genericptr_t) sliarray[i].str), sliarray[i].str = 0;
+ }
+ return sliarray;
+}
+
+/* sortloot() callers should use this to free up memory it allocates */
+void
+unsortloot(loot_array_p)
+Loot **loot_array_p;
+{
+ if (*loot_array_p)
+ free((genericptr_t) *loot_array_p), *loot_array_p = (Loot *) 0;
+}
+
+#if 0 /* 3.6.0 'revamp' */
void
sortloot(olist, mode, by_nexthere)
struct obj **olist;
}
sortlootmode = 0;
}
+#endif /*0*/
void
assigninvlet(otmp)
otmp->age = ((otmp->age * otmp->quan) + (obj->age * obj->quan))
/ (otmp->quan + obj->quan);
- otmp->quan += obj->quan;
+ if (!otmp->globby)
+ otmp->quan += obj->quan;
/* temporary special case for gold objects!!!! */
if (otmp->oclass == COIN_CLASS)
otmp->owt = weight(otmp), otmp->bknown = 0;
if (is_mines_prize(obj)) {
u.uachieve.mines_luckstone = 1;
obj->record_achieve_special = NON_PM;
+ obj->nomerge = 0;
} else if (is_soko_prize(obj)) {
u.uachieve.finish_sokoban = 1;
obj->record_achieve_special = NON_PM;
+ obj->nomerge = 0;
}
}
&& obj->oartifact != ART_MJOLLNIR
&& (throwing_weapon(obj) || is_ammo(obj)))
setuqwep(obj);
-added:
+ added:
addinv_core2(obj);
carry_obj_effects(obj); /* carrying affects the obj */
update_inventory();
}
}
if (Fumbling) {
- if (drop_fmt)
- pline(drop_fmt, drop_arg);
- dropy(obj);
+ obj->nomerge = 1;
+ obj = addinv(obj); /* dropping expects obj to be in invent */
+ goto drop_it;
} else {
long oquan = obj->quan;
int prev_encumbr = near_capacity(); /* before addinv() */
obj = addinv(obj);
if (inv_cnt(FALSE) > 52 || ((obj->otyp != LOADSTONE || !obj->cursed)
&& near_capacity() > prev_encumbr)) {
- if (drop_fmt)
- pline(drop_fmt, drop_arg);
/* undo any merge which took place */
if (obj->quan > oquan)
obj = splitobj(obj, oquan);
- dropx(obj);
+ goto drop_it;
} else {
if (flags.autoquiver && !uquiver && !obj->owornmask
&& (is_missile(obj) || ammo_and_launcher(obj, uwep)
}
}
return obj;
+
+ drop_it:
+ if (drop_fmt)
+ pline(drop_fmt, drop_arg);
+ obj->nomerge = 0;
+ if (can_reach_floor(TRUE)) {
+ dropx(obj);
+ } else {
+ freeinv(obj);
+ hitfloor(obj, FALSE);
+ }
+ return (struct obj *) 0; /* might be gone */
}
/* useup() all of an item regardless of its quantity */
* http://concord.wikia.com/wiki/List_of_Fictional_Currencies
*/
static const char *const currencies[] = {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
"Altarian Dollar", /* The Hitchhiker's Guide to the Galaxy */
"Ankh-Morpork Dollar", /* Discworld */
"auric", /* The Domination of Draka */
{
const char *res;
-#if 0 /*JP*/
+#if 0 /*JP:T*/
res = Hallucination ? currencies[rn2(SIZE(currencies))] : "zorkmid";
if (amount != 1L)
res = makeplural(res);
register const char *let, *word;
{
register struct obj *otmp;
- register char ilet;
+ register char ilet = 0;
char buf[BUFSZ], qbuf[QBUFSZ];
char lets[BUFSZ], altlets[BUFSZ], *ap;
register int foo = 0;
boolean msggiven = FALSE;
boolean oneloop = FALSE;
long dummymask;
+ Loot *sortedinvent, *srtinv;
#if 1 /*JP*/
const char *jword;
if (!flags.invlet_constant)
reassign();
- else
- /* in case invent is in packorder, force it to be in invlet
- order before collecing candidate inventory letters;
- if player responds with '?' or '*' it will be changed
- back by display_pickinv(), but by then we'll have 'lets'
- and so won't have to re-sort in the for(;;) loop below */
- sortloot(&invent, SORTLOOT_INVLET, FALSE);
- for (otmp = invent; otmp; otmp = otmp->nobj) {
+ /* force invent to be in invlet order before collecting candidate
+ inventory letters */
+ sortedinvent = sortloot(&invent, SORTLOOT_INVLET, FALSE,
+ (boolean FDECL((*), (OBJ_P))) 0);
+
+ for (srtinv = sortedinvent; (otmp = srtinv->obj) != 0; ++srtinv) {
if (&bp[foo] == &buf[sizeof buf - 1]
|| ap == &altlets[sizeof altlets - 1]) {
/* we must have a huge number of NOINVSYM items somehow */
allowall = usegold = TRUE;
}
}
+ unsortloot(&sortedinvent);
bp[foo] = 0;
if (foo == 0 && bp > buf && bp[-1] == ' ')
/*JP
You("don't have anything %sto %s.", foox ? "else " : "", word);
*/
- You("%s%s\82à\82Ì\82ð\8e\9d\82Á\82Ä\82¢\82È\82¢\81D", foox ? "\91¼\82É" : "", jconj(jword, "\82ê\82é"));
+ You("%s%s\82à\82Ì\82ð\8e\9d\82Á\82Ä\82¢\82È\82¢\81D", foox ? "\91¼\82É" : "", jcan(jword));
return (struct obj *) 0;
} else if (!strcmp(word, "write on")) { /* ugly check for magic marker */
/* we wanted all scrolls and books in altlets[], but that came with
if (!allowcnt) {
/*JP
- pline("No count allowed with this command.");
+ pline("No count allowed with this command.");
*/
- pline("\82±\82Ì\83R\83}\83\93\83h\82É\90\94\8e\9a\82Í\82Â\82©\82¦\82È\82¢\81D");
+ pline("\82±\82Ì\83R\83}\83\93\83h\82É\90\94\8e\9a\82Í\82Â\82©\82¦\82È\82¢\81D");
continue;
}
ilet = get_count(NULL, ilet, LARGEST_INT, &tmpcnt, TRUE);
You("\89½\82©\82ð%s\82Ó\82è\82ð\82µ\82½\81D", bp);
#endif
}
- return (allownone ? &zeroobj : (struct obj *) 0);
+ return (allownone ? (struct obj *) &zeroobj : (struct obj *) 0);
}
-redo_menu:
+ redo_menu:
/* since gold is now kept in inventory, we need to do processing for
select-from-invent before checking whether gold has been picked */
if (ilet == '?' || ilet == '*') {
menuquery[0] = qbuf[0] = '\0';
if (iflags.force_invmenu)
+/*JP
Sprintf(menuquery, "What do you want to %s?", word);
+*/
+ Sprintf(menuquery, "%s%s%s\82©\81H", what, joshi, jpolite(jword));
if (!strcmp(word, "grease"))
- Sprintf(qbuf, "your %s", makeplural(body_part(FINGER)));
+/*JP
+ Sprintf(qbuf, "your %s", fingers_or_gloves(FALSE));
+*/
+ Sprintf(qbuf, "\82 \82È\82½\82Ì%s", fingers_or_gloves(FALSE));
else if (!strcmp(word, "write with"))
+/*JP
Sprintf(qbuf, "your %s", body_part(FINGERTIP));
+*/
+ Sprintf(qbuf, "\82 \82È\82½\82Ì%s", body_part(FINGERTIP));
else if (!strcmp(word, "wield"))
+#if 0 /*JP:T*/
Sprintf(qbuf, "your %s %s%s", uarmg ? "gloved" : "bare",
makeplural(body_part(HAND)),
!uwep ? " (wielded)" : "");
+#else
+ Sprintf(qbuf, "\89½\82à\8eè\82É\82µ\82È\82¢%s",
+ !uwep ? "(\8c»\8dÝ)" : "");
+#endif
else if (!strcmp(word, "ready"))
+#if 0 /*JP*/
Sprintf(qbuf, "empty quiver%s",
!uquiver ? " (nothing readied)" : "");
+#else
+ Sprintf(qbuf, "\8bó\82Ì\96î\93\9b%s",
+ !uquiver ? " (\89½\82à\8f\80\94õ\82µ\82Ä\82¢\82È\82¢)" : "");
+#endif
if (ilet == '?' && !*lets && *altlets)
allowed_choices = altlets;
if (!ilet)
continue;
if (ilet == HANDS_SYM)
- return &zeroobj;
+ return (struct obj *) &zeroobj; /* cast away 'const' */
if (ilet == '\033') {
if (flags.verbose)
pline1(Never_mind);
/*JP
You("don't have that many! You have only %ld.", otmp->quan);
*/
- pline("\82»\82ñ\82È\82É\82½\82\82³\82ñ\82Í\8e\9d\82Á\82Ä\82¢\82È\82¢\81I\82¹\82¢\82º\82¢%ld\8cÂ\82Á\82Ä\82Æ\82±\82¾\81D", otmp->quan);
+ pline("\82»\82ñ\82È\82É\82½\82\82³\82ñ\82Í\8e\9d\82Á\82Ä\82¢\82È\82¢\81I\82¹\82¢\82º\82¢%ld%s\82Á\82Ä\82Æ\82±\82¾\81D", otmp->quan, numeral(otmp));
if (in_doagain)
return (struct obj *) 0;
continue;
is_worn(otmp)
struct obj *otmp;
{
- return (otmp->owornmask & (W_ARMOR | W_ACCESSORY | W_SADDLE | W_WEAPON))
+ return (otmp->owornmask & (W_ARMOR | W_ACCESSORY | W_SADDLE | W_WEAPONS))
? TRUE
: FALSE;
}
/* Interactive version of getobj - used for Drop, Identify, and Takeoff (A).
Return the number of times fn was called successfully.
If combo is TRUE, we just use this to get a category list. */
-/*JP CHECK: 3.6.0 \82Ì\8cÄ\82Ñ\8fo\82µ\8c³
-do.c:962: || (result = ggetobj("drop", drop, 0, FALSE, (unsigned *) 0)) < -1)
-do.c:1009: i = ggetobj("drop", drop, 0, TRUE, &ggoresults);
-do_wear.c:2955: || (result = ggetobj("take off", select_off, 0, FALSE,
-do_wear.c:3007: if (ggetobj("take off", select_off, 0, TRUE, (unsigned *) 0) == -2)
-invent.c:2014: n = ggetobj("identify", identify, id_limit, FALSE,
+/*JP CHECK: 3.6.6 \82Ì\8cÄ\82Ñ\8fo\82µ\8c³
+do.c:1068: || (result = ggetobj("drop", drop, 0, FALSE, (unsigned *) 0)) < -1)
+do.c:1117: i = ggetobj("drop", drop, 0, TRUE, &ggoresults);
+do_wear.c:3153: || (result = ggetobj("take off", select_off, 0, FALSE,
+do_wear.c:3207: i = ggetobj("take off", select_off, 0, TRUE, &ggofeedback);
+invent.c:2564: n = ggetobj("identify", identify, id_limit, FALSE,
*/
int
ggetobj(word, fn, mx, combo, resultflags)
ilets[iletct] = '\0';
for (;;) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
Sprintf(qbuf, "What kinds of thing do you want to %s? [%s]",
word, ilets);
#else
* If allflag then no questions are asked. Mx gives the max number
* of objects to be treated. Return the number of objects treated.
*/
-/*JP CHECK: 3.6.0 \82Å\82Ì\8cÄ\82Ñ\8fo\82µ\8c³
-invent.c:1886: int cnt = askchain(&invent, olets, allflag, fn, ckfn, mx, word);
-pickup.c:3145: if (askchain(objlist, (one_by_one ? (char *) 0 : selection), allflag,
+/*JP CHECK: 3.6.2 \82Å\82Ì\8cÄ\82Ñ\8fo\82µ\8c³
+invent.c:2228: int cnt = askchain(&invent, olets, allflag, fn, ckfn, mx, word);
+pickup.c:3208: if (askchain(objlist, (one_by_one ? (char *) 0 : selection), allflag,
word\82É\82Í\93®\8e\8c\82ª\89p\8cê\82Å\93ü\82é\81B
*/
int
askchain(objchn, olets, allflag, fn, ckfn, mx, word)
-struct obj **objchn;
+struct obj **objchn; /* *objchn might change */
int allflag, mx;
const char *olets, *word; /* olets is an Obj Class char array */
int FDECL((*fn), (OBJ_P)), FDECL((*ckfn), (OBJ_P));
{
struct obj *otmp, *otmpo;
register char sym, ilet;
- register int cnt = 0, dud = 0, tmp;
+ int cnt = 0, dud = 0, tmp;
boolean takeoff, nodot, ident, take_out, put_in, first, ininv, bycat;
char qbuf[QBUFSZ], qpfx[QBUFSZ];
+ Loot *sortedchn = 0;
takeoff = taking_off(word);
ident = !strcmp(word, "identify");
/* someday maybe we'll sort by 'olets' too (temporarily replace
flags.packorder and pass SORTLOOT_PACK), but not yet... */
- sortloot(objchn, SORTLOOT_INVLET, FALSE);
+ sortedchn = sortloot(objchn, SORTLOOT_INVLET, FALSE,
+ (boolean FDECL((*), (OBJ_P))) 0);
first = TRUE;
/*
* For example, if a person specifies =/ then first all rings
* will be asked about followed by all wands. -dgk
*/
-nextclass:
+ nextclass:
ilet = 'a' - 1;
if (*objchn && (*objchn)->oclass == COIN_CLASS)
ilet--; /* extra iteration */
* track of which list elements have already been processed.
*/
bypass_objlist(*objchn, FALSE); /* clear chain's bypass bits */
- while ((otmp = nxt_unbypassed_obj(*objchn)) != 0) {
+ while ((otmp = nxt_unbypassed_loot(sortedchn, *objchn)) != 0) {
if (ilet == 'z')
ilet = 'A';
else if (ilet == 'Z')
Sprintf(qpfx, "%s: ", word), *qpfx = highc(*qpfx);
first = FALSE;
}
-#if 0 /*JP*/
+#if 0 /*JP:T*/
(void) safe_qbuf(qbuf, qpfx, "?", otmp,
ininv ? safeq_xprname : doname,
ininv ? safeq_shortxprname : ansimpleoname,
}
if (olets && *olets && *++olets)
goto nextclass;
+
if (!takeoff && (dud || cnt))
/*JP
pline("That was all.");
pline("No applicable objects.");
*/
pline("\82»\82ê\82Í\82Å\82«\82È\82¢\81D");
-ret:
+ ret:
+ unsortloot(&sortedchn);
bypass_objlist(*objchn, FALSE);
return cnt;
}
}
}
}
+/* count the unidentified items */
+int
+count_unidentified(objchn)
+struct obj *objchn;
+{
+ int unid_cnt = 0;
+ struct obj *obj;
+
+ for (obj = objchn; obj; obj = obj->nobj)
+ if (not_fully_identified(obj))
+ ++unid_cnt;
+ return unid_cnt;
+}
/* dialog with user to identify a given number of items; 0 means all */
void
int id_limit;
boolean learning_id; /* true if we just read unknown identify scroll */
{
- struct obj *obj, *the_obj;
- int n, unid_cnt;
-
- unid_cnt = 0;
- the_obj = 0; /* if unid_cnt ends up 1, this will be it */
- for (obj = invent; obj; obj = obj->nobj)
- if (not_fully_identified(obj))
- ++unid_cnt, the_obj = obj;
+ struct obj *obj;
+ int n, unid_cnt = count_unidentified(invent);
if (!unid_cnt) {
#if 0 /*JP:T*/
#endif
} else if (!id_limit || id_limit >= unid_cnt) {
/* identify everything */
- if (unid_cnt == 1) {
- (void) identify(the_obj);
- } else {
- /* TODO: use fully_identify_obj and cornline/menu/whatever here
- */
- for (obj = invent; obj; obj = obj->nobj)
- if (not_fully_identified(obj))
- (void) identify(obj);
+ /* TODO: use fully_identify_obj and cornline/menu/whatever here */
+ for (obj = invent; obj; obj = obj->nobj) {
+ if (not_fully_identified(obj)) {
+ (void) identify(obj);
+ if (unid_cnt == 1)
+ break;
+ }
}
} else {
/* identify up to `id_limit' items */
update_inventory();
}
+/* persistent inventory window is maintained by interface code;
+ 'update_inventory' used to be a macro for
+ (*windowprocs.win_update_inventory) but the restore hackery
+ was getting out of hand; this is now a central call point */
+void
+update_inventory()
+{
+ if (restoring)
+ return;
+
+ /*
+ * Ought to check (windowprocs.wincap2 & WC2_PERM_INVENT) here....
+ *
+ * We currently don't skip this call when iflags.perm_invent is False
+ * because curses uses that to disable a previous perm_invent window
+ * (after toggle via 'O'; perhaps the options code should handle that).
+ */
+ (*windowprocs.win_update_inventory)();
+}
+
/* should of course only be called for things in invent */
STATIC_OVL char
obj_to_let(obj)
*/
if (cost != 0 || let == '*') {
/* if dot is true, we're doing Iu, otherwise Ix */
+#if 0 /*JP:T*/
Sprintf(li,
-#if 0 /*JP*/
iflags.menu_tab_sep ? "%c - %s\t%6ld %s"
: "%c - %-45s %6ld %s",
+ (dot && use_invlet ? obj->invlet : let),
+ (txt ? txt : doname(obj)), cost, currency(cost));
#else
+ Sprintf(li,
iflags.menu_tab_sep ? "%c - %s\t%6ld%s"
: "%c - %-45s %6ld%s",
-#endif
(dot && use_invlet ? obj->invlet : let),
(txt ? txt : doname(obj)), cost, currency(cost));
+#endif
} else {
/* ordinary inventory display or pickup message */
Sprintf(li, "%c - %s%s", (use_invlet ? obj->invlet : let),
static const char not_carrying_anything[] = "Not carrying anything";
*/
static const char not_carrying_anything[] = "\89½\82à\8e\9d\82Á\82Ä\82¢\82È\82¢";
- struct obj *otmp;
+ struct obj *otmp, wizid_fakeobj;
char ilet, ret;
char *invlet = flags.inv_order;
int n, classcount;
winid win; /* windows being used */
anything any;
menu_item *selected;
+ unsigned sortflags;
+ Loot *sortedinvent, *srtinv;
+ boolean wizid = (wizard && iflags.override_ID), gotsomething = FALSE;
if (lets && !*lets)
lets = 0; /* simplify tests: (lets) instead of (lets && *lets) */
- if (flags.perm_invent && (lets || xtra_choice)) {
+ if (iflags.perm_invent && (lets || xtra_choice || wizid)) {
/* partial inventory in perm_invent setting; don't operate on
full inventory window, use an alternate one instead; create
the first time needed and keep it for re-use as needed later */
* more than 1; for the last one, we don't need a precise number.
* For perm_invent update we force 'more than 1'.
*/
- n = (flags.perm_invent && !lets && !want_reply) ? 2
+ n = (iflags.perm_invent && !lets && !want_reply) ? 2
: lets ? (int) strlen(lets)
: !invent ? 0 : !invent->nobj ? 1 : 2;
/* for xtra_choice, there's another 'item' not included in initial 'n';
return ret;
}
- sortloot(&invent,
- (((flags.sortloot == 'f') ? SORTLOOT_LOOT : SORTLOOT_INVLET)
- | (flags.sortpack ? SORTLOOT_PACK : 0)),
- FALSE);
+ sortflags = (flags.sortloot == 'f') ? SORTLOOT_LOOT : SORTLOOT_INVLET;
+ if (flags.sortpack)
+ sortflags |= SORTLOOT_PACK;
+ sortedinvent = sortloot(&invent, sortflags, FALSE,
+ (boolean FDECL((*), (OBJ_P))) 0);
start_menu(win);
any = zeroany;
if (wizard && iflags.override_ID) {
+ int unid_cnt;
char prompt[QBUFSZ];
- any.a_char = -1;
- /* wiz_identify stuffed the wiz_identify command character (^I)
- into iflags.override_ID for our use as an accelerator */
- Sprintf(prompt, "Debug Identify (%s to permanently identify)",
- visctrl(iflags.override_ID));
- add_menu(win, NO_GLYPH, &any, '_', iflags.override_ID, ATR_NONE,
- prompt, MENU_UNSELECTED);
- } else if (xtra_choice) {
+ unid_cnt = count_unidentified(invent);
+ Sprintf(prompt, "Debug Identify"); /* 'title' rather than 'prompt' */
+ if (unid_cnt)
+ Sprintf(eos(prompt),
+ " -- unidentified or partially identified item%s",
+ plur(unid_cnt));
+ add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, prompt, MENU_UNSELECTED);
+ if (!unid_cnt) {
+ add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE,
+ "(all items are permanently identified already)",
+ MENU_UNSELECTED);
+ gotsomething = TRUE;
+ } else {
+ any.a_obj = &wizid_fakeobj;
+ Sprintf(prompt, "select %s to permanently identify",
+ (unid_cnt == 1) ? "it": "any or all of them");
+ /* wiz_identify stuffed the wiz_identify command character (^I)
+ into iflags.override_ID for our use as an accelerator;
+ it could be ambiguous if player has assigned a letter to
+ the #wizidentify command, so include it as a group accelator
+ but use '_' as the primary selector */
+ if (unid_cnt > 1)
+ Sprintf(eos(prompt), " (%s for all)",
+ visctrl(iflags.override_ID));
+ add_menu(win, NO_GLYPH, &any, '_', iflags.override_ID, ATR_NONE,
+ prompt, MENU_UNSELECTED);
+ gotsomething = TRUE;
+ }
+ } else if (xtra_choice) {
/* wizard override ID and xtra_choice are mutually exclusive */
if (flags.sortpack)
add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
any.a_char = HANDS_SYM; /* '-' */
add_menu(win, NO_GLYPH, &any, HANDS_SYM, 0, ATR_NONE,
xtra_choice, MENU_UNSELECTED);
+ gotsomething = TRUE;
}
-nextclass:
+ nextclass:
classcount = 0;
- for (otmp = invent; otmp; otmp = otmp->nobj) {
+ for (srtinv = sortedinvent; (otmp = srtinv->obj) != 0; ++srtinv) {
if (lets && !index(lets, otmp->invlet))
continue;
if (!flags.sortpack || otmp->oclass == *invlet) {
+ if (wizid && !not_fully_identified(otmp))
+ continue;
any = zeroany; /* all bits zero */
ilet = otmp->invlet;
if (flags.sortpack && !classcount) {
MENU_UNSELECTED);
classcount++;
}
- any.a_char = ilet;
- add_menu(win, obj_to_glyph(otmp), &any, ilet, 0, ATR_NONE,
- doname(otmp), MENU_UNSELECTED);
+ if (wizid)
+ any.a_obj = otmp;
+ else
+ any.a_char = ilet;
+ add_menu(win, obj_to_glyph(otmp, rn2_on_display_rng), &any, ilet,
+ wizid ? def_oc_syms[(int) otmp->oclass].sym : 0,
+ ATR_NONE, doname(otmp), MENU_UNSELECTED);
+ gotsomething = TRUE;
}
}
if (flags.sortpack) {
}
if (iflags.force_invmenu && lets && want_reply) {
any = zeroany;
-#if 0 /*JP*/
+#if 0 /*JP:T*/
add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
"Special", MENU_UNSELECTED);
#else
"\93Á\8eê", MENU_UNSELECTED);
#endif
any.a_char = '*';
-#if 0 /*JP*/
+#if 0 /*JP:T*/
add_menu(win, NO_GLYPH, &any, '*', 0, ATR_NONE,
"(list everything)", MENU_UNSELECTED);
#else
add_menu(win, NO_GLYPH, &any, '*', 0, ATR_NONE,
"(\91S\82Ä\82Ì\88ê\97\97)", MENU_UNSELECTED);
#endif
+ gotsomething = TRUE;
}
+ unsortloot(&sortedinvent);
/* for permanent inventory where we intend to show everything but
nothing has been listed (because there isn't anyhing to list;
- recognized via any.a_char still being zero; the n==0 case above
- gets skipped for perm_invent), put something into the menu */
- if (flags.perm_invent && !lets && !any.a_char) {
+ the n==0 case above gets skipped for perm_invent), put something
+ into the menu */
+ if (iflags.perm_invent && !lets && !gotsomething) {
any = zeroany;
add_menu(win, NO_GLYPH, &any, 0, 0, 0,
not_carrying_anything, MENU_UNSELECTED);
}
end_menu(win, query && *query ? query : (char *) 0);
- n = select_menu(win, want_reply ? PICK_ONE : PICK_NONE, &selected);
+ n = select_menu(win,
+ wizid ? PICK_ANY : want_reply ? PICK_ONE : PICK_NONE,
+ &selected);
if (n > 0) {
- ret = selected[0].item.a_char;
- if (out_cnt)
- *out_cnt = selected[0].count;
+ if (wizid) {
+ int i;
+
+ /* identifying items will update perm_invent, calling this
+ routine recursively, and we don't want the nested call
+ to filter on unID'd items */
+ iflags.override_ID = 0;
+ ret = '\0';
+ for (i = 0; i < n; ++i) {
+ otmp = selected[i].item.a_obj;
+ if (otmp == &wizid_fakeobj) {
+ identify_pack(0, FALSE);
+ } else {
+ if (not_fully_identified(otmp))
+ (void) identify(otmp);
+ }
+ }
+ } else {
+ ret = selected[0].item.a_char;
+ if (out_cnt)
+ *out_cnt = selected[0].count;
+ }
free((genericptr_t) selected);
} else
ret = !n ? '\0' : '\033'; /* cancelled */
classcount++;
}
any.a_char = ilet;
- add_menu(win, obj_to_glyph(otmp), &any, ilet, 0, ATR_NONE,
+ add_menu(win, obj_to_glyph(otmp, rn2_on_display_rng),
+ &any, ilet, 0, ATR_NONE,
doname(otmp), MENU_UNSELECTED);
}
}
}
}
+/* count everything inside a container, or just shop-owned items inside */
long
-count_contents(container, nested, quantity, everything)
+count_contents(container, nested, quantity, everything, newdrop)
struct obj *container;
boolean nested, /* include contents of any nested containers */
quantity, /* count all vs count separate stacks */
- everything; /* all objects vs only unpaid objects */
+ everything, /* all objects vs only unpaid objects */
+ newdrop; /* on floor, but hero-owned items haven't been marked
+ * no_charge yet and shop-owned items are still marked
+ * unpaid -- used when asking the player whether to sell */
{
- struct obj *otmp;
+ struct obj *otmp, *topc;
+ boolean shoppy = FALSE;
long count = 0L;
+ if (!everything && !newdrop) {
+ xchar x, y;
+
+ for (topc = container; topc->where == OBJ_CONTAINED;
+ topc = topc->ocontainer)
+ continue;
+ if (topc->where == OBJ_FLOOR && get_obj_location(topc, &x, &y, 0))
+ shoppy = costly_spot(x, y);
+ }
for (otmp = container->cobj; otmp; otmp = otmp->nobj) {
if (nested && Has_contents(otmp))
- count += count_contents(otmp, nested, quantity, everything);
- if (everything || otmp->unpaid)
+ count += count_contents(otmp, nested, quantity, everything,
+ newdrop);
+ if (everything || otmp->unpaid || (shoppy && !otmp->no_charge))
count += quantity ? otmp->quan : 1L;
}
return count;
char contbuf[BUFSZ];
/* Shopkeeper knows what to charge for contents */
+/*JP
Sprintf(contbuf, "%s contents", s_suffix(xname(otmp)));
+*/
+ Sprintf(contbuf, "%s\82Ì\92\86\90g", xname(otmp));
putstr(win, 0,
xprname((struct obj *) 0, contbuf, CONTAINED_SYM,
TRUE, contcost, 0L));
}
putstr(win, 0, "");
-#if 0 /*JP*/
+#if 0 /*JP:T*/
putstr(win, 0,
xprname((struct obj *) 0, "Total:", '*', FALSE, totcost, 0L));
#else
if (billx)
(void) doinvbill(1);
else
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("No used-up objects%s.",
unpaid_count ? " on your shopping bill" : "");
#else
/*JP
You("have no %sobjects%s.", before, after);
*/
- You("%s%s\82à\82Ì\82Í\89½\82à\8e\9d\82Á\82Ä\82¢\82È\82¢\81D", before, after);
+ You("%s%s\82à\82Ì\82Í\89½\82à\8e\9d\82Á\82Ä\82¢\82È\82¢\81D", before, after);
return 0;
}
this_type = oclass;
else if (IS_SINK(ltyp))
cmap = S_sink; /* "sink" */
else if (IS_ALTAR(ltyp)) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
Sprintf(altbuf, "%saltar to %s (%s)",
((lev->altarmask & AM_SHRINE)
&& (Is_astralevel(&u.uz) || Is_sanctum(&u.uz)))
if (u.uswallow && u.ustuck) {
struct monst *mtmp = u.ustuck;
+ /*
+ * FIXME?
+ * Engulfer's inventory can include worn items (specific case is
+ * Juiblex being created with an amulet as random defensive item)
+ * which will be flagged as "(being worn)". This code includes
+ * such a worn item under the header "Contents of <mon>'s stomach",
+ * a nifty trick for how/where to wear stuff. The situation is
+ * rare enough to turn a blind eye.
+ *
+ * 3.6.3: Pickup has been changed to decline to pick up a worn
+ * item from inside an engulfer, but if player tries, it just
+ * says "you can't" without giving a reason why (which would be
+ * something along the lines of "because it's worn on the outside
+ * so is unreachable from in here...").
+ */
#if 0 /*JP:T*/
Sprintf(fbuf, "Contents of %s %s", s_suffix(mon_nam(mtmp)),
mbodypart(mtmp, STOMACH));
/*JP
if (dfeature && !strncmp(dfeature, "altar ", 6)) {
*/
- if (dfeature && !strncmp(dfeature, "\8dÕ\92d", 4)) {
+ if (dfeature && !STRNCMP2(dfeature, "\8dÕ\92d")) {
/* don't say "altar" twice, dfeature has more info */
/*JP
You("try to feel what is here.");
*/
There("\82±\82±\82É\82Í%s\88ê\82Â\82à\82Ì\82ª\82 \82é\81D", picked_some ? "\82à\82¤" : "");
else
-#if 0 /*JP*/
+#if 0 /*JP:T*/
There("are %s%s objects here.",
(obj_cnt < 5)
? "a few"
putstr(tmpwin, 0, fbuf);
putstr(tmpwin, 0, "");
}
-#if 0 /*JP*/
+#if 0 /*JP:T*/
Sprintf(buf, "%s that %s here:",
picked_some ? "Other things" : "Things",
Blind ? "you feel" : "are");
Strcpy(kbuf, corpse_xname(otmp, (const char *) 0, CXN_PFX_THE));
if (poly_when_stoned(youmonst.data))
-#if 0 /*JP*/
+#if 0 /*JP:T*/
You("touched %s with your bare %s.", kbuf,
makeplural(body_part(HAND)));
#else
{
int objnamelth = 0, otmpnamelth = 0;
- if (obj == otmp)
- return FALSE; /* already the same object */
- if (obj->otyp != otmp->otyp)
- return FALSE; /* different types */
- if (obj->nomerge) /* explicitly marked to prevent merge */
+ /* fail if already the same object, if different types, if either is
+ explicitly marked to prevent merge, or if not mergable in general */
+ if (obj == otmp || obj->otyp != otmp->otyp
+ || obj->nomerge || otmp->nomerge || !objects[obj->otyp].oc_merge)
return FALSE;
/* coins of the same kind will always merge */
if (obj->oclass == COIN_CLASS)
return TRUE;
- if (obj->unpaid != otmp->unpaid || obj->spe != otmp->spe
- || obj->cursed != otmp->cursed || obj->blessed != otmp->blessed
- || obj->no_charge != otmp->no_charge || obj->obroken != otmp->obroken
- || obj->otrapped != otmp->otrapped || obj->lamplit != otmp->lamplit
- || obj->bypass != otmp->bypass)
+ if (obj->bypass != otmp->bypass
+ || obj->cursed != otmp->cursed || obj->blessed != otmp->blessed)
return FALSE;
if (obj->globby)
* or don't inhibit their merger.
*/
+ if (obj->unpaid != otmp->unpaid || obj->spe != otmp->spe
+ || obj->no_charge != otmp->no_charge || obj->obroken != otmp->obroken
+ || obj->otrapped != otmp->otrapped || obj->lamplit != otmp->lamplit)
+ return FALSE;
+
if (obj->oclass == FOOD_CLASS
&& (obj->oeaten != otmp->oeaten || obj->orotten != otmp->orotten))
return FALSE;
/* the messages used to refer to "carrying gold", but that didn't
take containers into account */
long umoney = money_cnt(invent);
+
if (!umoney)
/*JP
Your("wallet is empty.");
* This must match the object class order.
*/
STATIC_VAR NEARDATA const char *names[] = {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
0, "Illegal objects", "Weapons", "Armor", "Rings", "Amulets", "Tools",
"Comestibles", "Potions", "Scrolls", "Spellbooks", "Wands", "Coins",
"Gems/Stones", "Boulders/Statues", "Iron balls", "Chains", "Venoms"
const char *adj_type;
boolean ever_mind = FALSE, collect;
- if (!invent) {
-/*JP
- You("aren't carrying anything to adjust.");
-*/
+ /* when no invent, or just gold in '$' slot, there's nothing to adjust */
+ if (!invent || (invent->oclass == COIN_CLASS
+ && invent->invlet == GOLD_SYM && !invent->nobj)) {
+#if 0 /*JP:T*/
+ You("aren't carrying anything %s.",
+ !invent ? "to adjust" : "adjustable");
+#else
You("\8f\87\8f\98\82ð\95Ï\82¦\82é\82à\82Ì\82ð\89½\82à\8e\9d\82Á\82Ä\82¢\82È\82¢\81D");
+#endif
return 0;
}
compatible stacks get collected along the way,
but splitting to same slot is not */
|| (splitting && let == obj->invlet)) {
- noadjust:
+ noadjust:
if (splitting)
(void) merged(&splitting, &obj);
if (!ever_mind)
pline1(Never_mind);
return 0;
} else if (let == GOLD_SYM && obj->oclass != COIN_CLASS) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("Only gold coins may be moved into the '%c' slot.",
GOLD_SYM);
#else
break; /* got one */
if (trycnt == 5)
goto noadjust;
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("Select an inventory slot letter."); /* else try again */
#else
pline("\8e\9d\82¿\95¨\82Ì\95¶\8e\9a\82ð\91I\82ñ\82Å\82\82¾\82³\82¢\81D");
have_inv = (mon->minvent != 0), have_any = (have_inv || incl_hero),
pickings = (dflags & MINV_PICKMASK);
-#if 0 /*JP*/
+#if 0 /*JP:T*/
Sprintf(tmp, "%s %s:", s_suffix(noit_Monnam(mon)),
do_all ? "possessions" : "armament");
#else
* displaying 'weapon in claw', etc. properly.
*/
youmonst.data = mon->data;
+ /* in case inside a shop, don't append "for sale" prices */
+ iflags.suppress_price++;
n = query_objlist(title ? title : tmp, &(mon->minvent),
(INVORDER_SORT | (incl_hero ? INCLUDE_HERO : 0)),
&selected, pickings,
do_all ? allow_all : worn_wield_only);
- set_uasmon();
+
+ iflags.suppress_price--;
+ /* was 'set_uasmon();' but that potentially has side-effects */
+ youmonst.data = &mons[u.umonnum]; /* most basic part of set_uasmon */
} else {
/*JP
invdisp_nothing(title ? title : tmp, "(none)");
int n;
menu_item *selected = 0;
-#if 0 /*JP*/
+#if 0 /*JP:T*/
(void) safe_qbuf(qbuf, "Contents of ", ":", obj, doname, ansimpleoname,
"that");
#else