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
+1 -1
View File
@@ -713,7 +713,7 @@ struct instance_globals {
const char *hname; /* name of the game (argv[0] of main) */ const char *hname; /* name of the game (argv[0] of main) */
int hackpid; /* current process id */ int hackpid; /* current process id */
char chosen_windowtype[WINTYPELEN]; char chosen_windowtype[WINTYPELEN];
int bases[MAXOCLASSES]; int bases[MAXOCLASSES + 1];
int multi; int multi;
const char *multi_reason; const char *multi_reason;
int nroom; int nroom;
+26 -6
View File
@@ -108,8 +108,8 @@ boolean domaterial;
void void
init_objects() init_objects()
{ {
register int i, first, last, sum; int i, first, last, sum;
register char oclass; char oclass, prevoclass;
#ifdef TEXTCOLOR #ifdef TEXTCOLOR
#define COPY_OBJ_DESCR(o_dst, o_src) \ #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 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. /* bug fix to prevent "initialization error" abort on Intel Xenix.
* reported by mikew@semike * reported by mikew@semike
*/ */
for (i = 0; i < MAXOCLASSES; i++) for (i = 0; i <= MAXOCLASSES; i++)
g.bases[i] = 0; g.bases[i] = 0;
/* initialize object descriptions */ /* initialize object descriptions */
for (i = 0; i < NUM_OBJECTS; i++) 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, /* init base; if probs given check that they add up to 1000,
otherwise compute probs */ otherwise compute probs */
first = 0; first = 0;
prevoclass = -1;
while (first < NUM_OBJECTS) { while (first < NUM_OBJECTS) {
oclass = objects[first].oc_class; 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; last = first + 1;
while (last < NUM_OBJECTS && objects[last].oc_class == oclass) while (last < NUM_OBJECTS && objects[last].oc_class == oclass)
last++; last++;
@@ -170,7 +181,18 @@ init_objects()
if (sum != 1000) if (sum != 1000)
error("init-prob error for class %d (%d%%)", oclass, sum); error("init-prob error for class %d (%d%%)", oclass, sum);
first = last; 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 descriptions */
shuffle_all(); shuffle_all();
#ifdef USE_TILES #ifdef USE_TILES
@@ -221,9 +243,7 @@ int *lo_p, *hi_p; /* output: range that item belongs among */
case VENOM_CLASS: case VENOM_CLASS:
/* entire class */ /* entire class */
*lo_p = g.bases[ocls]; *lo_p = g.bases[ocls];
for (i = *lo_p; objects[i].oc_class == ocls; i++) *hi_p = g.bases[ocls + 1] - 1;
continue;
*hi_p = i - 1;
break; break;
} }
+15 -8
View File
@@ -2897,13 +2897,19 @@ int xtra_prob; /* to force 0% random generation items to also be considered */
int i, n = 0; int i, n = 0;
short validobjs[NUM_OBJECTS]; short validobjs[NUM_OBJECTS];
register const char *zn; register const char *zn;
int prob, maxprob = 0; int lo, hi, prob, maxprob = 0;
if (!name || !*name) if (!name || !*name)
return STRANGE_OBJECT; 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: /* FIXME:
* When this spans classes (the !oclass case), the item * When this spans classes (the !oclass case), the item
* probabilities are not very useful because they don't take * 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 * "blank" would have 10/11 chance to yield a blook even though
* scrolls are supposed to be much more common than books.] * scrolls are supposed to be much more common than books.]
*/ */
for (i = oclass ? g.bases[(int) oclass] : STRANGE_OBJECT + 1; for (i = lo; i <= hi; ++i) {
i < NUM_OBJECTS && (!oclass || objects[i].oc_class == oclass);
++i) {
/* don't match extra descriptions (w/o real name) */ /* don't match extra descriptions (w/o real name) */
if ((zn = OBJ_NAME(objects[i])) == 0) if ((zn = OBJ_NAME(objects[i])) == 0)
continue; continue;
@@ -3840,9 +3844,12 @@ struct obj *no_wish;
} }
if (((typ = rnd_otyp_by_namedesc(actualn, oclass, 1)) != STRANGE_OBJECT) 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(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; goto typfnd;
typ = 0; typ = 0;