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].
This commit is contained in:
PatR
2020-04-19 04:18:22 -07:00
parent 8c744de8cd
commit 37ef5a2561
3 changed files with 42 additions and 15 deletions

View File

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

View File

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

View File

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