Allow identifying stackable items by comparison to identical items

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.
This commit is contained in:
Alex Smith
2023-11-19 01:16:40 +00:00
parent 11ad859c4c
commit 86c29f5b47
2 changed files with 42 additions and 3 deletions

View File

@@ -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

View File

@@ -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
@@ -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;
@@ -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;
}
@@ -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) {
@@ -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 */