New debug command #wizobjprobs for listing item probabilities

As of the change to allow for item probabilities that don't add up
to 1000, it's become a little difficult to figure out the exact
probabilities from the source code, which makes it hard to balance
item generation. Adding a tool to list the probabilities helps.

Part of the problem is that changing an item's probability without
balancing it elsewhere is usually wrong: doing that would in effect
take the probability equally from (or add the probability equally
to) all other items in the class, which might break the balancing
of those items due to the probability change.

As such, it is usually better to make an intentional decision about
which items should be less and which items should be more likely to
generate, then change them in a balancing way (meaning that the
probabilities of objects that weren't intentionally changed remain
unchanged). Doing a complex such change makes arithmetic errors
fairly likely, though, so it's useful to have a command that verifies
that it's been done correctly.

This command is primarily intended as a development aid, so it's
included only in debug builds and pre-release builds (the same as
other similar commands like #wizmondiff).
This commit is contained in:
Alex Smith
2026-03-21 05:05:48 +00:00
parent 26fd5e7d73
commit 62a50413d3
4 changed files with 46 additions and 2 deletions

View File

@@ -30,6 +30,7 @@ Debug-Mode Quick Reference:
#wizloadlua == load and execute a lua script
#wizmakemap == recreate the current dungeon level
#wizmondiff == [Opt] check for discrepancies in monster difficulty ratings
#wizobjprobs == [Opt] list actual probabilities of item generation
#wizrumorcheck == validate rumor indexing; also show first, second, and last
random engravings, epitaphs, and hallucinatory monsters
#wizseenv == show map locations' seen vectors

View File

@@ -3854,6 +3854,7 @@ extern void wizcustom_callback(winid win, int glyphnum, char *id);
#if (NH_DEVEL_STATUS != NH_STATUS_RELEASED) || defined(DEBUG)
extern int wiz_display_macros(void);
extern int wiz_mon_diff(void);
extern int wiz_objprobs(void);
#endif
extern void sanity_check(void);

View File

@@ -1956,6 +1956,10 @@ struct ext_func_tab extcmdlist[] = {
wiz_load_splua, IFBURIED | WIZMODECMD | NOFUZZERCMD, NULL },
{ '\0', "wizloadlua", "load and execute a lua script",
wiz_load_lua, IFBURIED | WIZMODECMD | NOFUZZERCMD, NULL },
#if (NH_DEVEL_STATUS != NH_STATUS_RELEASED) || defined(DEBUG)
{ '\0', "wizobjprobs", "list object generation probabilities",
wiz_objprobs, IFBURIED | WIZMODECMD, NULL },
#endif
{ '\0', "wizmakemap", "recreate the current level",
wiz_makemap, IFBURIED | WIZMODECMD, NULL },
{ C('f'), "wizmap", "map the level",

View File

@@ -1776,9 +1776,7 @@ wiz_display_macros(void)
destroy_nhwindow(win);
return ECMD_OK;
}
#endif /* (NH_DEVEL_STATUS != NH_STATUS_RELEASED) || defined(DEBUG) */
#if (NH_DEVEL_STATUS != NH_STATUS_RELEASED) || defined(DEBUG)
/* the #wizmondiff command */
int
wiz_mon_diff(void)
@@ -1820,6 +1818,46 @@ wiz_mon_diff(void)
destroy_nhwindow(win);
return ECMD_OK;
}
/* the #wizobjprobs command */
int
wiz_objprobs(void)
{
int win;
char buf[BUFSZ];
int probsum[MAXOCLASSES];
int otyp;
int oclass = objects[FIRST_OBJECT].oc_class;
memset(probsum, 0, sizeof probsum);
for (otyp = FIRST_OBJECT; otyp < NUM_OBJECTS; otyp++) {
probsum[(int) objects[otyp].oc_class] += objects[otyp].oc_prob;
}
win = create_nhwindow(NHW_TEXT);
for (otyp = FIRST_OBJECT; otyp < NUM_OBJECTS; otyp++) {
/* placeholders for extra descriptions aren't generatable objects */
if (!OBJ_NAME(objects[otyp]))
continue;
if ((int) objects[otyp].oc_class != oclass) {
putstr(win, 0, "");
}
oclass = objects[otyp].oc_class;
Snprintf(buf, sizeof buf, "%4d / %4d (%6.2f%%): %s",
objects[otyp].oc_prob,
probsum[oclass],
(float) objects[otyp].oc_prob * 100.f /
(float) probsum[oclass],
OBJ_NAME(objects[otyp]));
putstr(win, 0, buf);
}
display_nhwindow(win, FALSE);
destroy_nhwindow(win);
return ECMD_OK;
}
#endif /* (NH_DEVEL_STATUS != NH_STATUS_RELEASED) || defined(DEBUG) */
/* #migratemons command */