releasing inventory window(s)

This should address the issue that the problem patch to display_pickinv()
was trying to deal with:  releasing the inventory window before exiting
the program so Pasi's memory checker doesn't think it's a memory leak.

Not related, but in the same file:
The older qsort comparison routines are tagged with CFDECLSPEC to deal
with some C vs C++ interaction issue.  I added that to the relatively
recently added 'sortloot' qsort compare callback.

I also changed worn_wield_only(), although it isn't actually called.
(display_minventory() has provisions to call it, but both of the latter's
callers pass in MINV_ALL so allow_all() gets used instead.)
This commit is contained in:
PatR
2015-11-02 18:14:57 -08:00
parent 91369e7a76
commit 69b13d574d
4 changed files with 213 additions and 158 deletions

View File

@@ -1,4 +1,4 @@
/* NetHack 3.6 extern.h $NHDT-Date: 1446336781 2015/11/01 00:13:01 $ $NHDT-Branch: master $:$NHDT-Revision: 1.511 $ */
/* NetHack 3.6 extern.h $NHDT-Date: 1446516834 2015/11/03 02:13:54 $ $NHDT-Branch: master $:$NHDT-Revision: 1.513 $ */
/* Copyright (c) Steve Creps, 1988. */
/* NetHack may be freely redistributed. See license for details. */
@@ -910,8 +910,8 @@ E boolean NDECL(wearing_armor);
E boolean FDECL(is_worn, (struct obj *));
E struct obj *FDECL(g_at, (int, int));
E struct obj *FDECL(getobj, (const char *, const char *));
E int FDECL(ggetobj,
(const char *, int (*)(OBJ_P), int, BOOLEAN_P, unsigned *));
E int FDECL(ggetobj, (const char *, int (*)(OBJ_P), int,
BOOLEAN_P, unsigned *));
E int FDECL(askchain, (struct obj **, const char *, int, int (*)(OBJ_P),
int (*)(OBJ_P), int, const char *));
E void FDECL(fully_identify_obj, (struct obj *));
@@ -945,6 +945,7 @@ E char *FDECL(let_to_name, (CHAR_P, BOOLEAN_P, BOOLEAN_P));
E void NDECL(free_invbuf);
E void NDECL(reassign);
E int NDECL(doorganize);
E void NDECL(free_pickinv_cache);
E int FDECL(count_unpaid, (struct obj *));
E int FDECL(count_buc, (struct obj *, int));
E long FDECL(count_contents, (struct obj *, BOOLEAN_P, BOOLEAN_P, BOOLEAN_P));

View File

@@ -1,4 +1,4 @@
/* NetHack 3.6 end.c $NHDT-Date: 1434408399 2015/06/15 22:46:39 $ $NHDT-Branch: master $:$NHDT-Revision: 1.100 $ */
/* NetHack 3.6 end.c $NHDT-Date: 1446510332 2015/11/03 00:25:32 $ $NHDT-Branch: master $:$NHDT-Revision: 1.102 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
@@ -214,7 +214,7 @@ NH_panictrace_libc()
for (x = 0; x < count; x++) {
raw_printf("[%lu] %s", (unsigned long) x, info[x]);
}
/* free(info); Don't risk it. */
/* free(info); -- Don't risk it. */
return TRUE;
#else
return FALSE;
@@ -273,22 +273,23 @@ NH_panictrace_gdb()
/*
* The order of these needs to match the macros in hack.h.
*/
static NEARDATA const char *deaths[] =
{ /* the array of death */
"died", "choked", "poisoned", "starvation", "drowning", "burning",
"dissolving under the heat and pressure", "crushed", "turned to stone",
"turned into slime", "genocided", "panic", "trickery", "quit",
"escaped", "ascended"
};
static NEARDATA const char *deaths[] = {
/* the array of death */
"died", "choked", "poisoned", "starvation", "drowning", "burning",
"dissolving under the heat and pressure", "crushed", "turned to stone",
"turned into slime", "genocided", "panic", "trickery", "quit",
"escaped", "ascended"
};
static NEARDATA const char *ends[] = { /* "when you..." */
"died", "choked", "were poisoned",
"starved", "drowned", "burned",
"dissolved in the lava",
"were crushed", "turned to stone",
"turned into slime", "were genocided",
"panicked", "were tricked", "quit",
"escaped", "ascended"
static NEARDATA const char *ends[] = {
/* "when you %s" */
"died", "choked", "were poisoned",
"starved", "drowned", "burned",
"dissolved in the lava",
"were crushed", "turned to stone",
"turned into slime", "were genocided",
"panicked", "were tricked", "quit",
"escaped", "ascended"
};
static boolean Schroedingers_cat = FALSE;
@@ -366,8 +367,8 @@ done2()
#ifndef NO_SIGNAL
/*ARGSUSED*/
STATIC_PTR void done_intr(
sig_unused) /* called as signal() handler, so sent at least one arg */
STATIC_PTR void
done_intr(sig_unused) /* called as signal() handler, so sent at least 1 arg */
int sig_unused UNUSED;
{
done_stopprint++;
@@ -396,10 +397,11 @@ struct monst *mtmp;
int how;
{
char buf[BUFSZ];
struct permonst *mptr = mtmp->data, *champtr = (mtmp->cham >= LOW_PM)
? &mons[mtmp->cham]
: mptr;
boolean distorted = (boolean)(Hallucination && canspotmon(mtmp)),
struct permonst *mptr = mtmp->data,
*champtr = ((mtmp->cham >= LOW_PM)
? &mons[mtmp->cham]
: mptr);
boolean distorted = (boolean) (Hallucination && canspotmon(mtmp)),
mimicker = (mtmp->m_ap_type == M_AP_MONSTER),
imitator = (mptr != champtr || mimicker);
@@ -452,8 +454,9 @@ int how;
Strcpy(shape, an(fakenm));
/* omit "called" to avoid excessive verbosity */
Sprintf(eos(buf),
alt ? "%s in %s form" : mimicker ? "%s disguised as %s"
: "%s imitating %s",
alt ? "%s in %s form"
: mimicker ? "%s disguised as %s"
: "%s imitating %s",
realnm, shape);
mptr = mtmp->data; /* reset for mimicker case */
} else if (mptr == &mons[PM_GHOST]) {
@@ -462,9 +465,8 @@ int how;
Sprintf(eos(buf), " of %s", MNAME(mtmp));
} else if (mtmp->isshk) {
const char *shknm = shkname(mtmp),
*honorific = shkname_is_pname(mtmp) ? "" : mtmp->female
? "Ms. "
: "Mr. ";
*honorific = shkname_is_pname(mtmp) ? ""
: mtmp->female ? "Ms. " : "Mr. ";
Sprintf(eos(buf), "%s%s, the shopkeeper", honorific, shknm);
killer.format = KILLED_BY;
@@ -925,7 +927,7 @@ int how;
}
/*
* The game is now over...
* The game is now over...
*/
die:
@@ -1092,6 +1094,8 @@ die:
/* clean up unneeded windows */
if (have_windows) {
wait_synch();
if (WIN_INVEN != WIN_ERR)
destroy_nhwindow(WIN_INVEN), WIN_INVEN = WIN_ERR;
display_nhwindow(WIN_MESSAGE, TRUE);
destroy_nhwindow(WIN_MAP), WIN_MAP = WIN_ERR;
#ifndef STATUS_VIA_WINDOWPORT
@@ -1130,8 +1134,8 @@ die:
}
if (how == ESCAPED || how == ASCENDED) {
register struct monst *mtmp;
register struct obj *otmp;
struct monst *mtmp;
struct obj *otmp;
register struct val_list *val;
register int i;

View File

@@ -1,4 +1,4 @@
/* NetHack 3.6 invent.c $NHDT-Date: 1445388918 2015/10/21 00:55:18 $ $NHDT-Branch: master $:$NHDT-Revision: 1.175 $ */
/* NetHack 3.6 invent.c $NHDT-Date: 1446516832 2015/11/03 02:13:52 $ $NHDT-Branch: master $:$NHDT-Revision: 1.178 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
@@ -7,7 +7,7 @@
#define NOINVSYM '#'
#define CONTAINED_SYM '>' /* designator for inside a container */
STATIC_DCL int FDECL(sortloot_cmp, (struct obj *, struct obj *));
STATIC_DCL int FDECL(CFDECLSPEC sortloot_cmp, (struct obj *, struct obj *));
STATIC_DCL void NDECL(reorder_invent);
STATIC_DCL boolean FDECL(mergable, (struct obj *, struct obj *));
STATIC_DCL void FDECL(noarmor, (BOOLEAN_P));
@@ -40,11 +40,13 @@ static int lastinvnr = 51; /* 0 ... 51 (never saved&restored) */
* suddenly become a choice for all the inventory-class commands, which
* would probably cause mass confusion. the test for inventory venom
* is only WIZARD and not wizard because the wizard can leave venom lying
* around on a bones level for normal players to find.
* around on a bones level for normal players to find. [Note to the
* confused: 'WIZARD' used to be a compile-time conditional so this was
* guarded by #ifdef WIZARD/.../#endif.]
*/
static char venom_inv[] = { VENOM_CLASS, 0 }; /* (constant) */
int
STATIC_OVL int CFDECLSPEC
sortloot_cmp(obj1, obj2)
struct obj *obj1;
struct obj *obj2;
@@ -104,7 +106,9 @@ struct obj *obj2;
return val2 - val1; /* Because bigger is better. */
}
return 0; /* They're identical, as far as we're concerned. */
/* They're identical, as far as we're concerned,
but we want to force a determistic order between them. */
return (obj1->o_id > obj2->o_id) ? 1 : -1;
}
struct obj **
@@ -316,18 +320,17 @@ struct obj **potmp, **pobj;
setnotworn(otmp);
setworn(otmp, wmask);
setnotworn(obj);
}
#if 0
/* (this should not be necessary, since items
already in a monster's inventory don't ever get
merged into other objects [only vice versa]) */
else if (obj->owornmask && mcarried(otmp)) {
} else if (obj->owornmask && mcarried(otmp)) {
if (obj == MON_WEP(otmp->ocarry)) {
MON_WEP(otmp->ocarry) = otmp;
otmp->owornmask = W_WEP;
MON_WEP(otmp->ocarry) = otmp;
otmp->owornmask = W_WEP;
}
}
#endif /*0*/
}
/* handle puddings a bit differently; absorption will
* free the other object automatically so we can just
@@ -335,11 +338,11 @@ struct obj **potmp, **pobj;
if (Is_pudding(obj)) {
pudding_merge_message(otmp, obj);
obj_absorb(potmp, pobj);
return (1);
return 1;
}
obfree(obj, otmp); /* free(obj), bill->otmp */
return (1);
return 1;
}
return 0;
}
@@ -477,7 +480,7 @@ added:
addinv_core2(obj);
carry_obj_effects(obj); /* carrying affects the obj */
update_inventory();
return (obj);
return obj;
}
/*
@@ -595,8 +598,8 @@ void
useup(obj)
register struct obj *obj;
{
/* Note: This works correctly for containers because they */
/* (containers) don't merge. */
/* Note: This works correctly for containers because they (containers)
don't merge. */
if (obj->quan > 1L) {
obj->in_use = FALSE; /* no longer in use */
obj->quan--;
@@ -763,12 +766,13 @@ register int type;
for (otmp = invent; otmp; otmp = otmp->nobj)
if (otmp->otyp == type)
return (otmp);
return ((struct obj *) 0);
return otmp;
return (struct obj *) 0;
}
/** Fictional and not-so-fictional currencies.
* http://concord.wikia.com/wiki/List_of_Fictional_Currencies */
/* Fictional and not-so-fictional currencies.
* http://concord.wikia.com/wiki/List_of_Fictional_Currencies
*/
static const char *const currencies[] = {
"Altarian Dollar", /* The Hitchhiker's Guide to the Galaxy */
"Ankh-Morpork Dollar", /* Discworld */
@@ -812,8 +816,8 @@ have_lizard()
for (otmp = invent; otmp; otmp = otmp->nobj)
if (otmp->otyp == CORPSE && otmp->corpsenm == PM_LIZARD)
return (TRUE);
return (FALSE);
return TRUE;
return FALSE;
}
/* 3.6.0 tribute */
@@ -825,7 +829,7 @@ u_have_novel()
for (otmp = invent; otmp; otmp = otmp->nobj)
if (otmp->otyp == SPE_NOVEL)
return otmp;
return (struct obj *)0;
return (struct obj *) 0;
}
struct obj *
@@ -837,12 +841,12 @@ register struct obj *objchn;
while (objchn) {
if (objchn->o_id == id)
return (objchn);
return objchn;
if (Has_contents(objchn) && (temp = o_on(id, objchn->cobj)))
return temp;
objchn = objchn->nobj;
}
return ((struct obj *) 0);
return (struct obj *) 0;
}
boolean
@@ -854,8 +858,8 @@ int x, y;
for (otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere)
if (obj == otmp)
return (TRUE);
return (FALSE);
return TRUE;
return FALSE;
}
struct obj *
@@ -863,12 +867,13 @@ g_at(x, y)
register int x, y;
{
register struct obj *obj = level.objects[x][y];
while (obj) {
if (obj->oclass == COIN_CLASS)
return obj;
obj = obj->nexthere;
}
return ((struct obj *) 0);
return (struct obj *) 0;
}
/* compact a string of inventory letters by dashing runs of letters */
@@ -936,9 +941,9 @@ const char *action;
/*
* getobj returns:
* struct obj *xxx: object to do something with.
* (struct obj *) 0 error return: no object.
* &zeroobj explicitly no object (as in w-).
* struct obj *xxx: object to do something with.
* (struct obj *) 0 error return: no object.
* &zeroobj explicitly no object (as in w-).
!!!! test if gold can be used in unusual ways (eaten etc.)
!!!! may be able to remove "usegold"
*/
@@ -1147,7 +1152,7 @@ register const char *let, *word;
if (!foo && !allowall && !allownone) {
You("don't have anything %sto %s.", foox ? "else " : "", word);
return ((struct obj *) 0);
return (struct obj *) 0;
}
for (;;) {
cnt = 0;
@@ -1189,18 +1194,19 @@ register const char *let, *word;
if (index(quitchars, ilet)) {
if (flags.verbose)
pline1(Never_mind);
return ((struct obj *) 0);
return (struct obj *) 0;
}
if (ilet == '-') {
if (!allownone) {
char *suf = NULL;
char *suf = (char *) 0;
strcpy(buf, word);
if ((bp = strstr(buf, " on the "))
!= NULL) { /* rub on the stone[s] */
if ((bp = strstr(buf, " on the ")) != 0) {
/* rub on the stone[s] */
*bp = '\0';
suf = (bp + 1);
}
if ((bp = strstr(buf, " or ")) != NULL) {
if ((bp = strstr(buf, " or ")) != 0) {
*bp = '\0';
bp = (rn2(2) ? buf : (bp + 4));
} else
@@ -1283,12 +1289,12 @@ register const char *let, *word;
if (!otmp) {
You("don't have that object.");
if (in_doagain)
return ((struct obj *) 0);
return (struct obj *) 0;
continue;
} else if (cnt < 0 || otmp->quan < cnt) {
You("don't have that many! You have only %ld.", otmp->quan);
if (in_doagain)
return ((struct obj *) 0);
return (struct obj *) 0;
continue;
}
break;
@@ -1296,7 +1302,7 @@ register const char *let, *word;
if (!allowall && let && !index(let, otmp->oclass)
&& !(usegold && otmp->oclass == COIN_CLASS)) {
silly_thing(word, otmp);
return ((struct obj *) 0);
return (struct obj *) 0;
}
if (allowcnt == 2) { /* cnt given */
if (cnt == 0)
@@ -1310,7 +1316,7 @@ register const char *let, *word;
otmp->corpsenm = (int) cnt;
}
}
return (otmp);
return otmp;
}
void
@@ -1354,15 +1360,15 @@ struct obj *otmp;
STATIC_PTR int
ckvalidcat(otmp)
register struct obj *otmp;
struct obj *otmp;
{
/* use allow_category() from pickup.c */
return ((int) allow_category(otmp));
return (int) allow_category(otmp);
}
STATIC_PTR int
ckunpaid(otmp)
register struct obj *otmp;
struct obj *otmp;
{
return (otmp->unpaid || (Has_contents(otmp) && count_unpaid(otmp->cobj)));
}
@@ -1435,7 +1441,7 @@ unsigned *resultflags;
takeoff = ident = allflag = m_seen = FALSE;
if (!invent) {
You("have nothing to %s.", word);
return (0);
return 0;
}
add_valid_menu_class(0); /* reset */
if (taking_off(word)) {
@@ -1478,7 +1484,7 @@ unsigned *resultflags;
ilets);
getlin(qbuf, buf);
if (buf[0] == '\033')
return (0);
return 0;
if (index(buf, 'i')) {
if (display_inventory((char *) 0, TRUE) == '\033')
return 0;
@@ -1563,14 +1569,16 @@ unsigned *resultflags;
}
}
if (m_seen)
if (m_seen) {
return (allflag || (!oletct && ckfn != ckunpaid)) ? -2 : -3;
else if (flags.menu_style != MENU_TRADITIONAL && combo && !allflag)
} else if (flags.menu_style != MENU_TRADITIONAL && combo && !allflag) {
return 0;
else /*!!!! if (allowgold == 2 && !oletct)
!!!! return 1; you dropped gold (or at least tried to)
!!!! test gold dropping
else*/ {
#if 0
/* !!!! test gold dropping */
} else if (allowgold == 2 && !oletct) {
return 1; /* you dropped gold (or at least tried to) */
#endif
} else {
int cnt = askchain(&invent, olets, allflag, fn, ckfn, mx, word);
/*
* askchain() has already finished the job in this case
@@ -1625,10 +1633,10 @@ nextclass:
* (dropping a burning potion of oil while levitating creates
* an explosion which can destroy inventory items), so simple
* list traversal
* for (otmp = *objchn; otmp; otmp = otmp2) {
* otmp2 = otmp->nobj;
* ...
* }
* for (otmp = *objchn; otmp; otmp = otmp2) {
* otmp2 = otmp->nobj;
* ...
* }
* is inadequate here. Use each object's bypass bit to keep
* track of which list elements have already been processed.
*/
@@ -1721,11 +1729,11 @@ nextclass:
pline("No applicable objects.");
ret:
bypass_objlist(*objchn, FALSE);
return (cnt);
return cnt;
}
/*
* Object identification routines:
* Object identification routines:
*/
/* make an object actually be identified; no display updating */
@@ -1860,9 +1868,10 @@ learn_unseen_invent()
update_inventory();
}
/* should of course only be called for things in invent */
STATIC_OVL char
obj_to_let(obj) /* should of course only be called for things in invent */
register struct obj *obj;
obj_to_let(obj)
struct obj *obj;
{
if (!flags.invlet_constant) {
obj->invlet = NOINVSYM;
@@ -1878,7 +1887,7 @@ register struct obj *obj;
void
prinv(prefix, obj, quan)
const char *prefix;
register struct obj *obj;
struct obj *obj;
long quan;
{
if (!prefix)
@@ -1911,8 +1920,8 @@ long quan; /* if non-0, print this quantity, not obj->quan */
/*
* If let is:
* * Then obj == null and we are printing a total amount.
* > Then the object is contained and doesn't have an inventory letter.
* * Then obj == null and we are printing a total amount.
* > Then the object is contained and doesn't have an inventory letter.
*/
if (cost != 0 || let == '*') {
/* if dot is true, we're doing Iu, otherwise Ix */
@@ -1960,7 +1969,7 @@ struct obj *list, **last_found;
if (list == *last_found)
*last_found = (struct obj *) 0;
} else
return (*last_found = list);
return ((*last_found = list));
}
if (Has_contents(list)) {
if ((obj = find_unpaid(list->cobj, last_found)) != 0)
@@ -1971,6 +1980,22 @@ struct obj *list, **last_found;
return (struct obj *) 0;
}
/* for perm_invent when operating on a partial inventory display, so that
the persistent one doesn't get shrunk during filtering for item selection
then regrown to full inventory, possibly being resized in the process */
static winid cached_pickinv_win = WIN_ERR;
/* #ifdef FREE_ALL_MEMORY */
void
free_pickinv_cache()
{
if (cached_pickinv_win != WIN_ERR) {
destroy_nhwindow(cached_pickinv_win);
cached_pickinv_win = WIN_ERR;
}
}
/* #endif */
/*
* Internal function used by display_inventory and getobj that can display
* inventory and return a count as well as a letter. If out_cnt is not null,
@@ -1987,31 +2012,31 @@ long *out_cnt;
char *invlet = flags.inv_order;
int i, n, classcount;
winid win; /* windows being used */
static winid local_win = WIN_ERR; /* window for partial menus */
anything any;
menu_item *selected;
struct obj **oarray;
/* overridden by global flag */
if (flags.perm_invent) {
win = (lets && *lets) ? local_win : WIN_INVEN;
/* create the first time used */
if (win == WIN_ERR)
win = local_win = create_nhwindow(NHW_MENU);
if (flags.perm_invent && lets && *lets) {
/* 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 */
if (cached_pickinv_win == WIN_ERR)
cached_pickinv_win = create_nhwindow(NHW_MENU);
win = cached_pickinv_win;
} else
win = WIN_INVEN;
/*
Exit early if no inventory -- but keep going if we are doing
a permanent inventory update. We need to keep going so the
permanent inventory window updates itself to remove the last
item(s) dropped. One down side: the addition of the exception
for permanent inventory window updates _can_ pop the window
up when it's not displayed -- even if it's empty -- because we
don't know at this level if its up or not. This may not be
an issue if empty checks are done before hand and the call
to here is short circuited away.
*/
* Exit early if no inventory -- but keep going if we are doing
* a permanent inventory update. We need to keep going so the
* permanent inventory window updates itself to remove the last
* item(s) dropped. One down side: the addition of the exception
* for permanent inventory window updates _can_ pop the window
* up when it's not displayed -- even if it's empty -- because we
* don't know at this level if its up or not. This may not be
* an issue if empty checks are done before hand and the call
* to here is short circuited away.
*/
if (!invent && !(flags.perm_invent && !lets && !want_reply)) {
pline("Not carrying anything.");
return 0;
@@ -2117,7 +2142,7 @@ nextclass:
*/
char
display_inventory(lets, want_reply)
register const char *lets;
const char *lets;
boolean want_reply;
{
return display_pickinv(lets, want_reply, (long *) 0);
@@ -2535,8 +2560,7 @@ dotypeinv()
if (oclass == COIN_CLASS)
return doprgold();
if (index(types, c) > index(types, '\033')) {
/* '> ESC' => "hidden choice", something known not to be carried
*/
/* '> ESC' => hidden choice, something known not to be carried */
const char *which = 0;
switch (c) {
@@ -2690,7 +2714,7 @@ boolean picked_some;
} else {
You("%s no objects here.", verb);
}
return (!!Blind);
return !!Blind;
}
if (!skip_objects && (trap = t_at(u.ux, u.uy)) && trap->tseen)
There("is %s here.",
@@ -2722,7 +2746,7 @@ boolean picked_some;
dfeature = 0; /* ice already identified */
if (!can_reach_floor(TRUE)) {
pline("But you can't reach it!");
return (0);
return 0;
}
}
@@ -2736,7 +2760,7 @@ boolean picked_some;
read_engr_at(u.ux, u.uy); /* Eric Backus */
if (!skip_objects && (Blind || !dfeature))
You("%s no objects here.", verb);
return (!!Blind);
return !!Blind;
}
/* we know there is something here */
@@ -2806,10 +2830,10 @@ boolean picked_some;
feel_cockatrice(otmp, FALSE);
read_engr_at(u.ux, u.uy); /* Eric Backus */
}
return (!!Blind);
return !!Blind;
}
/* explicitly look at what is here, including all objects */
/* the ':' command - explicitly look at what is here, including all objects */
int
dolook()
{
@@ -2862,8 +2886,9 @@ struct obj *obj;
return;
}
/* returns TRUE if obj & otmp can be merged */
STATIC_OVL boolean
mergable(otmp, obj) /* returns TRUE if obj & otmp can be merged */
mergable(otmp, obj)
register struct obj *otmp, *obj;
{
int objnamelth = 0, otmpnamelth = 0;
@@ -2882,7 +2907,7 @@ register struct obj *otmp, *obj;
|| obj->otrapped != otmp->otrapped || obj->lamplit != otmp->lamplit
|| obj->greased != otmp->greased || obj->oeroded != otmp->oeroded
|| obj->oeroded2 != otmp->oeroded2 || obj->bypass != otmp->bypass)
return (FALSE);
return FALSE;
if (obj->nomerge) /* explicitly marked to prevent merge */
return FALSE;
@@ -2894,7 +2919,7 @@ register struct obj *otmp, *obj;
if (obj->oclass == FOOD_CLASS
&& (obj->oeaten != otmp->oeaten || obj->orotten != otmp->orotten))
return (FALSE);
return FALSE;
if (obj->otyp == CORPSE || obj->otyp == EGG || obj->otyp == TIN) {
if (obj->corpsenm != otmp->corpsenm)
@@ -2910,7 +2935,7 @@ register struct obj *otmp, *obj;
/* allow candle merging only if their ages are close */
/* see begin_burn() for a reference for the magic "25" */
if (Is_candle(obj) && obj->age / 25 != otmp->age / 25)
return (FALSE);
return FALSE;
/* burning potions of oil never merge */
if (obj->otyp == POT_OIL && obj->lamplit)
@@ -2943,6 +2968,7 @@ register struct obj *otmp, *obj;
return FALSE;
}
/* the '$' command */
int
doprgold()
{
@@ -2957,6 +2983,7 @@ doprgold()
return 0;
}
/* the ')' command */
int
doprwep()
{
@@ -2994,15 +3021,21 @@ boolean report_uskin;
}
}
/* the '[' command */
int
doprarm()
{
char lets[8];
register int ct = 0;
/*
* Note: players sometimes get here by pressing a function key which
* transmits ''ESC [ <something>'' rather than by pressing '[';
* there's nothing we can--or should-do about that here.
*/
if (!wearing_armor()) {
noarmor(TRUE);
} else {
char lets[8];
register int ct = 0;
if (uarmu)
lets[ct++] = obj_to_let(uarmu);
if (uarm)
@@ -3023,6 +3056,7 @@ doprarm()
return 0;
}
/* the '=' command */
int
doprring()
{
@@ -3042,6 +3076,7 @@ doprring()
return 0;
}
/* the '"' command */
int
dopramulet()
{
@@ -3064,6 +3099,7 @@ struct obj *obj;
|| (obj->otyp == LEASH && obj->leashmon));
}
/* the '(' command */
int
doprtool()
{
@@ -3236,27 +3272,27 @@ reassign()
/* #adjust command
*
* User specifies a 'from' slot for inventory stack to move,
* then a 'to' slot for its destination. Open slots and those
* filled by compatible stacks are listed as likely candidates
* but user can pick any inventory letter (including 'from').
* All compatible items found are gathered into the 'from'
* stack as it is moved. If the 'to' slot isn't empty and
* doesn't merge, then its stack is swapped to the 'from' slot.
* User specifies a 'from' slot for inventory stack to move,
* then a 'to' slot for its destination. Open slots and those
* filled by compatible stacks are listed as likely candidates
* but user can pick any inventory letter (including 'from').
* All compatible items found are gathered into the 'from'
* stack as it is moved. If the 'to' slot isn't empty and
* doesn't merge, then its stack is swapped to the 'from' slot.
*
* If the user specifies a count when choosing the 'from' slot,
* and that count is less than the full size of the stack,
* then the stack will be split. The 'count' portion is moved
* to the destination, and the only candidate for merging with
* it is the stack already at the 'to' slot, if any. When the
* destination is non-empty but won't merge, whatever is there
* will be moved to an open slot; if there isn't any open slot
* available, the adjustment attempt fails.
* If the user specifies a count when choosing the 'from' slot,
* and that count is less than the full size of the stack,
* then the stack will be split. The 'count' portion is moved
* to the destination, and the only candidate for merging with
* it is the stack already at the 'to' slot, if any. When the
* destination is non-empty but won't merge, whatever is there
* will be moved to an open slot; if there isn't any open slot
* available, the adjustment attempt fails.
*
* Splitting has one special case: if 'to' slot is non-empty
* and is compatible with 'from' in all respects except for
* user-assigned names, the 'count' portion being moved is
* effectively renamed so that it will merge with 'to' stack.
* Splitting has one special case: if 'to' slot is non-empty
* and is compatible with 'from' in all respects except for
* user-assigned names, the 'count' portion being moved is
* effectively renamed so that it will merge with 'to' stack.
*/
int
doorganize() /* inventory organizer by Del Lamb */
@@ -3281,7 +3317,7 @@ doorganize() /* inventory organizer by Del Lamb */
allowall[1] = ALL_CLASSES;
allowall[2] = '\0';
if (!(obj = getobj(allowall, "adjust")))
return (0);
return 0;
/* figure out whether user gave a split count to getobj() */
splitting = bumped = 0;
@@ -3440,7 +3476,7 @@ doorganize() /* inventory organizer by Del Lamb */
if (splitting)
clear_splitobjs(); /* reset splitobj context */
update_inventory();
return (0);
return 0;
}
/* common to display_minventory and display_cinventory */
@@ -3466,15 +3502,25 @@ const char *hdr, *txt;
return;
}
/* query_objlist callback: return things that could possibly be worn/wielded
*/
/* query_objlist callback: return things that are worn or wielded */
STATIC_OVL boolean
worn_wield_only(obj)
struct obj *obj;
{
return (obj->oclass == WEAPON_CLASS || obj->oclass == ARMOR_CLASS
|| obj->oclass == AMULET_CLASS || obj->oclass == RING_CLASS
|| obj->oclass == TOOL_CLASS);
#if 1
/* check for things that *are* worn or wielded (only used for monsters,
so we don't worry about excluding W_CHAIN, W_ARTI and the like) */
return (boolean) (obj->owornmask != 0L);
#else
/* this used to check for things that *might* be worn or wielded,
but that's not particularly interesting */
if (is_weptool(obj) || is_wet_towel(obj) || obj->otyp == MEAT_RING)
return TRUE;
return (boolean) (obj->oclass == WEAPON_CLASS
|| obj->oclass == ARMOR_CLASS
|| obj->oclass == AMULET_CLASS
|| obj->oclass == RING_CLASS);
#endif
}
/*
@@ -3485,8 +3531,8 @@ struct obj *obj;
* By default, only worn and wielded items are displayed. The caller
* can pick one. Modifier flags are:
*
* MINV_NOLET - nothing selectable
* MINV_ALL - display all inventory
* MINV_NOLET - nothing selectable
* MINV_ALL - display all inventory
*/
struct obj *
display_minventory(mon, dflags, title)

View File

@@ -1,4 +1,4 @@
/* NetHack 3.6 save.c $NHDT-Date: 1432536532 2015/05/25 06:48:52 $ $NHDT-Branch: master $:$NHDT-Revision: 1.88 $ */
/* NetHack 3.6 save.c $NHDT-Date: 1446516854 2015/11/03 02:14:14 $ $NHDT-Branch: master $:$NHDT-Revision: 1.91 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
@@ -1387,10 +1387,14 @@ freedynamicdata()
if (iflags.wc_tile_file)
free(iflags.wc_tile_file);
free_autopickup_exceptions();
/* miscellaneous */
free_pickinv_cache();
#endif /* FREE_ALL_MEMORY */
#ifdef STATUS_VIA_WINDOWPORT
status_finish();
#endif
sysopt_release(); /* SYSCF strings */
return;
}