github issue #1275: curses init vs pauper

Reported by ars3niy, the curses interface could behave strangely on
the first turn if the 'pauper' option/conduct was specified.

There isn't any definitive flag indicating whether or not the game
has started.  Since 'moves' has traditionally been initialized to 1
rather than to 0, there were several instances of
|  if (moves <= 1 && invent != NULL)
being used to determine the starting state on the assumption that
once hero has inventory, the game has begun.  Introduction of the
'pauper' option made the test for non-Null invent become unreliable.
For paupers, the program would behave as if the game hadn't started
yet until the player finally made a time-consuming move.

This changes compile-time initialization of 'moves' from 1 to 0,
then sets it to 1 when initial inventory would be bestowed (even
when 'pauper' inhibits that).  That's probably not the best place
for it, but testing for 'moves==0' now should produce an identical
effect as 'moves<=1 && invent!=NULL' used to accomplish.

It would have been much simpler just to give paupers 1 gold piece,
or perhaps one rock, in place of usual starting gear so that their
initial inventory wouldn't be empty, but the moves+invent way of
checking for start-of-play has always bothered me.

Should 'pauper' be preventing 'nethack -X' from giving its starting
wand of wishing?  Conducts and explore mode don't really overlap so
maybe it doesn't matter.

Fixes #1275
This commit is contained in:
PatR
2024-08-31 14:08:04 -07:00
parent 8e85561725
commit 0ce2439e82
7 changed files with 26 additions and 18 deletions
+4 -1
View File
@@ -1,4 +1,4 @@
NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.1464 $ $NHDT-Date: 1723945837 2024/08/18 01:50:37 $ NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.1471 $ $NHDT-Date: 1725138479 2024/08/31 21:07:59 $
General Fixes and Modified Features General Fixes and Modified Features
----------------------------------- -----------------------------------
@@ -2021,6 +2021,9 @@ having #terrain display gas cloud regions as if they were traps didn't work
when a monster within a gas cloud was displayed on the map because the hero when a monster within a gas cloud was displayed on the map because the hero
was next to it, it remained displayed if hero moved away was next to it, it remained displayed if hero moved away
eating a pyrolisk egg on the floor triggered an "object lost" panic eating a pyrolisk egg on the floor triggered an "object lost" panic
core object creation and the curses interface's window handling both became
confused by the 'pauper' option/conduct because they assumed that invent
being Null meant that the game hadn't started yet
Fixes to 3.7.0-x Platform and/or Interface Problems Exposed Via git Repository Fixes to 3.7.0-x Platform and/or Interface Problems Exposed Via git Repository
+2 -2
View File
@@ -1,4 +1,4 @@
/* NetHack 3.7 attrib.c $NHDT-Date: 1651908297 2022/05/07 07:24:57 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.86 $ */ /* NetHack 3.7 attrib.c $NHDT-Date: 1725138479 2024/08/31 21:07:59 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.127 $ */
/* Copyright 1988, 1989, 1990, 1992, M. Stephenson */ /* Copyright 1988, 1989, 1990, 1992, M. Stephenson */
/* NetHack may be freely redistributed. See license for details. */ /* NetHack may be freely redistributed. See license for details. */
@@ -1072,7 +1072,7 @@ newhp(void)
hp += rnd(gu.urole.hpadv.inrnd); hp += rnd(gu.urole.hpadv.inrnd);
if (gu.urace.hpadv.inrnd > 0) if (gu.urace.hpadv.inrnd > 0)
hp += rnd(gu.urace.hpadv.inrnd); hp += rnd(gu.urace.hpadv.inrnd);
if (svm.moves <= 1L) { /* initial hero; skip for polyself to new man */ if (svm.moves == 0) { /* initial hero; skip for polyself to new man */
/* Initialize alignment stuff */ /* Initialize alignment stuff */
u.ualign.type = aligns[flags.initalign].value; u.ualign.type = aligns[flags.initalign].value;
u.ualign.record = gu.urole.initrecord; u.ualign.record = gu.urole.initrecord;
+2 -2
View File
@@ -1,4 +1,4 @@
/* NetHack 3.7 decl.c $NHDT-Date: 1720074480 2024/07/04 06:28:00 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.334 $ */ /* NetHack 3.7 decl.c $NHDT-Date: 1725138480 2024/08/31 21:08:00 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.337 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Michael Allison, 2009. */ /*-Copyright (c) Michael Allison, 2009. */
/* NetHack may be freely redistributed. See license for details. */ /* NetHack may be freely redistributed. See license for details. */
@@ -963,7 +963,7 @@ static const struct instance_globals_saved_m init_svm = {
/* dungeon.c */ /* dungeon.c */
UNDEFINED_PTR, /* mapseenchn */ UNDEFINED_PTR, /* mapseenchn */
/* decl.c */ /* decl.c */
1L, /* moves; misnamed turn counter */ 0L, /* moves; misnamed turn counter */
{ UNDEFINED_VALUES } /* mvitals */ { UNDEFINED_VALUES } /* mvitals */
}; };
+4 -5
View File
@@ -1,4 +1,4 @@
/* NetHack 3.7 mkobj.c $NHDT-Date: 1718999849 2024/06/21 19:57:29 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.299 $ */ /* NetHack 3.7 mkobj.c $NHDT-Date: 1725138481 2024/08/31 21:08:01 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.304 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Derek S. Ray, 2015. */ /*-Copyright (c) Derek S. Ray, 2015. */
/* NetHack may be freely redistributed. See license for details. */ /* NetHack may be freely redistributed. See license for details. */
@@ -1160,7 +1160,7 @@ mksobj(int otyp, boolean init, boolean artif)
otmp = newobj(); otmp = newobj();
*otmp = cg.zeroobj; *otmp = cg.zeroobj;
otmp->age = svm.moves; otmp->age = max(svm.moves, 1L);
otmp->o_id = next_ident(); otmp->o_id = next_ident();
otmp->quan = 1L; otmp->quan = 1L;
otmp->oclass = let; otmp->oclass = let;
@@ -1341,7 +1341,7 @@ start_corpse_timeout(struct obj *body)
action = ROT_CORPSE; /* default action: rot away */ action = ROT_CORPSE; /* default action: rot away */
rot_adjust = gi.in_mklev ? 25 : 10; /* give some variation */ rot_adjust = gi.in_mklev ? 25 : 10; /* give some variation */
age = svm.moves - body->age; age = max(svm.moves, 1) - body->age;
if (age > ROT_AGE) if (age > ROT_AGE)
when = rot_adjust; when = rot_adjust;
else else
@@ -2381,8 +2381,7 @@ obj_timer_checks(
/* mark the corpse as being on ice */ /* mark the corpse as being on ice */
otmp->on_ice = 1; otmp->on_ice = 1;
debugpline3("%s is now on ice at <%d,%d>.", The(xname(otmp)), x, debugpline3("%s is now on ice at <%d,%d>.", The(xname(otmp)), x, y);
y);
/* Adjust the time remaining */ /* Adjust the time remaining */
tleft *= ROT_ICE_ADJUSTMENT; tleft *= ROT_ICE_ADJUSTMENT;
restart_timer = TRUE; restart_timer = TRUE;
+7 -1
View File
@@ -1,4 +1,4 @@
/* NetHack 3.7 u_init.c $NHDT-Date: 1711165379 2024/03/23 03:42:59 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.106 $ */ /* NetHack 3.7 u_init.c $NHDT-Date: 1725138482 2024/08/31 21:08:02 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.110 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Robert Patrick Rankin, 2017. */ /*-Copyright (c) Robert Patrick Rankin, 2017. */
/* NetHack may be freely redistributed. See license for details. */ /* NetHack may be freely redistributed. See license for details. */
@@ -617,6 +617,12 @@ u_init_role(void)
{ {
int i; int i;
/* the program used to check moves<=1 && invent==NULL do decide whether
a new game has started, but due to the 'pauper' option/conduct, can't
rely on invent becoming non-Null anymore; instead, initialize moves
to 0 instead of 1 and then set it to 1 here, where invent init occurs */
svm.moves = 1L;
switch (Role_switch) { switch (Role_switch) {
/* rn2(100) > 50 necessary for some choices because some /* rn2(100) > 50 necessary for some choices because some
* random number generators are bad enough to seriously * random number generators are bad enough to seriously
+2 -2
View File
@@ -227,7 +227,7 @@ curses_character_input_dialog(
re-activate them now that input is being requested */ re-activate them now that input is being requested */
curses_got_input(); curses_got_input();
if (gi.invent || (svm.moves > 1)) { if (svm.moves > 0) {
curses_get_window_size(MAP_WIN, &map_height, &map_width); curses_get_window_size(MAP_WIN, &map_height, &map_width);
} else { } else {
map_height = term_rows; map_height = term_rows;
@@ -789,7 +789,7 @@ curses_display_nhmenu(
menu_determine_pages(current_menu); menu_determine_pages(current_menu);
/* Display pre and post-game menus centered */ /* Display pre and post-game menus centered */
if ((svm.moves <= 1 && !gi.invent) || program_state.gameover) { if (svm.moves == 0 || program_state.gameover) {
win = curses_create_window(wid, current_menu->width, win = curses_create_window(wid, current_menu->width,
current_menu->height, CENTER); current_menu->height, CENTER);
} else { /* Display during-game menus on the right out of the way */ } else { /* Display during-game menus on the right out of the way */
+5 -5
View File
@@ -69,7 +69,7 @@ curses_create_window(int wid, int width, int height, orient orientation)
if ((orientation == UP) || (orientation == DOWN) || if ((orientation == UP) || (orientation == DOWN) ||
(orientation == LEFT) || (orientation == RIGHT)) { (orientation == LEFT) || (orientation == RIGHT)) {
if (gi.invent || (svm.moves > 1)) { if (svm.moves > 0) {
map_border = curses_window_has_border(MAP_WIN); map_border = curses_window_has_border(MAP_WIN);
curses_get_window_xy(MAP_WIN, &mapx, &mapy); curses_get_window_xy(MAP_WIN, &mapx, &mapy);
curses_get_window_size(MAP_WIN, &maph, &mapw); curses_get_window_size(MAP_WIN, &maph, &mapw);
@@ -104,7 +104,7 @@ curses_create_window(int wid, int width, int height, orient orientation)
starty = (term_rows / 2) - (height / 2); starty = (term_rows / 2) - (height / 2);
break; break;
case UP: case UP:
if (gi.invent || (svm.moves > 1)) { if (svm.moves > 0) {
startx = (mapw / 2) - (width / 2) + mapx + mapb_offset; startx = (mapw / 2) - (width / 2) + mapx + mapb_offset;
} else { } else {
startx = 0; startx = 0;
@@ -113,7 +113,7 @@ curses_create_window(int wid, int width, int height, orient orientation)
starty = mapy + mapb_offset; starty = mapy + mapb_offset;
break; break;
case DOWN: case DOWN:
if (gi.invent || (svm.moves > 1)) { if (svm.moves > 0) {
startx = (mapw / 2) - (width / 2) + mapx + mapb_offset; startx = (mapw / 2) - (width / 2) + mapx + mapb_offset;
} else { } else {
startx = 0; startx = 0;
@@ -129,7 +129,7 @@ curses_create_window(int wid, int width, int height, orient orientation)
starty = term_rows - height; starty = term_rows - height;
break; break;
case RIGHT: case RIGHT:
if (gi.invent || (svm.moves > 1)) { if (svm.moves > 0) {
startx = (mapw + mapx + (mapb_offset * 2)) - width; startx = (mapw + mapx + (mapb_offset * 2)) - width;
} else { } else {
startx = term_cols - width; startx = term_cols - width;
@@ -222,7 +222,7 @@ curses_refresh_nethack_windows(void)
return; return;
} }
if ((svm.moves <= 1) && !gi.invent) { if (svm.moves == 0) {
/* Main windows not yet displayed; refresh base window instead */ /* Main windows not yet displayed; refresh base window instead */
touchwin(stdscr); touchwin(stdscr);
refresh(); refresh();