From 62a50413d35d42cd446d7228baee25fac97a3ab7 Mon Sep 17 00:00:00 2001 From: Alex Smith Date: Sat, 21 Mar 2026 05:05:48 +0000 Subject: [PATCH] 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). --- dat/wizhelp | 1 + include/extern.h | 1 + src/cmd.c | 4 ++++ src/wizcmds.c | 42 ++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 46 insertions(+), 2 deletions(-) diff --git a/dat/wizhelp b/dat/wizhelp index 88e1b3417..1945214b0 100644 --- a/dat/wizhelp +++ b/dat/wizhelp @@ -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 diff --git a/include/extern.h b/include/extern.h index 52358357e..998e7698c 100644 --- a/include/extern.h +++ b/include/extern.h @@ -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); diff --git a/src/cmd.c b/src/cmd.c index b10a017ba..b9cd4c799 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -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", diff --git a/src/wizcmds.c b/src/wizcmds.c index 31cb338cc..b045578b8 100644 --- a/src/wizcmds.c +++ b/src/wizcmds.c @@ -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 */