From 37ef5a2561f906fb302482ec686f4ac5d3be6f56 Mon Sep 17 00:00:00 2001 From: PatR Date: Sun, 19 Apr 2020 04:18:22 -0700 Subject: [PATCH] objects[] infrastructure The bases[] array allows finding the index of the first object in a particular class. Extend it so that bases[class + 1] - 1 is a reliable way to find the last object in any class. The array had to be extended by one so that the last class has a [class+1] entry available, and object initialization now makes sure that classes within objects[] are in ascending order so that [class+1] always holds a higher index than [class]. --- include/decl.h | 2 +- src/o_init.c | 32 ++++++++++++++++++++++++++------ src/objnam.c | 23 +++++++++++++++-------- 3 files changed, 42 insertions(+), 15 deletions(-) diff --git a/include/decl.h b/include/decl.h index b86254fb2..6b7142e57 100644 --- a/include/decl.h +++ b/include/decl.h @@ -713,7 +713,7 @@ struct instance_globals { const char *hname; /* name of the game (argv[0] of main) */ int hackpid; /* current process id */ char chosen_windowtype[WINTYPELEN]; - int bases[MAXOCLASSES]; + int bases[MAXOCLASSES + 1]; int multi; const char *multi_reason; int nroom; diff --git a/src/o_init.c b/src/o_init.c index b6b27ca91..be169843d 100644 --- a/src/o_init.c +++ b/src/o_init.c @@ -108,8 +108,8 @@ boolean domaterial; void init_objects() { - register int i, first, last, sum; - register char oclass; + int i, first, last, sum; + char oclass, prevoclass; #ifdef TEXTCOLOR #define COPY_OBJ_DESCR(o_dst, o_src) \ o_dst.oc_descr_idx = o_src.oc_descr_idx, o_dst.oc_color = o_src.oc_color @@ -120,7 +120,7 @@ init_objects() /* bug fix to prevent "initialization error" abort on Intel Xenix. * reported by mikew@semike */ - for (i = 0; i < MAXOCLASSES; i++) + for (i = 0; i <= MAXOCLASSES; i++) g.bases[i] = 0; /* initialize object descriptions */ for (i = 0; i < NUM_OBJECTS; i++) @@ -128,8 +128,19 @@ init_objects() /* init base; if probs given check that they add up to 1000, otherwise compute probs */ first = 0; + prevoclass = -1; while (first < NUM_OBJECTS) { oclass = objects[first].oc_class; + /* + * objects[] sanity check: must be in ascending oc_class order to + * be able to use bases[class+1]-1 for the end of a class's range. + * Also catches a non-contiguous class because reverting to any + * earlier class would involve switching back to a lower class + * number after having moved on to one or more other classes. + */ + if (oclass < prevoclass) + panic("objects[%d] class #%d not in order!", first, oclass); + last = first + 1; while (last < NUM_OBJECTS && objects[last].oc_class == oclass) last++; @@ -170,7 +181,18 @@ init_objects() if (sum != 1000) error("init-prob error for class %d (%d%%)", oclass, sum); first = last; + prevoclass = oclass; } + /* extra entry allows deriving the range of a class via + bases[class] through bases[class+1]-1 for all classes */ + g.bases[MAXOCLASSES] = NUM_OBJECTS; + /* hypothetically someone might remove all objects of some class, + or be adding a new class and not populated it yet, leaving gaps + in bases[]; guarantee that there are no such gaps */ + for (last = MAXOCLASSES - 1; last >= 0; --last) + if (!g.bases[last]) + g.bases[last] = g.bases[last + 1]; + /* shuffle descriptions */ shuffle_all(); #ifdef USE_TILES @@ -221,9 +243,7 @@ int *lo_p, *hi_p; /* output: range that item belongs among */ case VENOM_CLASS: /* entire class */ *lo_p = g.bases[ocls]; - for (i = *lo_p; objects[i].oc_class == ocls; i++) - continue; - *hi_p = i - 1; + *hi_p = g.bases[ocls + 1] - 1; break; } diff --git a/src/objnam.c b/src/objnam.c index 5db7e6212..237795c90 100644 --- a/src/objnam.c +++ b/src/objnam.c @@ -2897,13 +2897,19 @@ int xtra_prob; /* to force 0% random generation items to also be considered */ int i, n = 0; short validobjs[NUM_OBJECTS]; register const char *zn; - int prob, maxprob = 0; + int lo, hi, prob, maxprob = 0; if (!name || !*name) return STRANGE_OBJECT; - memset((genericptr_t) validobjs, 0, sizeof validobjs); - + (void) memset((genericptr_t) validobjs, 0, sizeof validobjs); + if (oclass) { + lo = g.bases[(uchar) oclass]; + hi = g.bases[(uchar) oclass + 1] - 1; + } else { + lo = STRANGE_OBJECT + 1; + hi = NUM_OBJECTS - 1; + } /* FIXME: * When this spans classes (the !oclass case), the item * probabilities are not very useful because they don't take @@ -2912,9 +2918,7 @@ int xtra_prob; /* to force 0% random generation items to also be considered */ * "blank" would have 10/11 chance to yield a blook even though * scrolls are supposed to be much more common than books.] */ - for (i = oclass ? g.bases[(int) oclass] : STRANGE_OBJECT + 1; - i < NUM_OBJECTS && (!oclass || objects[i].oc_class == oclass); - ++i) { + for (i = lo; i <= hi; ++i) { /* don't match extra descriptions (w/o real name) */ if ((zn = OBJ_NAME(objects[i])) == 0) continue; @@ -3840,9 +3844,12 @@ struct obj *no_wish; } if (((typ = rnd_otyp_by_namedesc(actualn, oclass, 1)) != STRANGE_OBJECT) - || ((typ = rnd_otyp_by_namedesc(dn, oclass, 1)) != STRANGE_OBJECT) + || (dn != actualn + && (typ = rnd_otyp_by_namedesc(dn, oclass, 1)) != STRANGE_OBJECT) || ((typ = rnd_otyp_by_namedesc(un, oclass, 1)) != STRANGE_OBJECT) - || ((typ = rnd_otyp_by_namedesc(origbp, oclass, 1)) != STRANGE_OBJECT)) + || (origbp != actualn + && ((typ = rnd_otyp_by_namedesc(origbp, oclass, 1)) + != STRANGE_OBJECT))) goto typfnd; typ = 0;