new container flags

[Attention: This patch increments EDITLEVEL in patchlevel.h, rendering all
 previous save and bones files obsolete.]

Here's the first cut at the two recommended flags lknown and cknown.
I've attempted to stay close to Pat's recommendations:
   "Containers ought to have two new flags:  lknown for lock status known,
    and cknown for contents known (ie, `secret').  Formatted box and chest
    descriptions should include locked/unlocked/broken when that is known
    and empty/nonempty (or something like "holds N items") when contents
    are known. The contents indicator would also apply to nonlockable
    containers."

I probably overlooked a place where a flag should be adjusted, but this
should give us a good starting point.

I wasn't sure what to do with the case of the auditory feedback for
magical locking "Click" and "Clunk". The question that came to my mind
was: Should those reveal the locked or unlocked status of a box?
I suppose if you knew the type of wand you were zapping or the spell
you were casting, you could argue that they should.

In the end, I opted for setting lknown right off the zap/cast effect
for anyone playing a Wizard role, and not setting it for anyone else,
thus advancing class differentiation a little bit too.

I haven't checked the cknown results under all flags.menu_style options
at this point, only MENU_FULL.
This commit is contained in:
nethack.allison
2004-12-15 23:50:18 +00:00
parent 10b227e242
commit 5a433fe0e0
10 changed files with 79 additions and 8 deletions
+2
View File
@@ -115,6 +115,8 @@ vampires can now shapeshift into bats and fog clouds; the latter can be done at
will to slip through locked doors will to slip through locked doors
shapeshifted vampire will transform back to vampire form after you defeat it and shapeshifted vampire will transform back to vampire form after you defeat it and
continue to fight in its native form continue to fight in its native form
container lknown flag for locked/unlocked/broken awareness
container cknown flag for container content awareness
Platform- and/or Interface-Specific New Features Platform- and/or Interface-Specific New Features
+3 -1
View File
@@ -92,7 +92,9 @@ struct obj {
Bitfield(in_use,1); /* for magic items before useup items */ Bitfield(in_use,1); /* for magic items before useup items */
Bitfield(bypass,1); /* mark this as an object to be skipped by bhito() */ Bitfield(bypass,1); /* mark this as an object to be skipped by bhito() */
/* 6 free bits */ Bitfield(cknown,1); /* contents of container assumed to be known */
Bitfield(lknown,1); /* locked/unlocked status is known */
/* 4 free bits */
int corpsenm; /* type of corpse is mons[corpsenm] */ int corpsenm; /* type of corpse is mons[corpsenm] */
#define leashmon corpsenm /* gets m_id of attached pet */ #define leashmon corpsenm /* gets m_id of attached pet */
+2 -2
View File
@@ -1,4 +1,4 @@
/* SCCS Id: @(#)patchlevel.h 3.4 2004/06/12 */ /* SCCS Id: @(#)patchlevel.h 3.4 2004/12/15 */
/* 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. */
@@ -13,7 +13,7 @@
* Incrementing EDITLEVEL can be used to force invalidation of old bones * Incrementing EDITLEVEL can be used to force invalidation of old bones
* and save files. * and save files.
*/ */
#define EDITLEVEL 14 #define EDITLEVEL 15
#define COPYRIGHT_BANNER_A \ #define COPYRIGHT_BANNER_A \
"NetHack, Copyright 1985-2004" "NetHack, Copyright 1985-2004"
+2
View File
@@ -516,12 +516,14 @@ xchar x, y;
You("break open the lock!"); You("break open the lock!");
kickobj->olocked = 0; kickobj->olocked = 0;
kickobj->obroken = 1; kickobj->obroken = 1;
kickobj->lknown = 1;
if (otrp) (void) chest_trap(kickobj, LEG, FALSE); if (otrp) (void) chest_trap(kickobj, LEG, FALSE);
return(1); return(1);
} }
} else { } else {
if (!rn2(3) || (martial() && !rn2(2))) { if (!rn2(3) || (martial() && !rn2(2))) {
pline_The("lid slams open, then falls shut."); pline_The("lid slams open, then falls shut.");
kickobj->lknown = 1;
if (otrp) (void) chest_trap(kickobj, LEG, FALSE); if (otrp) (void) chest_trap(kickobj, LEG, FALSE);
return(1); return(1);
} }
+17 -4
View File
@@ -1917,15 +1917,27 @@ dounpaid()
*/ */
for (otmp = invent; otmp; otmp = otmp->nobj) { for (otmp = invent; otmp; otmp = otmp->nobj) {
if (Has_contents(otmp)) { if (Has_contents(otmp)) {
long contcost = 0L;
marker = (struct obj *) 0; /* haven't found any */ marker = (struct obj *) 0; /* haven't found any */
while (find_unpaid(otmp->cobj, &marker)) { while (find_unpaid(otmp->cobj, &marker)) {
totcost += cost = unpaid_cost(marker); totcost += cost = unpaid_cost(marker);
save_unpaid = marker->unpaid; contcost += cost;
marker->unpaid = 0; /* suppress "(unpaid)" suffix */ if (otmp->cknown) {
putstr(win, 0, save_unpaid = marker->unpaid;
marker->unpaid = 0; /* suppress "(unpaid)" suffix */
putstr(win, 0,
xprname(marker, distant_name(marker, doname), xprname(marker, distant_name(marker, doname),
CONTAINED_SYM, TRUE, cost, 0L)); CONTAINED_SYM, TRUE, cost, 0L));
marker->unpaid = save_unpaid; marker->unpaid = save_unpaid;
}
}
if (!otmp->cknown) {
char contbuf[BUFSZ];
/* Shopkeeper knows what to charge for contents */
Sprintf(contbuf, "%s contents", s_suffix(xname(otmp)));
putstr(win, 0,
xprname((struct obj *)0, contbuf,
CONTAINED_SYM, TRUE, contcost, 0L));
} }
} }
} }
@@ -2937,6 +2949,7 @@ register struct obj *obj;
free((genericptr_t)selected); free((genericptr_t)selected);
} else } else
ret = (struct obj *) 0; ret = (struct obj *) 0;
obj->cknown = 1;
return ret; return ret;
} }
+7
View File
@@ -117,6 +117,7 @@ picklock() /* try to open/close a lock */
else xlock.door->doormask = D_LOCKED; else xlock.door->doormask = D_LOCKED;
} else { } else {
xlock.box->olocked = !xlock.box->olocked; xlock.box->olocked = !xlock.box->olocked;
xlock.box->lknown = 1;
if(xlock.box->otrapped) if(xlock.box->otrapped)
(void) chest_trap(xlock.box, FINGER, FALSE); (void) chest_trap(xlock.box, FINGER, FALSE);
} }
@@ -163,6 +164,7 @@ forcelock() /* try to force a locked chest */
You("succeed in forcing the lock."); You("succeed in forcing the lock.");
xlock.box->olocked = 0; xlock.box->olocked = 0;
xlock.box->obroken = 1; xlock.box->obroken = 1;
xlock.box->lknown = 1;
if(!xlock.picktyp && !rn2(3)) { if(!xlock.picktyp && !rn2(3)) {
struct monst *shkp; struct monst *shkp;
boolean costly; boolean costly;
@@ -301,6 +303,7 @@ pick_lock(pick) /* pick a lock with a given object */
safe_qbuf("", sizeof("There is here, unlock its lock?"), safe_qbuf("", sizeof("There is here, unlock its lock?"),
doname(otmp), an(simple_typename(otmp->otyp)), "a box"), doname(otmp), an(simple_typename(otmp->otyp)), "a box"),
verb, it ? "it" : "its lock"); verb, it ? "it" : "its lock");
otmp->lknown = 1;
c = ynq(qbuf); c = ynq(qbuf);
if(c == 'q') return(0); if(c == 'q') return(0);
@@ -461,12 +464,14 @@ doforce() /* try to force a chest with your weapon */
if (otmp->obroken || !otmp->olocked) { if (otmp->obroken || !otmp->olocked) {
There("is %s here, but its lock is already %s.", There("is %s here, but its lock is already %s.",
doname(otmp), otmp->obroken ? "broken" : "unlocked"); doname(otmp), otmp->obroken ? "broken" : "unlocked");
otmp->lknown = 1;
continue; continue;
} }
Sprintf(qbuf,"There is %s here, force its lock?", Sprintf(qbuf,"There is %s here, force its lock?",
safe_qbuf("", sizeof("There is here, force its lock?"), safe_qbuf("", sizeof("There is here, force its lock?"),
doname(otmp), an(simple_typename(otmp->otyp)), doname(otmp), an(simple_typename(otmp->otyp)),
"a box")); "a box"));
otmp->lknown = 1;
c = ynq(qbuf); c = ynq(qbuf);
if(c == 'q') return(0); if(c == 'q') return(0);
@@ -702,6 +707,7 @@ register struct obj *obj, *otmp; /* obj *is* a box */
pline("Klunk!"); pline("Klunk!");
obj->olocked = 1; obj->olocked = 1;
obj->obroken = 0; obj->obroken = 0;
if (Role_if(PM_WIZARD)) obj->lknown = 1;
res = 1; res = 1;
} /* else already closed and locked */ } /* else already closed and locked */
break; break;
@@ -711,6 +717,7 @@ register struct obj *obj, *otmp; /* obj *is* a box */
pline("Klick!"); pline("Klick!");
obj->olocked = 0; obj->olocked = 0;
res = 1; res = 1;
if (Role_if(PM_WIZARD)) obj->lknown = 1;
} else /* silently fix if broken */ } else /* silently fix if broken */
obj->obroken = 0; obj->obroken = 0;
break; break;
+2
View File
@@ -377,6 +377,8 @@ boolean artif;
otmp->dknown = 0; otmp->dknown = 0;
if (!objects[otmp->otyp].oc_uses_known) if (!objects[otmp->otyp].oc_uses_known)
otmp->known = 1; otmp->known = 1;
otmp->lknown = 0;
otmp->cknown = 0;
#ifdef INVISIBLE_OBJECTS #ifdef INVISIBLE_OBJECTS
otmp->oinvis = !rn2(1250); otmp->oinvis = !rn2(1250);
#endif #endif
+25
View File
@@ -569,6 +569,11 @@ register struct obj *obj;
if (obj->oinvis) Strcat(prefix,"invisible "); if (obj->oinvis) Strcat(prefix,"invisible ");
#endif #endif
/* "empty" goes at the beginning, but item count goes at the end */
if (obj->cknown &&
(Is_container(obj) || obj->otyp == STATUE) && !Has_contents(obj))
Strcat(prefix, "empty ");
if (obj->bknown && if (obj->bknown &&
obj->oclass != COIN_CLASS && obj->oclass != COIN_CLASS &&
(obj->otyp != POT_WATER || !objects[POT_WATER].oc_name_known (obj->otyp != POT_WATER || !objects[POT_WATER].oc_name_known
@@ -602,8 +607,28 @@ register struct obj *obj;
Strcat(prefix, "uncursed "); Strcat(prefix, "uncursed ");
} }
if (obj->lknown && Is_box(obj)) {
if (obj->obroken)
Strcat(prefix, "unlockable ");
else if (obj->olocked)
Strcat(prefix, "locked ");
else
Strcat(prefix, "unlocked ");
}
if (obj->greased) Strcat(prefix, "greased "); if (obj->greased) Strcat(prefix, "greased ");
if (obj->cknown && Has_contents(obj)) {
struct obj *curr;
long itemcount = 0L;
/* Count the number of contained objects */
for (curr = obj->cobj; curr; curr = curr->nobj)
itemcount += curr->quan;
Sprintf(eos(bp), " containing %ld item%s",
itemcount, plur(itemcount));
}
switch(obj->oclass) { switch(obj->oclass) {
case AMULET_CLASS: case AMULET_CLASS:
if(obj->owornmask & W_AMUL) if(obj->owornmask & W_AMUL)
+17
View File
@@ -1544,8 +1544,11 @@ lootcont:
if (cobj->olocked) { if (cobj->olocked) {
pline("Hmmm, it seems to be locked."); pline("Hmmm, it seems to be locked.");
cobj->lknown = 1;
continue; continue;
} }
cobj->lknown = 1;
if (cobj->otyp == BAG_OF_TRICKS) { if (cobj->otyp == BAG_OF_TRICKS) {
int tmp; int tmp;
You("carefully open the bag..."); You("carefully open the bag...");
@@ -2091,9 +2094,11 @@ register int held;
if (obj->olocked) { if (obj->olocked) {
pline("%s to be locked.", Tobjnam(obj, "seem")); pline("%s to be locked.", Tobjnam(obj, "seem"));
if (held) You("must put it down to unlock."); if (held) You("must put it down to unlock.");
obj->lknown = 1;
return 0; return 0;
} else if (obj->otrapped) { } else if (obj->otrapped) {
if (held) You("open %s...", the(xname(obj))); if (held) You("open %s...", the(xname(obj)));
obj->lknown = 1;
(void) chest_trap(obj, HAND, FALSE); (void) chest_trap(obj, HAND, FALSE);
/* even if the trap fails, you've used up this turn */ /* even if the trap fails, you've used up this turn */
if (multi >= 0) { /* in case we didn't become paralyzed */ if (multi >= 0) { /* in case we didn't become paralyzed */
@@ -2102,6 +2107,7 @@ register int held;
} }
return 1; return 1;
} }
obj->lknown = 1;
current_container = obj; /* for use by in/out_container */ current_container = obj; /* for use by in/out_container */
if (obj->spe == 1) { if (obj->spe == 1) {
@@ -2147,6 +2153,7 @@ register int held;
if (!outokay && !inokay) { if (!outokay && !inokay) {
pline("%s", emptymsg); pline("%s", emptymsg);
You("don't have anything to put in."); You("don't have anything to put in.");
if (used) obj->cknown = 1;
return used; return used;
} }
menuprompt[0] = '\0'; menuprompt[0] = '\0';
@@ -2201,6 +2208,7 @@ ask_again2:
break; break;
case 'q': case 'q':
default: default:
if (used) obj->cknown = 1;
return used; return used;
} }
} }
@@ -2215,6 +2223,7 @@ ask_again2:
#endif #endif
/* nothing to put in, but some feedback is necessary */ /* nothing to put in, but some feedback is necessary */
You("don't have anything to put in."); You("don't have anything to put in.");
if (used) obj->cknown = 1;
return used; return used;
} }
if (flags.menu_style != MENU_FULL) { if (flags.menu_style != MENU_FULL) {
@@ -2235,6 +2244,7 @@ ask_again2:
break; break;
case 'q': case 'q':
default: default:
if (used) obj->cknown = 1;
return used; return used;
} }
} }
@@ -2330,6 +2340,7 @@ boolean put_in;
} }
if (loot_everything) { if (loot_everything) {
container->cknown = 1;
for (otmp = container->cobj; otmp; otmp = otmp2) { for (otmp = container->cobj; otmp; otmp = otmp2) {
otmp2 = otmp->nobj; otmp2 = otmp->nobj;
res = out_container(otmp); res = out_container(otmp);
@@ -2338,6 +2349,7 @@ boolean put_in;
} else { } else {
mflags = INVORDER_SORT; mflags = INVORDER_SORT;
if (put_in && flags.invlet_constant) mflags |= USE_INVLET; if (put_in && flags.invlet_constant) mflags |= USE_INVLET;
if (takeout) container->cknown = 1;
Sprintf(buf,"%s what?", put_in ? putin : takeout); Sprintf(buf,"%s what?", put_in ? putin : takeout);
n = query_objlist(buf, put_in ? invent : container->cobj, n = query_objlist(buf, put_in ? invent : container->cobj,
mflags, &pick_list, PICK_ANY, mflags, &pick_list, PICK_ANY,
@@ -2511,6 +2523,7 @@ struct obj *box; /* or bag */
{ {
boolean empty_it = FALSE; boolean empty_it = FALSE;
box->lknown = 1;
if (box->olocked) { if (box->olocked) {
pline("It's locked."); pline("It's locked.");
} else if (box->otrapped) { } else if (box->otrapped) {
@@ -2524,16 +2537,19 @@ struct obj *box; /* or bag */
} else if (box->otyp == BAG_OF_TRICKS && box->spe > 0) { } else if (box->otyp == BAG_OF_TRICKS && box->spe > 0) {
/* apply (not loot) this bag; uses up one charge */ /* apply (not loot) this bag; uses up one charge */
bagotricks(box); bagotricks(box);
box->cknown = 1;
} else if (box->spe) { } else if (box->spe) {
char yourbuf[BUFSZ]; char yourbuf[BUFSZ];
observe_quantum_cat(box); observe_quantum_cat(box);
box->cknown = 1;
if (!Has_contents(box)) /* evidently a live cat came out */ if (!Has_contents(box)) /* evidently a live cat came out */
/* container type of "large box" is inferred */ /* container type of "large box" is inferred */
pline("%sbox is now empty.", Shk_Your(yourbuf, box)); pline("%sbox is now empty.", Shk_Your(yourbuf, box));
else /* holds cat corpse or other random stuff */ else /* holds cat corpse or other random stuff */
empty_it = TRUE; empty_it = TRUE;
} else if (!Has_contents(box)) { } else if (!Has_contents(box)) {
box->cknown = 1;
pline("It's empty."); pline("It's empty.");
} else { } else {
empty_it = TRUE; empty_it = TRUE;
@@ -2548,6 +2564,7 @@ struct obj *box; /* or bag */
int held = carried(box); int held = carried(box);
long loss = 0L; long loss = 0L;
box->cknown = 1;
pline("%s out%c", pline("%s out%c",
box->cobj->nobj ? "Objects spill" : "An object spills", box->cobj->nobj ? "Objects spill" : "An object spills",
!(highdrop || altarizing) ? ':' : '.'); !(highdrop || altarizing) ? ':' : '.');
+1
View File
@@ -1561,6 +1561,7 @@ struct obj *obj, *otmp;
o->dknown = 1; /* "seen", even if blind */ o->dknown = 1; /* "seen", even if blind */
(void) display_cinventory(obj); (void) display_cinventory(obj);
} }
obj->cknown = 1;
res = 1; res = 1;
} }
if (res) makeknown(WAN_PROBING); if (res) makeknown(WAN_PROBING);