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

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
-----------------------------------
@@ -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
was next to it, it remained displayed if hero moved away
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

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 */
/* NetHack may be freely redistributed. See license for details. */
@@ -1072,7 +1072,7 @@ newhp(void)
hp += rnd(gu.urole.hpadv.inrnd);
if (gu.urace.hpadv.inrnd > 0)
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 */
u.ualign.type = aligns[flags.initalign].value;
u.ualign.record = gu.urole.initrecord;

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) Michael Allison, 2009. */
/* NetHack may be freely redistributed. See license for details. */
@@ -963,7 +963,7 @@ static const struct instance_globals_saved_m init_svm = {
/* dungeon.c */
UNDEFINED_PTR, /* mapseenchn */
/* decl.c */
1L, /* moves; misnamed turn counter */
0L, /* moves; misnamed turn counter */
{ UNDEFINED_VALUES } /* mvitals */
};

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) Derek S. Ray, 2015. */
/* NetHack may be freely redistributed. See license for details. */
@@ -1160,7 +1160,7 @@ mksobj(int otyp, boolean init, boolean artif)
otmp = newobj();
*otmp = cg.zeroobj;
otmp->age = svm.moves;
otmp->age = max(svm.moves, 1L);
otmp->o_id = next_ident();
otmp->quan = 1L;
otmp->oclass = let;
@@ -1341,7 +1341,7 @@ start_corpse_timeout(struct obj *body)
action = ROT_CORPSE; /* default action: rot away */
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)
when = rot_adjust;
else
@@ -2381,8 +2381,7 @@ obj_timer_checks(
/* mark the corpse as being on ice */
otmp->on_ice = 1;
debugpline3("%s is now on ice at <%d,%d>.", The(xname(otmp)), x,
y);
debugpline3("%s is now on ice at <%d,%d>.", The(xname(otmp)), x, y);
/* Adjust the time remaining */
tleft *= ROT_ICE_ADJUSTMENT;
restart_timer = TRUE;

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) Robert Patrick Rankin, 2017. */
/* NetHack may be freely redistributed. See license for details. */
@@ -617,6 +617,12 @@ u_init_role(void)
{
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) {
/* rn2(100) > 50 necessary for some choices because some
* random number generators are bad enough to seriously

View File

@@ -227,7 +227,7 @@ curses_character_input_dialog(
re-activate them now that input is being requested */
curses_got_input();
if (gi.invent || (svm.moves > 1)) {
if (svm.moves > 0) {
curses_get_window_size(MAP_WIN, &map_height, &map_width);
} else {
map_height = term_rows;
@@ -789,7 +789,7 @@ curses_display_nhmenu(
menu_determine_pages(current_menu);
/* 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,
current_menu->height, CENTER);
} else { /* Display during-game menus on the right out of the way */

View File

@@ -69,7 +69,7 @@ curses_create_window(int wid, int width, int height, orient orientation)
if ((orientation == UP) || (orientation == DOWN) ||
(orientation == LEFT) || (orientation == RIGHT)) {
if (gi.invent || (svm.moves > 1)) {
if (svm.moves > 0) {
map_border = curses_window_has_border(MAP_WIN);
curses_get_window_xy(MAP_WIN, &mapx, &mapy);
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);
break;
case UP:
if (gi.invent || (svm.moves > 1)) {
if (svm.moves > 0) {
startx = (mapw / 2) - (width / 2) + mapx + mapb_offset;
} else {
startx = 0;
@@ -113,7 +113,7 @@ curses_create_window(int wid, int width, int height, orient orientation)
starty = mapy + mapb_offset;
break;
case DOWN:
if (gi.invent || (svm.moves > 1)) {
if (svm.moves > 0) {
startx = (mapw / 2) - (width / 2) + mapx + mapb_offset;
} else {
startx = 0;
@@ -129,7 +129,7 @@ curses_create_window(int wid, int width, int height, orient orientation)
starty = term_rows - height;
break;
case RIGHT:
if (gi.invent || (svm.moves > 1)) {
if (svm.moves > 0) {
startx = (mapw + mapx + (mapb_offset * 2)) - width;
} else {
startx = term_cols - width;
@@ -222,7 +222,7 @@ curses_refresh_nethack_windows(void)
return;
}
if ((svm.moves <= 1) && !gi.invent) {
if (svm.moves == 0) {
/* Main windows not yet displayed; refresh base window instead */
touchwin(stdscr);
refresh();