diff --git a/include/decl.h b/include/decl.h index 82543e4ee..941b45a09 100644 --- a/include/decl.h +++ b/include/decl.h @@ -1056,6 +1056,7 @@ struct instance_globals { /* o_init.c */ short disco[NUM_OBJECTS]; + short oclass_prob_totals[MAXOCLASSES]; /* objname.c */ /* distantname used by distant_name() to pass extra information to diff --git a/include/extern.h b/include/extern.h index 3305405b6..6bf82cd25 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1741,6 +1741,7 @@ extern void consoletty_exit(void); /* ### o_init.c ### */ extern void init_objects(void); +extern void init_oclass_probs(void); extern void obj_shuffle_range(int, int *, int *); extern int find_skates(void); extern boolean objdescr_is(struct obj *, const char *); diff --git a/include/objects.h b/include/objects.h index ba95a626a..7018417d3 100644 --- a/include/objects.h +++ b/include/objects.h @@ -651,7 +651,7 @@ BOOTS("levitation boots", "snow boots", OBJECT(OBJ(name, stone), \ BITS(0, 0, spec, 0, mgc, spec, 0, 0, 0, \ HARDGEM(mohs), 0, P_NONE, metal), \ - power, RING_CLASS, 0, 0, 3, cost, 0, 0, 0, 0, 15, color,sn) + power, RING_CLASS, 1, 0, 3, cost, 0, 0, 0, 0, 15, color,sn) RING("adornment", "wooden", ADORNED, 100, 1, 1, 2, WOOD, HI_WOOD, RIN_ADORNMENT), RING("gain strength", "granite", diff --git a/src/decl.c b/src/decl.c index 796079961..3a7ee43f3 100644 --- a/src/decl.c +++ b/src/decl.c @@ -528,6 +528,7 @@ const struct instance_globals g_init = { /* o_init.c */ DUMMY, /* disco */ + DUMMY, /* oclass_prob_totals */ /* objname.c */ 0, /* distantname */ diff --git a/src/mkobj.c b/src/mkobj.c index c2cd6a652..6d7902b7f 100644 --- a/src/mkobj.c +++ b/src/mkobj.c @@ -206,7 +206,7 @@ mksobj_migr_to_species( struct obj * mkobj(int oclass, boolean artif) { - int tprob, i, prob = rnd(1000); + int tprob, i, prob; if (oclass == RANDOM_CLASS) { const struct icp *iprobs = Is_rogue_level(&u.uz) @@ -223,13 +223,16 @@ mkobj(int oclass, boolean artif) i = rnd_class(g.bases[SPBOOK_CLASS], SPE_BLANK_PAPER); oclass = SPBOOK_CLASS; /* for sanity check below */ } else { + prob = rnd(g.oclass_prob_totals[oclass]); i = g.bases[oclass]; while ((prob -= objects[i].oc_prob) > 0) ++i; } - if (objects[i].oc_class != oclass || !OBJ_NAME(objects[i])) - panic("probtype error, oclass=%d i=%d", (int) oclass, i); + if (objects[i].oc_class != oclass || !OBJ_NAME(objects[i])) { + impossible("probtype error, oclass=%d i=%d", (int) oclass, i); + i = g.bases[oclass]; + } return mksobj(i, TRUE, artif); } diff --git a/src/o_init.c b/src/o_init.c index 22dcab445..ef1fd6036 100644 --- a/src/o_init.c +++ b/src/o_init.c @@ -42,7 +42,7 @@ shuffle_tiles(void) static void setgemprobs(d_level* dlev) { - int j, first, lev; + int j, first, lev, sum = 0; if (dlev) lev = (ledger_no(dlev) > maxledgerno()) ? maxledgerno() @@ -62,6 +62,11 @@ setgemprobs(d_level* dlev) } for (j = first; j <= LAST_GEM; j++) objects[j].oc_prob = (171 + j - first) / (LAST_GEM + 1 - first); + + /* recompute GEM_CLASS total oc_prob - including rocks/stones */ + for (j = g.bases[GEM_CLASS]; j < g.bases[GEM_CLASS + 1]; j++) + sum += objects[j].oc_prob; + g.oclass_prob_totals[GEM_CLASS] = sum; } /* shuffle descriptions on objects o_low to o_high */ @@ -106,7 +111,7 @@ shuffle(int o_low, int o_high, boolean domaterial) void init_objects(void) { - int i, first, last, sum, prevoclass; + int i, first, last, prevoclass; char oclass; #ifdef TEXTCOLOR #define COPY_OBJ_DESCR(o_dst, o_src) \ @@ -167,17 +172,6 @@ init_objects(void) break; } } - checkprob: - sum = 0; - for (i = first; i < last; i++) - sum += objects[i].oc_prob; - if (sum == 0) { - for (i = first; i < last; i++) - objects[i].oc_prob = (1000 + i - first) / (last - first); - goto checkprob; - } - if (sum != 1000) - error("init-prob error for class %d (%d%%)", oclass, sum); first = last; prevoclass = (int) oclass; } @@ -207,6 +201,8 @@ init_objects(void) objects[i].oc_name_known = nmkn ? 0 : 1; } } + /* compute oclass_prob_totals */ + init_oclass_probs(); /* shuffle descriptions */ shuffle_all(); @@ -216,6 +212,33 @@ init_objects(void) objects[WAN_NOTHING].oc_dir = rn2(2) ? NODIR : IMMEDIATE; } +/* Compute the total probability of each object class. + * Assumes g.bases[] has already been set. */ +void +init_oclass_probs(void) +{ + int i; + short sum; + int oclass; + for (oclass = 0; oclass < MAXOCLASSES; ++oclass) { + sum = 0; + for (i = g.bases[oclass]; i < g.bases[oclass + 1]; ++i) { + sum += objects[i].oc_prob; + } + if (sum <= 0 && oclass != ILLOBJ_CLASS + && g.bases[oclass] != g.bases[oclass + 1]) { + impossible("zero or negative probability total for oclass %d", + oclass); + /* gracefully fail by setting all members of this class to 1 */ + for (i = g.bases[oclass]; i < g.bases[oclass + 1]; ++i) { + objects[i].oc_prob = 1; + sum++; + } + } + g.oclass_prob_totals[oclass] = sum; + } +} + /* retrieve the range of objects that otyp shares descriptions with */ void obj_shuffle_range( diff --git a/src/restore.c b/src/restore.c index 1afa82693..ddabdab32 100644 --- a/src/restore.c +++ b/src/restore.c @@ -527,7 +527,7 @@ restgamestate(NHFILE* nhfp, unsigned int* stuckid, unsigned int* steedid) if (nhfp->structlevel) mread(nhfp->fd, (genericptr_t) &uid, sizeof uid); - + if (SYSOPT_CHECK_SAVE_UID && uid != (unsigned long) getuid()) { /* strange ... */ /* for wizard mode, issue a reminder; for others, treat it @@ -582,7 +582,7 @@ restgamestate(NHFILE* nhfp, unsigned int* stuckid, unsigned int* steedid) if (nhfp->structlevel) mread(nhfp->fd, (genericptr_t) &u, sizeof(struct you)); g.youmonst.cham = u.mcham; - + if (nhfp->structlevel) mread(nhfp->fd, (genericptr_t) timebuf, 14); timebuf[14] = '\0'; @@ -692,7 +692,7 @@ restgamestate(NHFILE* nhfp, unsigned int* stuckid, unsigned int* steedid) } freefruitchn(g.ffruit); /* clean up fruit(s) made by initoptions() */ g.ffruit = loadfruitchn(nhfp); - + restnames(nhfp); restore_waterlevel(nhfp); restore_msghistory(nhfp); @@ -857,6 +857,7 @@ dorecover(NHFILE* nhfp) substitute_tiles(&u.uz); #endif max_rank_sz(); /* to recompute g.mrank_sz (botl.c) */ + init_oclass_probs(); /* recompute g.oclass_prob_totals[] */ /* take care of iron ball & chain */ for (otmp = fobj; otmp; otmp = otmp->nobj) if (otmp->owornmask) @@ -1078,7 +1079,7 @@ getlev(NHFILE* nhfp, int pid, xchar lev) g.doorindex = g.rooms[g.nroom - 1].fdoor + g.rooms[g.nroom - 1].doorct; else g.doorindex = 0; - + restore_timers(nhfp, RANGE_LEVEL, elapsed); restore_light_sources(nhfp); fmon = restmonchn(nhfp);