From 3f837939bad97ec75d95f08da7e21d5b87501847 Mon Sep 17 00:00:00 2001 From: Alex Smith Date: Fri, 22 May 2026 06:02:00 +0100 Subject: [PATCH] Change the MAX_REROLLS option to be MAX_REROLL_RATE Having a hard cap on the number of rerolls doesn't help save CPU usage from excessive rerolling, because if the cap is set low enough to keep the CPU usage reasonable it isn't high enough for players to actually use the feature. Instead, allow capping the number of rerolls per second. (Sensible values seem to be in the 5-10 range.) If the player attempts more rerolls than this, show a paranoid confirmation prompt: the need to type the answer to the prompt will slow a human user down (and if the prompt is filled in too quickly, it will simply just be shown again, preventing attempts to use automation to skip the prompt). --- doc/fixes5-0-1.txt | 2 +- include/sys.h | 2 +- src/allmain.c | 36 ++++++++++++++++++++++++++++++++++++ src/cfgfiles.c | 10 +++++----- src/invent.c | 28 ++-------------------------- src/sys.c | 2 +- sys/unix/sysconf | 6 +++--- 7 files changed, 49 insertions(+), 37 deletions(-) diff --git a/doc/fixes5-0-1.txt b/doc/fixes5-0-1.txt index 564a6f4bf..5a37e9964 100644 --- a/doc/fixes5-0-1.txt +++ b/doc/fixes5-0-1.txt @@ -141,7 +141,7 @@ tty: allow custom glyph colors if they're basic 16 nethack colors General New Features -------------------- -sysconf option MAX_REROLLS to limit number of rerolls +sysconf option MAX_REROLL_RATE to limit rate at which rerolls are performed Platform- and/or Interface-Specific New Features diff --git a/include/sys.h b/include/sys.h index 6ad569dce..da060cad7 100644 --- a/include/sys.h +++ b/include/sys.h @@ -25,7 +25,7 @@ struct sysopt_s { * -1: getenv() didn't find a value for DEBUGFILES. */ int maxplayers; - int maxrerolls; + int maxrerollrate; int seduce; int check_save_uid; /* restoring savefile checks UID? */ int check_plname; /* use plname for checking wizards/explorers/shellers */ diff --git a/src/allmain.c b/src/allmain.c index 5c573da4b..90c4932ad 100644 --- a/src/allmain.c +++ b/src/allmain.c @@ -769,6 +769,17 @@ newgame(void) { int i; +#ifdef SYSCF + time_t last_reroll_time; + time_t cur_reroll_time; + int rerolls_this_second = 0; +# if defined(BSD) && !defined(POSIX_TYPES) +# define GET_REROLL_TIME(t) (void) time((long *) t); +# else +# define GET_REROLL_TIME(t) (void) time(t); +# endif +#endif /* defined(SYSCF) */ + /* make sure welcome messages are given before noticing monsters */ notice_mon_off(); disp.botlx = TRUE; @@ -819,7 +830,32 @@ newgame(void) docrt(); flush_screen(1); bot(); + +#ifdef SYSCF + GET_REROLL_TIME(&last_reroll_time); +#endif + while (u.uroleplay.reroll && reroll_menu()) { +#ifdef SYSCF + if (sysopt.maxrerollrate > 0) { + check_reroll_time: + GET_REROLL_TIME(&cur_reroll_time); + + if (last_reroll_time != cur_reroll_time) { + last_reroll_time = cur_reroll_time; + rerolls_this_second = 1; + } else { + if (rerolls_this_second >= sysopt.maxrerollrate) { + if (!paranoid_query(TRUE, "Continue rerolling?")) + break; + goto check_reroll_time; + } + ++rerolls_this_second; + } + } +#endif + + ++u.uroleplay.numrerolls; u_init_inventory_attrs(); bot(); } diff --git a/src/cfgfiles.c b/src/cfgfiles.c index 6e870169e..438c65478 100644 --- a/src/cfgfiles.c +++ b/src/cfgfiles.c @@ -74,7 +74,7 @@ staticfn boolean cnf_line_CHECK_PLNAME(char *); staticfn boolean cnf_line_SEDUCE(char *); staticfn boolean cnf_line_HIDEUSAGE(char *); staticfn boolean cnf_line_MAXPLAYERS(char *); -staticfn boolean cnf_line_MAX_REROLLS(char *); +staticfn boolean cnf_line_MAX_REROLL_RATE(char *); staticfn boolean cnf_line_PERSMAX(char *); staticfn boolean cnf_line_PERS_IS_UID(char *); staticfn boolean cnf_line_ENTRYMAX(char *); @@ -970,15 +970,15 @@ cnf_line_MAXPLAYERS(char *bufp) } staticfn boolean -cnf_line_MAX_REROLLS(char *bufp) +cnf_line_MAX_REROLL_RATE(char *bufp) { int n = atoi(bufp); if (n < 0 || n > 255) { - config_error_add("Illegal value in MAX_REROLLS (maximum is 255)"); + config_error_add("Illegal value in MAX_REROLL_RATE (maximum is 255)"); n = 10; } - sysopt.maxrerolls = n; + sysopt.maxrerollrate = n; return TRUE; } @@ -1363,7 +1363,7 @@ static const struct match_config_line_stmt { CNFL_S(SEDUCE, 6), CNFL_S(HIDEUSAGE, 9), CNFL_S(MAXPLAYERS, 10), - CNFL_S(MAX_REROLLS, 10), + CNFL_S(MAX_REROLL_RATE, 10), CNFL_S(PERSMAX, 7), CNFL_S(PERS_IS_UID, 11), CNFL_S(ENTRYMAX, 8), diff --git a/src/invent.c b/src/invent.c index a1ea94863..4c7f61bff 100644 --- a/src/invent.c +++ b/src/invent.c @@ -26,7 +26,6 @@ staticfn int ckvalidcat(struct obj *); staticfn int ckunpaid(struct obj *); staticfn char *safeq_xprname(struct obj *); staticfn char *safeq_shortxprname(struct obj *); -staticfn boolean hit_reroll_limit(int); staticfn char display_pickinv(const char *, const char *, const char *, boolean, boolean, long *); staticfn char display_used_invlets(char); @@ -2541,16 +2540,6 @@ askchain( return cnt; } -staticfn boolean -hit_reroll_limit(int curr) -{ -#ifdef SYSCF - if (sysopt.maxrerolls && curr >= (sysopt.maxrerolls-1)) - return TRUE; -#endif /*SYSCF*/ - return FALSE; -} - /* The menu for rerolling attributes and inventory. This is similar to the other inventory menus, but simpler to help it fit on @@ -2580,14 +2569,6 @@ reroll_menu(void) MENU_ITEMFLAGS_NONE); any.a_char = 'y'; Strcpy(buf, "reroll another character"); -#ifdef SYSCF - if (sysopt.maxrerolls > 0) { - char *bp = eos(buf); - - Sprintf(bp, " (%li/%i)", - u.uroleplay.numrerolls+1, sysopt.maxrerolls); - } -#endif /*SYSCF*/ add_menu(win, &nul_glyphinfo, &any, flags.lootabc ? 0 : 'r', 0, ATR_NONE, NO_COLOR, buf, MENU_ITEMFLAGS_NONE); any.a_char = 0; @@ -2618,7 +2599,7 @@ reroll_menu(void) if (select_menu(win, PICK_ONE, &pick_list) > 0) { option = pick_list[0].item.a_char; free((genericptr_t) pick_list); - } else if (!hit_reroll_limit(u.uroleplay.numrerolls)) { + } else { /* user closed the menu without selecting; unclear what their choice is here so ask again; but (e.g. for hangup handling) stop asking if the user cancels out again */ @@ -2626,12 +2607,7 @@ reroll_menu(void) } destroy_nhwindow(win); - if (option == 'y') { - ++u.uroleplay.numrerolls; - if (!hit_reroll_limit(u.uroleplay.numrerolls)) - return TRUE; - } - return FALSE; + return option == 'y'; } /* diff --git a/src/sys.c b/src/sys.c index a5a0e87e0..55e93eb02 100644 --- a/src/sys.c +++ b/src/sys.c @@ -59,7 +59,7 @@ sys_early_init(void) sysopt.genericusers = (char *) 0; sysopt.msghandler = (char *) 0; sysopt.maxplayers = 0; /* XXX eventually replace MAX_NR_OF_PLAYERS */ - sysopt.maxrerolls = 0; + sysopt.maxrerollrate = 0; sysopt.bones_pools = 0; sysopt.livelog = LL_NONE; diff --git a/sys/unix/sysconf b/sys/unix/sysconf index a8b136410..2d9676601 100644 --- a/sys/unix/sysconf +++ b/sys/unix/sysconf @@ -55,9 +55,9 @@ GENERICUSERS=play player game games nethack nethacker ec2-user # letter and "lock" (eg. alock, block, ...) MAXPLAYERS=10 -# Limit the number of rerolls -# Default is 0 (meaning infinite), valid values are 0-255 -MAX_REROLLS=0 +# Limit the number of rerolls per second when using the reroll option. +# 0 means that there is no limit on how quickly the user can reroll. +MAX_REROLL_RATE=0 # If not null, added to string "To get local support, " in the support # information help.