Skip to content

Commit

Permalink
Allow identifying stackable items by comparison to identical items
Browse files Browse the repository at this point in the history
NetHack has historically had problems (both in terms of interface
and in terms of gameplay exploits) caused by unidentified items
not stacking with identified items.  The 3.7 change to cause items
picked up by monsters to become unidentified has exacerbated this,
e.g. there's an undesirable strategy in which players give
ammunition to hostile monsters in order to unidentify it, allowing
it to stack with other unidentified ammunition so that the whole
stack can be enchanted with a single scroll.

This commit makes it possible to stack items with different
identification statuses (unles Blind), in effect causing the
unidentified items to be identified by comparing them to the
identified items (this is consistent with the mechanic via which
two stacks of unidentified items can be determined to be the same
as each other).  The hope is that this will prevent any gain from
exploits involving intentionally unidentifying (or intentionally
failing to identify) items, that it will prevent interface clutter
caused by (e.g.) a Ranger's main projectiles becoming partially
unidentified as a nymph picks them up and subsequently failing to
stack, and that it will reduce the incentive to backtrack to an
altar to merge, e.g., a stack of formally-known-uncursed and a
stack of informally-known-uncursed food rations to stack.
  • Loading branch information
Alex Smith committed Nov 19, 2023
1 parent 11ad859 commit 86c29f5
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 3 deletions.
2 changes: 2 additions & 0 deletions doc/fixes3-7-0.txt
Expand Up @@ -511,6 +511,8 @@ any blessed key was behaving as if was the rogue's Master Key when unlocking
when an unseen non-pet picks up or uses an item, hero loses known/dknown/
bknown/cknown/lknown memory of that item (so becomes unidentified; in
particular, player won't be asked what to call unseen thrown potion)
when picking up a stackable item, it can be identified by comparing it to
another identical item that is already identified
wishing for a partly eaten wraith corpse yielded "partly eaten food (1) more
nutritious than untouched food (0)"
if PREFIXES_IN_USE was defined (and VAR_PLAYGROUND forces it to be) when
Expand Down
43 changes: 40 additions & 3 deletions src/invent.c
Expand Up @@ -707,6 +707,7 @@ int
merged(struct obj **potmp, struct obj **pobj)
{
register struct obj *otmp = *potmp, *obj = *pobj;
boolean discovered = FALSE;

if (mergable(otmp, obj)) {
/* Approximate age: we do it this way because if we were to
Expand Down Expand Up @@ -745,6 +746,29 @@ merged(struct obj **potmp, struct obj **pobj)
if (obj->timed)
obj_stop_timers(obj); /* follows lights */

/* objects can be identified by comparing them (unless Blind,
but that is handled in mergable()); the object becomes
identified in a particular dimension if either object was
previously identified in that dimension, and if the
identification states don't match, one of them must have
previously been identified */
if (obj->known != otmp->known) {
otmp->known = TRUE;
discovered = TRUE;
}
if (obj->rknown != otmp->rknown) {
otmp->rknown = TRUE;
if (otmp->oerodeproof) {
discovered = TRUE;
}
}
if (obj->bknown != otmp->bknown) {
otmp->bknown = TRUE;
if (!Role_if(PM_CLERIC)) {
discovered = TRUE;
}
}

/* fixup for `#adjust' merging wielded darts, daggers, &c */
if (obj->owornmask && carried(otmp)) {
long wmask = otmp->owornmask | obj->owornmask;
Expand Down Expand Up @@ -802,6 +826,15 @@ merged(struct obj **potmp, struct obj **pobj)
return 1;
}

/* Print a message if item comparison discovers more
information about the items (with the exception of thrown
items, where this would be too spammy as such items get
unidentified by monsters very frequently). */
if (discovered && otmp->where == OBJ_INVENT &&
!obj->was_thrown && !otmp->was_thrown) {
pline("You learn more about your items by comparing them.");
}

obfree(obj, otmp); /* free(obj), bill->otmp */
return 1;
}
Expand Down Expand Up @@ -4548,14 +4581,15 @@ mergable(
return FALSE;

if (obj->dknown != otmp->dknown
|| (obj->bknown != otmp->bknown && !Role_if(PM_CLERIC))
|| (obj->bknown != otmp->bknown && !Role_if(PM_CLERIC) &&
(Blind || Hallucination))
|| obj->oeroded != otmp->oeroded || obj->oeroded2 != otmp->oeroded2
|| obj->greased != otmp->greased)
return FALSE;

if ((obj->oclass == WEAPON_CLASS || obj->oclass == ARMOR_CLASS)
&& (obj->oerodeproof != otmp->oerodeproof
|| obj->rknown != otmp->rknown))
|| (obj->rknown != otmp->rknown && (Blind || Hallucination))))
return FALSE;

if (obj->otyp == CORPSE || obj->otyp == EGG || obj->otyp == TIN) {
Expand Down Expand Up @@ -4614,7 +4648,10 @@ mergable(
if (obj->oartifact != otmp->oartifact)
return FALSE;

return (obj->known == otmp->known) ? TRUE : FALSE;
if (obj->known != otmp->known && (Blind || Hallucination))
return FALSE;

return TRUE;
}

/* the #showgold command */
Expand Down

0 comments on commit 86c29f5

Please sign in to comment.