From bcb9d35fe32d123f380e6a5d3c0bff33e0632a24 Mon Sep 17 00:00:00 2001 From: "nethack.rankin" Date: Tue, 15 Nov 2005 04:50:06 +0000 Subject: [PATCH] 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. --- include/extern.h | 1 + src/artifact.c | 11 ++-- src/o_init.c | 127 +++++++++++++++++++++++++++++++---------------- 3 files changed, 91 insertions(+), 48 deletions(-) diff --git a/include/extern.h b/include/extern.h index caf08669d..6d9f63840 100644 --- a/include/extern.h +++ b/include/extern.h @@ -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)); diff --git a/src/artifact.c b/src/artifact.c index f24537b4c..1dad6d9e6 100644 --- a/src/artifact.c +++ b/src/artifact.c @@ -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. diff --git a/src/o_init.c b/src/o_init.c index 3ad573736..ceb35d3c8 100644 --- a/src/o_init.c +++ b/src/o_init.c @@ -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 */