yet more artifact name handling (trunk only)

The fix to prevent naming an unknown gray stone "the Heart of Ahriman"
from revealing whether the object was a luckstone was inadequate to prevent
using the same trick with "the Mitre of Holiness" to determine if an unknown
helmet was a helm of brilliance.  (I don't know whether whoever figured out
the first one has realized the second yet; no one had mentioned it in the
newsgroup the last time I looked.)  To get this right we need to check for
objects sharing the same set of shuffled descriptions in addition to testing
whether they have identical descriptions.  Doing that meant reorganizing how
object shuffling is done, but it produces the same behavior as before.
This commit is contained in:
nethack.rankin
2005-11-15 04:50:06 +00:00
parent 179e30b2fe
commit bcb9d35fe3
3 changed files with 91 additions and 48 deletions

View File

@@ -1399,6 +1399,7 @@ E void NDECL(synch_cursor);
/* ### o_init.c ### */
E void NDECL(init_objects);
E void FDECL(obj_shuffle_range, (int,int *,int *));
E int NDECL(find_skates);
E void NDECL(oinit);
E void FDECL(savenames, (int,int));

View File

@@ -281,7 +281,7 @@ register const char *name;
register const struct artifact *a;
const char *aname, *odesc, *other;
boolean sametype[NUM_OBJECTS];
int i, otyp = otmp->otyp, ocls = objects[otyp].oc_class;
int i, lo, hi, otyp = otmp->otyp, ocls = objects[otyp].oc_class;
if (!*name) return FALSE;
if (!strncmpi(name, "the ", 4)) name += 4;
@@ -289,18 +289,21 @@ register const char *name;
/* decide what types of objects are the same as otyp;
if it's been discovered, then only itself matches;
otherwise, include all other undiscovered objects
of the same class which have the same description */
of the same class which have the same description
or share the same pool of shuffled descriptions */
(void) memset((genericptr_t)sametype, 0, sizeof sametype); /* FALSE */
sametype[otyp] = TRUE;
if (!objects[otyp].oc_name_known &&
(odesc = OBJ_DESCR(objects[otyp])) != 0)
(odesc = OBJ_DESCR(objects[otyp])) != 0) {
obj_shuffle_range(otyp, &lo, &hi);
for (i = bases[ocls]; i < NUM_OBJECTS; i++) {
if (objects[i].oc_class != ocls) break;
if (!objects[i].oc_name_known &&
(other = OBJ_DESCR(objects[i])) != 0 &&
!strcmp(odesc, other))
(!strcmp(odesc, other) || (i >= lo && i <= hi)))
sametype[i] = TRUE;
}
}
/* Since almost every artifact is SPFX_RESTR, it doesn't cost
us much to do the string comparison before the spfx check.

View File

@@ -1,4 +1,4 @@
/* SCCS Id: @(#)o_init.c 3.5 1999/12/09 */
/* SCCS Id: @(#)o_init.c 3.5 2005/11/14 */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
@@ -176,53 +176,92 @@ register char oclass;
#endif
}
/* retrieve the range of objects that otyp shares descriptions with */
void
obj_shuffle_range(otyp, lo_p, hi_p)
int otyp; /* input: representative item */
int *lo_p, *hi_p; /* output: range that item belongs among */
{
int i, ocls = objects[otyp].oc_class;
/* default is just the object itself */
*lo_p = *hi_p = otyp;
switch (ocls) {
case ARMOR_CLASS:
if (otyp >= HELMET && otyp <= HELM_OF_TELEPATHY)
*lo_p = HELMET, *hi_p = HELM_OF_TELEPATHY;
else if (otyp >= LEATHER_GLOVES && otyp <= GAUNTLETS_OF_DEXTERITY)
*lo_p = LEATHER_GLOVES, *hi_p = GAUNTLETS_OF_DEXTERITY;
else if (otyp >= CLOAK_OF_PROTECTION && otyp <= CLOAK_OF_DISPLACEMENT)
*lo_p = CLOAK_OF_PROTECTION, *hi_p = CLOAK_OF_DISPLACEMENT;
else if (otyp >= SPEED_BOOTS && otyp <= LEVITATION_BOOTS)
*lo_p = SPEED_BOOTS, *hi_p = LEVITATION_BOOTS;
break;
case POTION_CLASS:
/* potion of water has the only fixed description */
*lo_p = bases[POTION_CLASS];
*hi_p = POT_WATER - 1;
break;
case AMULET_CLASS:
case SCROLL_CLASS:
case SPBOOK_CLASS:
/* exclude non-magic types and also unique ones */
*lo_p = bases[ocls];
for (i = *lo_p; objects[i].oc_class == ocls; i++)
if (objects[i].oc_unique || !objects[i].oc_magic) break;
*hi_p = i - 1;
break;
case RING_CLASS:
case WAND_CLASS:
case VENOM_CLASS:
/* entire class */
*lo_p = bases[ocls];
for (i = *lo_p; objects[i].oc_class == ocls; i++) continue;
*hi_p = i - 1;
break;
}
/* artifact checking might ask about item which isn't part of any range
but fell within the classes that do have ranges specified above */
if (otyp < *lo_p || otyp > *hi_p) *lo_p = *hi_p = otyp;
return;
}
/* randomize object descriptions */
STATIC_OVL void
shuffle_all()
{
int first, last, oclass;
/* entire classes; obj_shuffle_range() handles their exceptions */
static char shuffle_classes[] = {
AMULET_CLASS,
POTION_CLASS,
RING_CLASS,
SCROLL_CLASS,
SPBOOK_CLASS,
WAND_CLASS,
VENOM_CLASS,
};
/* sub-class type ranges (one item from each group) */
static short shuffle_types[] = {
HELMET,
LEATHER_GLOVES,
CLOAK_OF_PROTECTION,
SPEED_BOOTS,
};
int first, last, idx;
for (oclass = 1; oclass < MAXOCLASSES; oclass++) {
first = bases[oclass];
last = first+1;
while (last < NUM_OBJECTS && objects[last].oc_class == oclass)
last++;
if (OBJ_DESCR(objects[first]) != (char *)0 &&
oclass != TOOL_CLASS &&
oclass != WEAPON_CLASS &&
oclass != ARMOR_CLASS &&
oclass != GEM_CLASS) {
int j = last-1;
if (oclass == POTION_CLASS)
j -= 1; /* only water has a fixed description */
else if (oclass == AMULET_CLASS ||
oclass == SCROLL_CLASS ||
oclass == SPBOOK_CLASS) {
while (!objects[j].oc_magic || objects[j].oc_unique)
j--;
}
/* non-magical amulets, scrolls, and spellbooks
* (ex. imitation Amulets, blank, scrolls of mail)
* and one-of-a-kind magical artifacts at the end of
* their class in objects[] have fixed descriptions.
*/
shuffle(first, j, TRUE);
}
}
/* shuffle the helmets */
shuffle(HELMET, HELM_OF_TELEPATHY, FALSE);
/* shuffle the gloves */
shuffle(LEATHER_GLOVES, GAUNTLETS_OF_DEXTERITY, FALSE);
/* shuffle the cloaks */
shuffle(CLOAK_OF_PROTECTION, CLOAK_OF_DISPLACEMENT, FALSE);
/* shuffle the boots [if they change, update find_skates() below] */
shuffle(SPEED_BOOTS, LEVITATION_BOOTS, FALSE);
/* do whole classes (amulets, &c) */
for (idx = 0; idx < SIZE(shuffle_classes); idx++) {
obj_shuffle_range(bases[shuffle_classes[idx]], &first, &last);
shuffle(first, last, TRUE);
}
/* do type ranges (helms, &c) */
for (idx = 0; idx < SIZE(shuffle_types); idx++) {
obj_shuffle_range(shuffle_types[idx], &first, &last);
shuffle(first, last, FALSE);
}
return;
}
/* find the object index for snow boots; used [once] by slippery ice code */