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. */ /* Copyright (c) Steve Creps, 1988. */
/* NetHack may be freely redistributed. See license for details. */ /* 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 boolean FDECL(is_worn, (struct obj *));
E struct obj *FDECL(g_at, (int, int)); E struct obj *FDECL(g_at, (int, int));
E struct obj *FDECL(getobj, (const char *, const char *)); E struct obj *FDECL(getobj, (const char *, const char *));
E int FDECL(ggetobj, E int FDECL(ggetobj, (const char *, int (*)(OBJ_P), int,
(const char *, int (*)(OBJ_P), int, BOOLEAN_P, unsigned *)); BOOLEAN_P, unsigned *));
E int FDECL(askchain, (struct obj **, const char *, int, int (*)(OBJ_P), E int FDECL(askchain, (struct obj **, const char *, int, int (*)(OBJ_P),
int (*)(OBJ_P), int, const char *)); int (*)(OBJ_P), int, const char *));
E void FDECL(fully_identify_obj, (struct obj *)); 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(free_invbuf);
E void NDECL(reassign); E void NDECL(reassign);
E int NDECL(doorganize); E int NDECL(doorganize);
E void NDECL(free_pickinv_cache);
E int FDECL(count_unpaid, (struct obj *)); E int FDECL(count_unpaid, (struct obj *));
E int FDECL(count_buc, (struct obj *, int)); E int FDECL(count_buc, (struct obj *, int));
E long FDECL(count_contents, (struct obj *, BOOLEAN_P, BOOLEAN_P, BOOLEAN_P)); 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. */ /* 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. */
@@ -214,7 +214,7 @@ NH_panictrace_libc()
for (x = 0; x < count; x++) { for (x = 0; x < count; x++) {
raw_printf("[%lu] %s", (unsigned long) x, info[x]); raw_printf("[%lu] %s", (unsigned long) x, info[x]);
} }
/* free(info); Don't risk it. */ /* free(info); -- Don't risk it. */
return TRUE; return TRUE;
#else #else
return FALSE; return FALSE;
@@ -273,22 +273,23 @@ NH_panictrace_gdb()
/* /*
* The order of these needs to match the macros in hack.h. * The order of these needs to match the macros in hack.h.
*/ */
static NEARDATA const char *deaths[] = static NEARDATA const char *deaths[] = {
{ /* the array of death */ /* the array of death */
"died", "choked", "poisoned", "starvation", "drowning", "burning", "died", "choked", "poisoned", "starvation", "drowning", "burning",
"dissolving under the heat and pressure", "crushed", "turned to stone", "dissolving under the heat and pressure", "crushed", "turned to stone",
"turned into slime", "genocided", "panic", "trickery", "quit", "turned into slime", "genocided", "panic", "trickery", "quit",
"escaped", "ascended" "escaped", "ascended"
}; };
static NEARDATA const char *ends[] = { /* "when you..." */ static NEARDATA const char *ends[] = {
"died", "choked", "were poisoned", /* "when you %s" */
"starved", "drowned", "burned", "died", "choked", "were poisoned",
"dissolved in the lava", "starved", "drowned", "burned",
"were crushed", "turned to stone", "dissolved in the lava",
"turned into slime", "were genocided", "were crushed", "turned to stone",
"panicked", "were tricked", "quit", "turned into slime", "were genocided",
"escaped", "ascended" "panicked", "were tricked", "quit",
"escaped", "ascended"
}; };
static boolean Schroedingers_cat = FALSE; static boolean Schroedingers_cat = FALSE;
@@ -366,8 +367,8 @@ done2()
#ifndef NO_SIGNAL #ifndef NO_SIGNAL
/*ARGSUSED*/ /*ARGSUSED*/
STATIC_PTR void done_intr( STATIC_PTR void
sig_unused) /* called as signal() handler, so sent at least one arg */ done_intr(sig_unused) /* called as signal() handler, so sent at least 1 arg */
int sig_unused UNUSED; int sig_unused UNUSED;
{ {
done_stopprint++; done_stopprint++;
@@ -396,10 +397,11 @@ struct monst *mtmp;
int how; int how;
{ {
char buf[BUFSZ]; char buf[BUFSZ];
struct permonst *mptr = mtmp->data, *champtr = (mtmp->cham >= LOW_PM) struct permonst *mptr = mtmp->data,
? &mons[mtmp->cham] *champtr = ((mtmp->cham >= LOW_PM)
: mptr; ? &mons[mtmp->cham]
boolean distorted = (boolean)(Hallucination && canspotmon(mtmp)), : mptr);
boolean distorted = (boolean) (Hallucination && canspotmon(mtmp)),
mimicker = (mtmp->m_ap_type == M_AP_MONSTER), mimicker = (mtmp->m_ap_type == M_AP_MONSTER),
imitator = (mptr != champtr || mimicker); imitator = (mptr != champtr || mimicker);
@@ -452,8 +454,9 @@ int how;
Strcpy(shape, an(fakenm)); Strcpy(shape, an(fakenm));
/* omit "called" to avoid excessive verbosity */ /* omit "called" to avoid excessive verbosity */
Sprintf(eos(buf), Sprintf(eos(buf),
alt ? "%s in %s form" : mimicker ? "%s disguised as %s" alt ? "%s in %s form"
: "%s imitating %s", : mimicker ? "%s disguised as %s"
: "%s imitating %s",
realnm, shape); realnm, shape);
mptr = mtmp->data; /* reset for mimicker case */ mptr = mtmp->data; /* reset for mimicker case */
} else if (mptr == &mons[PM_GHOST]) { } else if (mptr == &mons[PM_GHOST]) {
@@ -462,9 +465,8 @@ int how;
Sprintf(eos(buf), " of %s", MNAME(mtmp)); Sprintf(eos(buf), " of %s", MNAME(mtmp));
} else if (mtmp->isshk) { } else if (mtmp->isshk) {
const char *shknm = shkname(mtmp), const char *shknm = shkname(mtmp),
*honorific = shkname_is_pname(mtmp) ? "" : mtmp->female *honorific = shkname_is_pname(mtmp) ? ""
? "Ms. " : mtmp->female ? "Ms. " : "Mr. ";
: "Mr. ";
Sprintf(eos(buf), "%s%s, the shopkeeper", honorific, shknm); Sprintf(eos(buf), "%s%s, the shopkeeper", honorific, shknm);
killer.format = KILLED_BY; killer.format = KILLED_BY;
@@ -925,7 +927,7 @@ int how;
} }
/* /*
* The game is now over... * The game is now over...
*/ */
die: die:
@@ -1092,6 +1094,8 @@ die:
/* clean up unneeded windows */ /* clean up unneeded windows */
if (have_windows) { if (have_windows) {
wait_synch(); wait_synch();
if (WIN_INVEN != WIN_ERR)
destroy_nhwindow(WIN_INVEN), WIN_INVEN = WIN_ERR;
display_nhwindow(WIN_MESSAGE, TRUE); display_nhwindow(WIN_MESSAGE, TRUE);
destroy_nhwindow(WIN_MAP), WIN_MAP = WIN_ERR; destroy_nhwindow(WIN_MAP), WIN_MAP = WIN_ERR;
#ifndef STATUS_VIA_WINDOWPORT #ifndef STATUS_VIA_WINDOWPORT
@@ -1130,8 +1134,8 @@ die:
} }
if (how == ESCAPED || how == ASCENDED) { if (how == ESCAPED || how == ASCENDED) {
register struct monst *mtmp; struct monst *mtmp;
register struct obj *otmp; struct obj *otmp;
register struct val_list *val; register struct val_list *val;
register int i; 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. */ /* 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. */
@@ -7,7 +7,7 @@
#define NOINVSYM '#' #define NOINVSYM '#'
#define CONTAINED_SYM '>' /* designator for inside a container */ #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 void NDECL(reorder_invent);
STATIC_DCL boolean FDECL(mergable, (struct obj *, struct obj *)); STATIC_DCL boolean FDECL(mergable, (struct obj *, struct obj *));
STATIC_DCL void FDECL(noarmor, (BOOLEAN_P)); 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 * suddenly become a choice for all the inventory-class commands, which
* would probably cause mass confusion. the test for inventory venom * would probably cause mass confusion. the test for inventory venom
* is only WIZARD and not wizard because the wizard can leave venom lying * 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) */ static char venom_inv[] = { VENOM_CLASS, 0 }; /* (constant) */
int STATIC_OVL int CFDECLSPEC
sortloot_cmp(obj1, obj2) sortloot_cmp(obj1, obj2)
struct obj *obj1; struct obj *obj1;
struct obj *obj2; struct obj *obj2;
@@ -104,7 +106,9 @@ struct obj *obj2;
return val2 - val1; /* Because bigger is better. */ 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 ** struct obj **
@@ -316,18 +320,17 @@ struct obj **potmp, **pobj;
setnotworn(otmp); setnotworn(otmp);
setworn(otmp, wmask); setworn(otmp, wmask);
setnotworn(obj); setnotworn(obj);
}
#if 0 #if 0
/* (this should not be necessary, since items /* (this should not be necessary, since items
already in a monster's inventory don't ever get already in a monster's inventory don't ever get
merged into other objects [only vice versa]) */ 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)) { if (obj == MON_WEP(otmp->ocarry)) {
MON_WEP(otmp->ocarry) = otmp; MON_WEP(otmp->ocarry) = otmp;
otmp->owornmask = W_WEP; otmp->owornmask = W_WEP;
} }
}
#endif /*0*/ #endif /*0*/
}
/* handle puddings a bit differently; absorption will /* handle puddings a bit differently; absorption will
* free the other object automatically so we can just * free the other object automatically so we can just
@@ -335,11 +338,11 @@ struct obj **potmp, **pobj;
if (Is_pudding(obj)) { if (Is_pudding(obj)) {
pudding_merge_message(otmp, obj); pudding_merge_message(otmp, obj);
obj_absorb(potmp, pobj); obj_absorb(potmp, pobj);
return (1); return 1;
} }
obfree(obj, otmp); /* free(obj), bill->otmp */ obfree(obj, otmp); /* free(obj), bill->otmp */
return (1); return 1;
} }
return 0; return 0;
} }
@@ -477,7 +480,7 @@ added:
addinv_core2(obj); addinv_core2(obj);
carry_obj_effects(obj); /* carrying affects the obj */ carry_obj_effects(obj); /* carrying affects the obj */
update_inventory(); update_inventory();
return (obj); return obj;
} }
/* /*
@@ -595,8 +598,8 @@ void
useup(obj) useup(obj)
register struct obj *obj; register struct obj *obj;
{ {
/* Note: This works correctly for containers because they */ /* Note: This works correctly for containers because they (containers)
/* (containers) don't merge. */ don't merge. */
if (obj->quan > 1L) { if (obj->quan > 1L) {
obj->in_use = FALSE; /* no longer in use */ obj->in_use = FALSE; /* no longer in use */
obj->quan--; obj->quan--;
@@ -763,12 +766,13 @@ register int type;
for (otmp = invent; otmp; otmp = otmp->nobj) for (otmp = invent; otmp; otmp = otmp->nobj)
if (otmp->otyp == type) if (otmp->otyp == type)
return (otmp); return otmp;
return ((struct obj *) 0); return (struct obj *) 0;
} }
/** Fictional and not-so-fictional currencies. /* Fictional and not-so-fictional currencies.
* http://concord.wikia.com/wiki/List_of_Fictional_Currencies */ * http://concord.wikia.com/wiki/List_of_Fictional_Currencies
*/
static const char *const currencies[] = { static const char *const currencies[] = {
"Altarian Dollar", /* The Hitchhiker's Guide to the Galaxy */ "Altarian Dollar", /* The Hitchhiker's Guide to the Galaxy */
"Ankh-Morpork Dollar", /* Discworld */ "Ankh-Morpork Dollar", /* Discworld */
@@ -812,8 +816,8 @@ have_lizard()
for (otmp = invent; otmp; otmp = otmp->nobj) for (otmp = invent; otmp; otmp = otmp->nobj)
if (otmp->otyp == CORPSE && otmp->corpsenm == PM_LIZARD) if (otmp->otyp == CORPSE && otmp->corpsenm == PM_LIZARD)
return (TRUE); return TRUE;
return (FALSE); return FALSE;
} }
/* 3.6.0 tribute */ /* 3.6.0 tribute */
@@ -825,7 +829,7 @@ u_have_novel()
for (otmp = invent; otmp; otmp = otmp->nobj) for (otmp = invent; otmp; otmp = otmp->nobj)
if (otmp->otyp == SPE_NOVEL) if (otmp->otyp == SPE_NOVEL)
return otmp; return otmp;
return (struct obj *)0; return (struct obj *) 0;
} }
struct obj * struct obj *
@@ -837,12 +841,12 @@ register struct obj *objchn;
while (objchn) { while (objchn) {
if (objchn->o_id == id) if (objchn->o_id == id)
return (objchn); return objchn;
if (Has_contents(objchn) && (temp = o_on(id, objchn->cobj))) if (Has_contents(objchn) && (temp = o_on(id, objchn->cobj)))
return temp; return temp;
objchn = objchn->nobj; objchn = objchn->nobj;
} }
return ((struct obj *) 0); return (struct obj *) 0;
} }
boolean boolean
@@ -854,8 +858,8 @@ int x, y;
for (otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere) for (otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere)
if (obj == otmp) if (obj == otmp)
return (TRUE); return TRUE;
return (FALSE); return FALSE;
} }
struct obj * struct obj *
@@ -863,12 +867,13 @@ g_at(x, y)
register int x, y; register int x, y;
{ {
register struct obj *obj = level.objects[x][y]; register struct obj *obj = level.objects[x][y];
while (obj) { while (obj) {
if (obj->oclass == COIN_CLASS) if (obj->oclass == COIN_CLASS)
return obj; return obj;
obj = obj->nexthere; obj = obj->nexthere;
} }
return ((struct obj *) 0); return (struct obj *) 0;
} }
/* compact a string of inventory letters by dashing runs of letters */ /* compact a string of inventory letters by dashing runs of letters */
@@ -936,9 +941,9 @@ const char *action;
/* /*
* getobj returns: * getobj returns:
* struct obj *xxx: object to do something with. * struct obj *xxx: object to do something with.
* (struct obj *) 0 error return: no object. * (struct obj *) 0 error return: no object.
* &zeroobj explicitly no object (as in w-). * &zeroobj explicitly no object (as in w-).
!!!! test if gold can be used in unusual ways (eaten etc.) !!!! test if gold can be used in unusual ways (eaten etc.)
!!!! may be able to remove "usegold" !!!! may be able to remove "usegold"
*/ */
@@ -1147,7 +1152,7 @@ register const char *let, *word;
if (!foo && !allowall && !allownone) { if (!foo && !allowall && !allownone) {
You("don't have anything %sto %s.", foox ? "else " : "", word); You("don't have anything %sto %s.", foox ? "else " : "", word);
return ((struct obj *) 0); return (struct obj *) 0;
} }
for (;;) { for (;;) {
cnt = 0; cnt = 0;
@@ -1189,18 +1194,19 @@ register const char *let, *word;
if (index(quitchars, ilet)) { if (index(quitchars, ilet)) {
if (flags.verbose) if (flags.verbose)
pline1(Never_mind); pline1(Never_mind);
return ((struct obj *) 0); return (struct obj *) 0;
} }
if (ilet == '-') { if (ilet == '-') {
if (!allownone) { if (!allownone) {
char *suf = NULL; char *suf = (char *) 0;
strcpy(buf, word); strcpy(buf, word);
if ((bp = strstr(buf, " on the ")) if ((bp = strstr(buf, " on the ")) != 0) {
!= NULL) { /* rub on the stone[s] */ /* rub on the stone[s] */
*bp = '\0'; *bp = '\0';
suf = (bp + 1); suf = (bp + 1);
} }
if ((bp = strstr(buf, " or ")) != NULL) { if ((bp = strstr(buf, " or ")) != 0) {
*bp = '\0'; *bp = '\0';
bp = (rn2(2) ? buf : (bp + 4)); bp = (rn2(2) ? buf : (bp + 4));
} else } else
@@ -1283,12 +1289,12 @@ register const char *let, *word;
if (!otmp) { if (!otmp) {
You("don't have that object."); You("don't have that object.");
if (in_doagain) if (in_doagain)
return ((struct obj *) 0); return (struct obj *) 0;
continue; continue;
} else if (cnt < 0 || otmp->quan < cnt) { } else if (cnt < 0 || otmp->quan < cnt) {
You("don't have that many! You have only %ld.", otmp->quan); You("don't have that many! You have only %ld.", otmp->quan);
if (in_doagain) if (in_doagain)
return ((struct obj *) 0); return (struct obj *) 0;
continue; continue;
} }
break; break;
@@ -1296,7 +1302,7 @@ register const char *let, *word;
if (!allowall && let && !index(let, otmp->oclass) if (!allowall && let && !index(let, otmp->oclass)
&& !(usegold && otmp->oclass == COIN_CLASS)) { && !(usegold && otmp->oclass == COIN_CLASS)) {
silly_thing(word, otmp); silly_thing(word, otmp);
return ((struct obj *) 0); return (struct obj *) 0;
} }
if (allowcnt == 2) { /* cnt given */ if (allowcnt == 2) { /* cnt given */
if (cnt == 0) if (cnt == 0)
@@ -1310,7 +1316,7 @@ register const char *let, *word;
otmp->corpsenm = (int) cnt; otmp->corpsenm = (int) cnt;
} }
} }
return (otmp); return otmp;
} }
void void
@@ -1354,15 +1360,15 @@ struct obj *otmp;
STATIC_PTR int STATIC_PTR int
ckvalidcat(otmp) ckvalidcat(otmp)
register struct obj *otmp; struct obj *otmp;
{ {
/* use allow_category() from pickup.c */ /* use allow_category() from pickup.c */
return ((int) allow_category(otmp)); return (int) allow_category(otmp);
} }
STATIC_PTR int STATIC_PTR int
ckunpaid(otmp) ckunpaid(otmp)
register struct obj *otmp; struct obj *otmp;
{ {
return (otmp->unpaid || (Has_contents(otmp) && count_unpaid(otmp->cobj))); return (otmp->unpaid || (Has_contents(otmp) && count_unpaid(otmp->cobj)));
} }
@@ -1435,7 +1441,7 @@ unsigned *resultflags;
takeoff = ident = allflag = m_seen = FALSE; takeoff = ident = allflag = m_seen = FALSE;
if (!invent) { if (!invent) {
You("have nothing to %s.", word); You("have nothing to %s.", word);
return (0); return 0;
} }
add_valid_menu_class(0); /* reset */ add_valid_menu_class(0); /* reset */
if (taking_off(word)) { if (taking_off(word)) {
@@ -1478,7 +1484,7 @@ unsigned *resultflags;
ilets); ilets);
getlin(qbuf, buf); getlin(qbuf, buf);
if (buf[0] == '\033') if (buf[0] == '\033')
return (0); return 0;
if (index(buf, 'i')) { if (index(buf, 'i')) {
if (display_inventory((char *) 0, TRUE) == '\033') if (display_inventory((char *) 0, TRUE) == '\033')
return 0; return 0;
@@ -1563,14 +1569,16 @@ unsigned *resultflags;
} }
} }
if (m_seen) if (m_seen) {
return (allflag || (!oletct && ckfn != ckunpaid)) ? -2 : -3; 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; return 0;
else /*!!!! if (allowgold == 2 && !oletct) #if 0
!!!! return 1; you dropped gold (or at least tried to) /* !!!! test gold dropping */
!!!! test gold dropping } else if (allowgold == 2 && !oletct) {
else*/ { return 1; /* you dropped gold (or at least tried to) */
#endif
} else {
int cnt = askchain(&invent, olets, allflag, fn, ckfn, mx, word); int cnt = askchain(&invent, olets, allflag, fn, ckfn, mx, word);
/* /*
* askchain() has already finished the job in this case * askchain() has already finished the job in this case
@@ -1625,10 +1633,10 @@ nextclass:
* (dropping a burning potion of oil while levitating creates * (dropping a burning potion of oil while levitating creates
* an explosion which can destroy inventory items), so simple * an explosion which can destroy inventory items), so simple
* list traversal * list traversal
* for (otmp = *objchn; otmp; otmp = otmp2) { * for (otmp = *objchn; otmp; otmp = otmp2) {
* otmp2 = otmp->nobj; * otmp2 = otmp->nobj;
* ... * ...
* } * }
* is inadequate here. Use each object's bypass bit to keep * is inadequate here. Use each object's bypass bit to keep
* track of which list elements have already been processed. * track of which list elements have already been processed.
*/ */
@@ -1721,11 +1729,11 @@ nextclass:
pline("No applicable objects."); pline("No applicable objects.");
ret: ret:
bypass_objlist(*objchn, FALSE); bypass_objlist(*objchn, FALSE);
return (cnt); return cnt;
} }
/* /*
* Object identification routines: * Object identification routines:
*/ */
/* make an object actually be identified; no display updating */ /* make an object actually be identified; no display updating */
@@ -1860,9 +1868,10 @@ learn_unseen_invent()
update_inventory(); update_inventory();
} }
/* should of course only be called for things in invent */
STATIC_OVL char STATIC_OVL char
obj_to_let(obj) /* should of course only be called for things in invent */ obj_to_let(obj)
register struct obj *obj; struct obj *obj;
{ {
if (!flags.invlet_constant) { if (!flags.invlet_constant) {
obj->invlet = NOINVSYM; obj->invlet = NOINVSYM;
@@ -1878,7 +1887,7 @@ register struct obj *obj;
void void
prinv(prefix, obj, quan) prinv(prefix, obj, quan)
const char *prefix; const char *prefix;
register struct obj *obj; struct obj *obj;
long quan; long quan;
{ {
if (!prefix) if (!prefix)
@@ -1911,8 +1920,8 @@ long quan; /* if non-0, print this quantity, not obj->quan */
/* /*
* If let is: * If let is:
* * Then obj == null and we are printing a total amount. * * Then obj == null and we are printing a total amount.
* > Then the object is contained and doesn't have an inventory letter. * > Then the object is contained and doesn't have an inventory letter.
*/ */
if (cost != 0 || let == '*') { if (cost != 0 || let == '*') {
/* if dot is true, we're doing Iu, otherwise Ix */ /* if dot is true, we're doing Iu, otherwise Ix */
@@ -1960,7 +1969,7 @@ struct obj *list, **last_found;
if (list == *last_found) if (list == *last_found)
*last_found = (struct obj *) 0; *last_found = (struct obj *) 0;
} else } else
return (*last_found = list); return ((*last_found = list));
} }
if (Has_contents(list)) { if (Has_contents(list)) {
if ((obj = find_unpaid(list->cobj, last_found)) != 0) if ((obj = find_unpaid(list->cobj, last_found)) != 0)
@@ -1971,6 +1980,22 @@ struct obj *list, **last_found;
return (struct obj *) 0; 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 * 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, * 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; char *invlet = flags.inv_order;
int i, n, classcount; int i, n, classcount;
winid win; /* windows being used */ winid win; /* windows being used */
static winid local_win = WIN_ERR; /* window for partial menus */
anything any; anything any;
menu_item *selected; menu_item *selected;
struct obj **oarray; struct obj **oarray;
/* overridden by global flag */ if (flags.perm_invent && lets && *lets) {
if (flags.perm_invent) { /* partial inventory in perm_invent setting; don't operate on
win = (lets && *lets) ? local_win : WIN_INVEN; full inventory window, use an alternate one instead; create
/* create the first time used */ the first time needed and keep it for re-use as needed later */
if (win == WIN_ERR) if (cached_pickinv_win == WIN_ERR)
win = local_win = create_nhwindow(NHW_MENU); cached_pickinv_win = create_nhwindow(NHW_MENU);
win = cached_pickinv_win;
} else } else
win = WIN_INVEN; win = WIN_INVEN;
/* /*
Exit early if no inventory -- but keep going if we are doing * Exit early if no inventory -- but keep going if we are doing
a permanent inventory update. We need to keep going so the * a permanent inventory update. We need to keep going so the
permanent inventory window updates itself to remove the last * permanent inventory window updates itself to remove the last
item(s) dropped. One down side: the addition of the exception * item(s) dropped. One down side: the addition of the exception
for permanent inventory window updates _can_ pop the window * for permanent inventory window updates _can_ pop the window
up when it's not displayed -- even if it's empty -- because we * 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 * 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 * an issue if empty checks are done before hand and the call
to here is short circuited away. * to here is short circuited away.
*/ */
if (!invent && !(flags.perm_invent && !lets && !want_reply)) { if (!invent && !(flags.perm_invent && !lets && !want_reply)) {
pline("Not carrying anything."); pline("Not carrying anything.");
return 0; return 0;
@@ -2117,7 +2142,7 @@ nextclass:
*/ */
char char
display_inventory(lets, want_reply) display_inventory(lets, want_reply)
register const char *lets; const char *lets;
boolean want_reply; boolean want_reply;
{ {
return display_pickinv(lets, want_reply, (long *) 0); return display_pickinv(lets, want_reply, (long *) 0);
@@ -2535,8 +2560,7 @@ dotypeinv()
if (oclass == COIN_CLASS) if (oclass == COIN_CLASS)
return doprgold(); return doprgold();
if (index(types, c) > index(types, '\033')) { 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; const char *which = 0;
switch (c) { switch (c) {
@@ -2690,7 +2714,7 @@ boolean picked_some;
} else { } else {
You("%s no objects here.", verb); You("%s no objects here.", verb);
} }
return (!!Blind); return !!Blind;
} }
if (!skip_objects && (trap = t_at(u.ux, u.uy)) && trap->tseen) if (!skip_objects && (trap = t_at(u.ux, u.uy)) && trap->tseen)
There("is %s here.", There("is %s here.",
@@ -2722,7 +2746,7 @@ boolean picked_some;
dfeature = 0; /* ice already identified */ dfeature = 0; /* ice already identified */
if (!can_reach_floor(TRUE)) { if (!can_reach_floor(TRUE)) {
pline("But you can't reach it!"); 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 */ read_engr_at(u.ux, u.uy); /* Eric Backus */
if (!skip_objects && (Blind || !dfeature)) if (!skip_objects && (Blind || !dfeature))
You("%s no objects here.", verb); You("%s no objects here.", verb);
return (!!Blind); return !!Blind;
} }
/* we know there is something here */ /* we know there is something here */
@@ -2806,10 +2830,10 @@ boolean picked_some;
feel_cockatrice(otmp, FALSE); feel_cockatrice(otmp, FALSE);
read_engr_at(u.ux, u.uy); /* Eric Backus */ 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 int
dolook() dolook()
{ {
@@ -2862,8 +2886,9 @@ struct obj *obj;
return; return;
} }
/* returns TRUE if obj & otmp can be merged */
STATIC_OVL boolean STATIC_OVL boolean
mergable(otmp, obj) /* returns TRUE if obj & otmp can be merged */ mergable(otmp, obj)
register struct obj *otmp, *obj; register struct obj *otmp, *obj;
{ {
int objnamelth = 0, otmpnamelth = 0; int objnamelth = 0, otmpnamelth = 0;
@@ -2882,7 +2907,7 @@ register struct obj *otmp, *obj;
|| obj->otrapped != otmp->otrapped || obj->lamplit != otmp->lamplit || obj->otrapped != otmp->otrapped || obj->lamplit != otmp->lamplit
|| obj->greased != otmp->greased || obj->oeroded != otmp->oeroded || obj->greased != otmp->greased || obj->oeroded != otmp->oeroded
|| obj->oeroded2 != otmp->oeroded2 || obj->bypass != otmp->bypass) || obj->oeroded2 != otmp->oeroded2 || obj->bypass != otmp->bypass)
return (FALSE); return FALSE;
if (obj->nomerge) /* explicitly marked to prevent merge */ if (obj->nomerge) /* explicitly marked to prevent merge */
return FALSE; return FALSE;
@@ -2894,7 +2919,7 @@ register struct obj *otmp, *obj;
if (obj->oclass == FOOD_CLASS if (obj->oclass == FOOD_CLASS
&& (obj->oeaten != otmp->oeaten || obj->orotten != otmp->orotten)) && (obj->oeaten != otmp->oeaten || obj->orotten != otmp->orotten))
return (FALSE); return FALSE;
if (obj->otyp == CORPSE || obj->otyp == EGG || obj->otyp == TIN) { if (obj->otyp == CORPSE || obj->otyp == EGG || obj->otyp == TIN) {
if (obj->corpsenm != otmp->corpsenm) if (obj->corpsenm != otmp->corpsenm)
@@ -2910,7 +2935,7 @@ register struct obj *otmp, *obj;
/* allow candle merging only if their ages are close */ /* allow candle merging only if their ages are close */
/* see begin_burn() for a reference for the magic "25" */ /* see begin_burn() for a reference for the magic "25" */
if (Is_candle(obj) && obj->age / 25 != otmp->age / 25) if (Is_candle(obj) && obj->age / 25 != otmp->age / 25)
return (FALSE); return FALSE;
/* burning potions of oil never merge */ /* burning potions of oil never merge */
if (obj->otyp == POT_OIL && obj->lamplit) if (obj->otyp == POT_OIL && obj->lamplit)
@@ -2943,6 +2968,7 @@ register struct obj *otmp, *obj;
return FALSE; return FALSE;
} }
/* the '$' command */
int int
doprgold() doprgold()
{ {
@@ -2957,6 +2983,7 @@ doprgold()
return 0; return 0;
} }
/* the ')' command */
int int
doprwep() doprwep()
{ {
@@ -2994,15 +3021,21 @@ boolean report_uskin;
} }
} }
/* the '[' command */
int int
doprarm() 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()) { if (!wearing_armor()) {
noarmor(TRUE); noarmor(TRUE);
} else { } else {
char lets[8];
register int ct = 0;
if (uarmu) if (uarmu)
lets[ct++] = obj_to_let(uarmu); lets[ct++] = obj_to_let(uarmu);
if (uarm) if (uarm)
@@ -3023,6 +3056,7 @@ doprarm()
return 0; return 0;
} }
/* the '=' command */
int int
doprring() doprring()
{ {
@@ -3042,6 +3076,7 @@ doprring()
return 0; return 0;
} }
/* the '"' command */
int int
dopramulet() dopramulet()
{ {
@@ -3064,6 +3099,7 @@ struct obj *obj;
|| (obj->otyp == LEASH && obj->leashmon)); || (obj->otyp == LEASH && obj->leashmon));
} }
/* the '(' command */
int int
doprtool() doprtool()
{ {
@@ -3236,27 +3272,27 @@ reassign()
/* #adjust command /* #adjust command
* *
* User specifies a 'from' slot for inventory stack to move, * User specifies a 'from' slot for inventory stack to move,
* then a 'to' slot for its destination. Open slots and those * then a 'to' slot for its destination. Open slots and those
* filled by compatible stacks are listed as likely candidates * filled by compatible stacks are listed as likely candidates
* but user can pick any inventory letter (including 'from'). * but user can pick any inventory letter (including 'from').
* All compatible items found are gathered into the 'from' * All compatible items found are gathered into the 'from'
* stack as it is moved. If the 'to' slot isn't empty and * 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. * doesn't merge, then its stack is swapped to the 'from' slot.
* *
* If the user specifies a count when choosing 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, * and that count is less than the full size of the stack,
* then the stack will be split. The 'count' portion is moved * then the stack will be split. The 'count' portion is moved
* to the destination, and the only candidate for merging with * to the destination, and the only candidate for merging with
* it is the stack already at the 'to' slot, if any. When the * it is the stack already at the 'to' slot, if any. When the
* destination is non-empty but won't merge, whatever is there * 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 * will be moved to an open slot; if there isn't any open slot
* available, the adjustment attempt fails. * available, the adjustment attempt fails.
* *
* Splitting has one special case: if 'to' slot is non-empty * Splitting has one special case: if 'to' slot is non-empty
* and is compatible with 'from' in all respects except for * and is compatible with 'from' in all respects except for
* user-assigned names, the 'count' portion being moved is * user-assigned names, the 'count' portion being moved is
* effectively renamed so that it will merge with 'to' stack. * effectively renamed so that it will merge with 'to' stack.
*/ */
int int
doorganize() /* inventory organizer by Del Lamb */ doorganize() /* inventory organizer by Del Lamb */
@@ -3281,7 +3317,7 @@ doorganize() /* inventory organizer by Del Lamb */
allowall[1] = ALL_CLASSES; allowall[1] = ALL_CLASSES;
allowall[2] = '\0'; allowall[2] = '\0';
if (!(obj = getobj(allowall, "adjust"))) if (!(obj = getobj(allowall, "adjust")))
return (0); return 0;
/* figure out whether user gave a split count to getobj() */ /* figure out whether user gave a split count to getobj() */
splitting = bumped = 0; splitting = bumped = 0;
@@ -3440,7 +3476,7 @@ doorganize() /* inventory organizer by Del Lamb */
if (splitting) if (splitting)
clear_splitobjs(); /* reset splitobj context */ clear_splitobjs(); /* reset splitobj context */
update_inventory(); update_inventory();
return (0); return 0;
} }
/* common to display_minventory and display_cinventory */ /* common to display_minventory and display_cinventory */
@@ -3466,15 +3502,25 @@ const char *hdr, *txt;
return; 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 STATIC_OVL boolean
worn_wield_only(obj) worn_wield_only(obj)
struct obj *obj; struct obj *obj;
{ {
return (obj->oclass == WEAPON_CLASS || obj->oclass == ARMOR_CLASS #if 1
|| obj->oclass == AMULET_CLASS || obj->oclass == RING_CLASS /* check for things that *are* worn or wielded (only used for monsters,
|| obj->oclass == TOOL_CLASS); 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 * By default, only worn and wielded items are displayed. The caller
* can pick one. Modifier flags are: * can pick one. Modifier flags are:
* *
* MINV_NOLET - nothing selectable * MINV_NOLET - nothing selectable
* MINV_ALL - display all inventory * MINV_ALL - display all inventory
*/ */
struct obj * struct obj *
display_minventory(mon, dflags, title) 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. */ /* 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. */
@@ -1387,10 +1387,14 @@ freedynamicdata()
if (iflags.wc_tile_file) if (iflags.wc_tile_file)
free(iflags.wc_tile_file); free(iflags.wc_tile_file);
free_autopickup_exceptions(); free_autopickup_exceptions();
/* miscellaneous */
free_pickinv_cache();
#endif /* FREE_ALL_MEMORY */ #endif /* FREE_ALL_MEMORY */
#ifdef STATUS_VIA_WINDOWPORT #ifdef STATUS_VIA_WINDOWPORT
status_finish(); status_finish();
#endif #endif
sysopt_release(); /* SYSCF strings */ sysopt_release(); /* SYSCF strings */
return; return;
} }